Răsfoiți Sursa

Move Session::connect to authentication.rs

Paul Lietar 9 ani în urmă
părinte
comite
327bb8477e
3 a modificat fișierele cu 113 adăugiri și 111 ștergeri
  1. 102 8
      src/authentication.rs
  2. 2 2
      src/discovery.rs
  3. 9 101
      src/session.rs

+ 102 - 8
src/authentication.rs

@@ -1,15 +1,19 @@
 use byteorder::{BigEndian, ByteOrder};
 use crypto;
 use crypto::aes;
+use crypto::digest::Digest;
+use crypto::hmac::Hmac;
+use crypto::mac::Mac;
 use crypto::pbkdf2::pbkdf2;
 use crypto::sha1::Sha1;
-use crypto::hmac::Hmac;
-use crypto::digest::Digest;
 use protobuf::{self, Message, ProtobufEnum};
-use std::io::{self, Read};
+use rand::thread_rng;
+use std::io::{self, Read, Write};
 use std::result::Result;
 use rustc_serialize::base64::FromBase64;
 
+use connection::{PlainConnection, CipherConnection};
+use diffie_hellman::DHLocalKeys;
 use librespot_protocol as protocol;
 use librespot_protocol::authentication::AuthenticationType;
 use session::Session;
@@ -40,11 +44,99 @@ fn read_bytes<R: Read>(stream: &mut R) -> io::Result<Vec<u8>> {
 }
 
 impl Session {
+    pub fn connect(&self) -> CipherConnection {
+        let local_keys = DHLocalKeys::random(&mut thread_rng());
+
+        let mut connection = PlainConnection::connect().unwrap();
+
+        let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
+            build_info => {
+                product: protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY_EMBEDDED,
+                platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
+                version: 0x10800000000,
+            },
+            /*
+            fingerprints_supported => [
+                protocol::keyexchange::Fingerprint::FINGERPRINT_GRAIN
+            ],
+            */
+            cryptosuites_supported => [
+                protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
+                //protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_RC4_SHA1_HMAC
+            ],
+            /*
+            powschemes_supported => [
+                protocol::keyexchange::Powscheme::POW_HASH_CASH
+            ],
+            */
+            login_crypto_hello.diffie_hellman => {
+                gc: local_keys.public_key(),
+                server_keys_known: 1,
+            },
+            client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
+            padding: vec![0x1e],
+            feature_set => {
+                autoupdate2: true,
+            }
+        });
+
+        let init_client_packet = connection.send_packet_prefix(&[0, 4],
+                                                               &request.write_to_bytes().unwrap())
+                                           .unwrap();
+        let init_server_packet = connection.recv_packet().unwrap();
+
+        let response: protocol::keyexchange::APResponseMessage =
+            protobuf::parse_from_bytes(&init_server_packet[4..]).unwrap();
+
+        let remote_key = response.get_challenge()
+                                 .get_login_crypto_challenge()
+                                 .get_diffie_hellman()
+                                 .get_gs();
+
+        let shared_secret = local_keys.shared_secret(remote_key);
+        let (challenge, send_key, recv_key) = {
+            let mut data = Vec::with_capacity(0x64);
+            let mut mac = Hmac::new(Sha1::new(), &shared_secret);
+
+            for i in 1..6 {
+                mac.input(&init_client_packet);
+                mac.input(&init_server_packet);
+                mac.input(&[i]);
+                data.write(&mac.result().code()).unwrap();
+                mac.reset();
+            }
+
+            mac = Hmac::new(Sha1::new(), &data[..0x14]);
+            mac.input(&init_client_packet);
+            mac.input(&init_server_packet);
+
+            (mac.result().code().to_vec(),
+             data[0x14..0x34].to_vec(),
+             data[0x34..0x54].to_vec())
+        };
+
+        let packet = protobuf_init!(protocol::keyexchange::ClientResponsePlaintext::new(), {
+            login_crypto_response.diffie_hellman => {
+                hmac: challenge
+            },
+            pow_response => {},
+            crypto_response => {},
+        });
+
+
+        connection.send_packet(&packet.write_to_bytes().unwrap()).unwrap();
+
+        CipherConnection::new(connection.into_stream(),
+                              &send_key,
+                              &recv_key)
+    }
+
     fn login(&self,
              username: String,
              auth_data: Vec<u8>,
              typ: AuthenticationType)
              -> Result<(), ()> {
+
         let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
             login_credentials => {
                 username: username,
@@ -67,15 +159,17 @@ impl Session {
             }
         });
 
