Por qué el pasaporte de Telegram: sin fin

Hola% username%!



En la discusión de las noticias de Passport , surgieron discusiones acaloradas sobre la seguridad de la última nave de los autores de Telegram.

Veamos cómo encripta sus datos personales y hablemos sobre el verdadero extremo a extremo.

En pocas palabras, cómo funciona Passport.

  • Localmente, usando una contraseña, usted encripta sus datos personales (nombre, correo electrónico, escaneo de pasaportes, otros documentos).
  • Los datos cifrados + metainformación se cargan en la nube de Telegram.
  • Cuando necesita iniciar sesión en el servicio, el cliente descarga los datos de la nube, los descifra con una contraseña, los descifra en la clave pública del servicio que solicitó la información y los envía.

Consideraremos la primera parte, que se relaciona con el cifrado y el almacenamiento de datos personales.

End to End, según los desarrolladores, radica en el hecho de que la nube de Telegram supuestamente no puede descifrar sus datos personales, sino que solo ve "ruido aleatorio".

Echemos un vistazo más de cerca al código del algoritmo de cifrado para datos personales del cliente de escritorio que se encuentra aquí y veamos si el resultado de su trabajo cumple con los criterios de extremo a extremo.

Todo comienza con una contraseña. Aquí es el lugar donde se convierte en una clave de cifrado intermedia.

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/es418535/


All Articles