Loading...
Searching...
No Matches
signature_verifier.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019-2022 ExpoLab, UC Davis
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 */
25
27
28#include <cryptopp/aes.h>
29#include <cryptopp/cmac.h>
30#include <cryptopp/dsa.h>
31#include <cryptopp/eccrypto.h>
32#include <cryptopp/filters.h>
33#include <cryptopp/hex.h>
34#include <cryptopp/osrng.h>
35#include <cryptopp/pssr.h>
36#include <cryptopp/rsa.h>
37#include <cryptopp/sha.h>
38#include <cryptopp/whrlpool.h>
39#include <glog/logging.h>
40
42
43namespace resdb {
44
45namespace {
46
47// ================== for verify ====================================
48bool ED25519verifyString(const std::string& message,
49 const std::string& public_key,
50 const std::string& signature) {
51 CryptoPP::byte byteKey[CryptoPP::ed25519PrivateKey::PUBLIC_KEYLENGTH];
52 if (public_key.size() != CryptoPP::ed25519PrivateKey::PUBLIC_KEYLENGTH) {
53 LOG(ERROR) << "public key len invalid:" << public_key.size();
54 return false;
55 }
56 memcpy(byteKey, public_key.c_str(), public_key.size());
57 auto verifier = CryptoPP::ed25519::Verifier(byteKey);
58
59 bool valid = true;
60 CryptoPP::StringSource(
61 signature + message, true,
62 new CryptoPP::SignatureVerificationFilter(
63 verifier,
64 new CryptoPP::ArraySink((CryptoPP::byte*)&valid, sizeof(valid))));
65 if (!valid) {
66 LOG(ERROR) << "signature invalid. signature len:" << signature.size()
67 << " message len:" << message.size();
68 }
69 return valid;
70}
71
72bool CmacVerifyString(const std::string& message, const std::string& public_key,
73 const std::string& signature) {
74 bool res = false;
75 // KEY TRANSFORMATION
76 // https://stackoverflow.com/questions/26145776/string-to-secbyteblock-conversion
77 CryptoPP::SecByteBlock privKey((const unsigned char*)(public_key.data()),
78 public_key.size());
79 CryptoPP::CMAC<CryptoPP::AES> cmac(privKey.data(), privKey.size());
80 const int flags = CryptoPP::HashVerificationFilter::HASH_AT_END |
81 CryptoPP::HashVerificationFilter::PUT_RESULT;
82
83 // MESSAGE VERIFICATION
84 CryptoPP::StringSource ss3(
85 message + signature, true,
86 new CryptoPP::HashVerificationFilter(
87 cmac, new CryptoPP::ArraySink((CryptoPP::byte*)&res, sizeof(res)),
88 flags)); // StringSource
89 return res;
90}
91
92// ================== for sign ====================================
93
94std::string ED25519signString(const std::string& message,
95 CryptoPP::ed25519::Signer* signer) {
96 CryptoPP::AutoSeededRandomPool prng;
97 std::string signature;
98 CryptoPP::StringSource(
99 message, true,
100 new CryptoPP::SignerFilter(CryptoPP::NullRNG(), *signer,
101 new CryptoPP::StringSink(signature)));
102 return signature;
103}
104
105// CMAC-AES Signature generator
106// Return a token, mac, to verify the a message.
107std::string CmacSignString(const std::string& private_key,
108 const std::string& message) {
109 std::string mac = "";
110
111 // KEY TRANSFORMATION.
112 // https://stackoverflow.com/questions/26145776/string-to-secbyteblock-conversion
113
114 CryptoPP::SecByteBlock mac_private_key(
115 (const unsigned char*)(private_key.data()), private_key.size());
116
117 CryptoPP::CMAC<CryptoPP::AES> cmac(mac_private_key.data(),
118 mac_private_key.size());
119
120 CryptoPP::StringSource ss1(
121 message, true,
122 new CryptoPP::HashFilter(cmac, new CryptoPP::StringSink(mac)));
123 return mac;
124}
125
126} // namespace
127
128SignatureVerifier::SignatureVerifier(const KeyInfo& private_key,
129 const CertificateInfo& certificate_info) {
130 private_key_ = private_key;
131 if (private_key_.key().empty()) {
132 LOG(ERROR) << "private invalid";
133 }
134
135 node_id_ = certificate_info.node_id();
136 admin_public_key_ = certificate_info.admin_public_key();
137 AddPublicKey(certificate_info.public_key(), false);
138 if (private_key_.hash_type() == SignatureInfo::ED25519) {
139 CryptoPP::byte byteKey[CryptoPP::ed25519PrivateKey::SECRET_KEYLENGTH];
140 if (private_key_.key().size() !=
141 CryptoPP::ed25519PrivateKey::SECRET_KEYLENGTH) {
142 return;
143 }
144 memcpy(byteKey, private_key_.key().c_str(), private_key_.key().size());
145 signer_ = std::make_unique<CryptoPP::ed25519::Signer>(byteKey);
146 }
147}
148
149bool SignatureVerifier::AddPublicKey(const CertificateKey& public_key,
150 bool need_verify) {
151 std::unique_lock<std::shared_mutex> lk(mutex_);
152 if (need_verify &&
153 !VerifyKey(public_key.public_key_info(), public_key.certificate())) {
154 return false;
155 }
156 // LOG(ERROR) << "add public key from:"
157 // << public_key.public_key_info().node_id();
158 keys_[public_key.public_key_info().node_id()] = public_key;
159 return true;
160}
161
162absl::StatusOr<KeyInfo> SignatureVerifier::GetPublicKey(int64_t node_id) const {
163 std::shared_lock<std::shared_mutex> lk(mutex_);
164 auto it = keys_.find(node_id);
165 if (it == keys_.end()) {
166 return absl::InvalidArgumentError("Public key not exist.");
167 }
168 return it->second.public_key_info().key();
169}
170
171std::vector<CertificateKey> SignatureVerifier::GetAllPublicKeys() const {
172 std::shared_lock<std::shared_mutex> lk(mutex_);
173 std::vector<CertificateKey> keys;
174 for (auto key : keys_) {
175 keys.push_back(key.second);
176 }
177 return keys;
178}
179
181 std::shared_lock<std::shared_mutex> lk(mutex_);
182 return keys_.size();
183}
184
185// Funtion to calculate hash of a string.
186std::string SignatureVerifier::CalculateHash(const std::string& str) {
187 CryptoPP::byte const* pData = (CryptoPP::byte*)str.data();
188 unsigned int nDataLen = str.size();
189 CryptoPP::byte aDigest[CryptoPP::SHA256::DIGESTSIZE];
190
191 CryptoPP::SHA256().CalculateDigest(aDigest, pData, nDataLen);
192 return std::string((char*)aDigest, CryptoPP::SHA256::DIGESTSIZE);
193}
194
195absl::StatusOr<SignatureInfo> SignatureVerifier::SignMessage(
196 const std::string& message) {
197 SignatureInfo info;
198 info.set_node_id(node_id_);
199 switch (private_key_.hash_type()) {
200 case SignatureInfo::RSA:
201 info.set_signature(utils::RsaSignString(private_key_.key(), message));
202 break;
203 case SignatureInfo::ED25519:
204 info.set_signature(ED25519signString(message, signer_.get()));
205 break;
206 case SignatureInfo::CMAC_AES:
207 info.set_signature(CmacSignString(private_key_.key(), message));
208 break;
209 case SignatureInfo::ECDSA:
210 info.set_signature(utils::ECDSASignString(private_key_.key(), message));
211 break;
212 default:
213 break;
214 }
215 return info;
216}
217
218bool SignatureVerifier::VerifyMessage(const google::protobuf::Message& message,
219 const SignatureInfo& sign) {
220 std::string str;
221 if (!message.SerializeToString(&str)) {
222 return false;
223 }
224 return VerifyMessage(str, sign);
225}
226
227bool SignatureVerifier::VerifyMessage(const std::string& message,
228 const SignatureInfo& info) {
229 if (info.signature().empty()) {
230 LOG(ERROR) << " signature is empty";
231 return false;
232 }
233 auto public_key = GetPublicKey(info.node_id());
234 if (!public_key.ok()) {
235 LOG(ERROR) << "key not found:" << info.node_id();
236 return false;
237 }
238 return VerifyMessage(message, *public_key, info.signature());
239}
240
241absl::StatusOr<SignatureInfo> SignatureVerifier::SignCertificateKeyInfo(
242 const CertificateKeyInfo& info) {
243 std::string str;
244 if (!info.SerializeToString(&str)) {
245 return absl::InvalidArgumentError("Serialize fail");
246 }
248}
249
250bool SignatureVerifier::VerifyKey(const CertificateKeyInfo& info,
251 const SignatureInfo& sign) {
252 std::string str;
253 if (!info.SerializeToString(&str)) {
254 return false;
255 }
256 return VerifyMessage(str, admin_public_key_, sign.signature());
257}
258
259bool SignatureVerifier::VerifyMessage(const std::string& message,
260 const KeyInfo& public_key,
261 const std::string& signature) {
262 if (public_key.key().empty() || signature.empty()) {
263 LOG(ERROR) << "public is empty, size(" << public_key.key().size()
264 << ") or signature is empty, size(" << signature.size() << ")";
265 return false;
266 }
267 // LOG(ERROR) << "public key hash type:" << public_key.hash_type()
268 // << " key size:" << public_key.key().size()
269 // << " sig size:" << signature.size()
270 // << " msg size:" << message.size();
271 switch (public_key.hash_type()) {
272 case SignatureInfo::RSA:
273 return utils::RsaVerifyString(message, public_key.key(), signature);
274 case SignatureInfo::ED25519:
275 return ED25519verifyString(message, public_key.key(), signature);
276 case SignatureInfo::CMAC_AES:
277 return CmacVerifyString(message, public_key.key(), signature);
278 case SignatureInfo::ECDSA:
279 return utils::ECDSAVerifyString(message, public_key.key(), signature);
280 default:
281 return true;
282 }
283}
284
285} // namespace resdb
bool VerifyKey(const CertificateKeyInfo &info, const SignatureInfo &sign)
absl::StatusOr< SignatureInfo > SignCertificateKeyInfo(const CertificateKeyInfo &info)
absl::StatusOr< KeyInfo > GetPublicKey(int64_t node_id) const
SignatureVerifier(const KeyInfo &private_key, const CertificateInfo &certificate_info)
std::vector< CertificateKey > GetAllPublicKeys() const
static std::string CalculateHash(const std::string &str)
bool AddPublicKey(const CertificateKey &pub_key, bool need_verify=true)
virtual absl::StatusOr< SignatureInfo > SignMessage(const std::string &message)
virtual bool VerifyMessage(const std::string &message, const SignatureInfo &sign)
res
Definition addr.py:25
Definition keys.py:1
bool RsaVerifyString(const std::string &message, const std::string &public_key, const std::string &signature)
std::string ECDSASignString(const std::string &private_key, const std::string &message)
bool ECDSAVerifyString(const std::string &message, const std::string &public_key, const std::string &signature)
std::string RsaSignString(const std::string &private_key, const std::string &message)