Guest User

Aaron Polley

a guest
Feb 3rd, 2010
432
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.38 KB | None | 0 0
  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 <vector>
  61. #include <cstdio>
  62. #include "cryptopp560\config.h"
  63. #include "cryptopp560\hex.h"
  64. #include "cryptopp560\files.h"
  65. #include "cryptopp560\cryptlib.h"
  66. #include "cryptopp560\modes.h"
  67. #include "cryptopp560\osrng.h"
  68. #include "cryptopp560\filters.h"
  69. #include "cryptopp560\aes.h"
  70.  
  71. using namespace std;
  72. using namespace CryptoPP;
  73.  
  74. vector<void*> Vblocks;
  75.  
  76. class BasicCryptoPPWrap {
  77. public:
  78.  
  79.     static bool isHex(string checkForHex) {
  80.         size_t found;
  81.         found = checkForHex.find_first_not_of("0123456789ABCDEF");
  82.         if (found!=string::npos) {
  83.             // This string has non-hex characters in it
  84.             return false;
  85.         } else {
  86.             // only hex characters
  87.             return true;
  88.         }
  89.     }
  90.    
  91.     static string HexEncode(string binaryString) {
  92.        
  93.         if (isHex(binaryString)) {
  94.             // This string is already hex, don't convert it!
  95.             return binaryString;
  96.         } else {
  97.             string hexString;
  98.             StringSource(binaryString, true, new HexEncoder(new StringSink(hexString)));
  99.             return hexString;
  100.         }
  101.     }
  102.    
  103.     static string HexDecode(string hexString) {
  104.         if (isHex(hexString)) {
  105.             string binaryString;
  106.             StringSource(hexString, true, new HexDecoder(new StringSink(binaryString)));
  107.             return binaryString;
  108.         } else {
  109.             // it's already binary!
  110.             return hexString;
  111.         }
  112.     }    
  113.    
  114.     static string MREncryptStringAES(string plainText, string key, bool &err, string &errMsg) {
  115.         // returns an encypted string in binary
  116.         // This version will generate a random 16 byte initialization vector (iv) and prepend it to the actual encrypted text
  117.         // Use MRDecryptStringAES to decrypt this string
  118.         // use EncryptStringAES(plainText, key, iv, err) if you have already have an iv you want to use.
  119.         // key can be sent as a true binary "string" or a hex encoded string
  120.         try {
  121.             // get a random iv
  122.             string iv = ByteGen(AES::BLOCKSIZE);    // BLOCKSIZE is in bytes
  123.            
  124.             // convert the key if it is sent in hex
  125.             key = HexDecode(key);
  126.                        
  127.            
  128.             string cipherText = EncryptStringAES(plainText, key, iv, err, errMsg);
  129.             if (err) return "ERROR";
  130.            
  131.             return iv+cipherText;
  132.            
  133.         } catch (Exception& e) {
  134.             string errText = "Bad encrypt";
  135.             errMsg = e.GetWhat();
  136.             err = true;
  137.             return errText;
  138.         }
  139.     }
  140.    
  141.     static string EncryptStringAES(string plainText, string key, string iv, bool &err, string &errMsg) {
  142.         // returns an encypted string in binary
  143.         // This version uses the given iv and returns only the cipherText with no prepend
  144.         // use EncryptStringAES(plainText, key, err) if you want a random iv
  145.         // key and iv can be sent as a true binary "string" or a hex encoded string
  146.         try {
  147.             // convert the iv if it is sent in hex
  148.             iv = HexDecode(iv);        
  149.            
  150.             // convert the key if it is sent in hex
  151.             key = HexDecode(key);          
  152.            
  153.             // setup the encyptor
  154.             CBC_Mode< Rijndael >::Encryption e1( (byte *)key.c_str(), key.length(), (byte *)iv.c_str() );
  155.             // Encryption
  156.             string cipherText;
  157.             StringSource( plainText, true,
  158.                          new StreamTransformationFilter( e1, new CryptoPP::StringSink( cipherText )));
  159.            
  160.             // return the concatated iv and cipherText
  161.             err = false;
  162.             return cipherText;
  163.         } catch (Exception& e) {
  164.             string errText = "Bad encrypt";
  165.             errMsg = e.GetWhat();
  166.             err = true;
  167.             return errText;
  168.         }
  169.        
  170.     }
  171.    
  172.     static string MRDecryptStringAES(string ivAndCipherText, string key, bool &err, string &errMsg){
  173.         // returns the decrypted string
  174.         // This version expects a 16-byte initialization vector prepended to the cipherText
  175.         // This is the output generated by MREncryptStringAES
  176.         // ivAndCipherText & key can be given as hex or binary
  177.         try {
  178.             // convert ivAndCipherText as neccessary
  179.             ivAndCipherText = HexDecode(ivAndCipherText);
  180.                        
  181.             // convert key if necessary
  182.             key = HexDecode(key);
  183.                        
  184.             // recover the bits of the message
  185.             string iv;
  186.             iv.assign(ivAndCipherText, 0, 16);
  187.             string cipherText;
  188.             cipherText.assign(ivAndCipherText, 16, string::npos);
  189.            
  190.             string plainText = DecryptStringAES(cipherText, key, iv, err, errMsg);
  191.             if (err) return "ERROR";
  192.            
  193.             err = false;
  194.             return plainText;
  195.         } catch (Exception& e) {
  196.             string errText = "Bad decrypt";
  197.             errMsg = e.GetWhat();
  198.             err = true;
  199.             return errText;
  200.         }
  201.     }
  202.    
  203.     static string DecryptStringAES(string cipherText, string key, string iv, bool &err, string &errMsg){
  204.         // returns the decrypted string
  205.         // This version uses the given iv
  206.         // use DecryptStringAES(cipherText, key, err) if the iv is prepended to the cipherText
  207.         // cipherText, key, and iv can be given as hex or binary
  208.         try {
  209.             // convert ivAndCipherText as neccessary
  210.             cipherText = HexDecode(cipherText);
  211.                        
  212.             // convert key if necessary
  213.             key = HexDecode(key);
  214.                        
  215.             // convert iv if necessary
  216.             if (isHex(iv)) {
  217.                 iv = HexDecode(iv);
  218.             }
  219.            
  220.             // set up decrypter
  221.             CBC_Mode< Rijndael >::Decryption d((byte *)key.c_str(), key.length(), (byte *)iv.c_str());
  222.             // decrypt
  223.             string plainText;
  224.             StringSource( cipherText, true, new StreamTransformationFilter( d, new StringSink( plainText)));
  225.             err = false;
  226.             return plainText;
  227.         } catch (Exception& e) {
  228.             string errText = "Bad decrypt";
  229.             errMsg = e.GetWhat();
  230.             err = true;
  231.             return errText;
  232.         }
  233.     }
  234.    
  235.     static void EncryptFileAES(istream& inFile, ostream& outFile, string key, string iv, bool &err, string &errMsg) {
  236.         // will encrypt the file at filenameIn to filenameOut using AES
  237.         // WARNING: The iv must be known and retained for decryption!!
  238.         // key and iv can be hex or binary
  239.        
  240.        
  241.         // convert the key and iv
  242.         key = HexDecode(key);
  243.         iv = HexDecode(iv);
  244.         try {
  245.             // Set up the encrypter
  246.             CBC_Mode< Rijndael >::Encryption e1( (byte *)key.c_str(), key.length(), (byte *)iv.c_str() );
  247.             // encrypt
  248.             //if (filenameOut == "cout")
  249.             //  FileSource( filenameIn.c_str(), true, new StreamTransformationFilter( e1, new FileSink(cout)));
  250.             //else
  251.                 FileSource( inFile, true, new StreamTransformationFilter( e1, new FileSink(outFile)));
  252.             err= false;
  253.             return;
  254.         } catch (Exception& e) {
  255.             errMsg = e.GetWhat();
  256.             err = true;
  257.             return;
  258.         }
  259.     }
  260.    
  261.    
  262.     static void MREncryptFileAES(istream& inFile, ostream& outFile, string key, bool &err, string &errMsg) {
  263.         // will encrypt the file at inFile to outFile using AES
  264.         // but, adds a random iv to the beginning of the newly encrypted file which is recovered and used to decrypt it later.
  265.         // Use MRDecryptFileAES to decrypt this file
  266.         // key can be hex or binary
  267.         // programmers job to open and close the istream and ostream correctly!
  268.        
  269.         string iv = ByteGen(AES::BLOCKSIZE);
  270.        
  271.         // encrypt the file to temp
  272.         // generate a random file name that is unlikely to conflict with any existing names.
  273.         string tempName = HexEncode(ByteGen(8));
  274.         ofstream tempFile(tempName.c_str(), ios::binary);
  275.         EncryptFileAES(inFile, tempFile, key, iv, err, errMsg);
  276.         if (err) return;
  277.         tempFile.close();
  278.        
  279.         try {
  280.             // Now open a new file and put the iv in it
  281.                    
  282.             if (!outFile.good()) {
  283.                 err = true;
  284.                 errMsg = "Couldn't open desired output file";
  285.                 return;
  286.             }
  287.            
  288.             //write the iv to it
  289.             outFile.write(iv.c_str(), iv.length());
  290.            
  291.             // open the temp file and load into memory..
  292.             ifstream::pos_type size;
  293.             char * memblock;
  294.            
  295.             ifstream file(tempName.c_str(), ios::binary | ios::ate);
  296.             if (file.is_open()) {
  297.                 size = file.tellg();
  298.                 memblock = new char [size];
  299.                 file.seekg (0, ios::beg);
  300.                 file.read (memblock, size);
  301.                 file.close();
  302.             } else {
  303.                 err = true;
  304.                 errMsg = "Couldn't open encrypted temp file";
  305.                 return;
  306.             }
  307.            
  308.             // write the data to the finished file
  309.             outFile.write(memblock, size);
  310.            
  311.             delete[] memblock;
  312.            
  313.             // delete the temp file
  314.             remove(tempName.c_str());
  315.             err = false;
  316.             return;
  317.            
  318.         } catch (std::exception &e) {
  319.             errMsg = e.what();
  320.             err = true;
  321.             return;
  322.         }
  323.     }
  324.    
  325.        
  326.     static void DecryptFileAES(istream& inFile, ostream& outFile, string key, string iv, bool &err, string &errMsg) {
  327.         // will encrypt the file at filenameIn to filenameOut using AES
  328.         // WARNING: The correct iv MUST be provided
  329.         // key and iv can be hex or binary
  330.        
  331.         // convert the key and iv
  332.         key = HexDecode(key);
  333.         iv = HexDecode(iv);
  334.        
  335.         try {
  336.             // Set up the encrypter
  337.             CBC_Mode< Rijndael >::Decryption d ( (byte *)key.c_str(), key.length(), (byte *)iv.c_str() );
  338.             // encrypt
  339.             //if (filenameOut == "cout")
  340.             //  FileSource( filenameIn.c_str(), true, new StreamTransformationFilter( d, new FileSink(cout)));
  341.             //else
  342.                 FileSource( inFile, true, new StreamTransformationFilter( d, new FileSink(outFile)));
  343.             err= false;
  344.             return;
  345.         } catch (Exception& e) {
  346.             errMsg = e.GetWhat();
  347.             err = true;
  348.             return;
  349.         }
  350.     }
  351.    
  352.     static void MRDecryptFileAES(istream& inFile, ostream& outFile, string key, bool &err, string &errMsg) {
  353.         // Decrypts a file with a iv stored as the initial 16 bytes;
  354.         // This type of file is generated by MREncryptFileAES
  355.        
  356.         // first, open the file and load into memory..
  357.         ifstream::pos_type size;
  358.         int datasize;
  359.         char * ivblock;
  360.         char * datablock;
  361.        
  362.         if (inFile.good()) {
  363.             inFile.seekg(0, ios::end);
  364.             size = inFile.tellg();
  365.             inFile.seekg(0, ios::beg);
  366.             datasize = (int)size-16;
  367.             ivblock = new char[16];
  368.             datablock = new char[datasize];
  369.             inFile.read (ivblock, 16);
  370.             inFile.read(datablock, datasize);
  371.            
  372.         } else {
  373.             err = true;
  374.             errMsg = "Couldn't open encrypted input file";
  375.             return;
  376.         }
  377.        
  378.         // Make the iv
  379.         string iv;
  380.         iv.assign(ivblock, 16);
  381.         delete[] ivblock;
  382.        
  383.         //save the rest of the data as a temp file
  384.         // generate a random file name that is unlikely to conflict with any existing names.
  385.         string tempFile = HexEncode(ByteGen(8));
  386.         ofstream tempOut(tempFile.c_str(), ios::binary);
  387.         if (tempOut.is_open()) {
  388.             // save the data here.
  389.             tempOut.write(datablock, (datasize));
  390.             tempOut.close();
  391.             delete[] datablock;
  392.         } else {
  393.             err = true;
  394.             errMsg = "Couldn't create encrypted temporary file";
  395.             delete[] datablock;
  396.             return;
  397.         }
  398.        
  399.         ifstream tempIn(tempFile.c_str(), ios::binary);
  400.         // Now decrypt the temp file
  401.         DecryptFileAES(tempIn, outFile, key, iv, err, errMsg);
  402.        
  403.         tempIn.close();
  404.         remove(tempFile.c_str());      
  405.         if (err) return;
  406.        
  407.         err = false;
  408.         return;
  409.     }      
  410.    
  411.     static string BitGen(int howManyBits) {
  412.         // returns a new random key in binary of the given bit length
  413.         int byteLength = howManyBits/8; // bitLengths always better be div 8!!
  414.         return ByteGen(byteLength);
  415.     }
  416.    
  417.     static string ByteGen(int howManyBytes) {
  418.         // returns a new random key of the given byte length
  419.         AutoSeededRandomPool rnd;
  420.         byte* block = new byte[howManyBytes]; //Problem with howManyBytes variable being here set to 16 block value as AES requires 16 Blocks
  421.         Vblocks.push_back(block);
  422.         rnd.GenerateBlock(block, howManyBytes);
  423.         string blockString;
  424.         blockString.assign((char *)block, howManyBytes);
  425.         return blockString;
  426.     }
  427.  
  428.     static void cleanup(){
  429.         for(int i=0;i!=Vblocks.size();i++){
  430.             delete Vblocks.at(i);
  431.         }
  432.         Vblocks.~vector();
  433.     }
  434.    
  435.     static string hashSHA256(string inputString) {
  436.         // returns a SHA-256 encoded hash of the inputString in binary
  437.         // always returns 256 bits
  438.         SHA256 hash;
  439.         byte digest [ SHA256::DIGESTSIZE ];
  440.        
  441.         hash.CalculateDigest( digest, (byte *)inputString.c_str(), inputString.length() );
  442.         string hashString;
  443.         hashString.assign((char *)digest, sizeof(digest));
  444.        
  445.         return hashString;
  446.     }  
  447.    
  448. };
  449.  
  450. #endif
  451.  
  452.  
Advertisement
Add Comment
Please, Sign In to add comment