简体   繁体   中英

Using OpenSSL EVP. How to Encrypt a string and save the Encrypted string, key and IV to a file? Then Open the file and Decrypt back to string?

Hi All I have been struggling for a few days now and can't figure this out. I'm new to C++ and I'm trying to encrypt a string. Then Save the encrypted string, key and IV to a file.

The encryption works, I generate a Key and IV. Then Continue to encrypt the string. I then want to save the data to a file as follows.

I want to save the encrypted string on the first line of the file, the Key on the second line and the IV on the third line.

I'm struggling to save the data correctly.

From there, I would like to read the file. Set the first line as the string to decrypt, Second line as the Key and Third to use as the IV.

I think the issue I have is the correct way to save / write the data to a file and read the data back to decrypt the data.

Can someone help me to find the right direction.

Here Is what i have Got so far:

encryption.h

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <iostream>
#include <fstream>
using namespace std;



class Encryption {

    public:

    static std::string encodeText(const std::string &rawText, uint8_t key, uint8_t ivs)
    {
        uint8_t Keyt[32] = { key };
        uint8_t IV[AES_BLOCK_SIZE] = { ivs }; // Generate an AES Key

        // Make a copy of the IV to IVd as it seems to get destroyed when used
        uint8_t IVd[AES_BLOCK_SIZE];
        for (int i = 0; i < AES_BLOCK_SIZE; i++) {
            IVd[i] = IV[i];
        }

        /** Setup the AES Key structure required for use in the OpenSSL APIs **/
        AES_KEY* AesKey = new AES_KEY();
        AES_set_encrypt_key(Keyt, 256, AesKey);

        /** take an input string and pad it so it fits into 16 bytes (AES Block Size) **/
        const int UserDataSize = (const int)rawText.length();   // Get the length pre-padding
        int RequiredPadding = (AES_BLOCK_SIZE - (rawText.length() % AES_BLOCK_SIZE));   // Calculate required padding
        std::vector<unsigned char> PaddedTxt(rawText.begin(), rawText.end());   // Easier to Pad as a vector
        for (int i = 0; i < RequiredPadding; i++) {
            PaddedTxt.push_back(0); //  Increase the size of the string by
        }                           //  how much padding is necessary

        unsigned char* UserData = &PaddedTxt[0];// Get the padded text as an unsigned char array
        const int UserDataSizePadded = (const int)PaddedTxt.size();// and the length (OpenSSl is a C-API)

        /** Peform the encryption **/
        unsigned char EncryptedData[512] = { 0 }; // Hard-coded Array for OpenSSL (C++ can't dynamic arrays)
        AES_cbc_encrypt(UserData, EncryptedData, UserDataSizePadded, (const AES_KEY*)AesKey, IV, AES_ENCRYPT);

        string en = hex_print(EncryptedData, sizeof(EncryptedData));
        //string en = toIntStingFromChar(enh, sizeof(enh));

        return en;
    }

    static std::string decodeText(const std::string& rawText, uint8_t key, uint8_t ivs)
    {
        uint8_t Keyt[32] = {key};
        uint8_t IV[AES_BLOCK_SIZE] = {ivs}; // Generate an AES Key

        // Make a copy of the IV to IVd as it seems to get destroyed when used
        uint8_t IVd[AES_BLOCK_SIZE];
        for (int i = 0; i < AES_BLOCK_SIZE; i++) {
            IVd[i] = IV[i];
        }

        /** take an input string and pad it so it fits into 16 bytes (AES Block Size) **/
        const int UserDataSize = (const int)rawText.length();   // Get the length pre-padding
        int RequiredPadding = (AES_BLOCK_SIZE - (rawText.length() % AES_BLOCK_SIZE));   // Calculate required padding
        std::vector<unsigned char> PaddedTxt(rawText.begin(), rawText.end());   // Easier to Pad as a vector

        unsigned char* UserData = &PaddedTxt[0];// Get the padded text as an unsigned char array
        const int UserDataSizePadded = (const int)PaddedTxt.size();// and the length (OpenSSl is a C-API)

        /** Setup an AES Key structure for the decrypt operation **/
        AES_KEY* AesDecryptKey = new AES_KEY(); // AES Key to be used for Decryption
        AES_set_decrypt_key(Keyt, 256, AesDecryptKey);   // We Initialize this so we can use the OpenSSL Encryption API

        /** Decrypt the data. Note that we use the same function call. Only change is the last parameter **/
        unsigned char DecryptedData[512] = { 0 }; // Hard-coded as C++ doesn't allow for dynamic arrays and OpenSSL requires an array
        AES_cbc_encrypt(UserData, DecryptedData, UserDataSizePadded, (const AES_KEY*)AesDecryptKey, IVd, AES_DECRYPT);

        string de = hex_print(DecryptedData, sizeof(DecryptedData)-1);

        return de;
    }

