Storage::Cache::Key WebDocumentCacheKey(const WebFileLocation &location) { const auto dcId = uint64(location.dc()) & 0xFFULL; const auto url = location.url(); const auto hash = openssl::Sha256(bytes::make_span(url)); const auto bytes = bytes::make_span(hash); const auto bytes1 = bytes.subspan(0, sizeof(uint32)); const auto bytes2 = bytes.subspan(sizeof(uint32), sizeof(uint64)); const auto part1 = *reinterpret_cast<const uint32*>(bytes1.data()); const auto part2 = *reinterpret_cast<const uint64*>(bytes2.data()); return Storage::Cache::Key{ Data::kWebDocumentCacheTag | (dcId << 32) | part1, part2 }; }
base::byte_vector decrypt(base::const_byte_span data) const { Expects(isValid()); constexpr auto kDecryptSize = 256; auto result = base::byte_vector(kDecryptSize, gsl::byte {}); auto res = RSA_public_decrypt(kDecryptSize, reinterpret_cast<const unsigned char*>(data.data()), reinterpret_cast<unsigned char*>(result.data()), _rsa, RSA_NO_PADDING); if (res < 0 || res > kDecryptSize) { ERR_load_crypto_strings(); LOG(("RSA Error: RSA_public_encrypt failed, key fp: %1, result: %2, error: %3").arg(getFingerPrint()).arg(res).arg(ERR_error_string(ERR_get_error(), 0))); return base::byte_vector(); } else if (auto zeroBytes = kDecryptSize - res) { auto resultBytes = gsl::make_span(result); base::move_bytes(resultBytes.subspan(zeroBytes - res, res), resultBytes.subspan(0, res)); base::set_bytes(resultBytes.subspan(0, zeroBytes - res), gsl::byte {}); } return result; }
Storage::Cache::Key UrlCacheKey(const QString &location) { const auto url = location.toUtf8(); const auto hash = openssl::Sha256(bytes::make_span(url)); const auto bytes = bytes::make_span(hash); const auto bytes1 = bytes.subspan(0, sizeof(uint32)); const auto bytes2 = bytes.subspan(sizeof(uint32), sizeof(uint64)); const auto bytes3 = bytes.subspan( sizeof(uint32) + sizeof(uint64), sizeof(uint16)); const auto part1 = *reinterpret_cast<const uint32*>(bytes1.data()); const auto part2 = *reinterpret_cast<const uint64*>(bytes2.data()); const auto part3 = *reinterpret_cast<const uint16*>(bytes3.data()); return Storage::Cache::Key{ Data::kUrlCacheTag | (uint64(part3) << 32) | part1, part2 }; }
bool SpecialConfigRequest::decryptSimpleConfig(const QByteArray &bytes) { auto cleanBytes = bytes; auto removeFrom = std::remove_if(cleanBytes.begin(), cleanBytes.end(), [](char ch) { auto isGoodBase64 = (ch == '+') || (ch == '=') || (ch == '/') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'); return !isGoodBase64; }); if (removeFrom != cleanBytes.end()) { cleanBytes.remove(removeFrom - cleanBytes.begin(), cleanBytes.end() - removeFrom); } constexpr auto kGoodSizeBase64 = 344; if (cleanBytes.size() != kGoodSizeBase64) { LOG(("Config Error: Bad data size %1 required %2").arg(cleanBytes.size()).arg(kGoodSizeBase64)); return false; } constexpr auto kGoodSizeData = 256; auto decodedBytes = QByteArray::fromBase64(cleanBytes, QByteArray::Base64Encoding); if (decodedBytes.size() != kGoodSizeData) { LOG(("Config Error: Bad data size %1 required %2").arg(decodedBytes.size()).arg(kGoodSizeData)); return false; } auto publicKey = internal::RSAPublicKey(gsl::as_bytes(gsl::make_span(kPublicKey.c_str(), kPublicKey.size()))); auto decrypted = publicKey.decrypt(gsl::as_bytes(gsl::make_span(decodedBytes))); auto decryptedBytes = gsl::make_span(decrypted); constexpr auto kAesKeySize = CTRState::KeySize; constexpr auto kAesIvecSize = CTRState::IvecSize; auto aesEncryptedBytes = decryptedBytes.subspan(kAesKeySize); base::byte_array<kAesIvecSize> aesivec; base::copy_bytes(aesivec, decryptedBytes.subspan(CTRState::KeySize - CTRState::IvecSize, CTRState::IvecSize)); AES_KEY aeskey; AES_set_decrypt_key(reinterpret_cast<const unsigned char*>(decryptedBytes.data()), kAesKeySize * CHAR_BIT, &aeskey); AES_cbc_encrypt(reinterpret_cast<const unsigned char*>(aesEncryptedBytes.data()), reinterpret_cast<unsigned char*>(aesEncryptedBytes.data()), aesEncryptedBytes.size(), &aeskey, reinterpret_cast<unsigned char*>(aesivec.data()), AES_DECRYPT); constexpr auto kDigestSize = 16; auto dataSize = aesEncryptedBytes.size() - kDigestSize; auto data = aesEncryptedBytes.subspan(0, dataSize); auto hash = openssl::Sha256(data); if (base::compare_bytes(gsl::make_span(hash).subspan(0, kDigestSize), aesEncryptedBytes.subspan(dataSize)) != 0) { LOG(("Config Error: Bad digest.")); return false; } mtpBuffer buffer; buffer.resize(data.size() / sizeof(mtpPrime)); base::copy_bytes(gsl::as_writeable_bytes(gsl::make_span(buffer)), data); auto from = &*buffer.cbegin(); auto end = from + buffer.size(); auto realLength = *from++; if (realLength <= 0 || realLength > dataSize || (realLength & 0x03)) { LOG(("Config Error: Bad length %1.").arg(realLength)); return false; } try { _simpleConfig.read(from, end); } catch (...) { LOG(("Config Error: Could not read configSimple.")); return false; } if ((end - from) * sizeof(mtpPrime) != (dataSize - realLength)) { LOG(("Config Error: Bad read length %1, should be %2.").arg((end - from) * sizeof(mtpPrime)).arg(dataSize - realLength)); return false; } return true; }