1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #include "td/mtproto/RSA.h"
8
9 #include "td/mtproto/mtproto_api.h"
10
11 #include "td/utils/as.h"
12 #include "td/utils/common.h"
13 #include "td/utils/crypto.h"
14 #include "td/utils/misc.h"
15 #include "td/utils/ScopeGuard.h"
16 #include "td/utils/Slice.h"
17 #include "td/utils/Status.h"
18 #include "td/utils/tl_storers.h"
19
20 #include <openssl/bio.h>
21 #include <openssl/bn.h>
22 #include <openssl/opensslv.h>
23 #include <openssl/pem.h>
24 #if OPENSSL_VERSION_NUMBER < 0x30000000L || defined(LIBRESSL_VERSION_NUMBER)
25 #include <openssl/rsa.h>
26 #endif
27
28 namespace td {
29 namespace mtproto {
30
RSA(BigNum n,BigNum e)31 RSA::RSA(BigNum n, BigNum e) : n_(std::move(n)), e_(std::move(e)) {
32 }
33
clone() const34 RSA RSA::clone() const {
35 return RSA(n_.clone(), e_.clone());
36 }
37
from_pem_public_key(Slice pem)38 Result<RSA> RSA::from_pem_public_key(Slice pem) {
39 init_crypto();
40
41 auto *bio =
42 BIO_new_mem_buf(const_cast<void *>(static_cast<const void *>(pem.ubegin())), narrow_cast<int32>(pem.size()));
43 if (bio == nullptr) {
44 return Status::Error("Cannot create BIO");
45 }
46 SCOPE_EXIT {
47 BIO_free(bio);
48 };
49
50 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
51 EVP_PKEY *rsa = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr);
52 #else
53 auto rsa = PEM_read_bio_RSAPublicKey(bio, nullptr, nullptr, nullptr);
54 #endif
55 if (rsa == nullptr) {
56 return Status::Error("Error while reading RSA public key");
57 }
58 SCOPE_EXIT {
59 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
60 EVP_PKEY_free(rsa);
61 #else
62 RSA_free(rsa);
63 #endif
64 };
65
66 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
67 if (!EVP_PKEY_is_a(rsa, "RSA")) {
68 return Status::Error("Key is not an RSA key");
69 }
70 if (EVP_PKEY_size(rsa) != 256) {
71 return Status::Error("EVP_PKEY_size != 256");
72 }
73 #else
74 if (RSA_size(rsa) != 256) {
75 return Status::Error("RSA_size != 256");
76 }
77 #endif
78
79 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
80 BIGNUM *n_num = nullptr;
81 BIGNUM *e_num = nullptr;
82
83 int res = EVP_PKEY_get_bn_param(rsa, "n", &n_num);
84 CHECK(res == 1 && n_num != nullptr);
85 res = EVP_PKEY_get_bn_param(rsa, "e", &e_num);
86 CHECK(res == 1 && e_num != nullptr);
87
88 auto n = static_cast<void *>(n_num);
89 auto e = static_cast<void *>(e_num);
90 #else
91 const BIGNUM *n_num;
92 const BIGNUM *e_num;
93
94 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
95 RSA_get0_key(rsa, &n_num, &e_num, nullptr);
96 #else
97 n_num = rsa->n;
98 e_num = rsa->e;
99 #endif
100
101 auto n = static_cast<void *>(BN_dup(n_num));
102 auto e = static_cast<void *>(BN_dup(e_num));
103 if (n == nullptr || e == nullptr) {
104 return Status::Error("Cannot dup BIGNUM");
105 }
106 #endif
107
108 return RSA(BigNum::from_raw(n), BigNum::from_raw(e));
109 }
110
get_fingerprint() const111 int64 RSA::get_fingerprint() const {
112 // string objects are necessary, because mtproto_api::rsa_public_key contains Slice inside
113 string n_str = n_.to_binary();
114 string e_str = e_.to_binary();
115 mtproto_api::rsa_public_key public_key(n_str, e_str);
116 size_t size = tl_calc_length(public_key);
117 std::vector<unsigned char> tmp(size);
118 size = tl_store_unsafe(public_key, tmp.data());
119 CHECK(size == tmp.size());
120 unsigned char key_sha1[20];
121 sha1(Slice(tmp.data(), tmp.size()), key_sha1);
122 return as<int64>(key_sha1 + 12);
123 }
124
size() const125 size_t RSA::size() const {
126 // Checked in RSA::from_pem_public_key step
127 return 256;
128 }
129
encrypt(Slice from,MutableSlice to) const130 bool RSA::encrypt(Slice from, MutableSlice to) const {
131 CHECK(from.size() == 256)
132 CHECK(to.size() == 256)
133 int bits = n_.get_num_bits();
134 CHECK(bits >= 2041 && bits <= 2048);
135
136 BigNum x = BigNum::from_binary(from);
137 if (BigNum::compare(x, n_) >= 0) {
138 return false;
139 }
140
141 BigNumContext ctx;
142 BigNum y;
143 BigNum::mod_exp(y, x, e_, n_, ctx);
144 to.copy_from(y.to_binary(256));
145 return true;
146 }
147
decrypt_signature(Slice from,MutableSlice to) const148 void RSA::decrypt_signature(Slice from, MutableSlice to) const {
149 CHECK(from.size() == 256);
150 BigNumContext ctx;
151 BigNum x = BigNum::from_binary(from);
152 BigNum y;
153 BigNum::mod_exp(y, x, e_, n_, ctx);
154 to.copy_from(y.to_binary(256));
155 }
156
157 } // namespace mtproto
158 } // namespace td
159