From 0ece30dc7c0e34b4c5911969b8fa99c33c6d023c Mon Sep 17 00:00:00 2001 From: George Hazan Date: Wed, 30 Nov 2022 17:48:47 +0300 Subject: Telegram: update for TDLIB --- .../Telegram/tdlib/td/tdutils/test/crypto.cpp | 333 ++++++++++++++++++++- 1 file changed, 319 insertions(+), 14 deletions(-) (limited to 'protocols/Telegram/tdlib/td/tdutils/test/crypto.cpp') diff --git a/protocols/Telegram/tdlib/td/tdutils/test/crypto.cpp b/protocols/Telegram/tdlib/td/tdutils/test/crypto.cpp index faf4ef61a4..9e81ef132c 100644 --- a/protocols/Telegram/tdlib/td/tdutils/test/crypto.cpp +++ b/protocols/Telegram/tdlib/td/tdutils/test/crypto.cpp @@ -1,20 +1,47 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/utils/base64.h" +#include "td/utils/benchmark.h" #include "td/utils/common.h" #include "td/utils/crypto.h" +#include "td/utils/Random.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/tests.h" +#include "td/utils/UInt.h" #include static td::vector strings{"", "1", "short test string", td::string(1000000, 'a')}; #if TD_HAVE_OPENSSL +#if TD_HAVE_ZLIB +TEST(Crypto, Aes) { + td::Random::Xorshift128plus rnd(123); + td::UInt256 key; + rnd.bytes(as_slice(key)); + td::string plaintext(16, '\0'); + td::string encrypted(16, '\0'); + td::string decrypted(16, '\0'); + rnd.bytes(plaintext); + + td::AesState encryptor; + encryptor.init(as_slice(key), true); + td::AesState decryptor; + decryptor.init(as_slice(key), false); + + encryptor.encrypt(td::as_slice(plaintext).ubegin(), td::as_slice(encrypted).ubegin(), 16); + decryptor.decrypt(td::as_slice(encrypted).ubegin(), td::as_slice(decrypted).ubegin(), 16); + + CHECK(decrypted == plaintext); + CHECK(decrypted != encrypted); + CHECK(td::crc32(encrypted) == 178892237); +} + TEST(Crypto, AesCtrState) { td::vector answers1{0u, 1141589763u, 596296607u, 3673001485u, 2302125528u, 330967191u, 2047392231u, 3537459563u, 307747798u, 2149598133u}; @@ -42,46 +69,177 @@ TEST(Crypto, AesCtrState) { } td::AesCtrState state; - state.init(key, iv); + state.init(as_slice(key), as_slice(iv)); td::string t(length, '\0'); - state.encrypt(s, t); + std::size_t pos = 0; + for (const auto &str : td::rand_split(td::string(length, '\0'))) { + auto len = str.size(); + state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len)); + pos += len; + } ASSERT_EQ(answers1[i], td::crc32(t)); - state.init(key, iv); - state.decrypt(t, t); - ASSERT_STREQ(s, t); + state.init(as_slice(key), as_slice(iv)); + pos = 0; + for (const auto &str : td::rand_split(td::string(length, '\0'))) { + auto len = str.size(); + state.decrypt(td::Slice(t).substr(pos, len), td::MutableSlice(t).substr(pos, len)); + pos += len; + } + ASSERT_STREQ(td::base64_encode(s), td::base64_encode(t)); for (auto &c : iv.raw) { c = 0xFF; } - state.init(key, iv); - state.encrypt(s, t); + state.init(as_slice(key), as_slice(iv)); + pos = 0; + for (const auto &str : td::rand_split(td::string(length, '\0'))) { + auto len = str.size(); + state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len)); + pos += len; + } ASSERT_EQ(answers2[i], td::crc32(t)); i++; } } +TEST(Crypto, AesIgeState) { + td::vector answers1{0u, 2045698207u, 2423540300u, 525522475u, 1545267325u, 724143417u}; + + std::size_t i = 0; + for (auto length : {0, 16, 32, 256, 1024, 65536}) { + td::uint32 seed = length; + td::string s(length, '\0'); + for (auto &c : s) { + seed = seed * 123457567u + 987651241u; + c = static_cast((seed >> 23) & 255); + } + + td::UInt256 key; + for (auto &c : key.raw) { + seed = seed * 123457567u + 987651241u; + c = (seed >> 23) & 255; + } + td::UInt256 iv; + for (auto &c : iv.raw) { + seed = seed * 123457567u + 987651241u; + c = (seed >> 23) & 255; + } + + td::AesIgeState state; + state.init(as_slice(key), as_slice(iv), true); + td::string t(length, '\0'); + td::UInt256 iv_copy = iv; + td::string u(length, '\0'); + std::size_t pos = 0; + for (const auto &str : td::rand_split(td::string(length / 16, '\0'))) { + auto len = 16 * str.size(); + state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len)); + td::aes_ige_encrypt(as_slice(key), as_slice(iv_copy), td::Slice(s).substr(pos, len), + td::MutableSlice(u).substr(pos, len)); + pos += len; + } + + ASSERT_EQ(answers1[i], td::crc32(t)); + ASSERT_EQ(answers1[i], td::crc32(u)); + + state.init(as_slice(key), as_slice(iv), false); + iv_copy = iv; + pos = 0; + for (const auto &str : td::rand_split(td::string(length / 16, '\0'))) { + auto len = 16 * str.size(); + state.decrypt(td::Slice(t).substr(pos, len), td::MutableSlice(t).substr(pos, len)); + td::aes_ige_decrypt(as_slice(key), as_slice(iv_copy), td::Slice(u).substr(pos, len), + td::MutableSlice(u).substr(pos, len)); + pos += len; + } + ASSERT_STREQ(td::base64_encode(s), td::base64_encode(t)); + ASSERT_STREQ(td::base64_encode(s), td::base64_encode(u)); + + i++; + } +} + +TEST(Crypto, AesCbcState) { + td::vector answers1{0u, 3617355989u, 3449188102u, 186999968u, 4244808847u, 2626031206u}; + + std::size_t i = 0; + for (auto length : {0, 16, 32, 256, 1024, 65536}) { + td::uint32 seed = length; + td::string s(length, '\0'); + for (auto &c : s) { + seed = seed * 123457567u + 987651241u; + c = static_cast((seed >> 23) & 255); + } + + td::UInt256 key; + for (auto &c : key.raw) { + seed = seed * 123457567u + 987651241u; + c = (seed >> 23) & 255; + } + td::UInt128 iv; + for (auto &c : iv.raw) { + seed = seed * 123457567u + 987651241u; + c = (seed >> 23) & 255; + } + + td::AesCbcState state(as_slice(key), as_slice(iv)); + td::string t(length, '\0'); + td::UInt128 iv_copy = iv; + td::string u(length, '\0'); + std::size_t pos = 0; + for (const auto &str : td::rand_split(td::string(length / 16, '\0'))) { + auto len = 16 * str.size(); + state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len)); + td::aes_cbc_encrypt(as_slice(key), as_slice(iv_copy), td::Slice(s).substr(pos, len), + td::MutableSlice(u).substr(pos, len)); + pos += len; + } + + ASSERT_EQ(answers1[i], td::crc32(t)); + ASSERT_EQ(answers1[i], td::crc32(u)); + + state = td::AesCbcState(as_slice(key), as_slice(iv)); + iv_copy = iv; + pos = 0; + for (const auto &str : td::rand_split(td::string(length / 16, '\0'))) { + auto len = 16 * str.size(); + state.decrypt(td::Slice(t).substr(pos, len), td::MutableSlice(t).substr(pos, len)); + td::aes_cbc_decrypt(as_slice(key), as_slice(iv_copy), td::Slice(u).substr(pos, len), + td::MutableSlice(u).substr(pos, len)); + pos += len; + } + ASSERT_STREQ(td::base64_encode(s), td::base64_encode(t)); + ASSERT_STREQ(td::base64_encode(s), td::base64_encode(u)); + + i++; + } +} +#endif + TEST(Crypto, Sha256State) { for (auto length : {0, 1, 31, 32, 33, 9999, 10000, 10001, 999999, 1000001}) { auto s = td::rand_string(std::numeric_limits::min(), std::numeric_limits::max(), length); td::UInt256 baseline; - td::sha256(s, td::MutableSlice(baseline.raw, 32)); + td::sha256(s, as_slice(baseline)); td::Sha256State state; - td::sha256_init(&state); + state.init(); + td::Sha256State state2 = std::move(state); auto v = td::rand_split(s); for (auto &x : v) { - td::sha256_update(x, &state); + state2.feed(x); } + state = std::move(state2); td::UInt256 result; - td::sha256_final(&state, td::MutableSlice(result.raw, 32)); + state.extract(as_slice(result)); ASSERT_TRUE(baseline == result); } } TEST(Crypto, PBKDF) { - td::vector passwords{"", "qwerty", std::string(1000, 'a')}; - td::vector salts{"", "qwerty", std::string(1000, 'a')}; + td::vector passwords{"", "qwerty", td::string(1000, 'a')}; + td::vector salts{"", "qwerty", td::string(1000, 'a')}; td::vector iteration_counts{1, 2, 1000}; td::vector answers{ "984LZT0tcqQQjPWr6RL/3Xd2Ftu7J6cOggTzri0Pb60=", "lzmEEdaupDp3rO+SImq4J41NsGaL0denanJfdoCsRcU=", @@ -145,6 +303,32 @@ TEST(Crypto, md5) { ASSERT_STREQ(answers[i], td::base64_encode(output)); } } + +TEST(Crypto, hmac_sha256) { + td::vector answers{ + "t33rfT85UOe6N00BhsNwobE+f2TnW331HhdvQ4GdJp8=", "BQl5HF2jqhCz4JTqhAs+H364oxboh7QlluOMHuuRVh8=", + "NCCPuZBsAPBd/qr3SyeYE+e1RNgzkKJCS/+eXDBw8zU=", "mo3ahTkyLKfoQoYA0s7vRZULuH++vqwFJD0U5n9HHw0="}; + + for (std::size_t i = 0; i < strings.size(); i++) { + td::string output(32, '\0'); + td::hmac_sha256("cucumber", strings[i], output); + ASSERT_STREQ(answers[i], td::base64_encode(output)); + } +} + +TEST(Crypto, hmac_sha512) { + td::vector answers{ + "o28hTN1m/TGlm/VYxDIzOdUE4wMpQzO8hVcTkiP2ezEJXtrOvCjRnl20aOV1S8axA5Te0TzIjfIoEAtpzamIsA==", + "32X3GslSz0HDznSrCNt++ePRcFVSUSD+tfOVannyxS+yLt/om11qILCE64RFTS8/B84gByMzC3FuAlfcIam/KA==", + "BVqe5rK1Fg1i+C7xXTAzT9vDPcf3kQQpTtse6rT/EVDzKo9AUo4ZwyUyJ0KcLHoffIjul/TuJoBg+wLz7Z7r7g==", + "WASmeku5Pcfz7N0Kp4Q3I9sxtO2MiaBXA418CY0HvjdtmAo7QY+K3E0o9UemgGzz41KqeypzRC92MwOAOnXJLA=="}; + + for (std::size_t i = 0; i < strings.size(); i++) { + td::string output(64, '\0'); + td::hmac_sha512("cucumber", strings[i], output); + ASSERT_STREQ(answers[i], td::base64_encode(output)); + } +} #endif #if TD_HAVE_ZLIB @@ -157,6 +341,69 @@ TEST(Crypto, crc32) { } #endif +#if TD_HAVE_CRC32C +TEST(Crypto, crc32c) { + td::vector answers{0u, 2432014819u, 1077264849u, 1131405888u}; + + for (std::size_t i = 0; i < strings.size(); i++) { + ASSERT_EQ(answers[i], td::crc32c(strings[i])); + + auto v = td::rand_split(strings[i]); + td::uint32 a = 0; + td::uint32 b = 0; + for (auto &x : v) { + a = td::crc32c_extend(a, x); + auto x_crc = td::crc32c(x); + b = td::crc32c_extend(b, x_crc, x.size()); + } + ASSERT_EQ(answers[i], a); + ASSERT_EQ(answers[i], b); + } +} + +TEST(Crypto, crc32c_benchmark) { + class Crc32cExtendBenchmark final : public td::Benchmark { + public: + explicit Crc32cExtendBenchmark(size_t chunk_size) : chunk_size_(chunk_size) { + } + td::string get_description() const final { + return PSTRING() << "Crc32c with chunk_size=" << chunk_size_; + } + void start_up_n(int n) final { + if (n > (1 << 20)) { + cnt_ = n / (1 << 20); + n = (1 << 20); + } else { + cnt_ = 1; + } + data_ = td::string(n, 'a'); + } + void run(int n) final { + td::uint32 res = 0; + for (int i = 0; i < cnt_; i++) { + td::Slice data(data_); + while (!data.empty()) { + auto head = data.substr(0, chunk_size_); + data = data.substr(head.size()); + res = td::crc32c_extend(res, head); + } + } + td::do_not_optimize_away(res); + } + + private: + size_t chunk_size_; + td::string data_; + int cnt_; + }; + bench(Crc32cExtendBenchmark(2)); + bench(Crc32cExtendBenchmark(8)); + bench(Crc32cExtendBenchmark(32)); + bench(Crc32cExtendBenchmark(128)); + bench(Crc32cExtendBenchmark(65536)); +} +#endif + TEST(Crypto, crc64) { td::vector answers{0ull, 3039664240384658157ull, 17549519902062861804ull, 8794730974279819706ull}; @@ -164,3 +411,61 @@ TEST(Crypto, crc64) { ASSERT_EQ(answers[i], td::crc64(strings[i])); } } + +TEST(Crypto, crc16) { + td::vector answers{0, 9842, 25046, 37023}; + + for (std::size_t i = 0; i < strings.size(); i++) { + ASSERT_EQ(answers[i], td::crc16(strings[i])); + } +} + +static td::Slice rsa_private_key = R"ABCD( +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDeYT5/prmLEa2Q +tZND+UwTmif8kl2VlXaMCjj1k1lJJq8BqS8cVM2vPnOPzFoiC2LYykhm4kk7goCC +ZH6wez9yakg28fcq0Ycv0x8DL1K+VKHJuwIhVfQs//IY1/cBOrMESc+NQowPbv1t +TIFxBO2gebnpLuseht8ix7XtpGC4qAaHN2aEvT2cRsnA76TAK1RVxf1OYGUFBDzY +318WpVZfVIjcQ7K9+eU6b2Yb84VLlvJXw3e1rvw+fBzx2EjpD4zhXy11YppWDyV6 +HEb2hs3cGS/LbHfHvdcSfil2omaJP97MDEEY2HFxjR/E5CEf2suvPzX4XS3RE+S3 +2aEJaaQbAgMBAAECggEAKo3XRNwls0wNt5xXcvF4smOUdUuY5u/0AHZQUgYBVvM1 +GA9E+ZnsxjUgLgs/0DX3k16aHj39H4sohksuxxy+lmlqKkGBN8tioC85RwW+Qre1 +QgIsNS7ai+XqcQCavrx51z88nV53qNhnXIwAVR1JT6Ubg1i8G1pZxrEKyk/jRlJd +mGjf6vjitH//PPkghPJ/D42k93YRcy+duOgqYDQpLZp8DiEGfYrX10B1H7HrWLV+ +Wp5KO1YXtKgQUplj6kYy72bVajbxYTvzgjaaKsh74jBO0uT3tHTtXG0dcKGb0VR/ +cqP/1H/lC9bAnAqAGefNusGJQZIElvTsrpIQXOeZsQKBgQD2W04S+FjqYYFjnEFX +6eL4it01afs5M3/C6CcI5JQtN6p+Na4NCSILol33xwhakn87zqdADHawBYQVQ8Uw +dPurl805wfkzN3AbfdDmtx0IJ8vK4HFpktRjfpwBVhlVtm1doAYFqqsuCF2vWW1t +mM2YOSq4AnRHCeBb/P6kRIW0MwKBgQDnFawKKqiC4tuyBOkkEhexlm7x9he0md7D +3Z2hc3Bmdcq1niw4wBq3HUxGLReGCcSr5epKSQwkunlTn5ZSC6Rmbe4zxsGIwbb3 +5W3342swBaoxEIuBokBvZ/xUOXVwiqKj+S/NzVkZcnT6K9V/HnUCQR+JBbQxFQaX +iiezcjKoeQKBgCIVUcDoIQ0UPl10ocmy7xbpx177calhSZzCl5vwW9vBptHdRV5C +VDZ92ThNjgdR205/8b23u7fwm2yBusdQd/0ufFMwVfTTB6yWBI/W56pYLya7VJWB +nebB/n1k1w53tbvNRugDy7kLqUJ4Qd521ILp7dIVbNbjM+omH2jEnibnAoGBAIM5 +a1jaoJay/M86uqohHBNcuePtO8jzF+1iDAGC7HFCsrov+CzB6mnR2V6AfLtBEM4M +4d8NXDf/LKawGUy+D72a74m3dG+UkbJ0Nt5t5pB+pwb1vkL/QFgDVOb/OhGOqI01 +FFBqLA6nUIZAHhzxzsBY+u90rb6xkey8J49faiUBAoGAaMgOgEvQB5H19ZL5tMkl +A/DKtTz/NFzN4Zw/vNPVb7eNn4jg9M25d9xqvL4acOa+nuV3nLHbcUWE1/7STXw1 +gT58CvoEmD1AiP95nup+HKHENJ1DWMgF5MDfVQwGCvWP5/Qy89ybr0eG8HjbldbN +MpSmzz2wOz152oGdOd3syT4= +-----END PRIVATE KEY----- +)ABCD"; + +static td::Slice rsa_public_key = R"ABCD( +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3mE+f6a5ixGtkLWTQ/lM +E5on/JJdlZV2jAo49ZNZSSavAakvHFTNrz5zj8xaIgti2MpIZuJJO4KAgmR+sHs/ +cmpINvH3KtGHL9MfAy9SvlShybsCIVX0LP/yGNf3ATqzBEnPjUKMD279bUyBcQTt +oHm56S7rHobfIse17aRguKgGhzdmhL09nEbJwO+kwCtUVcX9TmBlBQQ82N9fFqVW +X1SI3EOyvfnlOm9mG/OFS5byV8N3ta78Pnwc8dhI6Q+M4V8tdWKaVg8lehxG9obN +3Bkvy2x3x73XEn4pdqJmiT/ezAxBGNhxcY0fxOQhH9rLrz81+F0t0RPkt9mhCWmk +GwIDAQAB +-----END PUBLIC KEY----- +)ABCD"; + +TEST(Crypto, rsa) { + auto value = td::rand_string('a', 'z', 200); + auto encrypted_value = td::rsa_encrypt_pkcs1_oaep(rsa_public_key, value).move_as_ok(); + auto decrypted_value = td::rsa_decrypt_pkcs1_oaep(rsa_private_key, encrypted_value.as_slice()).move_as_ok(); + ASSERT_TRUE(decrypted_value.as_slice().truncate(value.size()) == value); +} -- cgit v1.2.3