Ton

Форк
0
/
Ed25519.cpp 
402 строки · 12.0 Кб
1
/*
2
    This file is part of TON Blockchain Library.
3

4
    TON Blockchain Library is free software: you can redistribute it and/or modify
5
    it under the terms of the GNU Lesser General Public License as published by
6
    the Free Software Foundation, either version 2 of the License, or
7
    (at your option) any later version.
8

9
    TON Blockchain Library is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
    GNU Lesser General Public License for more details.
13

14
    You should have received a copy of the GNU Lesser General Public License
15
    along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
16

17
    Copyright 2017-2020 Telegram Systems LLP
18
*/
19
#include "crypto/Ed25519.h"
20

21
#if TD_HAVE_OPENSSL
22

23
#include <openssl/opensslv.h>
24

25
#if OPENSSL_VERSION_NUMBER >= 0x10101000L && OPENSSL_VERSION_NUMBER != 0x20000000L || defined(OPENSSL_IS_BORINGSSL)
26

27
#include "td/utils/base64.h"
28
#include "td/utils/BigNum.h"
29
#include "td/utils/format.h"
30
#include "td/utils/logging.h"
31
#include "td/utils/misc.h"
32
#include "td/utils/ScopeGuard.h"
33

34
#include <openssl/evp.h>
35
#include <openssl/pem.h>
36
#include <openssl/x509.h>
37

38
#else
39

40
#include "crypto/ellcurve/Ed25519.h"
41

42
#endif
43

