1 // validat8.cpp - originally written and placed in the public domain by Wei Dai
2 //                CryptoPP::Test namespace added by JW in February 2017.
3 //                Source files split in July 2018 to expedite compiles.
4 
5 #include "pch.h"
6 
7 #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
8 
9 #include "cryptlib.h"
10 #include "cpu.h"
11 #include "validate.h"
12 
13 #include "asn.h"
14 #include "oids.h"
15 
16 #include "luc.h"
17 #include "rsa.h"
18 #include "xtr.h"
19 #include "rabin.h"
20 #include "pubkey.h"
21 #include "elgamal.h"
22 #include "xtrcrypt.h"
23 #include "eccrypto.h"
24 
25 #include "hex.h"
26 #include "base64.h"
27 
28 #include <iostream>
29 #include <iomanip>
30 #include <sstream>
31 
32 // Aggressive stack checking with VS2005 SP1 and above.
33 #if (_MSC_FULL_VER >= 140050727)
34 # pragma strict_gs_check (on)
35 #endif
36 
37 #if CRYPTOPP_MSC_VERSION
38 # pragma warning(disable: 4505 4355)
39 #endif
40 
41 NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)42 NAMESPACE_BEGIN(Test)
43 
44 inline byte* C2B(char* ptr) {
45     return reinterpret_cast<byte*>(ptr);
46 }
47 
C2B(const char * ptr)48 inline const byte* C2B(const char* ptr) {
49     return reinterpret_cast<const byte*>(ptr);
50 }
51 
ValidateRSA_Encrypt()52 bool ValidateRSA_Encrypt()
53 {
54 	// Must be large enough for RSA-3072 to test SHA3_256
55 	byte out[256], outPlain[128];
56 	bool pass = true, fail;
57 
58 	{
59 		FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder);
60 		RSAES_PKCS1v15_Decryptor rsaPriv(keys);
61 		RSAES_PKCS1v15_Encryptor rsaPub(rsaPriv);
62 
63 		pass = CryptoSystemValidate(rsaPriv, rsaPub) && pass;
64 	}
65 	{
66 		RSAES<OAEP<SHA1> >::Decryptor rsaPriv(GlobalRNG(), 512);
67 		RSAES<OAEP<SHA1> >::Encryptor rsaPub(rsaPriv);
68 
69 		pass = CryptoSystemValidate(rsaPriv, rsaPub) && pass;
70 	}
71 	{
72 		byte *plain = (byte *)
73 			"\x54\x85\x9b\x34\x2c\x49\xea\x2a";
74 		static const byte encrypted[] =
75 			"\x14\xbd\xdd\x28\xc9\x83\x35\x19\x23\x80\xe8\xe5\x49\xb1\x58\x2a"
76 			"\x8b\x40\xb4\x48\x6d\x03\xa6\xa5\x31\x1f\x1f\xd5\xf0\xa1\x80\xe4"
77 			"\x17\x53\x03\x29\xa9\x34\x90\x74\xb1\x52\x13\x54\x29\x08\x24\x52"
78 			"\x62\x51";
79 		static const byte oaepSeed[] =
80 			"\xaa\xfd\x12\xf6\x59\xca\xe6\x34\x89\xb4\x79\xe5\x07\x6d\xde\xc2"
81 			"\xf0\x6c\xb5\x8f";
82 		ByteQueue bq;
83 		bq.Put(oaepSeed, 20);
84 		FixedRNG rng(bq);
85 
86 		FileSource privFile(DataDir("TestData/rsa400pv.dat").c_str(), true, new HexDecoder);
87 		FileSource pubFile(DataDir("TestData/rsa400pb.dat").c_str(), true, new HexDecoder);
88 		RSAES_OAEP_SHA_Decryptor rsaPriv;
89 		rsaPriv.AccessKey().BERDecodePrivateKey(privFile, false, 0);
90 		RSAES_OAEP_SHA_Encryptor rsaPub(pubFile);
91 
92 		memset(out, 0, 50);
93 		memset(outPlain, 0, 8);
94 		rsaPub.Encrypt(rng, plain, 8, out);
95 		DecodingResult result = rsaPriv.FixedLengthDecrypt(GlobalRNG(), encrypted, outPlain);
96 		fail = !result.isValidCoding || (result.messageLength!=8) || memcmp(out, encrypted, 50) || memcmp(plain, outPlain, 8);
97 		pass = pass && !fail;
98 
99 		std::cout << (fail ? "FAILED    " : "passed    ");
100 		std::cout << "PKCS 2.0 encryption and decryption\n";
101 	}
102 
103 	return pass;
104 }
105 
ValidateLUC_Encrypt()106 bool ValidateLUC_Encrypt()
107 {
108 	FileSource f(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder);
109 	LUCES_OAEP_SHA_Decryptor priv(GlobalRNG(), 512);
110 	LUCES_OAEP_SHA_Encryptor pub(priv);
111 	return CryptoSystemValidate(priv, pub);
112 }
113 
ValidateLUC_DL_Encrypt()114 bool ValidateLUC_DL_Encrypt()
115 {
116 	std::cout << "\nLUC-IES validation suite running...\n\n";
117 
118 	FileSource fc(DataDir("TestData/lucc512.dat").c_str(), true, new HexDecoder);
119 	LUC_IES<>::Decryptor privC(fc);
120 	LUC_IES<>::Encryptor pubC(privC);
121 	return CryptoSystemValidate(privC, pubC);
122 }
123 
ValidateRabin_Encrypt()124 bool ValidateRabin_Encrypt()
125 {
126 	FileSource f(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder);
127 	RabinES<OAEP<SHA1> >::Decryptor priv(f);
128 	RabinES<OAEP<SHA1> >::Encryptor pub(priv);
129 	return CryptoSystemValidate(priv, pub);
130 }
131 
ValidateECP_Encrypt()132 bool ValidateECP_Encrypt()
133 {
134 	ECIES<ECP>::Decryptor cpriv(GlobalRNG(), ASN1::secp192r1());
135 	ECIES<ECP>::Encryptor cpub(cpriv);
136 	ByteQueue bq;
137 	cpriv.GetKey().DEREncode(bq);
138 	cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
139 	cpub.GetKey().DEREncode(bq);
140 
141 	cpub.AccessKey().Precompute();
142 	cpriv.AccessKey().Precompute();
143 	bool pass = CryptoSystemValidate(cpriv, cpub);
144 
145 	std::cout << "Turning on point compression..." << std::endl;
146 	cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true);
147 	cpub.AccessKey().AccessGroupParameters().SetPointCompression(true);
148 	pass = CryptoSystemValidate(cpriv, cpub) && pass;
149 
150 	return pass;
151 }
152 
153 // https://github.com/weidai11/cryptopp/issues/856
154 // Not to be confused with NullHash in trunhash.h.
155 class NULL_Hash : public CryptoPP::IteratedHashWithStaticTransform
156     <CryptoPP::word32, CryptoPP::BigEndian, 32, 0, NULL_Hash, 0>
157 {
158 public:
InitState(HashWordType * state)159     static void InitState(HashWordType *state) {
160         CRYPTOPP_UNUSED(state);
161     }
Transform(CryptoPP::word32 * digest,const CryptoPP::word32 * data)162     static void Transform(CryptoPP::word32 *digest, const CryptoPP::word32 *data) {
163         CRYPTOPP_UNUSED(digest); CRYPTOPP_UNUSED(data);
164     }
StaticAlgorithmName()165     static const char *StaticAlgorithmName() {
166         return "NULL_Hash";
167     }
168 };
169 
170 // https://github.com/weidai11/cryptopp/issues/856
171 template <class EC, class HASH = SHA1, class COFACTOR_OPTION = NoCofactorMultiplication, bool DHAES_MODE = true, bool LABEL_OCTETS = false>
172 struct ECIES_NULLDigest
173 	: public DL_ES<
174 		DL_Keys_EC<EC>,
175 		DL_KeyAgreementAlgorithm_DH<typename EC::Point, COFACTOR_OPTION>,
176 		DL_KeyDerivationAlgorithm_P1363<typename EC::Point, DHAES_MODE, P1363_KDF2<HASH> >,
177 		DL_EncryptionAlgorithm_Xor<HMAC<NULL_Hash>, DHAES_MODE, LABEL_OCTETS>,
178 		ECIES<EC> >
179 {
180 	// TODO: fix this after name is standardized
StaticAlgorithmNameECIES_NULLDigest181 	CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES-NULLDigest";}
182 };
183 
ValidateECP_NULLDigest_Encrypt()184 bool ValidateECP_NULLDigest_Encrypt()
185 {
186 	ECIES_NULLDigest<ECP>::Decryptor cpriv(GlobalRNG(), ASN1::secp256k1());
187 	ECIES_NULLDigest<ECP>::Encryptor cpub(cpriv);
188 	ByteQueue bq;
189 	cpriv.GetKey().DEREncode(bq);
190 	cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
191 	cpub.GetKey().DEREncode(bq);
192 
193 	cpub.AccessKey().Precompute();
194 	cpriv.AccessKey().Precompute();
195 	bool pass = CryptoSystemValidate(cpriv, cpub);
196 
197 	std::cout << "Turning on point compression..." << std::endl;
198 	cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true);
199 	cpub.AccessKey().AccessGroupParameters().SetPointCompression(true);
200 	pass = CryptoSystemValidate(cpriv, cpub) && pass;
201 
202 	return pass;
203 }
204 
205 // Ensure interop with Crypto++ 5.6.4 and earlier
ValidateECP_Legacy_Encrypt()206 bool ValidateECP_Legacy_Encrypt()
207 {
208 	std::cout << "\nLegacy ECIES ECP validation suite running...\n\n";
209 	bool pass = true;
210 	{
211 		FileSource fc(DataDir("TestData/ecies_p160.dat").c_str(), true, new HexDecoder);
212 		ECIES<ECP,SHA1,NoCofactorMultiplication,false,true>::Decryptor privC(fc);
213 		ECIES<ECP,SHA1,NoCofactorMultiplication,false,true>::Encryptor pubC(privC);
214 
215 		pass = CryptoSystemValidate(privC, pubC) && pass;
216 
217 		// Test data generated by Crypto++ 5.6.2.
218 		// Also see https://github.com/weidai11/cryptopp/pull/857.
219 		const std::string plain = "Yoda said, Do or do not. There is no try.";
220 		const std::string cipher =
221 			"\x04\xF6\xC1\xB1\xFA\xAC\x8A\xD5\xD3\x96\xE7\x13\xAE\xBD\x0C\xCE"
222 			"\x15\xCF\x44\x54\x08\x63\xCC\xBF\x89\x4D\xD0\xB8\x38\xA1\x3A\xB2"
223 			"\x90\x75\x86\x82\x7F\x9D\x95\x26\xA5\x74\x13\x3A\x74\x63\x11\x71"
224 			"\x70\x4C\x01\xA4\x08\x04\x95\x69\x6A\x91\xF0\xC0\xA4\xBD\x1E\xAA"
225 			"\x59\x57\xB8\xA9\xD2\xF7\x7C\x98\xE3\xC5\xE3\xF4\x4F\xA7\x6E\x73"
226 			"\x83\xF3\x1E\x05\x73\xA4\xEE\x63\x55\xFD\x6D\x31\xBB\x9E\x36\x4C"
227 			"\x79\xD0\x76\xC0\x0D\xE9";
228 
229 		std::string recover;
230 		recover.resize(privC.MaxPlaintextLength(cipher.size()));
231 
232 		DecodingResult result = privC.Decrypt(GlobalRNG(), C2B(&cipher[0]), cipher.size(), C2B(&recover[0]));
233 		if (result.isValidCoding)
234 			recover.resize(result.messageLength);
235 		else
236 			recover.resize(0);
237 
238 		pass = (plain == recover) && pass;
239 		std::cout << (pass ? "passed    " : "FAILED    ");
240 		std::cout << "decryption known answer\n";
241 	}
242 	return pass;
243 }
244 
245 // Ensure interop with Crypto++ 5.6.4 and earlier
ValidateEC2N_Legacy_Encrypt()246 bool ValidateEC2N_Legacy_Encrypt()
247 {
248 	std::cout << "\nLegacy ECIES EC2N validation suite running...\n\n";
249 	bool pass = true;
250 	{
251 		FileSource fc(DataDir("TestData/ecies_t163.dat").c_str(), true, new HexDecoder);
252 		ECIES<EC2N,SHA1,NoCofactorMultiplication,false,true>::Decryptor privC(fc);
253 		ECIES<EC2N,SHA1,NoCofactorMultiplication,false,true>::Encryptor pubC(privC);
254 
255 		pass = CryptoSystemValidate(privC, pubC) && pass;
256 
257 		// Test data generated by Crypto++ 5.6.2.
258 		// Also see https://github.com/weidai11/cryptopp/pull/857.
259 		const std::string plain = "Yoda said, Do or do not. There is no try.";
260 		const std::string cipher =
261 			"\x04\x01\x3F\x64\x94\x6A\xBE\x2B\x7E\x48\x67\x63\xA2\xD4\x01\xEF"
262 			"\x2B\x13\x1C\x9A\x1B\x7C\x07\x4B\x89\x78\x6C\x65\x51\x1C\x1A\x4E"
263 			"\x20\x7F\xB5\xBF\x12\x3B\x6E\x0A\x87\xFD\xB7\x94\xEF\x4B\xED\x40"
264 			"\xD4\x7A\xCF\xB6\xFC\x9B\x6D\xB0\xB8\x43\x99\x7E\x37\xC1\xF0\xC0"
265 			"\x95\xD4\x80\xE1\x8B\x84\xAE\x64\x9F\xA5\xBA\x32\x95\x8A\xD1\xBE"
266 			"\x7F\xDE\x7E\xA9\xE6\x59\xBF\x89\xA6\xE9\x9F\x5B\x64\xB4\xDD\x0E"
267 			"\x76\xB6\x82\xF6\xA9\xAD\xB5\xC4";
268 
269 		std::string recover;
270 		recover.resize(privC.MaxPlaintextLength(cipher.size()));
271 
272 		DecodingResult result = privC.Decrypt(GlobalRNG(), C2B(&cipher[0]), cipher.size(), C2B(&recover[0]));
273 		if (result.isValidCoding)
274 			recover.resize(result.messageLength);
275 		else
276 			recover.resize(0);
277 
278 		pass = (plain == recover) && pass;
279 		std::cout << (pass ? "passed    " : "FAILED    ");
280 		std::cout << "decryption known answer\n";
281 	}
282 	return pass;
283 }
284 
ValidateEC2N_Encrypt()285 bool ValidateEC2N_Encrypt()
286 {
287 	// DEREncode() changed to Save() at Issue 569.
288 	ECIES<EC2N>::Decryptor cpriv(GlobalRNG(), ASN1::sect193r1());
289 	ECIES<EC2N>::Encryptor cpub(cpriv);
290 	ByteQueue bq;
291 	cpriv.AccessMaterial().Save(bq);
292 	cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
293 	cpub.AccessMaterial().Save(bq);
294 	bool pass = CryptoSystemValidate(cpriv, cpub);
295 
296 	std::cout << "Turning on point compression..." << std::endl;
297 	cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true);
298 	cpub.AccessKey().AccessGroupParameters().SetPointCompression(true);
299 	pass = CryptoSystemValidate(cpriv, cpub) && pass;
300 
301 	return pass;
302 }
303 
ValidateElGamal()304 bool ValidateElGamal()
305 {
306 	std::cout << "\nElGamal validation suite running...\n\n";
307 	bool pass = true;
308 	{
309 		// Data from https://github.com/weidai11/cryptopp/issues/876.
310 		const std::string encodedPublicKey =
311 			"MHYwTwYGKw4HAgEBMEUCIQDebUvQDd9UPMmD27BJ ovZSIgWfexL0SWkfJQPMLsJvMwIgDy/kEthwO6Q+"
312 			"L8XHnzumnEKs+txH8QkQD+M/8u82ql0DIwACIAY6 rfW+BTcRZ9QAJovgoB8DgNLJ8ocqOeF4nEBB0DHH";
313 		StringSource decodedPublicKey(encodedPublicKey, true, new Base64Decoder);
314 
315 		ElGamal::PublicKey publicKey;
316 		publicKey.Load(decodedPublicKey);
317 		pass = publicKey.Validate(GlobalRNG(), 3) && pass;
318 	}
319 	{
320 		// Data from https://github.com/weidai11/cryptopp/issues/876.
321 		const std::string encodedPrivateKey =
322 			"MHkCAQAwTwYGKw4HAgEBMEUCIQDebUvQDd9UPMmD 27BJovZSIgWfexL0SWkfJQPMLsJvMwIgDy/kEthw"
323 			"O6Q+L8XHnzumnEKs+txH8QkQD+M/8u82ql0EIwIh AJb0S4TZLvApTVjXZyocPJ5tUgWgRqScXm5vNqu2"
324 			"YqdM";
325 		StringSource decodedPrivateKey(encodedPrivateKey, true, new Base64Decoder);
326 
327 		ElGamal::PrivateKey privateKey;
328 		privateKey.Load(decodedPrivateKey);
329 		pass = privateKey.Validate(GlobalRNG(), 3) && pass;
330 	}
331 	{
332 		FileSource fc(DataDir("TestData/elgc1024.dat").c_str(), true, new HexDecoder);
333 		ElGamalDecryptor privC(fc);
334 		ElGamalEncryptor pubC(privC);
335 		privC.AccessKey().Precompute();
336 		ByteQueue queue;
337 		privC.AccessKey().SavePrecomputation(queue);
338 		privC.AccessKey().LoadPrecomputation(queue);
339 
340 		pass = CryptoSystemValidate(privC, pubC) && pass;
341 	}
342 	return pass;
343 }
344 
ValidateDLIES()345 bool ValidateDLIES()
346 {
347 	std::cout << "\nDLIES validation suite running...\n\n";
348 	bool pass = true;
349 	{
350 		FileSource fc(DataDir("TestData/dlie1024.dat").c_str(), true, new HexDecoder);
351 		DLIES<>::Decryptor privC(fc);
352 		DLIES<>::Encryptor pubC(privC);
353 		pass = CryptoSystemValidate(privC, pubC) && pass;
354 	}
355 	{
356 		std::cout << "Generating new encryption key..." << std::endl;
357 		DLIES<>::GroupParameters gp;
358 		gp.GenerateRandomWithKeySize(GlobalRNG(), 128);
359 		DLIES<>::Decryptor decryptor;
360 		decryptor.AccessKey().GenerateRandom(GlobalRNG(), gp);
361 		DLIES<>::Encryptor encryptor(decryptor);
362 
363 		pass = CryptoSystemValidate(decryptor, encryptor) && pass;
364 	}
365 	return pass;
366 }
367 
368 NAMESPACE_END  // Test
369 NAMESPACE_END  // CryptoPP
370