scclib
Stable Cloud Computing C++ Library
cipher.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/cipher.h>
32 #include <gtest/gtest.h>
33 #include <string>
34 #include <fstream>
35 #include <map>
36 #include <vector>
37 #include <encode/hex.h>
38 
51 using std::cout;
52 using std::endl;
53 using std::map;
54 using std::pair;
55 using std::string;
56 using scc::encode::Hex;
58 
59 using CharVec = std::vector<char>;
60 
61 string key16 = "use a 16 b key!!";
62 string key24 = "use a 24 b key!!!!!!!!!!";
63 string key32 = "use a 32 b key!!!!!!!!!!!!!!!!!!";
64 string nonce = "the nonce!!!";
65 string adddata = "this is the additional data";
66 string plain = "\
67 To be, or not to be, that is the question: \n\
68 Whether 'tis nobler in the mind to suffer \n\
69 The slings and arrows of outrageous fortune, \n\
70 Or to take Arms against a Sea of troubles, \n\
71 And by opposing end them: to die, to sleep; \n\
72 No more; and by a sleep, to say we end \n\
73 The heart-ache, and the thousand natural shocks \n\
74 That Flesh is heir to? 'Tis a consummation \n\
75 Devoutly to be wished. To die, to sleep, \n\
76 perchance to Dream; aye, there's the rub...";
77 
78 using mappair = std::pair<const string,Cipher>;
79 
80 struct Ciphertest : public testing::Test
81 {
82  map<string, Cipher> ciphers;
83  Ciphertest()
84  {
85  // construct these to avoid construction of default cipher (which is not allowed)
86  ciphers.insert(std::make_pair(std::string("gcm16"), Cipher(Cipher::aes_gcm_type, key16)));
87  ciphers.insert(std::make_pair(std::string("gcm24"), Cipher(Cipher::aes_gcm_type, key24)));
88  ciphers.insert(std::make_pair(std::string("gcm32"), Cipher(Cipher::aes_gcm_type, key32)));
89  ciphers.insert(std::make_pair(std::string("ccm16"), Cipher(Cipher::aes_ccm_type, key16)));
90  ciphers.insert(std::make_pair(std::string("ccm24"), Cipher(Cipher::aes_ccm_type, key24)));
91  ciphers.insert(std::make_pair(std::string("ccm32"), Cipher(Cipher::aes_ccm_type, key32)));
92  }
93  virtual ~Ciphertest() {}
94  void reset(mappair& c, const string& nonce, const string& aad)
95  {
96  cout << "reset for: " << c.first << " nonce " << nonce.size() << " bytes, aad " << aad.size() << " bytes" << endl;
97  c.second.reset(nonce.data(), nonce.size(), aad.data(), aad.size());
98  }
99  void reset(mappair& c, const string& nonce)
100  {
101  cout << "reset for: " << c.first << " nonce " << nonce.size() << " bytes" << endl;
102  c.second.reset(nonce.data(), nonce.size());
103  }
104  string auth_tag(mappair& c)
105  {
106  cout << "auth tag for: " << c.first << endl;
107  CharVec tag;
108  tag.resize(16);
109  c.second.auth_tag(tag.data(), tag.size());
110  return Hex::bin_to_hex(tag, 16);
111  }
112  CharVec enc(mappair& c, const string& plain)
113  {
114  cout << "encrypt " << plain.size() << " bytes for: " << c.first << endl;
115  CharVec cipher;
116  cipher.resize(plain.size(), '\0');
117  c.second.encrypt(plain.data(), plain.size(), cipher.data(), cipher.size());
118  return cipher;
119  }
120  string dec(mappair& c, const CharVec& cipher)
121  {
122  cout << "decrypt " << cipher.size() << " bytes for: " << c.first << endl;
123  string plain;
124  plain.resize(cipher.size(), '\0');
125  c.second.decrypt(cipher.data(), cipher.size(), plain.data(), plain.size());
126  return plain;
127  }
128 };
129 
130 #if 0
131 // mgw Not sure about auth tag without data...
132 TEST_F(Ciphertest, nonce_only)
133 {
134  for (auto& c: ciphers)
135  {
136  string tag0 = auth_tag(c);
137  cout << "tag0 for " << c.first << ": " << tag0 << endl;
138 
139  reset(c, nonce);
140  string tag1 = auth_tag(c);
141  cout << "tag1 for " << c.first << ": " << tag1 << endl;
142  ASSERT_EQ(tag0, tag1);
143 
144  reset(c, nonce);
145  string tag2 = auth_tag(c);
146  cout << "tag2 for " << c.first << ": " << tag2 << endl;
147  ASSERT_EQ(tag1, tag2);
148  }
149 }
150 #endif
151 
152 TEST_F(Ciphertest, authdata_only)
153 {
154  for (auto& c: ciphers)
155  {
156  string tag0 = auth_tag(c);
157  cout << "tag0 for " << c.first << ": " << tag0 << endl;
158 
159  reset(c, nonce, adddata);
160  string tag1 = auth_tag(c);
161  cout << "tag1 for " << c.first << ": " << tag1 << endl;
162  ASSERT_NE(tag0, tag1);
163 
164  reset(c, nonce, adddata);
165  string tag2 = auth_tag(c);
166  cout << "tag2 for " << c.first << ": " << tag1 << endl;
167  ASSERT_EQ(tag1, tag2);
168  }
169 }
170 
171 TEST_F(Ciphertest, enc_reset)
172 {
173  for (auto& c: ciphers)
174  {
175  reset(c, nonce);
176  CharVec cip0 = enc(c, plain);
177  string tag0 = auth_tag(c);
178 
179  reset(c, nonce);
180  CharVec cip1 = enc(c, plain);
181  string tag1 = auth_tag(c);
182 
183  ASSERT_EQ(cip0, cip1);
184  ASSERT_EQ(tag0, tag1);
185  }
186 }
187 
188 TEST_F(Ciphertest, enc_reset_adddata)
189 {
190  for (auto& c: ciphers)
191  {
192  reset(c, nonce, adddata);
193  CharVec cip0 = enc(c, plain);
194  string tag0 = auth_tag(c);
195 
196  reset(c, nonce, adddata);
197  CharVec cip1 = enc(c, plain);
198  string tag1 = auth_tag(c);
199 
200  ASSERT_EQ(cip0, cip1);
201  ASSERT_EQ(tag0, tag1);
202  }
203 }
204 
205 TEST_F(Ciphertest, enc_dec)
206 {
207  for (auto& c: ciphers)
208  {
209  reset(c, nonce);
210  CharVec cip = enc(c, plain);
211  string tag = auth_tag(c);
212 
213  reset(c, nonce);
214  string plain1 = dec(c, cip);
215  string tag1 = auth_tag(c);
216 
217  ASSERT_EQ(plain, plain1);
218  ASSERT_EQ(tag, tag1);
219  }
220 }
221 
222 TEST_F(Ciphertest, enc_dec_adddata)
223 {
224  for (auto& c: ciphers)
225  {
226  reset(c, nonce, adddata);
227  CharVec cip = enc(c, plain);
228  string tag = auth_tag(c);
229 
230  reset(c, nonce, adddata);
231  string plain1 = dec(c, cip);
232  string tag1 = auth_tag(c);
233 
234  ASSERT_EQ(plain, plain1);
235  ASSERT_EQ(tag, tag1);
236  }
237 }
238 
239 TEST_F(Ciphertest, enc_dec_samebuf)
240 {
241  for (auto& c: ciphers)
242  {
243  reset(c, nonce, adddata);
244 
245  CharVec buf(plain.begin(), plain.end());
246  buf.resize(plain.size()+1024, '\0'); // both encrypt and decrypt should be able to handle larger target buffer
247 
248  CharVec verify(plain.begin(), plain.end());
249  verify.resize(plain.size()+1024, '\0');
250 
251  auto size = plain.size();
252 
253  cout << "encrypt in place " << size << "bytes for: " << c.first << endl;
254 
255  c.second.encrypt(buf.data(), size, buf.data(), buf.size());
256 
257  CharVec enctag(16, '\0');
258  c.second.auth_tag(enctag.data(), enctag.size());
259 
260  reset(c, nonce, adddata);
261 
262  cout << "decrypt in place " << size << "bytes for: " << c.first << endl;
263 
264  c.second.decrypt(buf.data(), size, buf.data(), buf.size());
265 
266  CharVec dectag(16, '\0');
267  c.second.auth_tag(dectag.data(), dectag.size());
268 
269  ASSERT_EQ(buf, verify);
270  ASSERT_EQ(enctag, dectag);
271  }
272 }
Symmetric block ciphers.
Symmetric block cipher.
Definition: cipher.h:97
Binary to hex string converter.