diff options
Diffstat (limited to 'sodcrypto.cc')
-rw-r--r-- | sodcrypto.cc | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/sodcrypto.cc b/sodcrypto.cc new file mode 100644 index 0000000..b92c6e0 --- /dev/null +++ b/sodcrypto.cc @@ -0,0 +1,354 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <iostream> +#include "namespaces.hh" +#include "noinitvector.hh" +#include "misc.hh" +#include "base64.hh" +#include "sodcrypto.hh" + + +#ifdef HAVE_LIBSODIUM + +string newKey() +{ + std::string key; + key.resize(crypto_secretbox_KEYBYTES); + + randombytes_buf(reinterpret_cast<unsigned char*>(&key.at(0)), key.size()); + + return "\""+Base64Encode(key)+"\""; +} + +bool sodIsValidKey(const std::string& key) +{ + return key.size() == crypto_secretbox_KEYBYTES; +} + +std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) +{ + if (!sodIsValidKey(key)) { + throw std::runtime_error("Invalid encryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key"); + } + + std::string ciphertext; + ciphertext.resize(msg.length() + crypto_secretbox_MACBYTES); + crypto_secretbox_easy(reinterpret_cast<unsigned char*>(&ciphertext.at(0)), + reinterpret_cast<const unsigned char*>(msg.c_str()), + msg.length(), + nonce.value, + reinterpret_cast<const unsigned char*>(key.c_str())); + + nonce.increment(); + return ciphertext; +} + +std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) +{ + std::string decrypted; + + if (msg.length() < crypto_secretbox_MACBYTES) { + throw std::runtime_error("Could not decrypt message of size " + std::to_string(msg.length())); + } + + if (!sodIsValidKey(key)) { + throw std::runtime_error("Invalid decryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key"); + } + + decrypted.resize(msg.length() - crypto_secretbox_MACBYTES); + + if (crypto_secretbox_open_easy(reinterpret_cast<unsigned char*>(const_cast<char *>(decrypted.data())), + reinterpret_cast<const unsigned char*>(msg.c_str()), + msg.length(), + nonce.value, + reinterpret_cast<const unsigned char*>(key.c_str())) != 0) { + throw std::runtime_error("Could not decrypt message, please check that the key configured with setKey() is correct"); + } + + nonce.increment(); + return decrypted; +} +#else +std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) +{ + return msg; +} +std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce) +{ + return msg; +} + +string newKey() +{ + return "\"plaintext\""; +} + +bool sodIsValidKey(const std::string& key) +{ + return true; +} + +#endif + + +#include "base64.hh" +#include <inttypes.h> + +namespace anonpdns { +static char B64Decode1(char cInChar) +{ + // The incoming character will be A-Z, a-z, 0-9, +, /, or =. + // The idea is to quickly determine which grouping the + // letter belongs to and return the associated value + // without having to search the global encoding string + // (the value we're looking for would be the resulting + // index into that string). + // + // To do that, we'll play some tricks... + unsigned char iIndex = '\0'; + switch ( cInChar ) { + case '+': + iIndex = 62; + break; + + case '/': + iIndex = 63; + break; + + case '=': + iIndex = 0; + break; + + default: + // Must be 'A'-'Z', 'a'-'z', '0'-'9', or an error... + // + // Numerically, small letters are "greater" in value than + // capital letters and numerals (ASCII value), and capital + // letters are "greater" than numerals (again, ASCII value), + // so we check for numerals first, then capital letters, + // and finally small letters. + iIndex = '9' - cInChar; + if ( iIndex > 0x3F ) { + // Not from '0' to '9'... + iIndex = 'Z' - cInChar; + if ( iIndex > 0x3F ) { + // Not from 'A' to 'Z'... + iIndex = 'z' - cInChar; + if ( iIndex > 0x3F ) { + // Invalid character...cannot + // decode! + iIndex = 0x80; // set the high bit + } // if + else { + // From 'a' to 'z' + iIndex = (('z' - iIndex) - 'a') + 26; + } // else + } // if + else { + // From 'A' to 'Z' + iIndex = ('Z' - iIndex) - 'A'; + } // else + } // if + else { + // Adjust the index... + iIndex = (('9' - iIndex) - '0') + 52; + } // else + break; + + } // switch + + return iIndex; +} + +static inline char B64Encode1(unsigned char uc) +{ + if (uc < 26) + { + return 'A'+uc; + } + if (uc < 52) + { + return 'a'+(uc-26); + } + if (uc < 62) + { + return '0'+(uc-52); + } + if (uc == 62) + { + return '+'; + } + return '/'; +}; + + + +} +using namespace anonpdns; + +template<typename Container> int B64Decode(const std::string& strInput, Container& strOutput) +{ + // Set up a decoding buffer + long cBuf = 0; + char* pBuf = (char*)&cBuf; + + // Decoding management... + int iBitGroup = 0, iInNum = 0; + + // While there are characters to process... + // + // We'll decode characters in blocks of 4, as + // there are 4 groups of 6 bits in 3 bytes. The + // incoming Base64 character is first decoded, and + // then it is inserted into the decode buffer + // (with any relevant shifting, as required). + // Later, after all 3 bytes have been reconstituted, + // we assign them to the output string, ultimately + // to be returned as the original message. + int iInSize = strInput.size(); + unsigned char cChar = '\0'; + uint8_t pad = 0; + while ( iInNum < iInSize ) { + // Fill the decode buffer with 4 groups of 6 bits + cBuf = 0; // clear + pad = 0; + for ( iBitGroup = 0; iBitGroup < 4; ++iBitGroup ) { + if ( iInNum < iInSize ) { + // Decode a character + if(strInput.at(iInNum)=='=') + pad++; + while(isspace(strInput.at(iInNum))) + iInNum++; + cChar = B64Decode1(strInput.at(iInNum++)); + + } // if + else { + // Decode a padded zero + cChar = '\0'; + } // else + + // Check for valid decode + if ( cChar > 0x7F ) + return -1; + + // Adjust the bits + switch ( iBitGroup ) { + case 0: + // The first group is copied into + // the least significant 6 bits of + // the decode buffer...these 6 bits + // will eventually shift over to be + // the most significant bits of the + // third byte. + cBuf = cBuf | cChar; + break; + + default: + // For groupings 1-3, simply shift + // the bits in the decode buffer over + // by 6 and insert the 6 from the + // current decode character. + cBuf = (cBuf << 6) | cChar; + break; + + } // switch + } // for + + // Interpret the resulting 3 bytes...note there + // may have been padding, so those padded bytes + // are actually ignored. +#if BYTE_ORDER == BIG_ENDIAN + strOutput.push_back(pBuf[sizeof(long)-3]); + strOutput.push_back(pBuf[sizeof(long)-2]); + strOutput.push_back(pBuf[sizeof(long)-1]); +#else + strOutput.push_back(pBuf[2]); + strOutput.push_back(pBuf[1]); + strOutput.push_back(pBuf[0]); +#endif + } // while + if(pad) + strOutput.resize(strOutput.size()-pad); + + return 1; +} + +template int B64Decode<std::vector<uint8_t>>(const std::string& strInput, std::vector<uint8_t>& strOutput); +template int B64Decode<PacketBuffer>(const std::string& strInput, PacketBuffer& strOutput); +template int B64Decode<std::string>(const std::string& strInput, std::string& strOutput); + +/* +www.kbcafe.com +Copyright 2001-2002 Randy Charles Morin +The Encode static method takes an array of 8-bit values and returns a base-64 stream. +*/ + + +std::string Base64Encode (const std::string& vby) +{ + std::string retval; + if (vby.size () == 0) + { + return retval; + }; + for (unsigned int i = 0; i < vby.size (); i += 3) + { + unsigned char by1 = 0, by2 = 0, by3 = 0; + by1 = vby[i]; + if (i + 1 < vby.size ()) + { + by2 = vby[i + 1]; + }; + if (i + 2 < vby.size ()) + { + by3 = vby[i + 2]; + } + unsigned char by4 = 0, by5 = 0, by6 = 0, by7 = 0; + by4 = by1 >> 2; + by5 = ((by1 & 0x3) << 4) | (by2 >> 4); + by6 = ((by2 & 0xf) << 2) | (by3 >> 6); + by7 = by3 & 0x3f; + retval += B64Encode1 (by4); + retval += B64Encode1 (by5); + if (i + 1 < vby.size ()) + { + retval += B64Encode1 (by6); + } + else + { + retval += "="; + }; + if (i + 2 < vby.size ()) + { + retval += B64Encode1 (by7); + } + else + { + retval += "="; + }; + /* if ((i % (76 / 4 * 3)) == 0) + { + retval += "\r\n"; + }*/ + }; + return retval; +}; |