Gargage redundancy character at the end of original text when decrypt using Crypto++

╄→гoц情女王★ 提交于 2019-12-25 04:48:05

问题


I am using Crypto++, CTR mode, to encrypt and decrypt text in C++. Everything seem to worked 99%. Ecrypting success, decrypting is give back the original text too, but I given some extra random garbage redundancy text like 'ð', at the end of the decrypted text. This extra part is random generated each time I run the code. Is there something wrong in my code?


Encrypt a string to a string

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;
    }
}

Decrypt a ciphered string to a string

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;

}

Wrap encryptString function above.

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;
 }

Wrap decryptString function above.

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;
}

My test script is simple. Read the some.txt content ("I love you"), write it to s1.txt to check if the reading is right. Encrypt, decrypt, then write the recovered text to another file (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.
}

According to the accept answer, Solution is: updated my encrypt() like this:

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;
}

Just allocate writeable's length = cipher's length. Set the terminator at writeble[len]


回答1:


That tends to happen when you have things like buffer overruns and unterminated strings. If we look at your encrypt function we see a buffer overrun:

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

See here you allocated len bytes, where len is one larger than cipher. But when you terminate the string, you are using len to index which is out-of-bounds.

You should either use len-1 or cipher.size() for the terminator index.




回答2:


char* encrypt(char * plainText, ... );
char* decrypt(char * cipher, ... );

You can also avoid encryptString and decryptString and the extra copy. I'll show you the encrypt, the decrypt is similar.

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();
}

I did not compile and run it, so you will have to clear the compiler issues in the code above. They should all be minor, like conversions and casts.

You usually don't need to worry about the NULL; just use the ptr and len. You can create a std::string from the decrypted ciphertext with string recovered = string(ptr, len);. std::string will produce a NULL when needed, but its usually not needed.

Detach is not a typo. You use it to Attach a new filter and delete a previous filter. You use it to avoid memory leaks.



来源:https://stackoverflow.com/questions/40601847/gargage-redundancy-character-at-the-end-of-original-text-when-decrypt-using-cryp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!