]>
Commit | Line | Data |
---|---|---|
6edbf68a PL |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
fc3c07b4 | 4 | * |
6edbf68a PL |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
fc3c07b4 | 8 | * |
6edbf68a PL |
9 | * In addition, for the avoidance of any doubt, permission is granted to |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
fc3c07b4 | 12 | * |
6edbf68a PL |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
fc3c07b4 | 17 | * |
6edbf68a PL |
18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
fc3c07b4 | 21 | */ |
6d01c80c | 22 | #include <iostream> |
23 | #include "namespaces.hh" | |
24 | #include "misc.hh" | |
25 | #include "base64.hh" | |
8c732ebf | 26 | #include "sodcrypto.hh" |
6d01c80c | 27 | |
6d01c80c | 28 | |
0b62ec78 | 29 | #ifdef HAVE_LIBSODIUM |
30 | ||
8c732ebf | 31 | string newKey() |
6d01c80c | 32 | { |
13d895c9 RG |
33 | std::string key; |
34 | key.resize(crypto_secretbox_KEYBYTES); | |
35 | ||
36 | randombytes_buf(reinterpret_cast<unsigned char*>(&key.at(0)), key.size()); | |
37 | ||
38 | return "\""+Base64Encode(key)+"\""; | |
6d01c80c | 39 | } |
40 | ||
9c9b4998 RG |
41 | bool sodIsValidKey(const std::string& key) |
42 | { | |
43 | return key.size() == crypto_secretbox_KEYBYTES; | |
44 | } | |
45 | ||
8c732ebf | 46 | std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) |
6d01c80c | 47 | { |
9c9b4998 RG |
48 | if (!sodIsValidKey(key)) { |
49 | throw std::runtime_error("Invalid encryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key"); | |
50 | } | |
51 | ||
13d895c9 RG |
52 | std::string ciphertext; |
53 | ciphertext.resize(msg.length() + crypto_secretbox_MACBYTES); | |
54 | crypto_secretbox_easy(reinterpret_cast<unsigned char*>(&ciphertext.at(0)), | |
55 | reinterpret_cast<const unsigned char*>(msg.c_str()), | |
56 | msg.length(), | |
57 | nonce.value, | |
58 | reinterpret_cast<const unsigned char*>(key.c_str())); | |
6d01c80c | 59 | |
8c732ebf | 60 | nonce.increment(); |
13d895c9 | 61 | return ciphertext; |
6d01c80c | 62 | } |
63 | ||
8c732ebf | 64 | std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) |
6d01c80c | 65 | { |
13d895c9 RG |
66 | std::string decrypted; |
67 | ||
68 | if (msg.length() < crypto_secretbox_MACBYTES) { | |
e807a521 | 69 | throw std::runtime_error("Could not decrypt message of size " + std::to_string(msg.length())); |
13d895c9 RG |
70 | } |
71 | ||
9c9b4998 RG |
72 | if (!sodIsValidKey(key)) { |
73 | throw std::runtime_error("Invalid decryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key"); | |
74 | } | |
75 | ||
13d895c9 | 76 | decrypted.resize(msg.length() - crypto_secretbox_MACBYTES); |
6d01c80c | 77 | |
c2a16005 | 78 | if (crypto_secretbox_open_easy(reinterpret_cast<unsigned char*>(const_cast<char *>(decrypted.data())), |
13d895c9 RG |
79 | reinterpret_cast<const unsigned char*>(msg.c_str()), |
80 | msg.length(), | |
81 | nonce.value, | |
82 | reinterpret_cast<const unsigned char*>(key.c_str())) != 0) { | |
9c9b4998 | 83 | throw std::runtime_error("Could not decrypt message, please check that the key configured with setKey() is correct"); |
6d01c80c | 84 | } |
13d895c9 | 85 | |
8c732ebf | 86 | nonce.increment(); |
13d895c9 | 87 | return decrypted; |
6d01c80c | 88 | } |
0b62ec78 | 89 | #else |
90 | std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) | |
91 | { | |
92 | return msg; | |
93 | } | |
94 | std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) | |
95 | { | |
96 | return msg; | |
97 | } | |
98 | ||
99 | string newKey() | |
100 | { | |
101 | return "\"plaintext\""; | |
102 | } | |
103 | ||
9c9b4998 RG |
104 | bool sodIsValidKey(const std::string& key) |
105 | { | |
106 | return true; | |
107 | } | |
0b62ec78 | 108 | |
109 | #endif | |
8c732ebf | 110 | |
111 | ||
1489accc | 112 | #include "base64.hh" |
113 | #include <inttypes.h> | |
114 | ||
115 | namespace anonpdns { | |
116 | char B64Decode1(char cInChar) | |
117 | { | |
118 | // The incoming character will be A-Z, a-z, 0-9, +, /, or =. | |
119 | // The idea is to quickly determine which grouping the | |
120 | // letter belongs to and return the associated value | |
121 | // without having to search the global encoding string | |
122 | // (the value we're looking for would be the resulting | |
123 | // index into that string). | |
124 | // | |
125 | // To do that, we'll play some tricks... | |
126 | unsigned char iIndex = '\0'; | |
127 | switch ( cInChar ) { | |
128 | case '+': | |
129 | iIndex = 62; | |
130 | break; | |
131 | ||
132 | case '/': | |
133 | iIndex = 63; | |
134 | break; | |
135 | ||
136 | case '=': | |
137 | iIndex = 0; | |
138 | break; | |
139 | ||
140 | default: | |
141 | // Must be 'A'-'Z', 'a'-'z', '0'-'9', or an error... | |
142 | // | |
143 | // Numerically, small letters are "greater" in value than | |
144 | // capital letters and numerals (ASCII value), and capital | |
145 | // letters are "greater" than numerals (again, ASCII value), | |
146 | // so we check for numerals first, then capital letters, | |
147 | // and finally small letters. | |
148 | iIndex = '9' - cInChar; | |
149 | if ( iIndex > 0x3F ) { | |
150 | // Not from '0' to '9'... | |
151 | iIndex = 'Z' - cInChar; | |
152 | if ( iIndex > 0x3F ) { | |
153 | // Not from 'A' to 'Z'... | |
154 | iIndex = 'z' - cInChar; | |
155 | if ( iIndex > 0x3F ) { | |
156 | // Invalid character...cannot | |
157 | // decode! | |
158 | iIndex = 0x80; // set the high bit | |
159 | } // if | |
160 | else { | |
161 | // From 'a' to 'z' | |
162 | iIndex = (('z' - iIndex) - 'a') + 26; | |
163 | } // else | |
164 | } // if | |
165 | else { | |
166 | // From 'A' to 'Z' | |
167 | iIndex = ('Z' - iIndex) - 'A'; | |
168 | } // else | |
169 | } // if | |
170 | else { | |
171 | // Adjust the index... | |
172 | iIndex = (('9' - iIndex) - '0') + 52; | |
173 | } // else | |
174 | break; | |
175 | ||
176 | } // switch | |
177 | ||
178 | return iIndex; | |
179 | } | |
180 | ||
181 | inline char B64Encode1(unsigned char uc) | |
182 | { | |
183 | if (uc < 26) | |
184 | { | |
185 | return 'A'+uc; | |
186 | } | |
187 | if (uc < 52) | |
188 | { | |
189 | return 'a'+(uc-26); | |
190 | } | |
191 | if (uc < 62) | |
192 | { | |
193 | return '0'+(uc-52); | |
194 | } | |
195 | if (uc == 62) | |
196 | { | |
197 | return '+'; | |
198 | } | |
199 | return '/'; | |
200 | }; | |
201 | ||
202 | ||
203 | ||
204 | } | |
205 | using namespace anonpdns; | |
206 | ||
207 | int B64Decode(const std::string& strInput, std::string& strOutput) | |
208 | { | |
209 | // Set up a decoding buffer | |
210 | long cBuf = 0; | |
211 | char* pBuf = (char*)&cBuf; | |
212 | ||
213 | // Decoding management... | |
214 | int iBitGroup = 0, iInNum = 0; | |
215 | ||
216 | // While there are characters to process... | |
217 | // | |
218 | // We'll decode characters in blocks of 4, as | |
219 | // there are 4 groups of 6 bits in 3 bytes. The | |
220 | // incoming Base64 character is first decoded, and | |
221 | // then it is inserted into the decode buffer | |
222 | // (with any relevant shifting, as required). | |
223 | // Later, after all 3 bytes have been reconstituted, | |
224 | // we assign them to the output string, ultimately | |
225 | // to be returned as the original message. | |
226 | int iInSize = strInput.size(); | |
227 | unsigned char cChar = '\0'; | |
228 | uint8_t pad = 0; | |
229 | while ( iInNum < iInSize ) { | |
230 | // Fill the decode buffer with 4 groups of 6 bits | |
231 | cBuf = 0; // clear | |
232 | pad = 0; | |
233 | for ( iBitGroup = 0; iBitGroup < 4; ++iBitGroup ) { | |
234 | if ( iInNum < iInSize ) { | |
235 | // Decode a character | |
236 | if(strInput.at(iInNum)=='=') | |
237 | pad++; | |
238 | while(isspace(strInput.at(iInNum))) | |
239 | iInNum++; | |
240 | cChar = B64Decode1(strInput.at(iInNum++)); | |
241 | ||
242 | } // if | |
243 | else { | |
244 | // Decode a padded zero | |
245 | cChar = '\0'; | |
246 | } // else | |
247 | ||
248 | // Check for valid decode | |
249 | if ( cChar > 0x7F ) | |
250 | return -1; | |
251 | ||
252 | // Adjust the bits | |
253 | switch ( iBitGroup ) { | |
254 | case 0: | |
255 | // The first group is copied into | |
256 | // the least significant 6 bits of | |
257 | // the decode buffer...these 6 bits | |
258 | // will eventually shift over to be | |
259 | // the most significant bits of the | |
260 | // third byte. | |
261 | cBuf = cBuf | cChar; | |
262 | break; | |
263 | ||
264 | default: | |
265 | // For groupings 1-3, simply shift | |
266 | // the bits in the decode buffer over | |
267 | // by 6 and insert the 6 from the | |
268 | // current decode character. | |
269 | cBuf = (cBuf << 6) | cChar; | |
270 | break; | |
271 | ||
272 | } // switch | |
273 | } // for | |
274 | ||
275 | // Interpret the resulting 3 bytes...note there | |
276 | // may have been padding, so those padded bytes | |
277 | // are actually ignored. | |
57bec1a5 MK |
278 | #if BYTE_ORDER == BIG_ENDIAN |
279 | strOutput += pBuf[sizeof(long)-3]; | |
280 | strOutput += pBuf[sizeof(long)-2]; | |
281 | strOutput += pBuf[sizeof(long)-1]; | |
282 | #else | |
1489accc | 283 | strOutput += pBuf[2]; |
284 | strOutput += pBuf[1]; | |
285 | strOutput += pBuf[0]; | |
57bec1a5 | 286 | #endif |
1489accc | 287 | } // while |
288 | if(pad) | |
289 | strOutput.resize(strOutput.length()-pad); | |
290 | ||
291 | return 1; | |
292 | } | |
293 | ||
294 | /* | |
295 | www.kbcafe.com | |
296 | Copyright 2001-2002 Randy Charles Morin | |
297 | The Encode static method takes an array of 8-bit values and returns a base-64 stream. | |
298 | */ | |
299 | ||
300 | ||
301 | std::string Base64Encode (const std::string& vby) | |
302 | { | |
303 | std::string retval; | |
304 | if (vby.size () == 0) | |
305 | { | |
306 | return retval; | |
307 | }; | |
308 | for (unsigned int i = 0; i < vby.size (); i += 3) | |
309 | { | |
310 | unsigned char by1 = 0, by2 = 0, by3 = 0; | |
311 | by1 = vby[i]; | |
312 | if (i + 1 < vby.size ()) | |
313 | { | |
314 | by2 = vby[i + 1]; | |
315 | }; | |
316 | if (i + 2 < vby.size ()) | |
317 | { | |
318 | by3 = vby[i + 2]; | |
319 | } | |
320 | unsigned char by4 = 0, by5 = 0, by6 = 0, by7 = 0; | |
321 | by4 = by1 >> 2; | |
322 | by5 = ((by1 & 0x3) << 4) | (by2 >> 4); | |
323 | by6 = ((by2 & 0xf) << 2) | (by3 >> 6); | |
324 | by7 = by3 & 0x3f; | |
325 | retval += B64Encode1 (by4); | |
326 | retval += B64Encode1 (by5); | |
327 | if (i + 1 < vby.size ()) | |
328 | { | |
329 | retval += B64Encode1 (by6); | |
330 | } | |
331 | else | |
332 | { | |
333 | retval += "="; | |
334 | }; | |
335 | if (i + 2 < vby.size ()) | |
336 | { | |
337 | retval += B64Encode1 (by7); | |
338 | } | |
339 | else | |
340 | { | |
341 | retval += "="; | |
342 | }; | |
343 | /* if ((i % (76 / 4 * 3)) == 0) | |
344 | { | |
345 | retval += "\r\n"; | |
346 | }*/ | |
347 | }; | |
348 | return retval; | |
349 | }; |