解密密码导致丢失字母
decrypting cipher results in missing letters
我有一个 python 使用 AES cbc 模式加密字符串的端点,returns 将它发送到用 c++ 编写的客户端软件(十六进制 space 分隔格式)
c++ repo
的link
std::vector<unsigned char> cipher_as_chars(std::string cipher)
{
std::istringstream strm{cipher};
strm >> std::hex;
std::vector<unsigned char> res;
res.reserve(cipher.size() / 3 + 1);
int h;
while (strm >> h) {
res.push_back(static_cast<unsigned char>(h));
}
return res;
}
namespace client{
std::string decrypt_cipher(std::string cipher, std::string usr_key)
{
std::string original_text = "";
const std::vector<unsigned char> key = key_from_string(usr_key); // 16-char = 128-bit
const unsigned char iv[16] = {
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x56, 0x34, 0x35, 0x36
};
std::vector<unsigned char> encrypted = cipher_as_chars(cipher);
unsigned long padded_size = 0;
std::vector<unsigned char> decrypted(encrypted.size());
plusaes::decrypt_cbc(&encrypted[0], encrypted.size(), &key[0], key.size(), &iv, &decrypted[0], decrypted.size(), &padded_size);
for (int i =0 ; i < decrypted.size(); i++)
{
//cout << decrypted[i] << endl;
std::stringstream stream;
stream << decrypted[i];
original_text = original_text + stream.str();
}
return original_text;
}
}
def encrypt_string(key,text):
result = ''
while len(text)% 16 != 0 :
text = text+" "
string_as_bytes = text.encode('utf8')
obj = AES.new(key.encode("utf8"), AES.MODE_CBC, 'This is an IV456'.encode("utf8"))
cipher_text = obj.encrypt(string_as_bytes)
for item in bytearray(cipher_text):
result += f"{hex(item).replace('0x','')} "
return result
@api.route('/test')
def test_route():
return encrypt_string("Encryptionkey123", "Happy new year people")
如果我使用c++代码加密一个字符串并使用c++编写的解密函数解密它,服务器有一个与客户端软件相同的加密和解密功能,它工作正常并且我得到相同的字符串,但是当客户端读取 /test
的响应并加密它,C++ 客户端尝试解密它输出最后缺少 n 个字母的字符串
原文在python服务器Happy new year people
c++客户端中的输出Happy new year p
错误在于 C++ 库使用 PKCS#7 填充,而 python 代码使用 spaces。可怕的 C++ 库不检查填充是否在块大小之内,也不检查填充,因此它会根据找到的最终字符的值直接取消填充 - 对于 space,这是 0x20
。所以这将取消填充 32 个字节而不是任何正常的填充大小(我想知道当填充大于剩余的明文大小时它会做什么 - 可能是缓冲区下溢?)。
您必须在 python 中实施 PKCS#7 填充。这是将值 0x01
的 1 个字节添加到值 0x10
的 16 个字节。您可以看到一个实现 here。请注意,那里显示的 unpadding 与 C++ 库中一样容易受到攻击:相反,您 1 检查最后一个填充字节是否在 1.. 范围内,然后检查所有其他填充字节是否正确,如果没有则创建异常或错误代码。
另请注意 CBC 填充预言机、静态 IV 的使用等。使用 TLS 实现传输安全。
看看 this example pycrypto
是否支持 pkcs#7 填充你对填充的看法很差,只需使用该模块中的内置填充功能
示例取自 link
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.Padding import unpad
key=b'1234567890123456'
cipher=AES.new(key,AES.MODE_CBC)
text=b'secret text'
padtext=pad(text,16,style='pkcs7')
cipherText=cipher.encrypt(padtext)
print(padtext)
print(cipherText)
plaintext=cipher.decrypt(cipherText) #can't use same object to decrypt
print(plaintext)
您可能想要添加一些代码以将结果转换为十六进制分隔的字符串
我有一个 python 使用 AES cbc 模式加密字符串的端点,returns 将它发送到用 c++ 编写的客户端软件(十六进制 space 分隔格式) c++ repo
的link
std::vector<unsigned char> cipher_as_chars(std::string cipher)
{
std::istringstream strm{cipher};
strm >> std::hex;
std::vector<unsigned char> res;
res.reserve(cipher.size() / 3 + 1);
int h;
while (strm >> h) {
res.push_back(static_cast<unsigned char>(h));
}
return res;
}
namespace client{
std::string decrypt_cipher(std::string cipher, std::string usr_key)
{
std::string original_text = "";
const std::vector<unsigned char> key = key_from_string(usr_key); // 16-char = 128-bit
const unsigned char iv[16] = {
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x56, 0x34, 0x35, 0x36
};
std::vector<unsigned char> encrypted = cipher_as_chars(cipher);
unsigned long padded_size = 0;
std::vector<unsigned char> decrypted(encrypted.size());
plusaes::decrypt_cbc(&encrypted[0], encrypted.size(), &key[0], key.size(), &iv, &decrypted[0], decrypted.size(), &padded_size);
for (int i =0 ; i < decrypted.size(); i++)
{
//cout << decrypted[i] << endl;
std::stringstream stream;
stream << decrypted[i];
original_text = original_text + stream.str();
}
return original_text;
}
}
def encrypt_string(key,text):
result = ''
while len(text)% 16 != 0 :
text = text+" "
string_as_bytes = text.encode('utf8')
obj = AES.new(key.encode("utf8"), AES.MODE_CBC, 'This is an IV456'.encode("utf8"))
cipher_text = obj.encrypt(string_as_bytes)
for item in bytearray(cipher_text):
result += f"{hex(item).replace('0x','')} "
return result
@api.route('/test')
def test_route():
return encrypt_string("Encryptionkey123", "Happy new year people")
如果我使用c++代码加密一个字符串并使用c++编写的解密函数解密它,服务器有一个与客户端软件相同的加密和解密功能,它工作正常并且我得到相同的字符串,但是当客户端读取 /test
的响应并加密它,C++ 客户端尝试解密它输出最后缺少 n 个字母的字符串
原文在python服务器Happy new year people
c++客户端中的输出Happy new year p
错误在于 C++ 库使用 PKCS#7 填充,而 python 代码使用 spaces。可怕的 C++ 库不检查填充是否在块大小之内,也不检查填充,因此它会根据找到的最终字符的值直接取消填充 - 对于 space,这是 0x20
。所以这将取消填充 32 个字节而不是任何正常的填充大小(我想知道当填充大于剩余的明文大小时它会做什么 - 可能是缓冲区下溢?)。
您必须在 python 中实施 PKCS#7 填充。这是将值 0x01
的 1 个字节添加到值 0x10
的 16 个字节。您可以看到一个实现 here。请注意,那里显示的 unpadding 与 C++ 库中一样容易受到攻击:相反,您 1 检查最后一个填充字节是否在 1..
另请注意 CBC 填充预言机、静态 IV 的使用等。使用 TLS 实现传输安全。
看看 this example pycrypto
是否支持 pkcs#7 填充你对填充的看法很差,只需使用该模块中的内置填充功能
示例取自 link
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.Padding import unpad
key=b'1234567890123456'
cipher=AES.new(key,AES.MODE_CBC)
text=b'secret text'
padtext=pad(text,16,style='pkcs7')
cipherText=cipher.encrypt(padtext)
print(padtext)
print(cipherText)
plaintext=cipher.decrypt(cipherText) #can't use same object to decrypt
print(plaintext)
您可能想要添加一些代码以将结果转换为十六进制分隔的字符串