Crypto++ CTR模式手动工具
Crypto++ CTR mode manual implement
我正在尝试使用 Crypto++ 在 ECB 模式之上(但仍然)手动设置 CTR。
思路是:
For single block: Just use ECB For multiple block, use CTR algorithm
(AFAIK):
//We have n block of plain data -> M
PlainData M[n];
key;
iv;
char *CTR;
cipher ="";
for(i = 0; i<n; i++ ){
if(i ==0){
CTR = iv;
}
ei = encryptECB(CTR + i)
cipherI = xor(ei, M[i])
cipher += cipherI;
}
//我的xor()对两个char数组进行异或运算
void xor(char *s1, char* s2, char *& result, int len){
try{
int i;
for (i = 0; i < len; i++){
int u = s1[i] ^ s2[i];
result[i] = u;
}
result[i] = '[=11=]';
}
catch (...){
cout << "Errp";
}
}
测试 1:100% Crypto++ 点击率
string auto_ctr(char * s1, long size){
CTR_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
string cipherZ;
StringSource s(s1, true,
new StreamTransformationFilter(e,
new StringSink(cipherZ), BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING
)
);
return cipherZ;
}
测试 2:基于 ECB 的手动点击率
string encrypt(char* s1, int size){
ECB_Mode< AES >::Encryption e;
e.SetKey(key, size);
string cipher;
string s(s1, size);
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher), BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING
) // StreamTransformationFilter
); // StringSource
return cipher;
}
static string manual_ctr(char *plain, long &size){
int nBlocks = size / BLOCK_SIZE;
char* encryptBefore = new char[BLOCK_SIZE];
char *ci = new char[BLOCK_SIZE] ;
string cipher;
for (int i = 0; i < nBlocks; i++){
//If the first loop, CTR = IV
if (i == 0){
memcpy(encryptBefore, iv, BLOCK_SIZE);
}
encryptBefore[BLOCK_SIZE] = '[=13=]';
memcpy(encryptBefore, encryptBefore + i, BLOCK_SIZE);
char *buffer = new char[BLOCK_SIZE];
memcpy(buffer, &plain[i], BLOCK_SIZE);
buffer[BLOCK_SIZE] = '[=13=]';
//Encrypt the CTR
string e1 = encrypt(encryptBefore, BLOCK_SIZE);
//Xor it with m[i] => c[i]
xor((char*)e1.c_str(), buffer, ci, BLOCK_SIZE);
//Append to the summary cipher
/*for (int j = 0; j < BLOCK_SIZE/2; j++){
SetChar(cipher, ci[j], i*BLOCK_SIZE + j);
}*/
cipher += ci;
//Set the cipher back to iv
//memcpy(encryptBefore, ci, BLOCK_SIZE);
}
return cipher;
}
这是测试的主要内容:
void main(){
long size = 0;
char * plain = FileUtil::readAllByte("some1.txt", size);
string auto_result = auto_ctr(plain, size);
string manual_result = manual_ctr(plain, size);
getchar();
}
auto_result是:
"Yž+eÞsÂÙ\bü´\x1a¨Ü_ÙR•L¸Ð€¦å«ÎÍÊ[w®Ÿg\fT½\ý7!p\r^ÍdžúP\bîT\x3\x1cZï.s%\x1ei{ÚMˆØ…Pä¾õ\x46\r5\tâýï‚ú\x16ç’Qiæ²\x15š€á^ªê]W
ÊNqdŒ¥ ˆ†¾j%8.Ìù\x6Þ›ÔÏ’[c\x19"
manual_result是:
"Yž+eÞsÂÙ\bü´\x1a¨Ü_Ù·\x18ýuù\n\nl\x11Á\x19À†Žaðƒºñ®GäþŽá•\x11ÇYœf+^Q\x1a\x13B³‘QQµºëÑÌåM\"\x12\x115â\x10¿Ô„›s°‰=\x18*\x1c:²IF'n@ŠŠ¾mGÂzõžÀ\x1eÏ\SëYU¼í‘"
>
我的工具有什么问题?
由于您的第一个块似乎工作正常,我只搜索了计数器本身管理方面的问题,这似乎是我的错误:
memcpy(encryptBefore, encryptBefore + i, BLOCK_SIZE);
这里你试图增加你的 IV i
次,我想,但这不是发生的事情,你所做的是试图将 encryptBefore
指针的内容复制到 encryptBefore+i
跨越 BLOCK_SIZE
字节的指针。这根本不会增加 IV,但它适用于第一个块,因为 i=0
.
你想要做的实际上是使用 CryptoPP::Integer
创建一个大整数用作 IV 并递增该整数,然后使用 CryptoPP 中的 Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const
函数将其转换为字节数组Integer class 当你需要使用字节而不是整数时。
Ps:在执行i/o运算时,建议使用十六进制字符串,看看CryptoPP::HexEncoder
和HexDecoder
classes ,他们都是well documented on CryptoPP wiki。
我正在尝试使用 Crypto++ 在 ECB 模式之上(但仍然)手动设置 CTR。 思路是:
For single block: Just use ECB For multiple block, use CTR algorithm (AFAIK):
//We have n block of plain data -> M PlainData M[n]; key; iv; char *CTR; cipher =""; for(i = 0; i<n; i++ ){ if(i ==0){ CTR = iv; } ei = encryptECB(CTR + i) cipherI = xor(ei, M[i]) cipher += cipherI; }
//我的xor()对两个char数组进行异或运算
void xor(char *s1, char* s2, char *& result, int len){
try{
int i;
for (i = 0; i < len; i++){
int u = s1[i] ^ s2[i];
result[i] = u;
}
result[i] = '[=11=]';
}
catch (...){
cout << "Errp";
}
}
测试 1:100% Crypto++ 点击率
string auto_ctr(char * s1, long size){
CTR_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
string cipherZ;
StringSource s(s1, true,
new StreamTransformationFilter(e,
new StringSink(cipherZ), BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING
)
);
return cipherZ;
}
测试 2:基于 ECB 的手动点击率
string encrypt(char* s1, int size){
ECB_Mode< AES >::Encryption e;
e.SetKey(key, size);
string cipher;
string s(s1, size);
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher), BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING
) // StreamTransformationFilter
); // StringSource
return cipher;
}
static string manual_ctr(char *plain, long &size){
int nBlocks = size / BLOCK_SIZE;
char* encryptBefore = new char[BLOCK_SIZE];
char *ci = new char[BLOCK_SIZE] ;
string cipher;
for (int i = 0; i < nBlocks; i++){
//If the first loop, CTR = IV
if (i == 0){
memcpy(encryptBefore, iv, BLOCK_SIZE);
}
encryptBefore[BLOCK_SIZE] = '[=13=]';
memcpy(encryptBefore, encryptBefore + i, BLOCK_SIZE);
char *buffer = new char[BLOCK_SIZE];
memcpy(buffer, &plain[i], BLOCK_SIZE);
buffer[BLOCK_SIZE] = '[=13=]';
//Encrypt the CTR
string e1 = encrypt(encryptBefore, BLOCK_SIZE);
//Xor it with m[i] => c[i]
xor((char*)e1.c_str(), buffer, ci, BLOCK_SIZE);
//Append to the summary cipher
/*for (int j = 0; j < BLOCK_SIZE/2; j++){
SetChar(cipher, ci[j], i*BLOCK_SIZE + j);
}*/
cipher += ci;
//Set the cipher back to iv
//memcpy(encryptBefore, ci, BLOCK_SIZE);
}
return cipher;
}
这是测试的主要内容:
void main(){
long size = 0;
char * plain = FileUtil::readAllByte("some1.txt", size);
string auto_result = auto_ctr(plain, size);
string manual_result = manual_ctr(plain, size);
getchar();
}
auto_result是:
"Yž+eÞsÂÙ\bü´\x1a¨Ü_ÙR•L¸Ð€¦å«ÎÍÊ[w®Ÿg\fT½\ý7!p\r^ÍdžúP\bîT\x3\x1cZï.s%\x1ei{ÚMˆØ…Pä¾õ\x46\r5\tâýï‚ú\x16ç’Qiæ²\x15š€á^ªê]W ÊNqdŒ¥ ˆ†¾j%8.Ìù\x6Þ›ÔÏ’[c\x19"
manual_result是:
"Yž+eÞsÂÙ\bü´\x1a¨Ü_Ù·\x18ýuù\n\nl\x11Á\x19À†Žaðƒºñ®GäþŽá•\x11ÇYœf+^Q\x1a\x13B³‘QQµºëÑÌåM\"\x12\x115â\x10¿Ô„›s°‰=\x18*\x1c:²IF'n@ŠŠ¾mGÂzõžÀ\x1eÏ\SëYU¼í‘" >
我的工具有什么问题?
由于您的第一个块似乎工作正常,我只搜索了计数器本身管理方面的问题,这似乎是我的错误:
memcpy(encryptBefore, encryptBefore + i, BLOCK_SIZE);
这里你试图增加你的 IV i
次,我想,但这不是发生的事情,你所做的是试图将 encryptBefore
指针的内容复制到 encryptBefore+i
跨越 BLOCK_SIZE
字节的指针。这根本不会增加 IV,但它适用于第一个块,因为 i=0
.
你想要做的实际上是使用 CryptoPP::Integer
创建一个大整数用作 IV 并递增该整数,然后使用 CryptoPP 中的 Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const
函数将其转换为字节数组Integer class 当你需要使用字节而不是整数时。
Ps:在执行i/o运算时,建议使用十六进制字符串,看看CryptoPP::HexEncoder
和HexDecoder
classes ,他们都是well documented on CryptoPP wiki。