]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/sodcrypto.cc
Add some notes explaining why some validations are not relevant in the dnstap case.
[thirdparty/pdns.git] / pdns / sodcrypto.cc
CommitLineData
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 31string 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
41bool sodIsValidKey(const std::string& key)
42{
43 return key.size() == crypto_secretbox_KEYBYTES;
44}
45
8c732ebf 46std::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 64std::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
90std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce)
91{
92 return msg;
93}
94std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce)
95{
96 return msg;
97}
98
99string newKey()
100{
101 return "\"plaintext\"";
102}
103
9c9b4998
RG
104bool 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
115namespace anonpdns {
116char 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
181inline 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}
205using namespace anonpdns;
206
207int 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/*
295www.kbcafe.com
296Copyright 2001-2002 Randy Charles Morin
297The Encode static method takes an array of 8-bit values and returns a base-64 stream.
298*/
299
300
301std::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};