scclib
Stable Cloud Computing C++ Library
rsa.cc
Go to the documentation of this file.
1 /*
2 BSD 3-Clause License
3 
4 Copyright (c) 2022, Stable Cloud Computing, Inc.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 1. Redistributions of source code must retain the above copyright notice, this
10  list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <crypto/rsa.h>
32 #include <gtest/gtest.h>
33 #include <iostream>
34 #include <string>
35 #include <vector>
36 #include <fstream>
37 #include <encode/hex.h>
38 #include <crypto/hash.h>
39 
52 using std::cout;
53 using std::endl;
54 using std::string;
55 using scc::encode::Hex;
60 using scc::crypto::Hash;
63 
64 using charv = std::vector<char>;
65 
66 TEST(rsa_key, private_zero)
67 {
68  RsaPrivateKey k;
69  cout << "zero key:" << k.str();
70  cout << k.str();
71  ASSERT_EQ(k.width(), 0);
72 }
73 
74 TEST(rsa_key, private_generate)
75 {
76  RsaPrivateKey k;
77  k.generate(256);
78  cout << "256 bit key:" << k.str();
79  ASSERT_EQ(k.width(), 256);
80 }
81 
82 TEST(rsa_key, private_validate)
83 {
84  RsaPrivateKey k;
85  k.generate(256);
86  cout << "validate key:" << k.str();
87  ASSERT_EQ(k.width(), 256);
88  ASSERT_TRUE(k.validate());
89 }
90 
91 TEST(rsa_key, zero_construct)
92 {
93  RsaPrivateKey a;
94  ASSERT_EQ(a.width(), 0);
95  ASSERT_FALSE(a.validate());
96 }
97 
98 TEST(rsa_key, clear)
99 {
100  RsaPrivateKey a;
101  a.generate(512);
102  ASSERT_EQ(a.width(), 512);
103  ASSERT_TRUE(a.validate());
104  a.clear();
105  ASSERT_EQ(a.width(), 0);
106  ASSERT_FALSE(a.validate());
107 }
108 
109 TEST(rsa_key, copy_construct)
110 {
111  RsaPrivateKey a;
112  a.generate(512);
113  ASSERT_EQ(a.width(), 512);
114  ASSERT_TRUE(a.validate());
115 
116  RsaPrivateKey b(a);
117  ASSERT_EQ(a.width(), 512);
118  ASSERT_TRUE(a.validate());
119  ASSERT_EQ(b.width(), 512);
120  ASSERT_TRUE(b.validate());
121 }
122 
123 TEST(rsa_key, copy_op)
124 {
125  RsaPrivateKey a;
126  a.generate(512);
127  ASSERT_EQ(a.width(), 512);
128  ASSERT_TRUE(a.validate());
129 
130  RsaPrivateKey b;
131  b = a;
132  ASSERT_EQ(a.width(), 512);
133  ASSERT_TRUE(a.validate());
134  ASSERT_EQ(b.width(), 512);
135  ASSERT_TRUE(b.validate());
136 }
137 
138 TEST(rsa_key, move_construct)
139 {
140  RsaPrivateKey a;
141  a.generate(512);
142  ASSERT_EQ(a.width(), 512);
143  ASSERT_TRUE(a.validate());
144 
145  RsaPrivateKey b = std::move(a);
146  ASSERT_EQ(a.width(), 0);
147  ASSERT_FALSE(a.validate());
148  ASSERT_EQ(b.width(), 512);
149  ASSERT_TRUE(b.validate());
150 }
151 
152 TEST(rsa_key, move_op)
153 {
154  RsaPrivateKey a;
155  a.generate(512);
156  ASSERT_EQ(a.width(), 512);
157  ASSERT_TRUE(a.validate());
158 
159  RsaPrivateKey b;
160  b = std::move(a);
161  ASSERT_EQ(a.width(), 0);
162  ASSERT_FALSE(a.validate());
163  ASSERT_EQ(b.width(), 512);
164  ASSERT_TRUE(b.validate());
165 }
166 
167 static string plaintext =
168 "To be, or not to be, that is the question:\n"
169 "Whether 'tis nobler in the mind to suffer\n"
170 "The slings and arrows of outrageous fortune,\n"
171 "Or to take Arms against a Sea of troubles,\n"
172 "And by opposing end them: to die, to sleep;\n"
173 "No more; and by a sleep, to say we end\n"
174 "The heart-ache, and the thousand natural shocks\n"
175 "That Flesh is heir to? 'Tis a consummation\n"
176 "Devoutly to be wished. To die, to sleep,\n"
177 "perchance to Dream; aye, there's the rub...\n"
178 ;
179 
180 TEST(rsa_encryption, pkcs_signature)
181 {
182  cout << "*** Pkcs signature test" << endl;
183 
184  RsaPrivateKey key;
185  key.generate(1024);
186 
187  cout << "*** Key:\n" << key.str() << endl;
188 
189  cout << "*** Orig:\n" << plaintext << endl;
190 
191  charv sig;
192  PkcsSignature::sign(plaintext.data(), plaintext.size(), sig, key, PkcsSignature::HashType::sha256);
193 
194  cout << "*** Signature (" << sig.size() << " bytes):\n" << Hex::bin_to_hexstr(sig, ":", 16) << endl;
195 
196  ASSERT_EQ(sig.size(), PkcsSignature::size(key));
197 
198  RsaPublicKey pubkey = key.pub_key();
199 
200  bool ver = PkcsSignature::verify(plaintext.data(), plaintext.size(), sig, pubkey, PkcsSignature::HashType::sha256);
201  cout << "*** Verify: " << (ver ? "OK" : "FAIL") << endl;
202 
203  ASSERT_TRUE(ver);
204 
205  ver = PkcsSignature::verify(plaintext.data(), 1, sig, pubkey, PkcsSignature::HashType::sha256);
206  ASSERT_FALSE(ver);
207  ver = PkcsSignature::verify(plaintext.data(), plaintext.size(), sig.data(), 1, pubkey, PkcsSignature::HashType::sha256);
208  ASSERT_FALSE(ver);
209 
210  charv t(sig);
211  explicit_bzero(t.data(), t.size());
212  ver = PkcsSignature::verify(plaintext.data(), plaintext.size(), t.data(), t.size(), pubkey, PkcsSignature::HashType::sha256);
213  ASSERT_FALSE(ver);
214 }
215 
216 TEST(rsa_encryption, oaep_encrypt)
217 {
218  cout << "*** Oaep encryption test" << endl;
219 
220  RsaPrivateKey key;
221  key.generate(3072);
222  RsaPublicKey pub = key.pub_key();
223 
224  RsaOaepEncrypt enc(pub, Hash::sha1_type);
225 
226  cout << "plaintext size=" << plaintext.size() << endl;
227  cout << "enc max_msg_len=" << enc.max_msg_size() << endl;
228  cout << "enc cipher_len=" << enc.cipher_size() << endl;
229 
230  charv plain(plaintext.begin(), plaintext.end());
231  plain.resize(enc.max_msg_size());
232 
233  charv cipher;
234  cipher.resize(enc.cipher_size());
235 
236  string label("this is a label, which will be signed but not encrypted");
237 
238  enc.encrypt(plain.data(), plain.size(), cipher.data(), cipher.size(), label.data(), label.size());
239 
240  cout << "encrypted plain size=" << plain.size() << endl;
241 
242  RsaOaepDecrypt dec(key, Hash::sha1_type);
243 
244  charv decplain;
245  decplain.resize(dec.max_msg_size());
246 
247  int r = dec.decrypt(decplain.data(), decplain.size(), cipher.data(), cipher.size(), label.data(), label.size());
248 
249  cout << "decrypt returned " << r << endl;
250 
251  ASSERT_EQ(r, plain.size());
252  ASSERT_EQ(plain, decplain);
253 
254  r = dec.decrypt(decplain.data(), decplain.size(), cipher.data(), cipher.size());
255 
256  cout << "decrypt without label returned " << r << endl;
257 
258  ASSERT_EQ(r, -1);
259 
260  // same without labels
261  enc.encrypt(plain.data(), plain.size(), cipher.data(), cipher.size());
262  r = dec.decrypt(decplain.data(), decplain.size(), cipher.data(), cipher.size());
263  ASSERT_EQ(plain, decplain);
264 
265  // short data
266  plain.resize(dec.max_msg_size()/2);
267  enc.encrypt(plain.data(), plain.size(), cipher.data(), cipher.size());
268  r = dec.decrypt(decplain.data(), decplain.size(), cipher.data(), cipher.size());
269  ASSERT_EQ(r, dec.max_msg_size()/2);
270  decplain.resize(r);
271  ASSERT_EQ(plain, decplain);
272 }
273 
274 TEST(rsa_encryption, pss_signature)
275 {
276  cout << "*** Pss signature test" << endl;
277 
278  RsaPrivateKey key;
279  key.generate(1024);
280 
281  cout << "*** Key:\n" << key.str() << endl;
282 
283  cout << "*** Orig:\n" << plaintext << endl;
284 
285  charv sig;
286  PssSignature::sign(plaintext.data(), plaintext.size(), sig, key, PssSignature::HashType::sha256);
287 
288  cout << "*** Signature (" << sig.size() << " bytes):\n" << Hex::bin_to_hexstr(sig, ":", 16) << endl;
289 
290  ASSERT_EQ(sig.size(), PssSignature::size(key));
291 
292  RsaPublicKey pubkey = key.pub_key();
293 
294  bool ver = PssSignature::verify(plaintext.data(), plaintext.size(), sig, pubkey, PssSignature::HashType::sha256);
295  cout << "*** Verify: " << (ver ? "OK" : "FAIL") << endl;
296 
297  ASSERT_TRUE(ver);
298 
299  ver = PssSignature::verify(plaintext.data(), 1, sig, pubkey, PssSignature::HashType::sha256);
300  ASSERT_FALSE(ver);
301  ver = PssSignature::verify(plaintext.data(), plaintext.size(), sig.data(), 1, pubkey, PssSignature::HashType::sha256);
302  ASSERT_FALSE(ver);
303 
304  charv t(sig);
305  explicit_bzero(t.data(), t.size());
306  ver = PssSignature::verify(plaintext.data(), plaintext.size(), t.data(), t.size(), pubkey, PssSignature::HashType::sha256);
307  ASSERT_FALSE(ver);
308 }
General one-way hashing algorithms.
Definition: hash.h:88
PKCS #1 version 1.5 digital signature.
Definition: rsa.h:483
RSASSA-PSS https://tools.ietf.org/html/rfc8017#section-8.1 Notes on use in x.509: https://tools....
Definition: rsa.h:416
RSA OAEP decryption.
Definition: rsa.h:373
RSA OAEP encryption.
Definition: rsa.h:329
RSA Private Key.
Definition: rsa.h:185
bool validate(const RsaPublicKey &) const
Validate a public key with the private key.
void clear()
Clear and erase all data.
std::string str(unsigned=8) const
Output with formatted values.
void generate(int)
Generate a private key.
RsaPublicKey pub_key() const
Export the public key.
Definition: rsa.h:314
RSA Public Key.
Definition: rsa.h:69
int width() const
Bit width of the key.
One-way hashing and message digests.
Binary to hex string converter.
RSA public key cryptography.
TEST(inet_example, client_server_stream_test)
[Inet client server]
Definition: inet.cc:521