Share Pastebin
Guest
Public paste!

swarmapps

By: a guest | Nov 23rd, 2009 | Syntax: C++ | Size: 14.99 KB | Hits: 770 | Expires: Never
Copy text to clipboard
  1. // BasicCryptoPPWrap.h
  2. // By: Michael R. Rich, 2009
  3. // This code is placed into the public domain by its author
  4. // No warranty or guarantee of applicability or function is granted.
  5.  
  6. // This is a wrapper designed to allow rapid use of the Crypto++ cryptographic library in a multitude of applications.
  7. // It permits a developer with a nominal understanding of C++ to rapidly field apps that use cryptography to provide basic confidentiality.
  8. // I wrote it so that a developer need not use any other variable types than string to encrypt and decrypt at will.
  9. // Encrypting a string is as simple as:
  10. //        string plainText = "I don't want anyone seeing this without my permission!"
  11. //        string key = BasicCryptoPPWrap::BitGen(256);        // Better not lose this key!!
  12. //        bool err;
  13. //                string errMsg;
  14. //        string cipherText = BasicCryptoPPWrap::MREncryptStringAES(plainText, key, &err, &errMsg);
  15. // The returned string is not directly viewable.  In this case the string class is used as a handy data buffer for the crypto work.  If you want to see the
  16. // string, simply do this:
  17. //        cout << BasicCryptoPPWrap::HexEncode(cipherText) << "\n";
  18. // To see the text again:
  19. //        string recoveredText = BasicCryptoPPWrap::MRDecryptStringAES(cipherText, key, &err, &errMsg);
  20. //        cout << recoveredText << "\n";
  21. // A more comprehensive example can be seen in the sample code provided with this header
  22.  
  23. // To use the wrapper, you first need to successfully build and test the Crypto++ library.
  24. // Visit the Crypto++ hompage (www.cryptopp.com) for the latest code, build, and test instructions.
  25. // Then, add the Crypto++ directory to your include directories, link to the cryptopp library and include this header in your code.
  26.  
  27. // The Crypto++ library is a very powerful set of cryptographic tools, but I found the learning curve to get my first apps running with
  28. // it to be very high.  I examined all the sample code I could find, worked through the API documentation, and examined the
  29. // validation and test code before I finally started catching on.  Then I had to "grep" my way through the files to identify which headers I
  30. // needed to include for a given function.  All of this brainache is undoubtedly due to my own lack of skill and formal training.
  31.  
  32. // Nonetheless, once I got the pattern figured out, I didn't want to repeat it all over the place in my code, so I wrote this wrapper.
  33. // I don't want you to go through the same thing, so I'm offering this wrapper to those who can use it.
  34.  
  35. // This simplification comes at a cost of flexibility and performance.  I hope you outgrow this wrapper.  But, until you do, use it well!
  36.  
  37. // WARNINGS!!
  38. // Data encrypted with methods starting with "MREncrypt" implement a custom initialization vector protocol.  Essentially the iv is either prepended to
  39. // the string or the file you are using.  The "MRDecrypt" methods should be used to decrypt them.  Methods without the "MR" prefix are
  40. // designed to work with a separately supplied iv.
  41. //
  42. // The binary "strings" returned by this wrapper do not play well with the formatted input and output functions and operators (i.e. <<, >>, getLine, etc..)
  43. // You should use binary, unformatted functions to move them around.  See the MREncryptFileAES and MRDecryptFileAES methods for examples.
  44. //
  45. // This wrapper currently only uses one mode of AES encryption.  See flexibility and performance warning above!
  46. //
  47. // I am not a Crypto anything.  The word novice hardly even applies to me.  I am using the Crypto++ library in it's most basic form.
  48. // As a result, I wouldn't use this wrapper in anything serious like financial or medical records, or access to critical infrastructure control
  49. // routines.  I'm just saying.
  50.  
  51. // If you get a weird link error like "variable not in vtable" or "virtual thunk", add -DCRYPTOPP_DISABLE_ASM to the build options.
  52. // This apparently happens on Mac OS X from time to time (it happened to me)
  53.  
  54.  
  55. #ifndef __MRCRYPTOWRAP_H
  56. #define __MRCRYPTOWRAP_H
  57.  
  58. #include <iostream>
  59. #include <string>
  60. #include <cstdio>
  61. #include "config.h"
  62. #include "hex.h"
  63. #include "files.h"
  64. #include "cryptlib.h"
  65. #include "modes.h"
  66. #include "osrng.h"
  67. #include "filters.h"
  68. #include "aes.h"
  69.  
  70. using namespace std;
  71. using namespace CryptoPP;
  72.  
  73. class BasicCryptoPPWrap {
  74. public:
  75.        
  76.         static bool isHex(string checkForHex) {
  77.                 size_t found;
  78.                 found = checkForHex.find_first_not_of("0123456789ABCDEF");
  79.                 if (found!=string::npos) {
  80.                         // This string has non-hex characters in it
  81.                         return false;
  82.                 } else {
  83.                         // only hex characters
  84.                         return true;
  85.                 }
  86.         }
  87.        
  88.         static string HexEncode(string binaryString) {
  89.                
  90.                 if (isHex(binaryString)) {
  91.                         // This string is already hex, don't convert it!
  92.                         return binaryString;
  93.                 } else {
  94.                         string hexString;
  95.                         StringSource(binaryString, true, new HexEncoder(new StringSink(hexString)));
  96.                         return hexString;
  97.                 }
  98.         }
  99.        
  100.         static string HexDecode(string hexString) {
  101.                 if (isHex(hexString)) {
  102.                         string binaryString;
  103.                         StringSource(hexString, true, new HexDecoder(new StringSink(binaryString)));
  104.                         return binaryString;
  105.                 } else {
  106.                         // it's already binary!
  107.                         return hexString;
  108.                 }
  109.         }    
  110.    
  111.         static string MREncryptStringAES(string plainText, string key, bool &err, string &errMsg) {
  112.                 // returns an encypted string in binary
  113.                 // This version will generate a random 16 byte initialization vector (iv) and prepend it to the actual encrypted text
  114.                 // Use MRDecryptStringAES to decrypt this string
  115.                 // use EncryptStringAES(plainText, key, iv, err) if you have already have an iv you want to use.
  116.                 // key can be sent as a true binary "string" or a hex encoded string
  117.                 try {
  118.                         // get a random iv
  119.                         string iv = ByteGen(AES::BLOCKSIZE);    // BLOCKSIZE is in bytes
  120.                        
  121.                         // convert the key if it is sent in hex
  122.                         key = HexDecode(key);
  123.                                                
  124.                        
  125.                         string cipherText = EncryptStringAES(plainText, key, iv, err, errMsg);
  126.                         if (err) return "ERROR";
  127.                        
  128.                         return iv+cipherText;
  129.                        
  130.                 } catch (Exception& e) {
  131.                         string errText = "Bad encrypt";
  132.                         errMsg = e.GetWhat();
  133.                         err = true;
  134.                         return errText;
  135.                 }
  136.         }
  137.        
  138.         static string EncryptStringAES(string plainText, string key, string iv, bool &err, string &errMsg) {
  139.                 // returns an encypted string in binary
  140.                 // This version uses the given iv and returns only the cipherText with no prepend
  141.                 // use EncryptStringAES(plainText, key, err) if you want a random iv
  142.                 // key and iv can be sent as a true binary "string" or a hex encoded string
  143.                 try {
  144.                         // convert the iv if it is sent in hex
  145.                         iv = HexDecode(iv);                    
  146.                        
  147.                         // convert the key if it is sent in hex
  148.                         key = HexDecode(key);                  
  149.                        
  150.                         // setup the encyptor
  151.                         CBC_Mode< Rijndael >::Encryption e1( (byte *)key.c_str(), key.length(), (byte *)iv.c_str() );
  152.                         // Encryption
  153.                         string cipherText;
  154.                         StringSource( plainText, true,
  155.                                                  new StreamTransformationFilter( e1, new CryptoPP::StringSink( cipherText )));
  156.                        
  157.                         // return the concatated iv and cipherText
  158.                         err = false;
  159.                         return cipherText;
  160.                 } catch (Exception& e) {
  161.                         string errText = "Bad encrypt";
  162.                         errMsg = e.GetWhat();
  163.                         err = true;
  164.                         return errText;
  165.                 }
  166.                
  167.         }
  168.        
  169.         static string MRDecryptStringAES(string ivAndCipherText, string key, bool &err, string &errMsg){
  170.                 // returns the decrypted string
  171.                 // This version expects a 16-byte initialization vector prepended to the cipherText
  172.                 // This is the output generated by MREncryptStringAES
  173.                 // ivAndCipherText & key can be given as hex or binary
  174.                 try {
  175.                         // convert ivAndCipherText as neccessary
  176.                         ivAndCipherText = HexDecode(ivAndCipherText);
  177.                                                
  178.                         // convert key if necessary
  179.                         key = HexDecode(key);
  180.                                                
  181.                         // recover the bits of the message
  182.                         string iv;
  183.                         iv.assign(ivAndCipherText, 0, 16);
  184.                         string cipherText;
  185.                         cipherText.assign(ivAndCipherText, 16, string::npos);
  186.                        
  187.                         string plainText = DecryptStringAES(cipherText, key, iv, err, errMsg);
  188.                         if (err) return "ERROR";
  189.                        
  190.                         err = false;
  191.                         return plainText;
  192.                 } catch (Exception& e) {
  193.                         string errText = "Bad decrypt";
  194.                         errMsg = e.GetWhat();
  195.                         err = true;
  196.                         return errText;
  197.                 }
  198.         }
  199.        
  200.         static string DecryptStringAES(string cipherText, string key, string iv, bool &err, string &errMsg){
  201.                 // returns the decrypted string
  202.                 // This version uses the given iv
  203.                 // use DecryptStringAES(cipherText, key, err) if the iv is prepended to the cipherText
  204.                 // cipherText, key, and iv can be given as hex or binary
  205.                 try {
  206.                         // convert ivAndCipherText as neccessary
  207.                         cipherText = HexDecode(cipherText);
  208.                                                
  209.                         // convert key if necessary
  210.                         key = HexDecode(key);
  211.                                                
  212.                         // convert iv if necessary
  213.                         if (isHex(iv)) {
  214.                                 iv = HexDecode(iv);
  215.                         }
  216.                        
  217.                         // set up decrypter
  218.                         CBC_Mode< Rijndael >::Decryption d((byte *)key.c_str(), key.length(), (byte *)iv.c_str());
  219.                         // decrypt
  220.                         string plainText;
  221.                         StringSource( cipherText, true, new StreamTransformationFilter( d, new StringSink( plainText)));
  222.                         err = false;
  223.                         return plainText;
  224.                 } catch (Exception& e) {
  225.                         string errText = "Bad decrypt";
  226.                         errMsg = e.GetWhat();
  227.                         err = true;
  228.                         return errText;
  229.                 }
  230.         }
  231.        
  232.         static void EncryptFileAES(istream& inFile, ostream& outFile, string key, string iv, bool &err, string &errMsg) {
  233.                 // will encrypt the file at filenameIn to filenameOut using AES
  234.                 // WARNING: The iv must be known and retained for decryption!!
  235.                 // key and iv can be hex or binary
  236.                
  237.                
  238.                 // convert the key and iv
  239.                 key = HexDecode(key);
  240.                 iv = HexDecode(iv);
  241.                 try {
  242.                         // Set up the encrypter
  243.                         CBC_Mode< Rijndael >::Encryption e1( (byte *)key.c_str(), key.length(), (byte *)iv.c_str() );
  244.                         // encrypt
  245.                         //if (filenameOut == "cout")
  246.                         //      FileSource( filenameIn.c_str(), true, new StreamTransformationFilter( e1, new FileSink(cout)));
  247.                         //else
  248.                                 FileSource( inFile, true, new StreamTransformationFilter( e1, new FileSink(outFile)));
  249.                         err= false;
  250.                         return;
  251.                 } catch (Exception& e) {
  252.                         errMsg = e.GetWhat();
  253.                         err = true;
  254.                         return;
  255.                 }
  256.         }
  257.        
  258.        
  259.         static void MREncryptFileAES(istream& inFile, ostream& outFile, string key, bool &err, string &errMsg) {
  260.                 // will encrypt the file at inFile to outFile using AES
  261.                 // but, adds a random iv to the beginning of the newly encrypted file which is recovered and used to decrypt it later.
  262.                 // Use MRDecryptFileAES to decrypt this file
  263.                 // key can be hex or binary
  264.                 // programmers job to open and close the istream and ostream correctly!
  265.                
  266.                 string iv = ByteGen(AES::BLOCKSIZE);
  267.                
  268.                 // encrypt the file to temp
  269.                 // generate a random file name that is unlikely to conflict with any existing names.
  270.                 string tempName = HexEncode(ByteGen(8));
  271.                 ofstream tempFile(tempName.c_str(), ios::binary);
  272.                 EncryptFileAES(inFile, tempFile, key, iv, err, errMsg);
  273.                 if (err) return;
  274.                 tempFile.close();
  275.                
  276.                 try {
  277.                         // Now open a new file and put the iv in it
  278.                                        
  279.                         if (!outFile.good()) {
  280.                                 err = true;
  281.                                 errMsg = "Couldn't open desired output file";
  282.                                 return;
  283.                         }
  284.                        
  285.                         //write the iv to it
  286.                         outFile.write(iv.c_str(), iv.length());
  287.                        
  288.                         // open the temp file and load into memory..
  289.                         ifstream::pos_type size;
  290.                         char * memblock;
  291.                        
  292.                         ifstream file(tempName.c_str(), ios::binary | ios::ate);
  293.                         if (file.is_open()) {
  294.                                 size = file.tellg();
  295.                                 memblock = new char [size];
  296.                                 file.seekg (0, ios::beg);
  297.                                 file.read (memblock, size);
  298.                                 file.close();
  299.                         } else {
  300.                                 err = true;
  301.                                 errMsg = "Couldn't open encrypted temp file";
  302.                                 return;
  303.                         }
  304.                        
  305.                         // write the data to the finished file
  306.                         outFile.write(memblock, size);
  307.                        
  308.                         delete[] memblock;
  309.                        
  310.                         // delete the temp file
  311.                         remove(tempName.c_str());
  312.                         err = false;
  313.                         return;
  314.                        
  315.                 } catch (std::exception &e) {
  316.                         errMsg = e.what();
  317.                         err = true;
  318.                         return;
  319.                 }
  320.         }
  321.        
  322.                
  323.         static void DecryptFileAES(istream& inFile, ostream& outFile, string key, string iv, bool &err, string &errMsg) {
  324.                 // will encrypt the file at filenameIn to filenameOut using AES
  325.                 // WARNING: The correct iv MUST be provided
  326.                 // key and iv can be hex or binary
  327.                
  328.                 // convert the key and iv
  329.                 key = HexDecode(key);
  330.                 iv = HexDecode(iv);
  331.                
  332.                 try {
  333.                         // Set up the encrypter
  334.                         CBC_Mode< Rijndael >::Decryption d ( (byte *)key.c_str(), key.length(), (byte *)iv.c_str() );
  335.                         // encrypt
  336.                         //if (filenameOut == "cout")
  337.                         //      FileSource( filenameIn.c_str(), true, new StreamTransformationFilter( d, new FileSink(cout)));
  338.                         //else
  339.                                 FileSource( inFile, true, new StreamTransformationFilter( d, new FileSink(outFile)));
  340.                         err= false;
  341.                         return;
  342.                 } catch (Exception& e) {
  343.                         errMsg = e.GetWhat();
  344.                         err = true;
  345.                         return;
  346.                 }
  347.         }
  348.        
  349.         static void MRDecryptFileAES(istream& inFile, ostream& outFile, string key, bool &err, string &errMsg) {
  350.                 // Decrypts a file with a iv stored as the initial 16 bytes;
  351.                 // This type of file is generated by MREncryptFileAES
  352.                
  353.                 // first, open the file and load into memory..
  354.                 ifstream::pos_type size;
  355.                 int datasize;
  356.                 char * ivblock;
  357.                 char * datablock;
  358.                
  359.                 if (inFile.good()) {
  360.                         inFile.seekg(0, ios::end);
  361.                         size = inFile.tellg();
  362.                         inFile.seekg(0, ios::beg);
  363.                         datasize = (int)size-16;
  364.                         ivblock = new char[16];
  365.                         datablock = new char[datasize];
  366.                         inFile.read (ivblock, 16);
  367.                         inFile.read(datablock, datasize);
  368.                        
  369.                 } else {
  370.                         err = true;
  371.                         errMsg = "Couldn't open encrypted input file";
  372.                         return;
  373.                 }
  374.                
  375.                 // Make the iv
  376.                 string iv;
  377.                 iv.assign(ivblock, 16);
  378.                 delete[] ivblock;
  379.                
  380.                 //save the rest of the data as a temp file
  381.                 // generate a random file name that is unlikely to conflict with any existing names.
  382.                 string tempFile = HexEncode(ByteGen(8));
  383.                 ofstream tempOut(tempFile.c_str(), ios::binary);
  384.                 if (tempOut.is_open()) {
  385.                         // save the data here.
  386.                         tempOut.write(datablock, (datasize));
  387.                         tempOut.close();
  388.                         delete[] datablock;
  389.                 } else {
  390.                         err = true;
  391.                         errMsg = "Couldn't create encrypted temporary file";
  392.                         delete[] datablock;
  393.                         return;
  394.                 }
  395.                
  396.                 ifstream tempIn(tempFile.c_str(), ios::binary);
  397.                 // Now decrypt the temp file
  398.                 DecryptFileAES(tempIn, outFile, key, iv, err, errMsg);
  399.                
  400.                 tempIn.close();
  401.                 remove(tempFile.c_str());              
  402.                 if (err) return;
  403.                
  404.                 err = false;
  405.                 return;
  406.         }              
  407.        
  408.         static string BitGen(int howManyBits) {
  409.                 // returns a new random key in binary of the given bit length
  410.                 int byteLength = howManyBits/8; // bitLengths always better be div 8!!
  411.                 return ByteGen(byteLength);
  412.         }
  413.        
  414.         static string ByteGen(int howManyBytes) {
  415.                 // returns a new random key of the given byte length
  416.                 AutoSeededRandomPool rnd;
  417.                 byte block[howManyBytes];
  418.                 rnd.GenerateBlock(block, howManyBytes);
  419.                 string blockString;
  420.                 blockString.assign((char *)block, sizeof(block));
  421.                 return blockString;
  422.         }
  423.  
  424.        
  425.         static string hashSHA256(string inputString) {
  426.                 // returns a SHA-256 encoded hash of the inputString in binary
  427.                 // always returns 256 bits
  428.                 SHA256 hash;
  429.                 byte digest [ SHA256::DIGESTSIZE ];
  430.                
  431.                 hash.CalculateDigest( digest, (byte *)inputString.c_str(), inputString.length() );
  432.                 string hashString;
  433.                 hashString.assign((char *)digest, sizeof(digest));
  434.                
  435.                 return hashString;
  436.         }      
  437.        
  438. };
  439.  
  440. #endif