44
namespace td {
45

46
Ed25519::PublicKey::PublicKey(SecureString octet_string) : octet_string_(std::move(octet_string)) {
47
}
48

49
SecureString Ed25519::PublicKey::as_octet_string() const {
50
  return octet_string_.copy();
51
}
52

53
Ed25519::PrivateKey::PrivateKey(SecureString octet_string) : octet_string_(std::move(octet_string)) {
54
}
55

56
SecureString Ed25519::PrivateKey::as_octet_string() const {
57
  return octet_string_.copy();
58
}
59

60
#if OPENSSL_VERSION_NUMBER >= 0x10101000L && OPENSSL_VERSION_NUMBER != 0x20000000L || defined(OPENSSL_IS_BORINGSSL)
61

62
namespace detail {
63

64
static Result<SecureString> X25519_key_from_PKEY(EVP_PKEY *pkey, bool is_private) {
65
  auto func = is_private ? &EVP_PKEY_get_raw_private_key : &EVP_PKEY_get_raw_public_key;
66
  size_t len = 0;
67
  if (func(pkey, nullptr, &len) == 0) {
68
    return Status::Error("Failed to get raw key length");
69
  }
70
  CHECK(len == 32);
71

72
  SecureString result(len);
73
  if (func(pkey, result.as_mutable_slice().ubegin(), &len) == 0) {
74
    return Status::Error("Failed to get raw key");
75
  }
76
  return std::move(result);
77
}
78

79
static EVP_PKEY *X25519_key_to_PKEY(Slice key, bool is_private) {
80
  auto func = is_private ? &EVP_PKEY_new_raw_private_key : &EVP_PKEY_new_raw_public_key;
81
  return func(EVP_PKEY_ED25519, nullptr, key.ubegin(), key.size());
82
}
83

84
static Result<SecureString> X25519_pem_from_PKEY(EVP_PKEY *pkey, bool is_private, Slice password) {
85
  BIO *mem_bio = BIO_new(BIO_s_mem());
86
  SCOPE_EXIT {
87
    BIO_vfree(mem_bio);
88
  };
89
  if (is_private) {
90
    PEM_write_bio_PrivateKey(mem_bio, pkey, EVP_aes_256_cbc(), const_cast<unsigned char *>(password.ubegin()),
91
                             narrow_cast<int>(password.size()), nullptr, nullptr);
92
  } else {
93
    PEM_write_bio_PUBKEY(mem_bio, pkey);
94
  }
95
  char *data_ptr = nullptr;
96
  auto data_size = BIO_get_mem_data(mem_bio, &data_ptr);
97
  return std::string(data_ptr, data_size);
98
}
99

100
static int password_cb(char *buf, int size, int rwflag, void *u) {
101
  auto &password = *reinterpret_cast<Slice *>(u);
102
  auto password_size = narrow_cast<int>(password.size());
103
  if (size < password_size) {
104
    return -1;
105
  }
106
  if (rwflag == 0) {
107
    MutableSlice(buf, size).copy_from(password);
108
  }
109
  return password_size;
110
}
111

112
static EVP_PKEY *X25519_pem_to_PKEY(Slice pem, Slice password) {
113
  BIO *mem_bio = BIO_new_mem_buf(pem.ubegin(), narrow_cast<int>(pem.size()));
114
  SCOPE_EXIT {
115
    BIO_vfree(mem_bio);
116
  };
117

118
  return PEM_read_bio_PrivateKey(mem_bio, nullptr, password_cb, &password);
119
}
120

121
}  // namespace detail
122

123
Result<Ed25519::PrivateKey> Ed25519::generate_private_key() {
124
  EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(NID_ED25519, nullptr);
125
  if (pctx == nullptr) {
126
    return Status::Error("Can't create EVP_PKEY_CTX");
127
  }
128
  SCOPE_EXIT {
129
    EVP_PKEY_CTX_free(pctx);
130
  };
131

132
  if (EVP_PKEY_keygen_init(pctx) <= 0) {
133
    return Status::Error("Can't init keygen");
134
  }
135

136
  EVP_PKEY *pkey = nullptr;
137
  if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {
138
    return Status::Error("Can't generate random private key");
139
  }
140
  SCOPE_EXIT {
141
    EVP_PKEY_free(pkey);
142
  };
143

144
  TRY_RESULT(private_key, detail::X25519_key_from_PKEY(pkey, true));
145
  return std::move(private_key);
146
}
147

148
Result<Ed25519::PublicKey> Ed25519::PrivateKey::get_public_key() const {
149
  auto pkey = detail::X25519_key_to_PKEY(octet_string_, true);
150
  if (pkey == nullptr) {
151
    return Status::Error("Can't import private key");
152
  }
153
  SCOPE_EXIT {
154
    EVP_PKEY_free(pkey);
155
  };
156

157
  TRY_RESULT(key, detail::X25519_key_from_PKEY(pkey, false));
158
  return Ed25519::PublicKey(std::move(key));
159
}
160

161
Result<SecureString> Ed25519::PrivateKey::as_pem(Slice password) const {
162
  auto pkey = detail::X25519_key_to_PKEY(octet_string_, true);
163
  if (pkey == nullptr) {
164
    return Status::Error("Can't import private key");
165
  }
166
  SCOPE_EXIT {
167
    EVP_PKEY_free(pkey);
168
  };
169

170
  return detail::X25519_pem_from_PKEY(pkey, true, password);
171
}
172

173
Result<Ed25519::PrivateKey> Ed25519::PrivateKey::from_pem(Slice pem, Slice password) {
174
  auto pkey = detail::X25519_pem_to_PKEY(pem, password);
175
  if (pkey == nullptr) {
176
    return Status::Error("Can't import private key from pem");
177
  }
178
  TRY_RESULT(key, detail::X25519_key_from_PKEY(pkey, true));
179
  return Ed25519::PrivateKey(std::move(key));
180
}
181

182
Result<SecureString> Ed25519::PrivateKey::sign(Slice data) const {
183
  auto pkey = detail::X25519_key_to_PKEY(octet_string_, true);
184
  if (pkey == nullptr) {
185
    return Status::Error("Can't import private key");
186
  }
187
  SCOPE_EXIT {
188
    EVP_PKEY_free(pkey);
189
  };
190

191
  EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
192
  if (md_ctx == nullptr) {
193
    return Status::Error("Can't create EVP_MD_CTX");
194
  }
195
  SCOPE_EXIT {
196
    EVP_MD_CTX_free(md_ctx);
197
  };
198

199
  if (EVP_DigestSignInit(md_ctx, nullptr, nullptr, nullptr, pkey) <= 0) {
200
    return Status::Error("Can't init DigestSign");
201
  }
202

203
  SecureString res(64, '\0');
204
  size_t len = 64;
205
  if (EVP_DigestSign(md_ctx, res.as_mutable_slice().ubegin(), &len, data.ubegin(), data.size()) <= 0) {
206
    return Status::Error("Can't sign data");
207
  }
208
  return std::move(res);
209
}
210

211
Status Ed25519::PublicKey::verify_signature(Slice data, Slice signature) const {
212
  auto pkey = detail::X25519_key_to_PKEY(octet_string_, false);
213
  if (pkey == nullptr) {
214
    return Status::Error("Can't import public key");
215
  }
216
  SCOPE_EXIT {
217
    EVP_PKEY_free(pkey);
218
  };
219

220
  EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
221
  if (md_ctx == nullptr) {
222
    return Status::Error("Can't create EVP_MD_CTX");
223
  }
224
  SCOPE_EXIT {
225
    EVP_MD_CTX_free(md_ctx);
226
  };
227

228
  if (EVP_DigestVerifyInit(md_ctx, nullptr, nullptr, nullptr, pkey) <= 0) {
229
    return Status::Error("Can't init DigestVerify");
230
  }
231

232
  if (EVP_DigestVerify(md_ctx, signature.ubegin(), signature.size(), data.ubegin(), data.size())) {
233
    return Status::OK();
234
  }
235
  return Status::Error("Wrong signature");
236
}
237

238
Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key) {
239
  BigNum p = BigNum::from_hex("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed").move_as_ok();
240
  auto public_y = public_key.as_octet_string();
241
  public_y.as_mutable_slice()[31] = static_cast<char>(public_y[31] & 127);
242
  BigNum y = BigNum::from_le_binary(public_y);
243
  BigNum y2 = y.clone();
244
  y += 1;
245
  y2 -= 1;
246

247
  BigNumContext context;
248

249
  BigNum::mod_sub(y2, p, y2, p, context);
250

251
  BigNum inverse_y_plus_1;
252
  BigNum::mod_inverse(inverse_y_plus_1, y2, p, context);
253

254
  BigNum u;
255
  BigNum::mod_mul(u, y, inverse_y_plus_1, p, context);
256

257
  auto pr_key = private_key.as_octet_string();
258
  unsigned char buf[64];
259
  SHA512(Slice(pr_key).ubegin(), 32, buf);
260
  buf[0] &= 248;
261
  buf[31] &= 127;
262
  buf[31] |= 64;
263

264
  auto pkey_private = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, nullptr, buf, 32);
