【问题标题】:Gargage redundancy character at the end of original text when decrypt using Crypto++使用 Crypto++ 解密时原始文本末尾的垃圾冗余字符
【发布时间】:2016-11-15 20:43:48
【问题描述】:

我正在使用 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] = '\0'; // 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()] = '\0'; // don't forget the terminating 0
    return writable;
}

我的测试脚本很简单。读取 some.txt 内容(“我爱你”),将其写入 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] = '\0'; // don't forget the terminating 0
    FileUtil::writeFile("w1.txt",writable, len);

    return writable;
}

只需分配可写长度 = 密码长度。将终止符设置为writeble[len]

【问题讨论】:

    标签: c++ encryption crypto++


    【解决方案1】:

    当您遇到缓冲区溢出和未终止的字符串等情况时,往往会发生这种情况。如果我们查看您的 encrypt 函数,我们会看到缓冲区溢出:

    len = cipher.size() + 1;
    char * writable = new  char[len];
    std::copy(cipher.begin(), cipher.end(), writable);
    writable[len] = '\0';
    

    看到这里你分配了len 字节,其中lencipher 大一。但是,当您终止字符串时,您正在使用len 来索引越界。

    您应该使用len-1cipher.size() 作为终止符索引。

    【讨论】:

    • 感谢您的回答。我做了两处改动:首先,allocate writeable = new char[len];第二,可写[len]='\0'。它现在工作了:)
    【解决方案2】:
    char* encrypt(char * plainText, ... );
    char* decrypt(char * cipher, ... );
    

    您也可以避免使用encryptStringdecryptString 以及额外的副本。我给你看encryptdecrypt 类似。

    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;只需使用ptrlen。您可以使用string recovered = string(ptr, len); 从解密的密文中创建std::stringstd::string 会在需要时生成NULL,但通常不需要。

    Detach 不是错字。你用它来Attach 一个新的过滤器和delete 一个以前的过滤器。您可以使用它来避免内存泄漏。

    【讨论】:

    • 我正在使用 Visual C++ 测试您的 encrypt() 函数,ArraySink sink(writable, extraLen) 出现语法错误;因为可写是char[],所以sink()时需要byte*类型
    • @Andiana - “我没有编译和运行它,所以你必须清除上面代码中的编译器问题。它们应该都是次要的,比如转换和强制转换”我>。将char* 转换为byte*;并将const char* 转换为const byte*
    • 我对 unique_ptr 有点困惑,它似乎是最好的解决方案,而不是 char* 或字符串,但我不知道在这种情况下如何使用它。我是否使用 writeble.get() 来获取其数据?
    • @Andiana - 我很抱歉我一直试图提供的帮助没有帮助。在继续使用 Crypto++ 库之前,也许您应该了解更多关于 C++ 的知识。
    猜你喜欢
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 2015-06-06
    相关资源
    最近更新 更多