forked from ton-blockchain/ton
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathp256.cpp
91 lines (83 loc) · 3.03 KB
/
p256.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "p256.h"
#include "td/utils/check.h"
#include "td/utils/misc.h"
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <iostream>
namespace td {
td::Status p256_check_signature(td::Slice data, td::Slice public_key, td::Slice signature) {
CHECK(public_key.size() == 33);
CHECK(signature.size() == 64);
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
if (pctx == nullptr) {
return td::Status::Error("Can't create EVP_PKEY_CTX");
}
SCOPE_EXIT {
EVP_PKEY_CTX_free(pctx);
};
if (EVP_PKEY_paramgen_init(pctx) <= 0) {
return td::Status::Error("EVP_PKEY_paramgen_init failed");
}
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) {
return td::Status::Error("EVP_PKEY_CTX_set_ec_paramgen_curve_nid failed");
}
EVP_PKEY* pkey = nullptr;
if (EVP_PKEY_paramgen(pctx, &pkey) <= 0) {
return td::Status::Error("EVP_PKEY_paramgen failed");
}
SCOPE_EXIT {
EVP_PKEY_free(pkey);
};
if (EVP_PKEY_set1_tls_encodedpoint(pkey, public_key.ubegin(), public_key.size()) <= 0) {
return td::Status::Error("Failed to import public key");
}
EVP_MD_CTX* md_ctx = EVP_MD_CTX_new();
if (md_ctx == nullptr) {
return td::Status::Error("Can't create EVP_MD_CTX");
}
SCOPE_EXIT {
EVP_MD_CTX_free(md_ctx);
};
if (EVP_DigestVerifyInit(md_ctx, nullptr, nullptr, nullptr, pkey) <= 0) {
return td::Status::Error("Can't init DigestVerify");
}
ECDSA_SIG* sig = ECDSA_SIG_new();
SCOPE_EXIT {
ECDSA_SIG_free(sig);
};
unsigned char buf[33];
buf[0] = 0;
std::copy(signature.ubegin(), signature.ubegin() + 32, buf + 1);
BIGNUM* r = BN_bin2bn(buf, 33, nullptr);
std::copy(signature.ubegin() + 32, signature.ubegin() + 64, buf + 1);
BIGNUM* s = BN_bin2bn(buf, 33, nullptr);
if (ECDSA_SIG_set0(sig, r, s) != 1) {
return td::Status::Error("Invalid signature");
}
unsigned char* signature_encoded = nullptr;
int signature_len = i2d_ECDSA_SIG(sig, &signature_encoded);
if (signature_len <= 0) {
return td::Status::Error("Invalid signature");
}
SCOPE_EXIT {
OPENSSL_free(signature_encoded);
};
if (EVP_DigestVerify(md_ctx, signature_encoded, signature_len, data.ubegin(), data.size()) == 1) {
return td::Status::OK();
}
return td::Status::Error("Wrong signature");
}
} // namespace td