265
  if (pkey_private == nullptr) {
266
    return Status::Error("Can't import private key");
267
  }
268
  SCOPE_EXIT {
269
    EVP_PKEY_free(pkey_private);
270
  };
271
  // LOG(ERROR) << buffer_to_hex(Slice(buf, 32));
272

273
  auto pub_key = u.to_le_binary(32);
274
  auto pkey_public = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, nullptr, Slice(pub_key).ubegin(), pub_key.size());
275
  if (pkey_public == nullptr) {
276
    return Status::Error("Can't import public key");
277
  }
278
  SCOPE_EXIT {
279
    EVP_PKEY_free(pkey_public);
280
  };
281
  // LOG(ERROR) << buffer_to_hex(pub_key);
282

283
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey_private, nullptr);
284
  if (ctx == nullptr) {
285
    return Status::Error("Can't create EVP_PKEY_CTX");
286
  }
287
  SCOPE_EXIT {
288
    EVP_PKEY_CTX_free(ctx);
289
  };
290

291
  if (EVP_PKEY_derive_init(ctx) <= 0) {
292
    return Status::Error("Can't init derive");
293
  }
294
  if (EVP_PKEY_derive_set_peer(ctx, pkey_public) <= 0) {
295
    return Status::Error("Can't init derive");
296
  }
297

298
  size_t result_len = 0;
299
  if (EVP_PKEY_derive(ctx, nullptr, &result_len) <= 0) {
300
    return Status::Error("Can't get result length");
301
  }
