Share Pastebin
Guest
Public paste!

Aaron Polley

By: a guest | Feb 3rd, 2010 | Syntax: C++ | Size: 15.38 KB | Hits: 94 | Expires: Never
This paste has a previous version, view the difference. 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 <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