Guest User

Aaron Polley

a guest
Jan 28th, 2010
351
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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 = new byte[howManyBytes]; //Correction for VC++ (Will not compile in VC++ without it)
  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
RAW Paste Data