session.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. use connection::{PlainConnection, CipherConnection};
  2. use keys::PrivateKeys;
  3. use librespot_protocol as protocol;
  4. use util;
  5. use crypto::sha1::Sha1;
  6. use crypto::digest::Digest;
  7. use protobuf::*;
  8. use rand::thread_rng;
  9. pub struct Config {
  10. pub application_key: Vec<u8>,
  11. pub user_agent: String,
  12. pub device_id: String,
  13. }
  14. pub struct Session {
  15. config: Config,
  16. connection: CipherConnection,
  17. }
  18. impl Session {
  19. pub fn new(mut config: Config) -> Session {
  20. config.device_id = {
  21. let mut h = Sha1::new();
  22. h.input_str(&config.device_id);
  23. h.result_str()
  24. };
  25. let keys = PrivateKeys::new();
  26. let mut connection = PlainConnection::connect().unwrap();
  27. let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
  28. build_info => {
  29. product: protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY_EMBEDDED,
  30. platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
  31. version: 0x10800000000,
  32. },
  33. /*
  34. fingerprints_supported => [
  35. protocol::keyexchange::Fingerprint::FINGERPRINT_GRAIN
  36. ],
  37. */
  38. cryptosuites_supported => [
  39. protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
  40. //protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_RC4_SHA1_HMAC
  41. ],
  42. /*
  43. powschemes_supported => [
  44. protocol::keyexchange::Powscheme::POW_HASH_CASH
  45. ],
  46. */
  47. login_crypto_hello.diffie_hellman => {
  48. gc: keys.public_key(),
  49. server_keys_known: 1,
  50. },
  51. client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
  52. padding: vec![0x1e],
  53. feature_set => {
  54. autoupdate2: true,
  55. }
  56. });
  57. let init_client_packet =
  58. connection.send_packet_prefix(&[0,4], &request.write_to_bytes().unwrap()).unwrap();
  59. let init_server_packet =
  60. connection.recv_packet().unwrap();
  61. let response : protocol::keyexchange::APResponseMessage =
  62. parse_from_bytes(&init_server_packet[4..]).unwrap();
  63. protobuf_bind!(response, {
  64. challenge => {
  65. login_crypto_challenge.diffie_hellman => {
  66. gs: remote_key,
  67. }
  68. }
  69. });
  70. let shared_keys = keys.add_remote_key(remote_key, &init_client_packet, &init_server_packet);
  71. let packet = protobuf_init!(protocol::keyexchange::ClientResponsePlaintext::new(), {
  72. login_crypto_response.diffie_hellman => {
  73. hmac: shared_keys.challenge().to_vec()
  74. },
  75. pow_response => {},
  76. crypto_response => {},
  77. });
  78. connection.send_packet(&packet.write_to_bytes().unwrap()).unwrap();
  79. Session {
  80. config: config,
  81. connection: connection.setup_cipher(shared_keys)
  82. }
  83. }
  84. pub fn login(&mut self, username: String, password: String) {
  85. let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
  86. login_credentials => {
  87. username: username,
  88. typ: protocol::authentication::Type::AUTHENTICATION_USER_PASS,
  89. auth_data: password.into_bytes(),
  90. },
  91. system_info => {
  92. cpu_family: protocol::authentication::CpuFamily::CPU_UNKNOWN,
  93. os: protocol::authentication::Os::OS_UNKNOWN,
  94. system_information_string: "librespot".to_string(),
  95. device_id: self.config.device_id.clone()
  96. },
  97. version_string: util::version::version_string(),
  98. appkey => {
  99. version: self.config.application_key[0] as u32,
  100. devkey: self.config.application_key[0x1..0x81].to_vec(),
  101. signature: self.config.application_key[0x81..0x141].to_vec(),
  102. useragent: self.config.user_agent.clone(),
  103. callback_hash: vec![0; 20],
  104. }
  105. });
  106. self.connection.send_encrypted_packet(
  107. 0xab,
  108. &packet.write_to_bytes().unwrap()).unwrap();
  109. loop {
  110. let (cmd, data) = self.connection.recv_packet().unwrap();
  111. println!("{:x}", cmd);
  112. }
  113. }
  114. }