2016-11-15 13 views
0

C++でテキストを暗号化および復号化するためにCrypto ++、CTRモードを使用しています。すべてが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. 
} 

答えを受け入れるによると、ソリューションがある

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]に設定してください。

答えて

2

バッファオーバーランや終端されていない文字列がある場合に発生する傾向があります。私たちはあなたのencrypt機能を見れば、我々は、バッファオーバーランを参照してください。

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

はここを参照してくださいあなたはlencipherより大きいものですlenバイトを割り当てられました。しかし、文字列を終了するときには、範囲外のものを指すためにlenを使用しています。

ターミネータのインデックスには、len-1またはcipher.size()のいずれかを使用する必要があります。

+0

あなたの答えをありがとう。私は2つの変更を加えました。まず、writeable = new char [len]を割り当てます。 2番目は書き込み可能[len] = '\ 0'です。それは今働いています:) – Andiana

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

またencryptStringdecryptStringや余分なコピーを避けることができます。私はあなたにencryptを、decryptは似ています。

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::stringを作成できます。 std::stringは、必要に応じてNULLを生成しますが、通常は必要ありません。

Detachは、ではなく、である。新しいフィルタAttachと前のフィルタdeleteに使用します。メモリリークを避けるために使用します。

+0

私はあなたのencrypt()関数をVisual C++を使ってテストしています.ArraySink sink(writable、extraLen)で構文エラーが発生しました。書き込み可能なのはchar []なので、sink()が必要なbyte *型の場合 – Andiana

+0

@Andiana - * "私はそれをコンパイルして実行しなかったので、上記のコードでコンパイラの問題をクリアする必要があります。コンバージョンやキャストのようなものです*。 'char *'を 'byte *'にキャストします。 'const char *'を 'const byte *'にキャストします。 – jww

+0

私は、unique_ptrとちょっと混乱しています。char *やstringの代わりに最善の解決策と思われますが、この場合はどのように使用するのか分かりません。 writeble.get()を使ってデータを取得しましたか? – Andiana

関連する問題