    // Convert Hex to string
    static std::string hex_print(const void* pv, size_t len)
    {
        std::string r;
        const unsigned char* p = (const unsigned char*)pv;
        if (NULL == pv)
            r = "null";
        else
        {
            size_t i = 0;
            for (i; i < len; ++i)
                r += ("%02X ", *p++);
        }
        return r;
    }

    // Generate a Key
    static unsigned char *generateKey(unsigned char *buf, size_t length) {
        
        if (!RAND_bytes(buf, length)) {
            return NULL;
        }
        return buf;
    }

    // Generate a IV
    static unsigned char* generateIv(unsigned char* buf, size_t length) {

        if (!RAND_bytes(buf, length)) {
            return NULL;
        }
        return buf;
    }

    // Convert int to string
    static std::string toIntSting(uint8_t Keyt[], int length) {
        
        std::string k;
        for (size_t i = 0; i < length; i++)
        {
            k += std::to_string(Keyt[i]);
        } 
        wxString s(k);
        wxLogDebug(s);
        return k;
    }

    // Convert int to string from a Char
    static std::string toIntStingFromChar(unsigned char* test, int length) {

        std::string k;
        for (size_t i = 0; i < length; i++)
        {
            k += std::to_string(test[i]);
        }
        wxString s(k);
        wxLogDebug(s);
        return k;
    }

    // Write the data to a file
    static void writeToFile(std::string text, std::string Keyt, std::string IV) {
        ofstream myfile;
        myfile.open("example.txt");
        myfile << text;
        myfile << "\n";
        myfile << Keyt;
        myfile << "\n";
        myfile << IV;
        myfile.close();
    }

    // Open the file With the encrypted data
    static std::string* OpenFile() {

        static string myArray[3];

        ifstream myfile("example.txt");
        if (myfile.is_open())
        {
            for (int i = 0; i < 3; ++i)
            {
                // line 1 = text to decrypt
                // line 2 = key
                // line 3 = IV
                myfile >> myArray[i];
            }
            myfile.close();
        }

        return myArray;
    }
};

I'm using it as follows

// Encrpyt
    uint8_t Keyt[32];
    uint8_t IV[AES_BLOCK_SIZE]; 
    // Generate an AES Key, IV
    Encryption::generateKey(Keyt, sizeof(Keyt));
    Encryption::generateKey(IV, sizeof(IV));

    // Convert the Key to a string for saving to a file
    wxString p = Encryption::toIntSting(Keyt, sizeof(Keyt));
    wxLogDebug(p);

    // Convert the IV to a string for saving to a file
    wxString i = Encryption::toIntSting(IV, sizeof(IV));
    wxLogDebug(i);

    // Encrypt the string
    string response = Encryption::encodeText("password to encrypt", *Keyt, *IV);
    wxString r(response);

    // Save / write to a file
    Encryption::writeToFile(r.ToStdString(), p.ToStdString(), i.ToStdString());


    // Decrypt
    // Open File and return
    // line 1 = text to decrypt
    // line 2 = key
    // line 3 = IV
    string data[3] = { *Encryption::OpenFile() };    
    
    unsigned char key[32] = { (unsigned char)data[1].c_str() };
    unsigned char ivss[32] = { (unsigned char)data[2].c_str() };

   string de = Encryption::decodeText(data[0].c_str(), *key, *ivss);

    wxString d = de;
    wxLogDebug(d);

When it writes to a file I get Something as follows: example.txt

b‡f‡2É>ƒ}ã[Å8kH° [¥%WÔù¡dÃy ¼                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
17892143551869940267171785144164159149238210130121845322513358186346341616556
246140155172213011360214244852359123919

Some times the encrypted text (first line) will take up two lines which already is incorrect. My heads all over the place and i can't even figure out how to continue / look towards any more. All examples I found on overflow and on other Blogs etc only print the data to screen put not on how to save the data to a file.

Thank you.

All I want to do is encrypt a string. Then Save the encrypted string, key and IV to a file. Then Open the file and decrypt the data.

To be able to read variable length binary data (as you seem to do in the first line) you need to write how much data you have to read for the first line, and the same for the following.

size data

Being size in binary (an int for example).

Then you read the length and the data in two steps.

char * buf;
file.read ((char*)&len, sizeof(int));
buf = new [len];
file.read (buf, len);
string = buf;
delete [] buf;

this for each line.

Take in account that binary data handled as strings may cause problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM