2

ファイルの暗号化と復号化に libgcrypt を使用しています。fread を使用して適切な量のバイトを取り込むときは、 によって適切に暗号化されるように、16-n バイトでパディングする必要がありますgcry_cipher_encrypt。ただし、復号化すると、null バイト/パディングがまだ存在します。16 バイト ブロックを読み書きし、最後にパディングを削除する方法はありますか?

#include <stdio.h>
#include <gcrypt.h>

#define algo GCRY_CIPHER_AES128
#define mode GCRY_CIPHER_MODE_CBC
#define KEY_LENGTH 16
#define BLOCK_LENGTH 16

int main(){

    char IV[16];
    char *encBuffer = NULL;
    FILE *in, *out, *reopen;
    char *key = "A key goes here!";
    gcry_cipher_hd_t handle;
    int bufSize = 16, bytes;

    memset(IV, 0, 16);

    encBuffer = malloc(bufSize);

    in = fopen("in.txt", "r");
    out = fopen("out.txt", "w");

    gcry_cipher_open(&handle, algo, mode, 0);
    gcry_cipher_setkey(handle, key, KEY_LENGTH);
    gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);

    while(1){
        bytes = fread(encBuffer, 1, bufSize, in);
        if (!bytes) break;
        while(bytes < bufSize)
            encBuffer[bytes++] = 0x0;
        gcry_cipher_encrypt(handle, encBuffer, bufSize, NULL, 0);
        bytes = fwrite(encBuffer, 1, bufSize, out);
    }

    gcry_cipher_close(handle);
    fclose(in);
    fclose(out);

    gcry_cipher_open(&handle, algo, mode, 0);
    gcry_cipher_setkey(handle, key, KEY_LENGTH);
    gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);

    reopen = fopen("out.txt", "r");
    out = fopen("decoded.txt", "w");

    while(1){
        bytes = fread(encBuffer, 1, bufSize, reopen);
        if (!bytes) break;
        gcry_cipher_decrypt(handle, encBuffer, bufSize, NULL, 0);
        bytes = fwrite(encBuffer, 1, bufSize, out);
    }

    gcry_cipher_close(handle);

    free(encBuffer);

    return 0;
}
4

5 に答える 5

1

ブロック暗号には多くの操作モードがあります。入力データの長さをブロックサイズの倍数にする必要があるものもあるため、基本的にプレーンテキストのパディングが必要です。しない人もいます。詳細については、こちらを参照してください。

パディングが必要なモードを使用する必要がある場合は、暗号化されたデータとともにプレーンテキストの長さを保存する必要があります。最も簡単な方法は、最後に追加のブロックに書き込むことです (そのブロックも暗号化してください!)。常にブロックを追加する必要がない、より洗練されたスキームが他にもあります。これを参照してください。

于 2016-03-07T05:40:38.133 に答える
1

パディングの量を正しく保存し、後で確認することで修正できましたzaph。書き込むバイト数とタイプを決定するために、PKCS#7を使用しました。NULL バイトを書き込むこともできましたが、違いはなかったので、標準に固執することもできます。

#include <stdio.h>
#include <gcrypt.h>

#define algo GCRY_CIPHER_AES128
#define mode GCRY_CIPHER_MODE_CBC
#define KEY_LENGTH 16
#define BLOCK_LENGTH 16

int main(){

    char IV[16], *encBuffer = NULL;
    char *key = "A key goes here!";
    int bufSize = 16, bytes, i=0, padding;

    FILE *in, *out, *reopen;
    gcry_cipher_hd_t handle;

    memset(IV, 0, 16);
    encBuffer = malloc(bufSize);

    // Open in/out for reading and writing
    in = fopen("in.txt", "r");
    out = fopen("out.txt", "w");

    // Set handle for encryption
    gcry_cipher_open(&handle, algo, mode, 0);
    gcry_cipher_setkey(handle, key, KEY_LENGTH);
    gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);

    // Read from in, write encrypted to out
    while(1){
        bytes = fread(encBuffer, 1, bufSize, in);
        if (!bytes) break;

        // If fread grabbed less than 16 bytes, that's our final line
        // Use the byte number for padding and pad N bytes of N
        if ( bytes < BLOCK_LENGTH ){ padding = 16-bytes; }

        while(bytes < bufSize)
            encBuffer[bytes++] = padding;
        gcry_cipher_encrypt(handle, encBuffer, bytes, NULL, 0);
        bytes = fwrite(encBuffer, 1, bufSize, out);
    }

    // Close handle and i/o files
    gcry_cipher_close(handle);
    fclose(in);
    fclose(out);

    // Set handle for decryption
    gcry_cipher_open(&handle, algo, mode, 0);
    gcry_cipher_setkey(handle, key, KEY_LENGTH);
    gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);

    // Reopen outfile, open decoded file
    reopen = fopen("out.txt", "r");
    out = fopen("decoded.txt", "w");

    //Loop until EOF
    while(1){
        i=0;
        bytes = fread(encBuffer, 1, bufSize, reopen);
        if (!bytes) break;
        gcry_cipher_decrypt(handle, encBuffer, bufSize, NULL, 0);
        // Read each block and check for padding
        while ( i++ < BLOCK_LENGTH ){
            // If padding is found write 16-padding bytes
            if ( encBuffer[i] == padding ){
                bytes = fwrite(encBuffer, 1, (16-padding), out);
                return 0;
            }
        }
        // If padding isn't found, write the whole buffer
        bytes = fwrite(encBuffer, 1, bufSize, out);
    }

    // Close the handle and free the buffer
    gcry_cipher_close(handle);
    free(encBuffer);

    return 0;
}
于 2016-03-07T15:38:17.270 に答える
0

cry_cipher はパディングについて言及していないようですが、暗号化されるデータが常にブロックサイズの倍数ではない場合、パディングが必要です。パディングは言うまでもなく、一種のボゾの動きです。おそらく、常に PKCS#7 パディングです。

パディングがある場合、通常のパディングはPKCS#7です(PKCS#5 は同じことが不可欠です)。PKCS#7 は、パディングのブロック サイズ バイトに少なくとも 1 つを常に追加し、パディング値は数値またはパディング バイトです。復号化すると、パディングが削除されます。

これは、暗号化される入力データがブロック サイズ (AES の場合は 16 バイト) の正確な倍数である場合、パディングのブロックが追加されることを意味します。暗号化された出力で 16 バイトの SO は 32 バイトになります。

于 2016-03-07T04:44:49.153 に答える
0

gcry_cipher_encrypt(handle, encBuffer, bytes, NULL, 0);これは私のコメントにありますが、代わり に電話する必要があると思います。freadファイルから読み取ったバイト数を返します。常にbufSizeバイトで暗号化する場合、ループ内でファイルの最後に到達すると、ファイルが 16 の完全な倍数でない限り、ファイルの一部ではない余分なバイトが暗号化関数に供給されます。バイト。暗号化ライブラリは、何がファイル データで何がそうでないかを認識せず、encBufferバッファ内にある末尾の余分な NULL を正しく暗号化および復号化しています。私の推測では、ユーザーは自分のデータのパディングについて心配する必要はなく、使用しているライブラリが内部でそれを処理する必要があります。

簡単なチェックは、encBuffer を 0x20 で初期化し、復号化されたファイルの末尾に余分なスペースがあるかどうかを確認することです。

于 2016-03-07T04:52:11.753 に答える