302
  if (result_len != 32) {
303
    return Status::Error("Unexpected result length");
304
  }
305

306
  SecureString result(result_len, '\0');
307
  if (EVP_PKEY_derive(ctx, result.as_mutable_slice().ubegin(), &result_len) <= 0) {
308
    return Status::Error("Failed to compute shared secret");
309
  }
310
  return std::move(result);
311
}
312

313
int Ed25519::version() {
314
  return OPENSSL_VERSION_NUMBER;
315
}
316

317
#else
318

319
Result<Ed25519::PrivateKey> Ed25519::generate_private_key() {
320
  crypto::Ed25519::PrivateKey private_key;
321
  if (!private_key.random_private_key(true)) {
322
    return Status::Error("Can't generate random private key");
323
  }
324
  SecureString private_key_buf(32);
325
  if (!private_key.export_private_key(private_key_buf.as_mutable_slice())) {
326
    return Status::Error("Failed to export private key");
327
  }
328
  return PrivateKey(std::move(private_key_buf));
329
}
330

331
Result<Ed25519::PublicKey> Ed25519::PrivateKey::get_public_key() const {
332
  crypto::Ed25519::PrivateKey private_key;
333
  if (!private_key.import_private_key(Slice(octet_string_).ubegin())) {
334
    return Status::Error("Bad private key");
335
  }
336
  SecureString public_key(32);
337
  if (!private_key.get_public_key().export_public_key(public_key.as_mutable_slice())) {
338
    return Status::Error("Failed to export public key");
339
  }
340
  return PublicKey(std::move(public_key));
341
}
342

343
Result<SecureString> Ed25519::PrivateKey::as_pem(Slice password) const {
344
  return Status::Error("Not supported");
345
}
346

347
Result<Ed25519::PrivateKey> Ed25519::PrivateKey::from_pem(Slice pem, Slice password) {
348
  return Status::Error("Not supported");
349
}
350

351
Result<SecureString> Ed25519::PrivateKey::sign(Slice data) const {
352
  crypto::Ed25519::PrivateKey private_key;
353
  if (!private_key.import_private_key(Slice(octet_string_).ubegin())) {
354
    return Status::Error("Bad private key");
355
  }
356
  SecureString signature(crypto::Ed25519::sign_bytes, '\0');
357
  if (!private_key.sign_message(signature.as_mutable_slice(), data)) {
358
    return Status::Error("Failed to sign message");
359
  }
360
  return std::move(signature);
361
}
362

363
Status Ed25519::PublicKey::verify_signature(Slice data, Slice signature) const {
364
  if (signature.size() != crypto::Ed25519::sign_bytes) {
365
    return Status::Error("Signature has invalid length");
366
  }
367

368
  crypto::Ed25519::PublicKey public_key;
369
  if (!public_key.import_public_key(Slice(octet_string_).ubegin())) {
370
    return Status::Error("Bad public key");
371
  }
372
  if (public_key.check_message_signature(signature, data)) {
373
    return Status::OK();
374
  }
375
  return Status::Error("Wrong signature");
376
}
377

378
Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key) {
379
  crypto::Ed25519::PrivateKey tmp_private_key;
380
  if (!tmp_private_key.import_private_key(Slice(private_key.as_octet_string()).ubegin())) {
381
    return Status::Error("Bad private key");
382
  }
383
  crypto::Ed25519::PublicKey tmp_public_key;
384
  if (!tmp_public_key.import_public_key(Slice(public_key.as_octet_string()).ubegin())) {
385
    return Status::Error("Bad public key");
386
  }
387
  SecureString shared_secret(32, '\0');
388
  if (!tmp_private_key.compute_shared_secret(shared_secret.as_mutable_slice(), tmp_public_key)) {
389
    return Status::Error("Failed to compute shared secret");
390
  }
391
  return std::move(shared_secret);
392
}
393

394
int Ed25519::version() {
395
  return 0;
396
}
397

398
#endif
399

400
}  // namespace td
401

402
#endif
403

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.