[英]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?
大家好,我已經苦苦掙扎了幾天,無法弄清楚這一點。 我是 C++ 的新手,我正在嘗試加密一個字符串。 然后將加密的字符串、密鑰和 IV 保存到文件中。
加密有效,我生成一個密鑰和 IV。 然后繼續加密字符串。 然后我想將數據保存到文件中,如下所示。
我想將加密的字符串保存在文件的第一行,將密鑰保存在第二行,將 IV 保存在第三行。
我正在努力正確保存數據。
從那里,我想閱讀文件。 將第一行設置為要解密的字符串,第二行設置為密鑰,第三行設置為 IV。
我認為我遇到的問題是將數據保存/寫入文件並讀回數據以解密數據的正確方法。
有人可以幫我找到正確的方向。
這是我到目前為止所得到的:
加密.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;
}
};
我使用它如下
// 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);
當它寫入文件時,我得到如下內容:example.txt
b‡f‡2É>ƒ}ã[Å8kH° [¥%WÔù¡dÃy ¼
17892143551869940267171785144164159149238210130121845322513358186346341616556
246140155172213011360214244852359123919
有時加密文本(第一行)會占用兩行已經不正確的行。 我的頭到處都是,我什至不知道如何繼續/再看下去。 我在溢出和其他博客等上找到的所有示例僅將數據打印到屏幕上,而不是關於如何將數據保存到文件中。
謝謝你。
我想做的就是加密一個字符串。 然后將加密的字符串、密鑰和 IV 保存到文件中。 然后打開文件並解密數據。
為了能夠讀取可變長度的二進制數據(就像您在第一行中所做的那樣),您需要為第一行編寫必須讀取的數據量,以下內容也是如此。
size data
二進制size
(例如int
)。
然后分兩步讀取長度和數據。
char * buf;
file.read ((char*)&len, sizeof(int));
buf = new [len];
file.read (buf, len);
string = buf;
delete [] buf;
這適用於每一行。
考慮到作為字符串處理的二進制數據可能會導致問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.