1616
1717 Copyright 2017-2020 Telegram Systems LLP
1818*/
19- #include < openssl/evp.h>
2019#include < openssl/opensslv.h>
21- #include < openssl/pem.h>
22- #include < openssl/x509.h>
2320
2421#include " crypto/Ed25519.h"
2522#include " td/utils/BigNum.h"
2623#include " td/utils/ScopeGuard.h"
2724#include " td/utils/base64.h"
28- #include " td/utils/format.h"
29- #include " td/utils/logging.h"
3025#include " td/utils/misc.h"
3126
27+ #if TD_HAVE_OPENSSL
28+
29+ #include < openssl/evp.h>
30+ #include < openssl/opensslv.h>
31+ #include < openssl/pem.h>
32+ #include < openssl/x509.h>
33+
34+ #include " td/utils/ThreadSafeCounter.h"
35+
3236namespace td {
3337
3438Ed25519::PublicKey::PublicKey (SecureString octet_string) : octet_string_(std::move(octet_string)) {
@@ -45,6 +49,7 @@ SecureString Ed25519::PrivateKey::as_octet_string() const {
4549 return octet_string_.copy ();
4650}
4751
52+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
4853namespace detail {
4954
5055static Result<SecureString> X25519_key_from_PKEY (EVP_PKEY *pkey, bool is_private) {
@@ -67,14 +72,17 @@ static EVP_PKEY *X25519_key_to_PKEY(Slice key, bool is_private) {
6772 return func (EVP_PKEY_ED25519, nullptr , key.ubegin (), key.size ());
6873}
6974
70- static Result<SecureString> X25519_pem_from_PKEY (EVP_PKEY *pkey, bool is_private, Slice password ) {
75+ static Result<SecureString> X25519_pem_from_PKEY (EVP_PKEY *pkey, bool is_private, std::optional< Slice> o_password ) {
7176 BIO *mem_bio = BIO_new (BIO_s_mem ());
7277 SCOPE_EXIT {
7378 BIO_vfree (mem_bio);
7479 };
7580 if (is_private) {
76- PEM_write_bio_PrivateKey (mem_bio, pkey, EVP_aes_256_cbc (), const_cast <unsigned char *>(password.ubegin ()),
77- narrow_cast<int >(password.size ()), nullptr , nullptr );
81+ auto *chipher = o_password ? EVP_aes_256_cbc () : nullptr ;
82+ const unsigned char *password = o_password ? o_password->ubegin () : nullptr ;
83+ size_t password_size = o_password ? o_password->size () : 0 ;
84+ PEM_write_bio_PrivateKey (mem_bio, pkey, chipher, const_cast <unsigned char *>(password),
85+ narrow_cast<int >(password_size), nullptr , nullptr );
7886 } else {
7987 PEM_write_bio_PUBKEY (mem_bio, pkey);
8088 }
@@ -105,8 +113,10 @@ static EVP_PKEY *X25519_pem_to_PKEY(Slice pem, Slice password) {
105113}
106114
107115} // namespace detail
116+ #endif
108117
109118Result<Ed25519::PrivateKey> Ed25519::generate_private_key () {
119+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
110120 EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (NID_ED25519, nullptr );
111121 if (pctx == nullptr ) {
112122 return Status::Error (" Can't create EVP_PKEY_CTX" );
@@ -129,9 +139,13 @@ Result<Ed25519::PrivateKey> Ed25519::generate_private_key() {
129139
130140 TRY_RESULT (private_key, detail::X25519_key_from_PKEY (pkey, true ));
131141 return std::move (private_key);
142+ #else
143+ return Status::Error (" Unsupported" );
144+ #endif
132145}
133146
134147Result<Ed25519::PublicKey> Ed25519::PrivateKey::get_public_key () const {
148+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
135149 auto pkey = detail::X25519_key_to_PKEY (octet_string_, true );
136150 if (pkey == nullptr ) {
137151 return Status::Error (" Can't import private key" );
@@ -142,9 +156,19 @@ Result<Ed25519::PublicKey> Ed25519::PrivateKey::get_public_key() const {
142156
143157 TRY_RESULT (key, detail::X25519_key_from_PKEY (pkey, false ));
144158 return Ed25519::PublicKey (std::move (key));
159+ #else
160+ return Status::Error (" Unsupported" );
161+ #endif
145162}
146163
147164Result<SecureString> Ed25519::PrivateKey::as_pem (Slice password) const {
165+ return as_pem (std::optional<td::Slice>(password));
166+ }
167+ Result<SecureString> Ed25519::PrivateKey::as_pem () const {
168+ return as_pem (std::nullopt );
169+ }
170+ Result<SecureString> Ed25519::PrivateKey::as_pem (std::optional<td::Slice> o_password) const {
171+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
148172 auto pkey = detail::X25519_key_to_PKEY (octet_string_, true );
149173 if (pkey == nullptr ) {
150174 return Status::Error (" Can't import private key" );
@@ -153,27 +177,58 @@ Result<SecureString> Ed25519::PrivateKey::as_pem(Slice password) const {
153177 EVP_PKEY_free (pkey);
154178 };
155179
156- return detail::X25519_pem_from_PKEY (pkey, true , password);
180+ return detail::X25519_pem_from_PKEY (pkey, true , o_password);
181+ #else
182+ return Status::Error (" Unsupported" );
183+ #endif
157184}
158185
159186Result<Ed25519::PrivateKey> Ed25519::PrivateKey::from_pem (Slice pem, Slice password) {
187+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
160188 auto pkey = detail::X25519_pem_to_PKEY (pem, password);
161189 if (pkey == nullptr ) {
162190 return Status::Error (" Can't import private key from pem" );
163191 }
164192 TRY_RESULT (key, detail::X25519_key_from_PKEY (pkey, true ));
165193 return Ed25519::PrivateKey (std::move (key));
194+ #else
195+ return Status::Error (" Unsupported" );
196+ #endif
166197}
167198
168- Result<SecureString> Ed25519::PrivateKey::sign (Slice data) const {
199+ struct Ed25519 ::PreparedPrivateKey {
200+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
201+ explicit PreparedPrivateKey (EVP_PKEY *pkey) : pkey_(pkey) {
202+ }
203+ EVP_PKEY *pkey_ = nullptr ;
204+ PreparedPrivateKey (const PreparedPrivateKey &) = delete;
205+ PreparedPrivateKey (const PreparedPrivateKey &&) = delete;
206+ PreparedPrivateKey &operator =(const PreparedPrivateKey &) = delete ;
207+ PreparedPrivateKey &operator =(const PreparedPrivateKey &&) = delete ;
208+ ~PreparedPrivateKey () {
209+ if (pkey_ != nullptr ) {
210+ EVP_PKEY_free (pkey_);
211+ pkey_ = nullptr ;
212+ }
213+ }
214+ #endif
215+ };
216+
217+ Result<std::shared_ptr<const Ed25519::PreparedPrivateKey>> Ed25519::PrivateKey::prepare () const {
218+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
169219 auto pkey = detail::X25519_key_to_PKEY (octet_string_, true );
170220 if (pkey == nullptr ) {
171221 return Status::Error (" Can't import private key" );
172222 }
173- SCOPE_EXIT {
174- EVP_PKEY_free (pkey);
175- };
223+ return std::make_shared<Ed25519::PreparedPrivateKey>(pkey);
224+ #else
225+ return Status::Error (" Unsupported" );
226+ #endif
227+ }
176228
229+ Result<SecureString> Ed25519::PrivateKey::sign (const PreparedPrivateKey &prepared_private_key, Slice data) {
230+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
231+ CHECK (prepared_private_key.pkey_ != nullptr );
177232 EVP_MD_CTX *md_ctx = EVP_MD_CTX_new ();
178233 if (md_ctx == nullptr ) {
179234 return Status::Error (" Can't create EVP_MD_CTX" );
@@ -182,7 +237,7 @@ Result<SecureString> Ed25519::PrivateKey::sign(Slice data) const {
182237 EVP_MD_CTX_free (md_ctx);
183238 };
184239
185- if (EVP_DigestSignInit (md_ctx, nullptr , nullptr , nullptr , pkey ) <= 0 ) {
240+ if (EVP_DigestSignInit (md_ctx, nullptr , nullptr , nullptr , prepared_private_key. pkey_ ) <= 0 ) {
186241 return Status::Error (" Can't init DigestSign" );
187242 }
188243
@@ -192,9 +247,26 @@ Result<SecureString> Ed25519::PrivateKey::sign(Slice data) const {
192247 return Status::Error (" Can't sign data" );
193248 }
194249 return std::move (res);
250+ #else
251+ return Status::Error (" Unsupported" );
252+ #endif
253+ }
254+
255+ Result<SecureString> Ed25519::PrivateKey::sign (Slice data) const {
256+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
257+ auto pkey = detail::X25519_key_to_PKEY (octet_string_, true );
258+ if (pkey == nullptr ) {
259+ return Status::Error (" Can't import private key" );
260+ }
261+ return sign (PreparedPrivateKey (pkey), data);
262+ #else
263+ return Status::Error (" Unsupported" );
264+ #endif
195265}
196266
197267Status Ed25519::PublicKey::verify_signature (Slice data, Slice signature) const {
268+ TD_PERF_COUNTER (Ed25519_verify_signature);
269+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
198270 auto pkey = detail::X25519_key_to_PKEY (octet_string_, false );
199271 if (pkey == nullptr ) {
200272 return Status::Error (" Can't import public key" );
@@ -219,12 +291,20 @@ Status Ed25519::PublicKey::verify_signature(Slice data, Slice signature) const {
219291 return Status::OK ();
220292 }
221293 return Status::Error (" Wrong signature" );
294+ #else
295+ return Status::Error (" Unsupported" );
296+ #endif
222297}
223298
224299Result<SecureString> Ed25519::compute_shared_secret (const PublicKey &public_key, const PrivateKey &private_key) {
300+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
225301 BigNum p = BigNum::from_hex (" 7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" ).move_as_ok ();
226302 auto public_y = public_key.as_octet_string ();
227- public_y.as_mutable_slice ()[31 ] = static_cast <char >(public_y[31 ] & 127 );
303+ MutableSlice pub_slc = public_y.as_mutable_slice ();
304+ if (pub_slc.size () != PublicKey::LENGTH) {
305+ return Status::Error (" Wrong public key" );
306+ }
307+ pub_slc[31 ] = static_cast <char >(public_y[31 ] & 127 );
228308 BigNum y = BigNum::from_le_binary (public_y);
229309 BigNum y2 = y.clone ();
230310 y += 1 ;
@@ -241,8 +321,11 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
241321 BigNum::mod_mul (u, y, inverse_y_plus_1, p, context);
242322
243323 auto pr_key = private_key.as_octet_string ();
324+ if (pr_key.size () != PrivateKey::LENGTH) {
325+ return Status::Error (" Wrong private key" );
326+ }
244327 unsigned char buf[64 ];
245- SHA512 (Slice (pr_key).ubegin (), 32 , buf);
328+ SHA512 (Slice (pr_key).ubegin (), pr_key. size () , buf);
246329 buf[0 ] &= 248 ;
247330 buf[31 ] &= 127 ;
248331 buf[31 ] |= 64 ;
@@ -254,17 +337,15 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
254337 SCOPE_EXIT {
255338 EVP_PKEY_free (pkey_private);
256339 };
257- // LOG(ERROR) << buffer_to_hex(Slice(buf, 32));
258340
259- auto pub_key = u.to_le_binary (32 );
341+ auto pub_key = u.to_le_binary (PublicKey::LENGTH );
260342 auto pkey_public = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, nullptr , Slice (pub_key).ubegin (), pub_key.size ());
261343 if (pkey_public == nullptr ) {
262344 return Status::Error (" Can't import public key" );
263345 }
264346 SCOPE_EXIT {
265347 EVP_PKEY_free (pkey_public);
266348 };
267- // LOG(ERROR) << buffer_to_hex(pub_key);
268349
269350 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new (pkey_private, nullptr );
270351 if (ctx == nullptr ) {
@@ -294,10 +375,44 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
294375 return Status::Error (" Failed to compute shared secret" );
295376 }
296377 return std::move (result);
378+ #else
379+ return Status::Error (" Unsupported" );
380+ #endif
381+ }
382+
383+ Result<SecureString> Ed25519::get_public_key (Slice private_key) {
384+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
385+ if (private_key.size () != PrivateKey::LENGTH) {
386+ return Status::Error (" Invalid X25519 private key" );
387+ }
388+ auto pkey_private = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, nullptr , private_key.ubegin (), private_key.size ());
389+ if (pkey_private == nullptr ) {
390+ return Status::Error (" Invalid X25519 private key" );
391+ }
392+ SCOPE_EXIT {
393+ EVP_PKEY_free (pkey_private);
394+ };
395+
396+ size_t len = 0 ;
397+ if (EVP_PKEY_get_raw_public_key (pkey_private, nullptr , &len) == 0 ) {
398+ return Status::Error (" Failed to get raw key length" );
399+ }
400+ CHECK (len == PublicKey::LENGTH);
401+
402+ SecureString result (len);
403+ if (EVP_PKEY_get_raw_public_key (pkey_private, result.as_mutable_slice ().ubegin (), &len) == 0 ) {
404+ return Status::Error (" Failed to get raw key" );
405+ }
406+ return std::move (result);
407+ #else
408+ return Status::Error (" Unsupported" );
409+ #endif
297410}
298411
299412int Ed25519::version () {
300413 return OPENSSL_VERSION_NUMBER;
301414}
302415
303416} // namespace td
417+
418+ #endif
0 commit comments