我有一个文本,其中包含电子邮件,用户名和密码,我加密它使用AES算法。
在我加密的时候,它似乎是正常的,但是当它开始解密时,只有一些部分(最初的48字节=3x16字节块)是可以的,但剩下的只是一些垃圾。
我尝试使用无符号字符代替字符串,但它也有同样的问题。
我不知道这个问题是在我的算法中还是在字符集中,但在我看来,这个算法似乎还行。
如果字符串包含空终止字符,它会导致string.size问题吗?我不知道AES中的密码是否可以包含空终止字符。
以下是代码:
int aes_set_key( aes_context *ctx, uint8 *key, int nbits ); //Prototype
void aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); //Prototype
void aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); //Prototype
char Buffer[255];
memset(Buffer, 0, sizeof(Buffer));
sprintf_s(Buffer, "%s\r\n%s\r\n%s", RegisterEdits[0], RegisterEdits[1], /*PasswordHash.c_str()*/RegisterEdits[2]); // Save email, username and password to buffer
MSGBOX(Buffer);
aes_context ctx;
unsigned char key[] = "0123456789ABCDEF"; // Encrypting/Decrypting key
unsigned char outputEnc[20];
unsigned char outputDec[20];
string CipherData; // Hold whole encrypted text
string Decrypted; // Hold whole decrypted text
memset(outputEnc, 0, sizeof(outputEnc));
memset(outputDec, 0, sizeof(outputDec));
aes_set_key(&ctx, key, 256);
int Step = 0;
char Temp[18];
do
{
memset(Temp, 0, sizeof(Temp));
_snprintf(Temp, 16, &Buffer[Step]);//Take first 16 bytes from Buffer at address 0 and copy them into Temp
Step += strlen(Temp); // Append the Temp size to stepper
memset(outputEnc, 0, sizeof(outputEnc));
aes_encrypt(&ctx, reinterpret_cast<unsigned char*>(Temp), outputEnc); // encrypt 16 bytes
CipherData += reinterpret_cast<char*>(outputEnc); //append the 16 encrypted bytes to string
}
while (Step < strlen(Buffer));
MSGBOX((LPSTR)CipherData.c_str()); //Let me see the cipher (seems to be ok)
//Trying little different algorithm than "do while" for decrypting
MSGBOX("Entering");
Step = 0;
for(int i = CipherData.size(); i >= 0; i-=16) //At the start we have cipher size
{
if(i < 16) // If we have less than 16 bytes in string left...*
{
Beep(1000, 100);
memset(Temp, 0, sizeof(Temp));
memcpy(Temp, &CipherData.c_str()[Step], CipherData.size()); // *...copy only the bytes that left.
MSGBOX(Temp);
aes_decrypt(&ctx, reinterpret_cast<unsigned char*>(Temp), outputDec);
Decrypted += reinterpret_cast<char*>(outputDec);
MSGBOX((LPSTR)Decrypted.c_str());
break;
}
else
{
//if we do have more than 16 bytes left in the string...
memset(Temp, 0, sizeof(Temp));
memcpy(Temp, &CipherData.c_str()[Step], 16); // ...Copy 16 bytes again (#)
MSGBOX(Temp);
aes_decrypt(&ctx, reinterpret_cast<unsigned char*>(Temp), outputDec); //decrypt 16 bytes
Decrypted += reinterpret_cast<char*>(outputDec); //append 16 decrypted bytes
CipherData = SubstractLastn(CipherData, 16); // IMPORTANT! Remove 16 bytes from the end of the string
Step += 16; // Append decrypted size to stepper
MSGBOX((LPSTR)Decrypted.c_str());
//FIX ME! - in 3rd iteration of this loop the CipherData seems to be corrupted in the part marked with (#)
}
}我愿意接受你们的任何帮助!
发布于 2015-05-16 10:11:00
您将加密的数据视为终止的字符串。AES加密可以(而且经常会)发出一个0x00八进制,这样做使得任何设计用来将空结束的字节序列过早地视为无用的算法(可以这么说)都是无用的。
你问题的核心是:
CipherData += reinterpret_cast<char*>(outputEnc);这有效地触发了operator +=(const char*)成员的std::basic_string<char>,它将附加您的输出编码,就像命中了终止符一样。不太好。
我不会试图修改您的代码,因为这并不是我一开始就这样做的。下面是一个简单的(我强调简单)的加密字符串的方法。
int main()
{
unsigned char key[] = "0123456789ABCDEF";
aes_context ctx = {};
aes_set_key(&ctx, key, 128);
// some simple message to encrypt
std::string str = "some simple message to encrypt";
// will hold out encrypted message
std::vector<uint8> encryptedBytes;
// encrypt the data.
for (auto it = str.begin(); it != str.end();)
{
uint8 plain[16] = {0}, enc[16] = {0};
size_t i = 0;
for (; it != str.end() && i < 16; ++i,++it)
plain[i] = *it;
aes_encrypt(&ctx, plain, enc);
encryptedBytes.insert(encryptedBytes.end(), enc, enc+16);
}
// now decrypt (not sure if this api requires resetting the
// key schedule, but it seems it can't hurt).
aes_set_key(&ctx, key, 128);
std::vector<uint8> decrypted;
for (auto it = encryptedBytes.begin(); it != encryptedBytes.end(); it = std::next(it,16))
{
uint8 tmp[16];
aes_decrypt(&ctx, &(*it), tmp);
decrypted.insert(decrypted.end(), tmp, tmp+16);
}
// rebuild string from data. stop at the terminator or end.
auto last = std::find(decrypted.begin(), decrypted.end(), 0);
std::string res(decrypted.begin(), last);
// show all three (original, cipher, decrypted)
std::cout << str << '\n';
print_hex(encryptedBytes.begin(), encryptedBytes.end());
std::cout << res << '\n';
}这利用了一个脑死亡的十六进制堆,它做出了大量的假设,所以你可以随意使用:
template<class Iter>
void print_hex(Iter beg, Iter end)
{
std::cout << std::hex << std::setfill('0');
unsigned int x = 0;
while (beg != end)
{
std::cout << std::setw(2) << static_cast<unsigned int>(*beg) << ' ';
if (++beg != end && ++x % 16 == 0)
std::cout << '\n';
}
std::cout << '\n';
}以上使用AES加密代码运行的输出如下:
some simple message to encrypt
82 56 5b a7 a5 b5 6a e9 e5 a4 a6 9d bb ee 14 db
6b 1e 54 b8 9d 7f 8c 16 18 c6 33 47 1c f1 48 25
some simple message to encrypt最后,一些值得注意的事情。首先,这迫切需要一个填充方案。一个常用的方法是PKCS7填充,这对于实现和确保解密文本的准确数量与原始加密是非常简单的。
其次,您在这段代码中看到的每个16值都应该用一个清单常量交换,这个常量就是正在使用的算法的块大小。魔术数字编程是不好的。不要像我那样,做你该做的。
祝你好运。
https://stackoverflow.com/questions/30271061
复制相似问题