New auth key generation algorithm.

This commit is contained in:
John Preston 2021-07-05 15:38:30 +03:00
parent a0540e0486
commit 95a7ce4622
1 changed files with 87 additions and 23 deletions

View File

@ -72,12 +72,39 @@ struct ParsedPQ {
return { pStr, qStr };
}
[[nodiscard]] bool IsGoodEncryptedInner(
bytes::const_span keyAesEncrypted,
const RSAPublicKey &key) {
Expects(keyAesEncrypted.size() == 256);
const auto modulus = key.getN();
const auto e = key.getE();
const auto shift = (256 - int(modulus.size()));
Assert(shift >= 0);
for (auto i = 0; i != 256; ++i) {
const auto a = keyAesEncrypted[i];
const auto b = (i < shift)
? bytes::type(0)
: modulus[i - shift];
if (a > b) {
return false;
} else if (a < b) {
return true;
}
}
return false;
}
template <typename PQInnerData>
[[nodiscard]] bytes::vector EncryptPQInnerRSA(
const PQInnerData &data,
const RSAPublicKey &key) {
constexpr auto kSkipPrimes = 6;
constexpr auto kMaxPrimes = 65; // 260 bytes
constexpr auto kPrime = sizeof(mtpPrime);
constexpr auto kDataWithPaddingPrimes = 192 / kPrime;
constexpr auto kMaxSizeInPrimes = 144 / kPrime;
constexpr auto kDataHashPrimes = (SHA256_DIGEST_LENGTH / kPrime);
constexpr auto kKeySize = 32;
constexpr auto kIvSize = 32;
using BoxedPQInnerData = std::conditional_t<
tl::is_boxed_v<PQInnerData>,
@ -85,31 +112,68 @@ template <typename PQInnerData>
tl::boxed<PQInnerData>>;
const auto boxed = BoxedPQInnerData(data);
const auto p_q_inner_size = tl::count_length(boxed);
const auto sizeInPrimes = (p_q_inner_size >> 2) + kSkipPrimes;
if (sizeInPrimes >= kMaxPrimes) {
auto tmp = mtpBuffer();
tmp.reserve(sizeInPrimes);
boxed.write(tmp);
LOG(("AuthKey Error: too large data for RSA encrypt, size %1").arg(sizeInPrimes * sizeof(mtpPrime)));
DEBUG_LOG(("AuthKey Error: bad data for RSA encrypt %1").arg(Logs::mb(&tmp[0], tmp.size() * 4).str()));
return {}; // can't be 255-byte string
const auto sizeInPrimes = (p_q_inner_size / kPrime);
if (sizeInPrimes > kMaxSizeInPrimes) {
return {};
}
auto encBuffer = mtpBuffer();
encBuffer.reserve(kMaxPrimes);
encBuffer.resize(kSkipPrimes);
boxed.write(encBuffer);
encBuffer.resize(kMaxPrimes);
const auto bytes = bytes::make_span(encBuffer);
auto dataWithPadding = mtpBuffer();
dataWithPadding.reserve(kDataWithPaddingPrimes);
boxed.write(dataWithPadding);
const auto hashSrc = bytes.subspan(
kSkipPrimes * sizeof(mtpPrime),
p_q_inner_size);
bytes::copy(bytes.subspan(sizeof(mtpPrime)), openssl::Sha1(hashSrc));
bytes::set_random(bytes.subspan(sizeInPrimes * sizeof(mtpPrime)));
// data_with_padding := data + random_padding_bytes;
dataWithPadding.resize(kDataWithPaddingPrimes);
const auto dataWithPaddingBytes = bytes::make_span(dataWithPadding);
bytes::set_random(dataWithPaddingBytes.subspan(sizeInPrimes * kPrime));
const auto bytesToEncrypt = bytes.subspan(3, 256);
return key.encrypt(bytesToEncrypt);
while (true) {
auto dataWithHash = mtpBuffer();
dataWithHash.reserve(kDataWithPaddingPrimes + kDataHashPrimes);
dataWithHash.append(dataWithPadding);
// data_pad_reversed := BYTE_REVERSE(data_with_padding);
ranges::reverse(bytes::make_span(dataWithHash));
// data_with_hash := data_pad_reversed
// + SHA256(temp_key + data_with_padding);
const auto tempKey = openssl::RandomValue<bytes::array<kKeySize>>();
dataWithHash.resize(kDataWithPaddingPrimes + kDataHashPrimes);
const auto dataWithHashBytes = bytes::make_span(dataWithHash);
bytes::copy(
dataWithHashBytes.subspan(kDataWithPaddingPrimes * kPrime),
openssl::Sha256(tempKey, bytes::make_span(dataWithPadding)));
auto aesEncrypted = mtpBuffer();
auto keyAesEncrypted = mtpBuffer();
aesEncrypted.resize(dataWithHash.size());
const auto aesEncryptedBytes = bytes::make_span(aesEncrypted);
// aes_encrypted := AES256_IGE(data_with_hash, temp_key, 0);
const auto tempIv = bytes::array<kIvSize>{ { bytes::type(0) } };
aesIgeEncryptRaw(
dataWithHashBytes.data(),
aesEncryptedBytes.data(),
dataWithHashBytes.size(),
tempKey.data(),
tempIv.data());
// temp_key_xor := temp_key XOR SHA256(aes_encrypted);
const auto fullSize = (kKeySize / kPrime) + dataWithHash.size();
keyAesEncrypted.resize(fullSize);
const auto keyAesEncryptedBytes = bytes::make_span(keyAesEncrypted);
const auto aesHash = openssl::Sha256(aesEncryptedBytes);
for (auto i = 0; i != kKeySize; ++i) {
keyAesEncryptedBytes[i] = tempKey[i] ^ aesHash[i];
}
// key_aes_encrypted := temp_key_xor + aes_encrypted;
bytes::copy(
keyAesEncryptedBytes.subspan(kKeySize),
aesEncryptedBytes);
if (IsGoodEncryptedInner(keyAesEncryptedBytes, key)) {
return key.encrypt(keyAesEncryptedBytes);
}
}
}
[[nodiscard]] std::string EncryptClientDHInner(