使用 Crypto++ 手动处理 CBC 加密
Manual CBC encryption handing with Crypto++
我正在尝试在 CBC 模式下进行手动加密,但仍然使用 Crypto++,只是想知道我是否可以手动进行加密。
CBC算法是(AFAIK):
Presume we have n block K[1]....k[n]
0. cipher = empty;
1. xor(IV, K1) -> t1
2. encrypt(t1) -> r1
3. cipher += r1
4. xor (r1, K2) -> t2
5. encrypt(t2) -> r2
6. cipher += r2
7. xor(r2, K3)->t3
8. ...
所以我尝试用Crypto++来实现它。我有一个只有字母数字字符的文本文件。测试 1 逐块(16 字节)读取文件并使用 CBC 模式手动加密它们,然后总结密码。测试 2 使用 Crypto++ 内置的 CBC 模式。
测试 1
char* key;
char* iv;
//Iterate in K[n] array of n blocks
BSIZE = 16;
std::string vectorToString(vector<char> v){
string s ="";
for (int i = 0; i < v.size(); i++){
s[i] = v[i];
}
return s;
}
vector<char> xor( vector<char> s1, vector<char> s2, int len){
vector<char> r;
for (int i = 0; i < len; i++){
int u = s1[i] ^ s2[i];
r.push_back(u);
}
return r;
}
vector<char> byteToVector(byte *b, int len){
vector<char> v;
for (int i = 0; i < len; i++){
v.push_back( b[i]);
}
return v;
}
string cbc_manual(byte [n]){
int i = 0;
//Open a file and read from it, buffer size = 16
// , equal to DEFAULT_BLOCK_SIZE
std::ifstream fin(fileName, std::ios::binary | std::ios::in);
const int BSIZE = 16;
vector<char> encryptBefore;
//This function will return cpc
string cpc ="";
while (!fin.eof()){
char buffer[BSIZE];
//Read a chunk of file
fin.read(buffer, BSIZE);
int sb = sizeof(buffer);
if (i == 0){
encryptBefore = byteToVector( iv, BSIZE);
}
//If i == 0, xor IV with current buffer
//else, xor encryptBefore with current buffer
vector<char> t1 = xor(encryptBefore, byteToVector((byte*) buffer, BSIZE), BSIZE);
//After xored, encrypt the xor result, it will be current step cipher
string r1= encrypt(t1, BSIZE).c_str();
cpc += r1;
const char* end = r1.c_str() ;
encryptBefore = stringToVector( r1);
i++;
}
return cpc;
}
这是我的 encrypt() 函数,因为我们只有一个块所以我使用 ECB (?) 模式
string encrypt(string s, int size){
ECB_Mode< AES >::Encryption e;
e.SetKey(key, size);
string cipher;
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
) // StreamTransformationFilter
); // StringSource
return cipher;
}
这是 100% Crypto++ 制作的解决方案:
测试 2
encryptCBC(char * plain){
CBC_Mode < AES >::Encryption encryption(key, sizeof(key), iv);
StreamTransformationFilter encryptor(encryption, NULL);
for (size_t j = 0; j < plain.size(); j++)
encryptor.Put((byte)plain[j]);
encryptor.MessageEnd();
size_t ready = encryptor.MaxRetrievable();
string cipher(ready, 0x00);
encryptor.Get((byte*)&cipher[0], cipher.size());
}
测试 1 和测试 2 的结果不同。事实上,测试 1 的密文包含测试 2 的结果。示例:
Test 1's result aaa[....]bbb[....]ccc[...]...
Test 2 (Crypto++ built-in CBC)'s result: aaabbbccc...
我知道 xor() 函数可能会导致与 "sameChar ^ sameChar = 0" 相关的问题,但我的代码中是否存在与算法相关的问题?
这是我在jww第一个解法后的Test 2.1
static string auto_cbc2(string plain, long size){
CBC_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
string cipherText;
CryptoPP::StringSource ss(plain, true,
new CryptoPP::StreamTransformationFilter(e,
new CryptoPP::StringSink(cipherText)
, BlockPaddingSchemeDef::NO_PADDING
) // StreamTransformationFilter
); // StringSource
return cipherText;
}
它抛出一个错误:
Unhandled exception at 0x7407A6F2 in AES-CRPP.exe: Microsoft C++
exception: CryptoPP::InvalidDataFormat at memory location 0x00EFEA74
我只在使用 BlockPaddingSchemeDef::NO_PADDING 时遇到此错误,尝试删除 BlockPaddingSchemeDef 或使用 BlockPaddingSchemeDef::DEFAULT_PADDING 时,我没有遇到错误。 :?
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)));
这默认使用 PKCS 填充。由于填充,它需要 16 字节的输入并产生 32 字节的输出。你应该做以下两件事之一。
首先,您可以使用BlockPaddingScheme::NO_PADDING
。类似于:
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
BlockPaddingScheme::NO_PADDING));
其次,您可以手动处理块,一次处理 16 个字节。类似于:
AES::Encryption encryptor(key, keySize);
byte ibuff[<some size>] = ...;
byte obuff[<some size>];
ASSERT(<some size> % AES::BLOCKSIZE == 0);
unsigned int BLOCKS = <some size>/AES::BLOCKSIZE;
for (unsigned int i=0; i<BLOCKS; i==)
{
encryptor.ProcessBlock(&ibuff[i*16], &obuff[i*16]);
// Do the CBC XOR thing...
}
您也许可以调用 ProcessAndXorBlock
from the BlockCipher
base class 并一次性完成。
我正在尝试在 CBC 模式下进行手动加密,但仍然使用 Crypto++,只是想知道我是否可以手动进行加密。 CBC算法是(AFAIK):
Presume we have n block K[1]....k[n]
0. cipher = empty;
1. xor(IV, K1) -> t1
2. encrypt(t1) -> r1
3. cipher += r1
4. xor (r1, K2) -> t2
5. encrypt(t2) -> r2
6. cipher += r2
7. xor(r2, K3)->t3
8. ...
所以我尝试用Crypto++来实现它。我有一个只有字母数字字符的文本文件。测试 1 逐块(16 字节)读取文件并使用 CBC 模式手动加密它们,然后总结密码。测试 2 使用 Crypto++ 内置的 CBC 模式。
测试 1
char* key;
char* iv;
//Iterate in K[n] array of n blocks
BSIZE = 16;
std::string vectorToString(vector<char> v){
string s ="";
for (int i = 0; i < v.size(); i++){
s[i] = v[i];
}
return s;
}
vector<char> xor( vector<char> s1, vector<char> s2, int len){
vector<char> r;
for (int i = 0; i < len; i++){
int u = s1[i] ^ s2[i];
r.push_back(u);
}
return r;
}
vector<char> byteToVector(byte *b, int len){
vector<char> v;
for (int i = 0; i < len; i++){
v.push_back( b[i]);
}
return v;
}
string cbc_manual(byte [n]){
int i = 0;
//Open a file and read from it, buffer size = 16
// , equal to DEFAULT_BLOCK_SIZE
std::ifstream fin(fileName, std::ios::binary | std::ios::in);
const int BSIZE = 16;
vector<char> encryptBefore;
//This function will return cpc
string cpc ="";
while (!fin.eof()){
char buffer[BSIZE];
//Read a chunk of file
fin.read(buffer, BSIZE);
int sb = sizeof(buffer);
if (i == 0){
encryptBefore = byteToVector( iv, BSIZE);
}
//If i == 0, xor IV with current buffer
//else, xor encryptBefore with current buffer
vector<char> t1 = xor(encryptBefore, byteToVector((byte*) buffer, BSIZE), BSIZE);
//After xored, encrypt the xor result, it will be current step cipher
string r1= encrypt(t1, BSIZE).c_str();
cpc += r1;
const char* end = r1.c_str() ;
encryptBefore = stringToVector( r1);
i++;
}
return cpc;
}
这是我的 encrypt() 函数,因为我们只有一个块所以我使用 ECB (?) 模式
string encrypt(string s, int size){
ECB_Mode< AES >::Encryption e;
e.SetKey(key, size);
string cipher;
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
) // StreamTransformationFilter
); // StringSource
return cipher;
}
这是 100% Crypto++ 制作的解决方案:
测试 2
encryptCBC(char * plain){
CBC_Mode < AES >::Encryption encryption(key, sizeof(key), iv);
StreamTransformationFilter encryptor(encryption, NULL);
for (size_t j = 0; j < plain.size(); j++)
encryptor.Put((byte)plain[j]);
encryptor.MessageEnd();
size_t ready = encryptor.MaxRetrievable();
string cipher(ready, 0x00);
encryptor.Get((byte*)&cipher[0], cipher.size());
}
测试 1 和测试 2 的结果不同。事实上,测试 1 的密文包含测试 2 的结果。示例:
Test 1's result aaa[....]bbb[....]ccc[...]...
Test 2 (Crypto++ built-in CBC)'s result: aaabbbccc...
我知道 xor() 函数可能会导致与 "sameChar ^ sameChar = 0" 相关的问题,但我的代码中是否存在与算法相关的问题?
这是我在jww第一个解法后的Test 2.1
static string auto_cbc2(string plain, long size){
CBC_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
string cipherText;
CryptoPP::StringSource ss(plain, true,
new CryptoPP::StreamTransformationFilter(e,
new CryptoPP::StringSink(cipherText)
, BlockPaddingSchemeDef::NO_PADDING
) // StreamTransformationFilter
); // StringSource
return cipherText;
}
它抛出一个错误:
Unhandled exception at 0x7407A6F2 in AES-CRPP.exe: Microsoft C++ exception: CryptoPP::InvalidDataFormat at memory location 0x00EFEA74
我只在使用 BlockPaddingSchemeDef::NO_PADDING 时遇到此错误,尝试删除 BlockPaddingSchemeDef 或使用 BlockPaddingSchemeDef::DEFAULT_PADDING 时,我没有遇到错误。 :?
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)));
这默认使用 PKCS 填充。由于填充,它需要 16 字节的输入并产生 32 字节的输出。你应该做以下两件事之一。
首先,您可以使用BlockPaddingScheme::NO_PADDING
。类似于:
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
BlockPaddingScheme::NO_PADDING));
其次,您可以手动处理块,一次处理 16 个字节。类似于:
AES::Encryption encryptor(key, keySize);
byte ibuff[<some size>] = ...;
byte obuff[<some size>];
ASSERT(<some size> % AES::BLOCKSIZE == 0);
unsigned int BLOCKS = <some size>/AES::BLOCKSIZE;
for (unsigned int i=0; i<BLOCKS; i==)
{
encryptor.ProcessBlock(&ibuff[i*16], &obuff[i*16]);
// Do the CBC XOR thing...
}
您也许可以调用 ProcessAndXorBlock
from the BlockCipher
base class 并一次性完成。