-        self.connect();
-        self.send_packet(0xab, &packet.write_to_bytes().unwrap()).unwrap();
-        let (cmd, data) = self.recv();
+        let mut connection = self.connect();
+        connection.send_packet(0xab, &packet.write_to_bytes().unwrap()).unwrap();
+        let (cmd, data) = connection.recv_packet().unwrap();
+
         match cmd {
             0xac => {
                 let welcome_data: protocol::authentication::APWelcome =
                     protobuf::parse_from_bytes(&data).unwrap();
-                self.0.data.write().unwrap().canonical_username =
-                    welcome_data.get_canonical_username().to_owned();
+
+                let username = welcome_data.get_canonical_username().to_owned();
+                self.authenticated(username, connection);
 
                 eprintln!("Authenticated !");
                 Ok(())

+ 2 - 2
src/discovery.rs

@@ -1,12 +1,12 @@
 use crypto;
 use crypto::mac::Mac;
 use crypto::digest::Digest;
-use zeroconf::DNSService;
-use tiny_http::{Method, Response, ResponseBox, Server};
 use num::BigUint;
 use url;
 use rand;
 use rustc_serialize::base64::{self, ToBase64, FromBase64};
+use tiny_http::{Method, Response, ResponseBox, Server};
+use zeroconf::DNSService;
 
 use session::Session;
 use diffie_hellman::{DH_GENERATOR, DH_PRIME};

+ 9 - 101
src/session.rs

@@ -1,27 +1,19 @@
 use crypto::digest::Digest;
-use crypto::mac::Mac;
 use crypto::sha1::Sha1;
-use crypto::hmac::Hmac;
 use eventual::Future;
-use protobuf::{self, Message};
-use rand::thread_rng;
 use std::io::Write;
 use std::path::PathBuf;
 use std::sync::{Mutex, RwLock, Arc, mpsc};
 
 use audio_key::{AudioKeyManager, AudioKey, AudioKeyError};
 use audio_file::{AudioFileManager, AudioFile};
-use connection::{self, PlainConnection, CipherConnection};
+use connection::{self, CipherConnection};
 use connection::PacketHandler;
-use diffie_hellman::DHLocalKeys;
-use librespot_protocol as protocol;
 use mercury::{MercuryManager, MercuryRequest, MercuryResponse};
 use metadata::{MetadataManager, MetadataRef, MetadataTrait};
 use stream::{StreamManager, StreamEvent};
 use util::{SpotifyId, FileId, mkdir_existing};
 
-use util;
-
 pub enum Bitrate {
     Bitrate96,
     Bitrate160,
@@ -37,14 +29,14 @@ pub struct Config {
 }
 
 pub struct SessionData {
-    pub country: String,
-    pub canonical_username: String,
-    pub device_id: String,
+    country: String,
+    canonical_username: String,
+    device_id: String,
 }
 
 pub struct SessionInternal {
     config: Config,
-    pub data: RwLock<SessionData>,
+    data: RwLock<SessionData>,
 
     mercury: Mutex<MercuryManager>,
     metadata: Mutex<MetadataManager>,
@@ -87,94 +79,10 @@ impl Session {
         }))
     }
 
-    pub fn connect(&self) {
-        let local_keys = DHLocalKeys::random(&mut thread_rng());
-
-        let mut connection = PlainConnection::connect().unwrap();
-
-        let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
-            build_info => {
-                product: protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY_EMBEDDED,
-                platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
-                version: 0x10800000000,
-            },
-            /*
-            fingerprints_supported => [
-                protocol::keyexchange::Fingerprint::FINGERPRINT_GRAIN
-            ],
-            */
-            cryptosuites_supported => [
-                protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
-                //protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_RC4_SHA1_HMAC
-            ],
-            /*
-            powschemes_supported => [
-                protocol::keyexchange::Powscheme::POW_HASH_CASH
-            ],
-            */
-            login_crypto_hello.diffie_hellman => {
-                gc: local_keys.public_key(),
-                server_keys_known: 1,
-            },
-            client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
-            padding: vec![0x1e],
-            feature_set => {
-                autoupdate2: true,
-            }
-        });
-
-        let init_client_packet = connection.send_packet_prefix(&[0, 4],
-                                                               &request.write_to_bytes().unwrap())
-                                           .unwrap();
-        let init_server_packet = connection.recv_packet().unwrap();
-
-        let response: protocol::keyexchange::APResponseMessage =
-            protobuf::parse_from_bytes(&init_server_packet[4..]).unwrap();
-
-        let remote_key = response.get_challenge()
-                                 .get_login_crypto_challenge()
-                                 .get_diffie_hellman()
-                                 .get_gs();
-
-        let shared_secret = local_keys.shared_secret(remote_key);
-        let (challenge, send_key, recv_key) = {
-            let mut data = Vec::with_capacity(0x64);
-            let mut mac = Hmac::new(Sha1::new(), &shared_secret);
-
-            for i in 1..6 {
-                mac.input(&init_client_packet);
-                mac.input(&init_server_packet);
-                mac.input(&[i]);
-                data.write(&mac.result().code()).unwrap();
-                mac.reset();
-            }
-
-            mac = Hmac::new(Sha1::new(), &data[..0x14]);
-            mac.input(&init_client_packet);
-            mac.input(&init_server_packet);
-
-            (mac.result().code().to_vec(),
-             data[0x14..0x34].to_vec(),
-             data[0x34..0x54].to_vec())
-        };
-
-        let packet = protobuf_init!(protocol::keyexchange::ClientResponsePlaintext::new(), {
-            login_crypto_response.diffie_hellman => {
-                hmac: challenge
-            },
-            pow_response => {},
-            crypto_response => {},
-        });
-
-
-        connection.send_packet(&packet.write_to_bytes().unwrap()).unwrap();
-
-        let cipher_connection = CipherConnection::new(connection.into_stream(),
-                                                      &send_key,
-                                                      &recv_key);
-
-        *self.0.rx_connection.lock().unwrap() = Some(cipher_connection.clone());
-        *self.0.tx_connection.lock().unwrap() = Some(cipher_connection);
+    pub fn authenticated(&self, username: String, connection: CipherConnection) {
+        self.0.data.write().unwrap().canonical_username = username;
+        *self.0.rx_connection.lock().unwrap() = Some(connection.clone());
+        *self.0.tx_connection.lock().unwrap() = Some(connection);
     }
 
     pub fn poll(&self) {