1//
2// CryptoTest.cpp
3//
4// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
5// and Contributors.
6//
7// SPDX-License-Identifier: BSL-1.0
8//
9
10
11#include "CryptoTest.h"
12#include "Poco/CppUnit/TestCaller.h"
13#include "Poco/CppUnit/TestSuite.h"
14#include "Poco/Crypto/CipherFactory.h"
15#include "Poco/Crypto/Cipher.h"
16#include "Poco/Crypto/CipherKey.h"
17#include "Poco/Crypto/X509Certificate.h"
18#include "Poco/Crypto/CryptoStream.h"
19#include "Poco/Crypto/CryptoTransform.h"
20#include "Poco/StreamCopier.h"
21#include "Poco/Base64Encoder.h"
22#include "Poco/HexBinaryEncoder.h"
23#include <sstream>
24
25
26using namespace Poco::Crypto;
27
28
29static const std::string APPINF_PEM(
30 "-----BEGIN CERTIFICATE-----\n"
31 "MIIESzCCAzOgAwIBAgIBATALBgkqhkiG9w0BAQUwgdMxEzARBgNVBAMMCmFwcGlu\n"
32 "Zi5jb20xNjA0BgNVBAoMLUFwcGxpZWQgSW5mb3JtYXRpY3MgU29mdHdhcmUgRW5n\n"
33 "aW5lZXJpbmcgR21iSDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxEjAQBgNVBAgMCUNh\n"
34 "cmludGhpYTELMAkGA1UEBhMCQVQxHjAcBgNVBAcMFVN0LiBKYWtvYiBpbSBSb3Nl\n"
35 "bnRhbDEtMCsGCSqGSIb3DQEJARYeZ3VlbnRlci5vYmlsdHNjaG5pZ0BhcHBpbmYu\n"
36 "Y29tMB4XDTA5MDUwNzE0NTY1NloXDTI5MDUwMjE0NTY1NlowgdMxEzARBgNVBAMM\n"
37 "CmFwcGluZi5jb20xNjA0BgNVBAoMLUFwcGxpZWQgSW5mb3JtYXRpY3MgU29mdHdh\n"
38 "cmUgRW5naW5lZXJpbmcgR21iSDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxEjAQBgNV\n"
39 "BAgMCUNhcmludGhpYTELMAkGA1UEBhMCQVQxHjAcBgNVBAcMFVN0LiBKYWtvYiBp\n"
40 "bSBSb3NlbnRhbDEtMCsGCSqGSIb3DQEJARYeZ3VlbnRlci5vYmlsdHNjaG5pZ0Bh\n"
41 "cHBpbmYuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA89GolWCR\n"
42 "KtLQclJ2M2QtpFqzNC54hUQdR6n8+DAeruH9WFwLSdWW2fEi+jrtd/WEWCdt4PxX\n"
43 "F2/eBYeURus7Hg2ZtJGDd3je0+Ygsv7+we4cMN/knaBY7rATqhmnZWk+yBpkf5F2\n"
44 "IHp9gBxUaJWmt/bq3XrvTtzrDXpCd4zg4zPXZ8IC8ket5o3K2vnkAOsIsgN+Ffqd\n"
45 "4GjF4dsblG6u6E3VarGRLwGtgB8BAZOA/33mV4FHSMkc4OXpAChaK3tM8YhrLw+m\n"
46 "XtsfqDiv1825S6OWFCKGj/iX8X2QAkrdB63vXCSpb3de/ByIUfp31PpMlMh6dKo1\n"
47 "vf7yj0nb2w0utQIDAQABoyowKDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAww\n"
48 "CgYIKwYBBQUHAwMwDQYJKoZIhvcNAQEFBQADggEBAM0cpfb4BgiU/rkYe121P581\n"
49 "ftg5Ck1PYYda1Fy/FgzbgJh2AwVo/6sn6GF79/QkEcWEgtCMNNO3LMTTddUUApuP\n"
50 "jnEimyfmUhIThyud/vryzTMNa/eZMwaAqUQWqLf+AwgqjUsBSMenbSHavzJOpsvR\n"
51 "LI0PQ1VvqB+3UGz0JUnBJiKvHs83Fdm4ewPAf3M5fGcIa+Fl2nU5Plzwzskj84f6\n"
52 "73ZlEEi3aW9JieNy7RWsMM+1E8Sj2CGRZC4BM9V1Fgnsh4+VHX8Eu7eHucvfeIYx\n"
53 "3mmLMoK4sCayL/FGhrUDw5AkWb8tKNpRXY+W60Et281yxQSeWLPIbatVzIWI0/M=\n"
54 "-----END CERTIFICATE-----\n"
55);
56
57
58CryptoTest::CryptoTest(const std::string& name): CppUnit::TestCase(name)
59{
60}
61
62
63CryptoTest::~CryptoTest()
64{
65}
66
67
68void CryptoTest::testEncryptDecrypt()
69{
70 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(CipherKey("aes256"));
71
72 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
73 {
74 std::string in(n, 'x');
75 std::string out = pCipher->encryptString(in, Cipher::ENC_NONE);
76 std::string result = pCipher->decryptString(out, Cipher::ENC_NONE);
77 assertTrue (in == result);
78 }
79
80 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
81 {
82 std::string in(n, 'x');
83 std::string out = pCipher->encryptString(in, Cipher::ENC_BASE64);
84 std::string result = pCipher->decryptString(out, Cipher::ENC_BASE64);
85 assertTrue (in == result);
86 }
87
88 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
89 {
90 std::string in(n, 'x');
91 std::string out = pCipher->encryptString(in, Cipher::ENC_BINHEX);
92 std::string result = pCipher->decryptString(out, Cipher::ENC_BINHEX);
93 assertTrue (in == result);
94 }
95}
96
97
98void CryptoTest::testEncryptDecryptWithSalt()
99{
100 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(CipherKey("aes256", "simplepwd", "Too much salt"));
101 Cipher::Ptr pCipher2 = CipherFactory::defaultFactory().createCipher(CipherKey("aes256", "simplepwd", "Too much salt"));
102
103 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
104 {
105 std::string in(n, 'x');
106 std::string out = pCipher->encryptString(in, Cipher::ENC_NONE);
107 std::string result = pCipher2->decryptString(out, Cipher::ENC_NONE);
108 assertTrue (in == result);
109 }
110
111 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
112 {
113 std::string in(n, 'x');
114 std::string out = pCipher->encryptString(in, Cipher::ENC_BASE64);
115 std::string result = pCipher2->decryptString(out, Cipher::ENC_BASE64);
116 assertTrue (in == result);
117 }
118
119 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
120 {
121 std::string in(n, 'x');
122 std::string out = pCipher->encryptString(in, Cipher::ENC_BINHEX);
123 std::string result = pCipher2->decryptString(out, Cipher::ENC_BINHEX);
124 assertTrue (in == result);
125 }
126}
127
128
129void CryptoTest::testEncryptDecryptWithSaltSha1()
130{
131 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(
132 CipherKey("aes256", "simplepwd", "Too much salt", 2000, "sha1"));
133 Cipher::Ptr pCipher2 = CipherFactory::defaultFactory().createCipher(
134 CipherKey("aes256", "simplepwd", "Too much salt", 2000, "sha1"));
135
136 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
137 {
138 std::string in(n, 'x');
139 std::string out = pCipher->encryptString(in, Cipher::ENC_NONE);
140 std::string result = pCipher2->decryptString(out, Cipher::ENC_NONE);
141 assertTrue (in == result);
142 }
143
144 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
145 {
146 std::string in(n, 'x');
147 std::string out = pCipher->encryptString(in, Cipher::ENC_BASE64);
148 std::string result = pCipher2->decryptString(out, Cipher::ENC_BASE64);
149 assertTrue (in == result);
150 }
151
152 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
153 {
154 std::string in(n, 'x');
155 std::string out = pCipher->encryptString(in, Cipher::ENC_BINHEX);
156 std::string result = pCipher2->decryptString(out, Cipher::ENC_BINHEX);
157 assertTrue (in == result);
158 }
159}
160
161
162void CryptoTest::testEncryptDecryptDESECB()
163{
164 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(CipherKey("des-ecb", "password"));
165
166 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
167 {
168 std::string in(n, 'x');
169 std::string out = pCipher->encryptString(in, Cipher::ENC_NONE);
170 std::string result = pCipher->decryptString(out, Cipher::ENC_NONE);
171 assertTrue (in == result);
172 }
173
174 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
175 {
176 std::string in(n, 'x');
177 std::string out = pCipher->encryptString(in, Cipher::ENC_BASE64);
178 std::string result = pCipher->decryptString(out, Cipher::ENC_BASE64);
179 assertTrue (in == result);
180 }
181
182 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
183 {
184 std::string in(n, 'x');
185 std::string out = pCipher->encryptString(in, Cipher::ENC_BINHEX);
186 std::string result = pCipher->decryptString(out, Cipher::ENC_BINHEX);
187 assertTrue (in == result);
188 }
189}
190
191
192void CryptoTest::testEncryptDecryptGCM()
193{
194 CipherKey key("aes-256-gcm");
195
196 CipherKey::ByteVec iv(20, 213);
197 key.setIV(iv);
198
199 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(key);
200
201 for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
202 {
203 std::stringstream str;
204 CryptoTransform* pEncryptor = pCipher->createEncryptor();
205 CryptoOutputStream encryptorStream(str, pEncryptor);
206 std::string in(n, 'x');
207 encryptorStream << in;
208 encryptorStream.close();
209 assertTrue (encryptorStream.good());
210
211 std::string tag = pEncryptor->getTag();
212
213 CryptoTransform* pDecryptor = pCipher->createDecryptor();
214 pDecryptor->setTag(tag);
215 CryptoInputStream decryptorStream(str, pDecryptor);
216 std::string out;
217 decryptorStream >> out;
218
219 assertTrue (in == out);
220 }
221}
222
223
224void CryptoTest::testPassword()
225{
226 CipherKey key("aes256", "password", "salt");
227
228 std::ostringstream keyStream;
229 Poco::Base64Encoder base64KeyEnc(keyStream);
230 base64KeyEnc.write(reinterpret_cast<const char*>(&key.getKey()[0]), key.keySize());
231 base64KeyEnc.close();
232 std::string base64Key = keyStream.str();
233 assertTrue (base64Key == "hIzxBt58GDd7/6mRp88bewKk42lM4QwaF78ek0FkVoA=");
234}
235
236
237void CryptoTest::testPasswordSha1()
238{
239 // the test uses 1 iteration, as the openssl executable does not allow to set a custom number
240 // of iterations
241 CipherKey key("aes256", "password", "saltsalt", 1, "sha1");
242
243 std::ostringstream keyStream;
244 Poco::HexBinaryEncoder hexKeyEnc(keyStream);
245 hexKeyEnc.write(reinterpret_cast<const char*>(&key.getKey()[0]), key.keySize());
246 hexKeyEnc.close();
247 std::string hexKey = keyStream.str();
248
249 std::ostringstream ivStream;
250 Poco::HexBinaryEncoder hexIvEnc(ivStream);
251 hexIvEnc.write(reinterpret_cast<const char*>(&key.getIV()[0]), key.ivSize());
252 hexIvEnc.close();
253 std::string hexIv = ivStream.str();
254
255 // got Hex value for key and iv using:
256 // openssl enc -e -a -md sha1 -aes256 -k password -S 73616c7473616c74 -P
257 // (where "salt" == 73616c74 in Hex, doubled for an 8 bytes salt, openssl padds the salt with 0
258 // whereas Poco's implementation padds with the existing bytes using a modulo operation)
259 assertTrue (hexIv == "c96049b0edc0b67af61ecc43d3de8898");
260 assertTrue (hexKey == "cab86dd6261710891e8cb56ee3625691a75df344f0bff4c12cf3596fc00b39c7");
261}
262
263
264void CryptoTest::testEncryptInterop()
265{
266 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(CipherKey("aes256", "password", "salt"));
267
268 const std::string plainText = "This is a secret message.";
269 const std::string expectedCipherText = "9HITTPaU3A/LaZzldbdnRZ109DKlshouKren/n8BsHc=";
270 std::string cipherText = pCipher->encryptString(plainText, Cipher::ENC_BASE64);
271 assertTrue (cipherText == expectedCipherText);
272}
273
274
275void CryptoTest::testDecryptInterop()
276{
277 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(CipherKey("aes256", "password", "salt"));
278
279 const std::string expectedPlainText = "This is a secret message.";
280 const std::string cipherText = "9HITTPaU3A/LaZzldbdnRZ109DKlshouKren/n8BsHc=";
281 std::string plainText = pCipher->decryptString(cipherText, Cipher::ENC_BASE64);
282 assertTrue (plainText == expectedPlainText);
283}
284
285
286void CryptoTest::testStreams()
287{
288 Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(CipherKey("aes256"));
289
290 static const std::string SECRET_MESSAGE = "This is a secret message. Don't tell anyone.";
291
292 std::stringstream sstr;
293 EncryptingOutputStream encryptor(sstr, *pCipher);
294 encryptor << SECRET_MESSAGE;
295 encryptor.close();
296
297 DecryptingInputStream decryptor(sstr, *pCipher);
298 std::string result;
299 Poco::StreamCopier::copyToString(decryptor, result);
300
301 assertTrue (result == SECRET_MESSAGE);
302 assertTrue (decryptor.eof());
303 assertTrue (!decryptor.bad());
304
305
306 std::istringstream emptyStream;
307 DecryptingInputStream badDecryptor(emptyStream, *pCipher);
308 Poco::StreamCopier::copyToString(badDecryptor, result);
309
310 assertTrue (badDecryptor.fail());
311 assertTrue (badDecryptor.bad());
312 assertTrue (!badDecryptor.eof());
313}
314
315
316void CryptoTest::testCertificate()
317{
318 std::istringstream certStream(APPINF_PEM);
319 X509Certificate cert(certStream);
320
321 std::string subjectName(cert.subjectName());
322 std::string issuerName(cert.issuerName());
323 std::string commonName(cert.commonName());
324 std::string country(cert.subjectName(X509Certificate::NID_COUNTRY));
325 std::string localityName(cert.subjectName(X509Certificate::NID_LOCALITY_NAME));
326 std::string stateOrProvince(cert.subjectName(X509Certificate::NID_STATE_OR_PROVINCE));
327 std::string organizationName(cert.subjectName(X509Certificate::NID_ORGANIZATION_NAME));
328 std::string organizationUnitName(cert.subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME));
329 std::string emailAddress(cert.subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS));
330 std::string serialNumber(cert.subjectName(X509Certificate::NID_SERIAL_NUMBER));
331
332 assertTrue (subjectName == "/CN=appinf.com/O=Applied Informatics Software Engineering GmbH/OU=Development/ST=Carinthia/C=AT/L=St. Jakob im Rosental/emailAddress=guenter.obiltschnig@appinf.com");
333 assertTrue (issuerName == subjectName);
334 assertTrue (commonName == "appinf.com");
335 assertTrue (country == "AT");
336 assertTrue (localityName == "St. Jakob im Rosental");
337 assertTrue (stateOrProvince == "Carinthia");
338 assertTrue (organizationName == "Applied Informatics Software Engineering GmbH");
339 assertTrue (organizationUnitName == "Development");
340 assertTrue (emailAddress == "guenter.obiltschnig@appinf.com");
341 assertTrue (serialNumber == "");
342
343 // fails with recent OpenSSL versions:
344 // assertTrue (cert.issuedBy(cert));
345
346 std::istringstream otherCertStream(APPINF_PEM);
347 X509Certificate otherCert(otherCertStream);
348
349 assertTrue (cert.equals(otherCert));
350}
351
352
353void CryptoTest::setUp()
354{
355}
356
357
358void CryptoTest::tearDown()
359{
360}
361
362
363CppUnit::Test* CryptoTest::suite()
364{
365 CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("CryptoTest");
366
367 CppUnit_addTest(pSuite, CryptoTest, testEncryptDecrypt);
368 CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptWithSalt);
369 CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptWithSaltSha1);
370 CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptDESECB);
371 CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptGCM);
372 CppUnit_addTest(pSuite, CryptoTest, testPassword);
373 CppUnit_addTest(pSuite, CryptoTest, testPasswordSha1);
374 CppUnit_addTest(pSuite, CryptoTest, testEncryptInterop);
375 CppUnit_addTest(pSuite, CryptoTest, testDecryptInterop);
376 CppUnit_addTest(pSuite, CryptoTest, testStreams);
377 CppUnit_addTest(pSuite, CryptoTest, testCertificate);
378
379 return pSuite;
380}
381