📜 ⬆️ ⬇️

Why Telegram Passport is No End to End

Hi% username%!



In the discussion of the news about Passport, there were heated discussions on the topic of security of the latest crafts from Telegram authors.
')
Let's see how he encrypts your personal data and talk about the real end-to-end.

In a nutshell, how Passport works.


We consider the first part, which concerns the encryption and storage of personal data.

End to End, according to the developers, is that the Telegram cloud allegedly cannot decipher your personal data, but sees only “random noise”.

Let's take a closer look at the code of the encryption algorithm for personal data from the desktop client, which is here and see if the result of its work satisfies the End-To-End criteria.

It all starts with a password. Here is the place where it turns into an intermediate encryption key.

bytes::vector CountPasswordHashForSecret(
		bytes::const_span salt,
		bytes::const_span password) {
	return openssl::Sha512(bytes::concatenate(
		salt,
		password,
		salt));
}

, SHA-512. . !

2018 . GPU SHA-512 . 10 GPU 8- 94 ( , , ) 5 .

, GPU, Telegram .

. , :

bytes::vector GenerateSecretBytes() {
	auto result = bytes::vector(kSecretSize);
	memset_rand(result.data(), result.size());
	const auto full = ranges::accumulate(
		result,
		0ULL,
		[](uint64 sum, gsl::byte value) { return sum + uchar(value); });
	const auto mod = (full % 255ULL);
	const auto add = 255ULL + 239 - mod;
	auto first = (static_cast<uchar>(result[0]) + add) % 255ULL;
	result[0] = static_cast<gsl::byte>(first);
	return result;
}

, .

«», HMAC AEAD , , , 239, :

bool CheckBytesMod255(bytes::const_span bytes) {
	const auto full = ranges::accumulate(
		bytes,
		0ULL,
		[](uint64 sum, gsl::byte value) { return sum + uchar(value); });
	const auto mod = (full % 255ULL);
	return (mod == 239);
}

-, . , , HMAC, .

. , . , :

EncryptedData EncryptData(
		bytes::const_span bytes,
		bytes::const_span dataSecret) {
	constexpr auto kFromPadding = kMinPadding + kAlignTo - 1;
	constexpr auto kPaddingDelta = kMaxPadding - kFromPadding;
	const auto randomPadding = kFromPadding
		+ (rand_value<uint32>() % kPaddingDelta);
	const auto padding = randomPadding
		- ((bytes.size() + randomPadding) % kAlignTo);
	Assert(padding >= kMinPadding && padding <= kMaxPadding);

	auto unencrypted = bytes::vector(padding + bytes.size());
	Assert(unencrypted.size() % kAlignTo == 0);

	unencrypted[0] = static_cast<gsl::byte>(padding);
	memset_rand(unencrypted.data() + 1, padding - 1);
	bytes::copy(
		gsl::make_span(unencrypted).subspan(padding),
		bytes);


32 255 .
dataHash. , .

	const auto dataHash = openssl::Sha256(unencrypted);
	const auto bytesForEncryptionKey = bytes::concatenate(
		dataSecret,
		dataHash);

	auto params = PrepareAesParams(bytesForEncryptionKey);
	return {
		{ dataSecret.begin(), dataSecret.end() },
		{ dataHash.begin(), dataHash.end() },
		Encrypt(unencrypted, std::move(params))
	};
}

. SHA-512 , dataHash.


:

  1. ,

« », , , . , AES (2^256).

Telegram , HMAC.

:

  1. , (GPU)
  2. (AES-NI)
  3. .
  4. - SHA-512 (GPU)
  5. (AES-NI)
  6. SHA-256, , :

if (padding < kMinPadding
		|| padding > kMaxPadding
		|| padding > decrypted.size()) {

, , . . GPU, AES-NI. , , . , ?

, , Don't roll your own crypto , End-to-End, .

, , , .

End-to-End


E2E , . , .

, , , , . Signal, (WhatsApp, etc). , , , .

, . .

Telegram , . , , .

P.S. E2E, VirgilSecurity , .

Source: https://habr.com/ru/post/418535/


All Articles