使用 Crypto++ 解密时原始文本末尾的车库冗余字符
Gargage redundancy character at the end of original text when decrypt using Crypto++
我正在使用 Crypto++,CTR 模式,在 C++ 中加密和解密文本。一切似乎都有效 99%。加密成功,解密也返回原始文本,但我在解密文本的末尾给出了一些额外的随机垃圾冗余文本,如“ð”。这个额外的部分是每次我 运行 代码时随机生成的。我的代码有问题吗?
将字符串加密为字符串
string encryptString(string plain, byte key[], int sizeKey, byte iv[], int sizeIV){
string cipher;
try{
CTR_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeKey, iv, sizeIV);
// The StreamTransformationFilter removes
// padding as required.
StringSource s(plain, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
)
);
#if 0
StreamTransformationFilter filter(e);
filter.Put((const byte*)plain.data(), plain.size());
filter.MessageEnd();
const size_t ret = filter.MaxRetrievable();
cipher.resize(ret);
filter.Get((byte*)cipher.data(), cipher.size());
#endif
return cipher;
}
catch (const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
return NULL;
}
}
将加密字符串解密为字符串
string decryptString(string cipher, byte key[], int sizeKey, byte iv[], int sizeIV){
string reco ="";
try{
CTR_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, sizeKey, iv, sizeIV);
StringSource s(cipher, true,
new StreamTransformationFilter(d,
new StringSink(reco)
)
);
}
catch (const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
}
return reco;
}
包装上面的 encryptString 函数。
char* encrypt(char * plainText, byte key[], int sizeKey, byte iv[], int sizeIV, long &len){
string cipher = encryptString(plainText, key, sizeKey, iv, sizeIV);
len = cipher.size() + 1;
char * writable = new char[len];
std::copy(cipher.begin(), cipher.end(), writable);
writable[len] = '[=12=]'; // don't forget the terminating 0
return writable;
}
包装上面的 decryptString 函数。
char* decrypt(char * cipher, byte key[], int sizeKey, byte iv[], int sizeIV, long len){
string ss(cipher, len);
long lengSS = ss.length();
string recovered = decryptString(ss, key, sizeKey, iv, sizeIV);
char * writable = new char[recovered.size() + 1];
std::copy(recovered.begin(), recovered.end(), writable);
writable[recovered.size()] = '[=13=]'; // don't forget the terminating 0
return writable;
}
我的测试脚本很简单。读取some.txt内容("I love you"),写入s1.txt,检查读取是否正确。加密、解密,然后将恢复的文本写入另一个文件 (d1.txt)。
int main(int argc, char* argv[])
{
AutoSeededRandomPool prng;
byte key[AES::DEFAULT_KEYLENGTH] = { '1', '2', '3', '4', '5', '6', '7', '8', '1', '2', '3', '4', '5', '6', '7', '8' };
//prng.GenerateBlock(key, sizeof(key));
byte iv[AES::BLOCKSIZE] = { '8', '7', '6', '5', '4', '3', '2', '1', '8', '7', '6', '5', '4', '3', '2', '1' };
prng.GenerateBlock(iv, sizeof(iv));
long size = 0;
char * s1 = FileUtil::readAllByte("some.txt");
//Result: s1.txt content is "I love you"
long len = 0;
char* result1 = encrypt(s1, key, sizeof(key), iv, sizeof(iv), len);
//Result: result1 is a bunch of ciphered characters
cout << "desc" << endl;
char* recovered1 = decrypt(result1, key, sizeof(key), iv, sizeof(iv), len);
//Result: recovered1="I love youð". Generally, it has form of "I love youX"
//X can be any garbage chatacter, and each time I run the code, X is one different
//character.
}
根据接受的答案,解决方案是:像这样更新我的 encrypt():
char* encrypt(char * plainText, byte key[], int sizeKey, byte iv[], int sizeIV, long &len){
string cipher = encryptString(plainText, key, sizeKey, iv, sizeIV);
FileUtil::writeFile("ss1.txt", cipher, cipher.length());
len = cipher.size() ;
char * writable = new char[len];
std::copy(cipher.begin(), cipher.end(), writable);
writable[len] = '[=15=]'; // don't forget the terminating 0
FileUtil::writeFile("w1.txt",writable, len);
return writable;
}
只分配writeable的长度= cipher的长度。将终止符设置为 writeble[len]
当您遇到缓冲区溢出和未终止的字符串等问题时,往往会发生这种情况。如果我们查看您的 encrypt
函数,我们会看到缓冲区溢出:
len = cipher.size() + 1;
char * writable = new char[len];
std::copy(cipher.begin(), cipher.end(), writable);
writable[len] = '[=10=]';
看到这里你分配了 len
个字节,其中 len
比 cipher
大一个。但是当您终止字符串时,您正在使用 len
来索引超出范围的内容。
您应该使用 len-1
或 cipher.size()
作为终止符索引。
char* encrypt(char * plainText, ... );
char* decrypt(char * cipher, ... );
您也可以避免 encryptString
和 decryptString
以及额外的副本。我给你看encrypt
,decrypt
也差不多。
char* encrypt(char * plainText, byte key[], int sizeKey, byte iv[], int sizeIV, long &len)
{
const unsigned long plainTextLen = len; len = 0;
const unsigned long extraLen = plainTextLen+16;
ArraySource source(plainText, plainTextLen, false);
unique_ptr<char[]> writable(new char[extraLen]);
ArraySink sink(writable, extraLen);
CTR_Mode< AES >::Encryption enc;
enc.SetKeyWithIV(key, sizeKey, iv, sizeIV);
source.Detach(new StreamTransformationFilter(enc, new Redirector(sink)));
source.PumpAll();
len = sink.TotalPutLength();
return writable.release();
}
我没有编译 运行 它,所以你必须清除上面代码中的编译器问题。它们应该都是次要的,例如转换和转换。
您通常不需要担心NULL
;只需使用 ptr
和 len
。您可以使用 string recovered = string(ptr, len);
从解密的密文创建 std::string
。 std::string
会在需要时生成 NULL
,但通常不需要。
Detach
不是 错字。您可以使用它 Attach
一个新的过滤器和 delete
一个以前的过滤器。您使用它来避免内存泄漏。
我正在使用 Crypto++,CTR 模式,在 C++ 中加密和解密文本。一切似乎都有效 99%。加密成功,解密也返回原始文本,但我在解密文本的末尾给出了一些额外的随机垃圾冗余文本,如“ð”。这个额外的部分是每次我 运行 代码时随机生成的。我的代码有问题吗?
将字符串加密为字符串
string encryptString(string plain, byte key[], int sizeKey, byte iv[], int sizeIV){
string cipher;
try{
CTR_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeKey, iv, sizeIV);
// The StreamTransformationFilter removes
// padding as required.
StringSource s(plain, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
)
);
#if 0
StreamTransformationFilter filter(e);
filter.Put((const byte*)plain.data(), plain.size());
filter.MessageEnd();
const size_t ret = filter.MaxRetrievable();
cipher.resize(ret);
filter.Get((byte*)cipher.data(), cipher.size());
#endif
return cipher;
}
catch (const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
return NULL;
}
}
将加密字符串解密为字符串
string decryptString(string cipher, byte key[], int sizeKey, byte iv[], int sizeIV){
string reco ="";
try{
CTR_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, sizeKey, iv, sizeIV);
StringSource s(cipher, true,
new StreamTransformationFilter(d,
new StringSink(reco)
)
);
}
catch (const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
}
return reco;
}
包装上面的 encryptString 函数。
char* encrypt(char * plainText, byte key[], int sizeKey, byte iv[], int sizeIV, long &len){
string cipher = encryptString(plainText, key, sizeKey, iv, sizeIV);
len = cipher.size() + 1;
char * writable = new char[len];
std::copy(cipher.begin(), cipher.end(), writable);
writable[len] = '[=12=]'; // don't forget the terminating 0
return writable;
}
包装上面的 decryptString 函数。
char* decrypt(char * cipher, byte key[], int sizeKey, byte iv[], int sizeIV, long len){
string ss(cipher, len);
long lengSS = ss.length();
string recovered = decryptString(ss, key, sizeKey, iv, sizeIV);
char * writable = new char[recovered.size() + 1];
std::copy(recovered.begin(), recovered.end(), writable);
writable[recovered.size()] = '[=13=]'; // don't forget the terminating 0
return writable;
}
我的测试脚本很简单。读取some.txt内容("I love you"),写入s1.txt,检查读取是否正确。加密、解密,然后将恢复的文本写入另一个文件 (d1.txt)。
int main(int argc, char* argv[])
{
AutoSeededRandomPool prng;
byte key[AES::DEFAULT_KEYLENGTH] = { '1', '2', '3', '4', '5', '6', '7', '8', '1', '2', '3', '4', '5', '6', '7', '8' };
//prng.GenerateBlock(key, sizeof(key));
byte iv[AES::BLOCKSIZE] = { '8', '7', '6', '5', '4', '3', '2', '1', '8', '7', '6', '5', '4', '3', '2', '1' };
prng.GenerateBlock(iv, sizeof(iv));
long size = 0;
char * s1 = FileUtil::readAllByte("some.txt");
//Result: s1.txt content is "I love you"
long len = 0;
char* result1 = encrypt(s1, key, sizeof(key), iv, sizeof(iv), len);
//Result: result1 is a bunch of ciphered characters
cout << "desc" << endl;
char* recovered1 = decrypt(result1, key, sizeof(key), iv, sizeof(iv), len);
//Result: recovered1="I love youð". Generally, it has form of "I love youX"
//X can be any garbage chatacter, and each time I run the code, X is one different
//character.
}
根据接受的答案,解决方案是:像这样更新我的 encrypt():
char* encrypt(char * plainText, byte key[], int sizeKey, byte iv[], int sizeIV, long &len){
string cipher = encryptString(plainText, key, sizeKey, iv, sizeIV);
FileUtil::writeFile("ss1.txt", cipher, cipher.length());
len = cipher.size() ;
char * writable = new char[len];
std::copy(cipher.begin(), cipher.end(), writable);
writable[len] = '[=15=]'; // don't forget the terminating 0
FileUtil::writeFile("w1.txt",writable, len);
return writable;
}
只分配writeable的长度= cipher的长度。将终止符设置为 writeble[len]
当您遇到缓冲区溢出和未终止的字符串等问题时,往往会发生这种情况。如果我们查看您的 encrypt
函数,我们会看到缓冲区溢出:
len = cipher.size() + 1;
char * writable = new char[len];
std::copy(cipher.begin(), cipher.end(), writable);
writable[len] = '[=10=]';
看到这里你分配了 len
个字节,其中 len
比 cipher
大一个。但是当您终止字符串时,您正在使用 len
来索引超出范围的内容。
您应该使用 len-1
或 cipher.size()
作为终止符索引。
char* encrypt(char * plainText, ... ); char* decrypt(char * cipher, ... );
您也可以避免 encryptString
和 decryptString
以及额外的副本。我给你看encrypt
,decrypt
也差不多。
char* encrypt(char * plainText, byte key[], int sizeKey, byte iv[], int sizeIV, long &len)
{
const unsigned long plainTextLen = len; len = 0;
const unsigned long extraLen = plainTextLen+16;
ArraySource source(plainText, plainTextLen, false);
unique_ptr<char[]> writable(new char[extraLen]);
ArraySink sink(writable, extraLen);
CTR_Mode< AES >::Encryption enc;
enc.SetKeyWithIV(key, sizeKey, iv, sizeIV);
source.Detach(new StreamTransformationFilter(enc, new Redirector(sink)));
source.PumpAll();
len = sink.TotalPutLength();
return writable.release();
}
我没有编译 运行 它,所以你必须清除上面代码中的编译器问题。它们应该都是次要的,例如转换和转换。
您通常不需要担心NULL
;只需使用 ptr
和 len
。您可以使用 string recovered = string(ptr, len);
从解密的密文创建 std::string
。 std::string
会在需要时生成 NULL
,但通常不需要。
Detach
不是 错字。您可以使用它 Attach
一个新的过滤器和 delete
一个以前的过滤器。您使用它来避免内存泄漏。