authentication.rs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. use aes::Aes192;
  2. use base64;
  3. use byteorder::{BigEndian, ByteOrder};
  4. use hmac::Hmac;
  5. use pbkdf2::pbkdf2;
  6. use protobuf::ProtobufEnum;
  7. use serde;
  8. use serde_json;
  9. use sha1::{Digest, Sha1};
  10. use std::fs::File;
  11. use std::io::{self, Read, Write};
  12. use std::ops::FnOnce;
  13. use std::path::Path;
  14. use crate::protocol::authentication::AuthenticationType;
  15. #[derive(Debug, Clone, Serialize, Deserialize)]
  16. pub struct Credentials {
  17. pub username: String,
  18. #[serde(serialize_with = "serialize_protobuf_enum")]
  19. #[serde(deserialize_with = "deserialize_protobuf_enum")]
  20. pub auth_type: AuthenticationType,
  21. #[serde(alias = "encoded_auth_blob")]
  22. #[serde(serialize_with = "serialize_base64")]
  23. #[serde(deserialize_with = "deserialize_base64")]
  24. pub auth_data: Vec<u8>,
  25. }
  26. impl Credentials {
  27. pub fn with_password(username: String, password: String) -> Credentials {
  28. Credentials {
  29. username: username,
  30. auth_type: AuthenticationType::AUTHENTICATION_USER_PASS,
  31. auth_data: password.into_bytes(),
  32. }
  33. }
  34. pub fn with_blob(username: String, encrypted_blob: &str, device_id: &str) -> Credentials {
  35. fn read_u8<R: Read>(stream: &mut R) -> io::Result<u8> {
  36. let mut data = [0u8];
  37. stream.read_exact(&mut data)?;
  38. Ok(data[0])
  39. }
  40. fn read_int<R: Read>(stream: &mut R) -> io::Result<u32> {
  41. let lo = read_u8(stream)? as u32;
  42. if lo & 0x80 == 0 {
  43. return Ok(lo);
  44. }
  45. let hi = read_u8(stream)? as u32;
  46. Ok(lo & 0x7f | hi << 7)
  47. }
  48. fn read_bytes<R: Read>(stream: &mut R) -> io::Result<Vec<u8>> {
  49. let length = read_int(stream)?;
  50. let mut data = vec![0u8; length as usize];
  51. stream.read_exact(&mut data)?;
  52. Ok(data)
  53. }
  54. let secret = Sha1::digest(device_id.as_bytes());
  55. let key = {
  56. let mut key = [0u8; 24];
  57. pbkdf2::<Hmac<Sha1>>(&secret, username.as_bytes(), 0x100, &mut key[0..20]);
  58. let hash = &Sha1::digest(&key[..20]);
  59. key[..20].copy_from_slice(hash);
  60. BigEndian::write_u32(&mut key[20..], 20);
  61. key
  62. };
  63. // decrypt data using ECB mode without padding
  64. let blob = {
  65. use aes::block_cipher_trait::generic_array::typenum::Unsigned;
  66. use aes::block_cipher_trait::generic_array::GenericArray;
  67. use aes::block_cipher_trait::BlockCipher;
  68. let mut data = base64::decode(encrypted_blob).unwrap();
  69. let cipher = Aes192::new(GenericArray::from_slice(&key));
  70. let block_size = <Aes192 as BlockCipher>::BlockSize::to_usize();
  71. assert_eq!(data.len() % block_size, 0);
  72. // replace to chunks_exact_mut with MSRV bump to 1.31
  73. for chunk in data.chunks_mut(block_size) {
  74. cipher.decrypt_block(GenericArray::from_mut_slice(chunk));
  75. }
  76. let l = data.len();
  77. for i in 0..l - 0x10 {
  78. data[l - i - 1] ^= data[l - i - 0x11];
  79. }
  80. data
  81. };
  82. let mut cursor = io::Cursor::new(&blob);
  83. read_u8(&mut cursor).unwrap();
  84. read_bytes(&mut cursor).unwrap();
  85. read_u8(&mut cursor).unwrap();
  86. let auth_type = read_int(&mut cursor).unwrap();
  87. let auth_type = AuthenticationType::from_i32(auth_type as i32).unwrap();
  88. read_u8(&mut cursor).unwrap();
  89. let auth_data = read_bytes(&mut cursor).unwrap();
  90. Credentials {
  91. username: username,
  92. auth_type: auth_type,
  93. auth_data: auth_data,
  94. }
  95. }
  96. fn from_reader<R: Read>(mut reader: R) -> Credentials {
  97. let mut contents = String::new();
  98. reader.read_to_string(&mut contents).unwrap();
  99. serde_json::from_str(&contents).unwrap()
  100. }
  101. pub(crate) fn from_file<P: AsRef<Path>>(path: P) -> Option<Credentials> {
  102. File::open(path).ok().map(Credentials::from_reader)
  103. }
  104. fn save_to_writer<W: Write>(&self, writer: &mut W) {
  105. let contents = serde_json::to_string(&self.clone()).unwrap();
  106. writer.write_all(contents.as_bytes()).unwrap();
  107. }
  108. pub(crate) fn save_to_file<P: AsRef<Path>>(&self, path: P) {
  109. let mut file = File::create(path).unwrap();
  110. self.save_to_writer(&mut file)
  111. }
  112. }
  113. fn serialize_protobuf_enum<T, S>(v: &T, ser: S) -> Result<S::Ok, S::Error>
  114. where
  115. T: ProtobufEnum,
  116. S: serde::Serializer,
  117. {
  118. serde::Serialize::serialize(&v.value(), ser)
  119. }
  120. fn deserialize_protobuf_enum<'de, T, D>(de: D) -> Result<T, D::Error>
  121. where
  122. T: ProtobufEnum,
  123. D: serde::Deserializer<'de>,
  124. {
  125. let v: i32 = serde::Deserialize::deserialize(de)?;
  126. T::from_i32(v).ok_or_else(|| serde::de::Error::custom("Invalid enum value"))
  127. }
  128. fn serialize_base64<T, S>(v: &T, ser: S) -> Result<S::Ok, S::Error>
  129. where
  130. T: AsRef<[u8]>,
  131. S: serde::Serializer,
  132. {
  133. serde::Serialize::serialize(&base64::encode(v.as_ref()), ser)
  134. }
  135. fn deserialize_base64<'de, D>(de: D) -> Result<Vec<u8>, D::Error>
  136. where
  137. D: serde::Deserializer<'de>,
  138. {
  139. let v: String = serde::Deserialize::deserialize(de)?;
  140. base64::decode(&v).map_err(|e| serde::de::Error::custom(e.to_string()))
  141. }
  142. pub fn get_credentials<F: FnOnce(&String) -> String>(
  143. username: Option<String>,
  144. password: Option<String>,
  145. cached_credentials: Option<Credentials>,
  146. prompt: F,
  147. ) -> Option<Credentials> {
  148. match (username, password, cached_credentials) {
  149. (Some(username), Some(password), _) => Some(Credentials::with_password(username, password)),
  150. (Some(ref username), _, Some(ref credentials)) if *username == credentials.username => {
  151. Some(credentials.clone())
  152. }
  153. (Some(username), None, _) => Some(Credentials::with_password(
  154. username.clone(),
  155. prompt(&username),
  156. )),
  157. (None, _, Some(credentials)) => Some(credentials),
  158. (None, _, None) => None,
  159. }
  160. }