passport_encryption.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "passport/passport_encryption.h"
  8. #include "base/openssl_help.h"
  9. #include "base/random.h"
  10. #include "mtproto/details/mtproto_rsa_public_key.h"
  11. #include <QtCore/QJsonDocument>
  12. #include <QtCore/QJsonArray>
  13. #include <QtCore/QJsonObject>
  14. namespace Passport {
  15. namespace {
  16. constexpr auto kAesKeyLength = 32;
  17. constexpr auto kAesIvLength = 16;
  18. constexpr auto kSecretSize = 32;
  19. constexpr auto kAesParamsHashSize = 64;
  20. constexpr auto kMinPadding = 32;
  21. constexpr auto kMaxPadding = 255;
  22. constexpr auto kAlignTo = 16;
  23. } // namespace
  24. struct AesParams {
  25. bytes::vector key;
  26. bytes::vector iv;
  27. };
  28. AesParams PrepareAesParamsWithHash(bytes::const_span hashForEncryptionKey) {
  29. Expects(hashForEncryptionKey.size() == kAesParamsHashSize);
  30. auto result = AesParams();
  31. result.key = bytes::make_vector(
  32. hashForEncryptionKey.subspan(0, kAesKeyLength));
  33. result.iv = bytes::make_vector(
  34. hashForEncryptionKey.subspan(kAesKeyLength, kAesIvLength));
  35. return result;
  36. }
  37. AesParams PrepareAesParams(bytes::const_span bytesForEncryptionKey) {
  38. return PrepareAesParamsWithHash(openssl::Sha512(bytesForEncryptionKey));
  39. }
  40. bytes::vector EncryptOrDecrypt(
  41. bytes::const_span initial,
  42. AesParams &&params,
  43. int encryptOrDecrypt) {
  44. Expects((initial.size() & 0x0F) == 0);
  45. Expects(params.key.size() == kAesKeyLength);
  46. Expects(params.iv.size() == kAesIvLength);
  47. auto aesKey = AES_KEY();
  48. const auto error = (encryptOrDecrypt == AES_ENCRYPT)
  49. ? AES_set_encrypt_key(
  50. reinterpret_cast<const uchar*>(params.key.data()),
  51. params.key.size() * CHAR_BIT,
  52. &aesKey)
  53. : AES_set_decrypt_key(
  54. reinterpret_cast<const uchar*>(params.key.data()),
  55. params.key.size() * CHAR_BIT,
  56. &aesKey);
  57. if (error != 0) {
  58. LOG(("App Error: Could not AES_set_encrypt_key, result %1"
  59. ).arg(error));
  60. return {};
  61. }
  62. auto result = bytes::vector(initial.size());
  63. AES_cbc_encrypt(
  64. reinterpret_cast<const uchar*>(initial.data()),
  65. reinterpret_cast<uchar*>(result.data()),
  66. initial.size(),
  67. &aesKey,
  68. reinterpret_cast<uchar*>(params.iv.data()),
  69. encryptOrDecrypt);
  70. return result;
  71. }
  72. bytes::vector Encrypt(
  73. bytes::const_span decrypted,
  74. AesParams &&params) {
  75. return EncryptOrDecrypt(decrypted, std::move(params), AES_ENCRYPT);
  76. }
  77. bytes::vector Decrypt(
  78. bytes::const_span encrypted,
  79. AesParams &&params) {
  80. return EncryptOrDecrypt(encrypted, std::move(params), AES_DECRYPT);
  81. }
  82. bool CheckBytesMod255(bytes::const_span bytes) {
  83. const auto full = ranges::accumulate(
  84. bytes,
  85. 0ULL,
  86. [](uint64 sum, gsl::byte value) { return sum + uchar(value); });
  87. const auto mod = (full % 255ULL);
  88. return (mod == 239);
  89. }
  90. bool CheckSecretBytes(bytes::const_span secret) {
  91. return CheckBytesMod255(secret);
  92. }
  93. bytes::vector GenerateSecretBytes() {
  94. auto result = bytes::vector(kSecretSize);
  95. bytes::set_random(result);
  96. const auto full = ranges::accumulate(
  97. result,
  98. 0ULL,
  99. [](uint64 sum, gsl::byte value) { return sum + uchar(value); });
  100. const auto mod = (full % 255ULL);
  101. const auto add = 255ULL + 239 - mod;
  102. auto first = (static_cast<uchar>(result[0]) + add) % 255ULL;
  103. result[0] = static_cast<gsl::byte>(first);
  104. return result;
  105. }
  106. bytes::vector DecryptSecretBytesWithHash(
  107. bytes::const_span encryptedSecret,
  108. bytes::const_span hashForEncryptionKey) {
  109. if (encryptedSecret.empty()) {
  110. return {};
  111. } else if (encryptedSecret.size() != kSecretSize) {
  112. LOG(("API Error: Wrong secret size %1"
  113. ).arg(encryptedSecret.size()));
  114. return {};
  115. }
  116. auto params = PrepareAesParamsWithHash(hashForEncryptionKey);
  117. auto result = Decrypt(encryptedSecret, std::move(params));
  118. if (!CheckSecretBytes(result)) {
  119. LOG(("API Error: Bad secret bytes."));
  120. return {};
  121. }
  122. return result;
  123. }
  124. bytes::vector DecryptSecretBytes(
  125. bytes::const_span encryptedSecret,
  126. bytes::const_span bytesForEncryptionKey) {
  127. return DecryptSecretBytesWithHash(
  128. encryptedSecret,
  129. openssl::Sha512(bytesForEncryptionKey));
  130. }
  131. bytes::vector EncryptSecretBytesWithHash(
  132. bytes::const_span secret,
  133. bytes::const_span hashForEncryptionKey) {
  134. Expects(secret.size() == kSecretSize);
  135. Expects(CheckSecretBytes(secret) == true);
  136. auto params = PrepareAesParamsWithHash(hashForEncryptionKey);
  137. return Encrypt(secret, std::move(params));
  138. }
  139. bytes::vector EncryptSecretBytes(
  140. bytes::const_span secret,
  141. bytes::const_span bytesForEncryptionKey) {
  142. Expects(secret.size() == kSecretSize);
  143. Expects(CheckSecretBytes(secret) == true);
  144. auto params = PrepareAesParams(bytesForEncryptionKey);
  145. return Encrypt(secret, std::move(params));
  146. }
  147. bytes::vector DecryptSecureSecret(
  148. bytes::const_span encryptedSecret,
  149. bytes::const_span passwordHashForSecret) {
  150. Expects(!encryptedSecret.empty());
  151. return DecryptSecretBytesWithHash(
  152. encryptedSecret,
  153. passwordHashForSecret);
  154. }
  155. bytes::vector EncryptSecureSecret(
  156. bytes::const_span secret,
  157. bytes::const_span passwordHashForSecret) {
  158. Expects(secret.size() == kSecretSize);
  159. return EncryptSecretBytesWithHash(secret, passwordHashForSecret);
  160. }
  161. bytes::vector SerializeData(const std::map<QString, QString> &data) {
  162. auto root = QJsonObject();
  163. for (const auto &[key, value] : data) {
  164. root.insert(key, value);
  165. }
  166. auto document = QJsonDocument(root);
  167. const auto result = document.toJson(QJsonDocument::Compact);
  168. return bytes::make_vector(result);
  169. }
  170. std::map<QString, QString> DeserializeData(bytes::const_span bytes) {
  171. const auto serialized = QByteArray::fromRawData(
  172. reinterpret_cast<const char*>(bytes.data()),
  173. bytes.size());
  174. auto error = QJsonParseError();
  175. auto document = QJsonDocument::fromJson(serialized, &error);
  176. if (error.error != QJsonParseError::NoError) {
  177. LOG(("API Error: Could not deserialize decrypted JSON, error %1"
  178. ).arg(error.errorString()));
  179. return {};
  180. } else if (!document.isObject()) {
  181. LOG(("API Error: decrypted JSON root is not an object."));
  182. return {};
  183. }
  184. auto object = document.object();
  185. auto result = std::map<QString, QString>();
  186. for (auto i = object.constBegin(), e = object.constEnd(); i != e; ++i) {
  187. const auto key = i.key();
  188. switch ((*i).type()) {
  189. case QJsonValue::Null: {
  190. LOG(("API Error: null found inside decrypted JSON root. "
  191. "Defaulting to empty string value."));
  192. result[key] = QString();
  193. } break;
  194. case QJsonValue::Undefined: {
  195. LOG(("API Error: undefined found inside decrypted JSON root. "
  196. "Defaulting to empty string value."));
  197. result[key] = QString();
  198. } break;
  199. case QJsonValue::Bool: {
  200. LOG(("API Error: bool found inside decrypted JSON root. "
  201. "Aborting."));
  202. return {};
  203. } break;
  204. case QJsonValue::Double: {
  205. LOG(("API Error: double found inside decrypted JSON root. "
  206. "Converting to string."));
  207. result[key] = QString::number((*i).toDouble());
  208. } break;
  209. case QJsonValue::String: {
  210. result[key] = (*i).toString();
  211. } break;
  212. case QJsonValue::Array: {
  213. LOG(("API Error: array found inside decrypted JSON root. "
  214. "Aborting."));
  215. return {};
  216. } break;
  217. case QJsonValue::Object: {
  218. LOG(("API Error: object found inside decrypted JSON root. "
  219. "Aborting."));
  220. return {};
  221. } break;
  222. }
  223. }
  224. return result;
  225. }
  226. std::vector<DataError> DeserializeErrors(bytes::const_span json) {
  227. const auto serialized = QByteArray::fromRawData(
  228. reinterpret_cast<const char*>(json.data()),
  229. json.size());
  230. auto error = QJsonParseError();
  231. auto document = QJsonDocument::fromJson(serialized, &error);
  232. if (error.error != QJsonParseError::NoError) {
  233. LOG(("API Error: Could not deserialize errors JSON, error %1"
  234. ).arg(error.errorString()));
  235. return {};
  236. } else if (!document.isArray()) {
  237. LOG(("API Error: Errors JSON root is not an array."));
  238. return {};
  239. }
  240. auto array = document.array();
  241. auto result = std::vector<DataError>();
  242. for (const auto error : array) {
  243. if (!error.isObject()) {
  244. LOG(("API Error: Not an object inside errors JSON."));
  245. continue;
  246. }
  247. auto fields = error.toObject();
  248. const auto typeIt = fields.constFind("type");
  249. if (typeIt == fields.constEnd()) {
  250. LOG(("API Error: type was not found in an error."));
  251. continue;
  252. } else if (!(*typeIt).isString()) {
  253. LOG(("API Error: type was not a string in an error."));
  254. continue;
  255. }
  256. const auto descriptionIt = fields.constFind("description");
  257. if (descriptionIt == fields.constEnd()) {
  258. LOG(("API Error: description was not found in an error."));
  259. continue;
  260. } else if (!(*typeIt).isString()) {
  261. LOG(("API Error: description was not a string in an error."));
  262. continue;
  263. }
  264. const auto targetIt = fields.constFind("target");
  265. if (targetIt == fields.constEnd()) {
  266. LOG(("API Error: target aws not found in an error."));
  267. continue;
  268. } else if (!(*targetIt).isString()) {
  269. LOG(("API Error: target was not as string in an error."));
  270. continue;
  271. }
  272. auto next = DataError();
  273. next.type = (*typeIt).toString();
  274. next.text = (*descriptionIt).toString();
  275. const auto fieldIt = fields.constFind("field");
  276. const auto fileHashIt = fields.constFind("file_hash");
  277. if (fieldIt != fields.constEnd()) {
  278. if (!(*fieldIt).isString()) {
  279. LOG(("API Error: field was not a string in an error."));
  280. continue;
  281. }
  282. next.key = (*fieldIt).toString();
  283. } else if (fileHashIt != fields.constEnd()) {
  284. if (!(*fileHashIt).isString()) {
  285. LOG(("API Error: file_hash was not a string in an error."));
  286. continue;
  287. }
  288. next.key = QByteArray::fromBase64(
  289. (*fileHashIt).toString().toUtf8());
  290. } else if ((*targetIt).toString() == "selfie") {
  291. next.key = QByteArray();
  292. }
  293. result.push_back(std::move(next));
  294. }
  295. return result;
  296. }
  297. EncryptedData EncryptData(bytes::const_span bytes) {
  298. return EncryptData(bytes, GenerateSecretBytes());
  299. }
  300. EncryptedData EncryptData(
  301. bytes::const_span bytes,
  302. bytes::const_span dataSecret) {
  303. constexpr auto kFromPadding = kMinPadding + kAlignTo - 1;
  304. constexpr auto kPaddingDelta = kMaxPadding - kFromPadding;
  305. const auto randomPadding = kFromPadding
  306. + (base::RandomValue<uint32>() % kPaddingDelta);
  307. const auto padding = randomPadding
  308. - ((bytes.size() + randomPadding) % kAlignTo);
  309. Assert(padding >= kMinPadding && padding <= kMaxPadding);
  310. auto unencrypted = bytes::vector(padding + bytes.size());
  311. Assert(unencrypted.size() % kAlignTo == 0);
  312. unencrypted[0] = static_cast<gsl::byte>(padding);
  313. base::RandomFill(unencrypted.data() + 1, padding - 1);
  314. bytes::copy(
  315. gsl::make_span(unencrypted).subspan(padding),
  316. bytes);
  317. const auto dataHash = openssl::Sha256(unencrypted);
  318. const auto bytesForEncryptionKey = bytes::concatenate(
  319. dataSecret,
  320. dataHash);
  321. auto params = PrepareAesParams(bytesForEncryptionKey);
  322. return {
  323. { dataSecret.begin(), dataSecret.end() },
  324. { dataHash.begin(), dataHash.end() },
  325. Encrypt(unencrypted, std::move(params))
  326. };
  327. }
  328. bytes::vector DecryptData(
  329. bytes::const_span encrypted,
  330. bytes::const_span dataHash,
  331. bytes::const_span dataSecret) {
  332. constexpr auto kDataHashSize = 32;
  333. if (encrypted.empty()) {
  334. return {};
  335. } else if (dataHash.size() != kDataHashSize) {
  336. LOG(("API Error: Bad data hash size %1").arg(dataHash.size()));
  337. return {};
  338. } else if (dataSecret.size() != kSecretSize) {
  339. LOG(("API Error: Bad data secret size %1").arg(dataSecret.size()));
  340. return {};
  341. }
  342. const auto bytesForEncryptionKey = bytes::concatenate(
  343. dataSecret,
  344. dataHash);
  345. auto params = PrepareAesParams(bytesForEncryptionKey);
  346. const auto decrypted = Decrypt(encrypted, std::move(params));
  347. if (bytes::compare(openssl::Sha256(decrypted), dataHash) != 0) {
  348. LOG(("API Error: Bad data hash."));
  349. return {};
  350. }
  351. const auto padding = static_cast<uint32>(decrypted[0]);
  352. if (padding < kMinPadding
  353. || padding > kMaxPadding
  354. || padding > decrypted.size()) {
  355. LOG(("API Error: Bad padding value %1").arg(padding));
  356. return {};
  357. }
  358. const auto bytes = gsl::make_span(decrypted).subspan(padding);
  359. return { bytes.begin(), bytes.end() };
  360. }
  361. bytes::vector PrepareValueHash(
  362. bytes::const_span dataHash,
  363. bytes::const_span valueSecret) {
  364. return openssl::Sha256(dataHash, valueSecret);
  365. }
  366. bytes::vector EncryptValueSecret(
  367. bytes::const_span valueSecret,
  368. bytes::const_span secret,
  369. bytes::const_span valueHash) {
  370. const auto bytesForEncryptionKey = bytes::concatenate(
  371. secret,
  372. valueHash);
  373. return EncryptSecretBytes(valueSecret, bytesForEncryptionKey);
  374. }
  375. bytes::vector DecryptValueSecret(
  376. bytes::const_span encrypted,
  377. bytes::const_span secret,
  378. bytes::const_span valueHash) {
  379. const auto bytesForEncryptionKey = bytes::concatenate(
  380. secret,
  381. valueHash);
  382. return DecryptSecretBytes(encrypted, bytesForEncryptionKey);
  383. }
  384. uint64 CountSecureSecretId(bytes::const_span secret) {
  385. const auto full = openssl::Sha256(secret);
  386. return *reinterpret_cast<const uint64*>(full.data());
  387. }
  388. bytes::vector EncryptCredentialsSecret(
  389. bytes::const_span secret,
  390. bytes::const_span publicKey) {
  391. const auto key = MTP::details::RSAPublicKey(publicKey);
  392. return key.encryptOAEPpadding(secret);
  393. }
  394. } // namespace Passport