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