2017-03-17 61 views
1

私の問題は、私は以下のOpenSSLコマンドからの出力を一致させるために、以下のCコードからAES 256 CTRの出力を得ることができないということです。CTR-AES256暗号化が一致していないOpenSSLは-aes-256-CTR

Cコードは、これを生成する:

5f b7 18 d1 28 62 7f 50 35 ba e9 67 a7 17 ab 22 
f9 e4 09 ce 23 26 7b 93 82 02 d3 87 eb 01 26 ac 
96 2c 01 8c c8 af f3 de a4 18 7f 29 46 00 2e 00 

OpenSSLのコマンドラインは、この生成:nonceIVしかし、ときに、同じだったので、最初の16のバイトが同じ

5f b7 18 d1 28 62 7f 50 35 ba e9 67 a7 17 ab 22 
3c 01 11 bd 39 14 74 76 31 57 a6 53 f9 00 09 b4 
6f a9 49 bc 6d 00 77 24 2d ef b9 c4 

に注意をnonceIVは次の反復で更新され、次に平文とXORされ、次の16バイトは異なるなど...?

なぜそれが起こるのか理解できませんか?誰もが最初の16バイトのチャンクの後に16進コードが異なる理由を知っていますか?

免責事項:私はCの専門家ではありません。

ありがとうございます!

Fox.txt

The quick brown fox jumped over the lazy dog 

その後foxy.exe

openssl enc -aes-256-ctr -in fox.txt -out foxy.exe -K 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 -iv f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff -nosalt -nopad -p 

を作成するには、次のOpenSSLコマンドを実行します。ここfoxy.exeが含まれているものです:

5f b7 18 d1 28 62 7f 50 35 ba e9 67 a7 17 ab 22 
3c 01 11 bd 39 14 74 76 31 57 a6 53 f9 00 09 b4 
6f a9 49 bc 6d 00 77 24 2d ef b9 c4 

を彼コードがあります。

#include <Windows.h> 

    // What is AES CTR 
    // 
    // AES - CTR (counter) mode is another popular symmetric encryption algorithm. 
    // 
    // It is advantageous because of a few features : 
    // 1. The data size does not have to be multiple of 16 bytes. 
    // 2. The encryption or decryption for all blocks of the data can happen in parallel, allowing faster implementation. 
    // 3. Encryption and decryption use identical implementation. 
    // 
    // Very important note : choice of initial counter is critical to the security of CTR mode. 
    // The requirement is that the same counter and AES key combination can never to used to encrypt more than more one 16 - byte block. 

    // Notes 
    // ----- 
    // * CTR mode does not require padding to block boundaries. 
    // 
    // * The IV size of AES is 16 bytes. 
    // 
    // * CTR mode doesn't need separate encrypt and decrypt method. Encryption key can be set once. 
    // 
    // * AES is a block cipher : it takes as input a 16 byte plaintext block, 
    // a secret key (16, 24 or 32 bytes) and outputs another 16 byte ciphertext block. 
    // 
    // References 
    // ---------- 
    // https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29 
    // https://www.cryptopp.com/wiki/CTR_Mode#Counter_Increment 
    // https://modexp.wordpress.com/2016/03/10/windows-ctr-mode-with-crypto-api/ 
    // https://msdn.microsoft.com/en-us/library/windows/desktop/jj650836(v=vs.85).aspx 
    // http://www.cryptogrium.com/aes-ctr.html 
    // http://www.bierkandt.org/encryption/symmetric_encryption.php 


    #define IV_SIZE 16 
    #define AES_BLOCK_SIZE 16 

    typedef struct _key_hdr_t { 
     PUBLICKEYSTRUC hdr;   // Indicates the type of BLOB and the algorithm that the key uses. 
     DWORD   len;   // The size, in bytes, of the key material. 
     char   key[32];  // The key material. 
    } key_hdr; 


    // NIST specifies two types of counters. 
    // 
    // First is a counter which is made up of a nonce and counter. 
    // The nonce is random, and the remaining bytes are counter bytes (which are incremented). 
    // For example, a 16 byte block cipher might use the high 8 bytes as a nonce, and the low 8 bytes as a counter. 
    // 
    // Second is a counter block, where all bytes are counter bytes and can be incremented as carries are generated. 
    // For example, in a 16 byte block cipher, all 16 bytes are counter bytes. 
    // 
    // This uses the second method, which means the entire byte block is treated as counter bytes. 

    void IncrementCounterByOne(char *inout) 
    { 
     int i; 

     for (i = 16 - 1; i >= 0; i--) { 
      inout[i]++; 
      if (inout[i]) { 
       break; 
      } 
     } 
    } 


    void XOR(char *plaintext, char *ciphertext, int plaintext_len) 
    { 
     int i; 

     for (i = 0; i < plaintext_len; i++) 
     { 
      plaintext[i] ^= ciphertext[i]; 
     } 
    } 


    unsigned int GetAlgorithmIdentifier(unsigned int aeskeylenbits) 
    { 
     switch (aeskeylenbits) 
     { 
     case 128: 
      return CALG_AES_128; 
     case 192: 
      return CALG_AES_192; 
     case 256: 
      return CALG_AES_256; 
     default: 
      return 0; 
     } 
    } 


    unsigned int GetKeyLengthBytes(unsigned int aeskeylenbits) 
    { 
     return aeskeylenbits/8; 
    } 


    void SetKeyData(key_hdr *key, unsigned int aeskeylenbits, char *pKey) 
    { 
     key->hdr.bType = PLAINTEXTKEYBLOB; 
     key->hdr.bVersion = CUR_BLOB_VERSION; 
     key->hdr.reserved = 0; 
     key->hdr.aiKeyAlg = GetAlgorithmIdentifier(aeskeylenbits); 
     key->len = GetKeyLengthBytes(aeskeylenbits); 
     memmove(key->key, pKey, key->len); 
    } 

    // point = pointer to the start of the plaintext, extent is the size (44 bytes) 
    void __stdcall AESCTR(char *point, int extent, char *pKey, char *pIV, unsigned int aeskeylenbits, char *bufOut) 
    { 
     HCRYPTPROV hProv; 
     HCRYPTKEY hSession; 
     key_hdr key; 
     DWORD  IV_len; 
     div_t  aesblocks; 
     char  nonceIV[64]; 
     char  tIV[64]; 
     char  *bufIn; 

     bufIn = point; 

     memmove(nonceIV, pIV, IV_SIZE); 

     SetKeyData(&key, aeskeylenbits, pKey); 

     CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); 

     CryptImportKey(hProv, (PBYTE)&key, sizeof(key), 0, CRYPT_NO_SALT, &hSession); 

     aesblocks = div(extent, AES_BLOCK_SIZE); 

     while (aesblocks.quot != 0) 
     { 
      IV_len = IV_SIZE; 
      memmove(tIV, nonceIV, IV_SIZE); 
      CryptEncrypt(hSession, 0, FALSE, 0, (BYTE *)tIV, &IV_len, sizeof(tIV)); 
      XOR(bufIn, tIV, AES_BLOCK_SIZE); 
      IncrementCounterByOne(nonceIV); 
      bufIn += AES_BLOCK_SIZE; 
      aesblocks.quot--; 
     } 

     if (aesblocks.rem != 0) 
     { 
      memmove(tIV, nonceIV, IV_SIZE); 
      CryptEncrypt(hSession, 0, TRUE, 0, (BYTE *)tIV, &IV_len, sizeof(tIV)); 
      XOR(bufIn, tIV, aesblocks.rem); 
     } 

     memmove(bufOut, point, extent); 

     CryptDestroyKey(hSession); 
     CryptReleaseContext(hProv, 0); 
    } 

は私がM $ CryptEncrypt()の提案擬似コードでこの作業を取得することができたセクション https://msdn.microsoft.com/en-us/library/windows/desktop/aa379924(v=vs.85).aspx備考:ここで

// Set the IV for the original key. Do not use the original key for 
// encryption or decryption after doing this because the key's 
// feedback register will get modified and you cannot change it. 
CryptSetKeyParam(hOriginalKey, KP_IV, newIV) 

while(block = NextBlock()) 
{ 
    // Create a duplicate of the original key. This causes the 
    // original key's IV to be copied into the duplicate key's 
    // feedback register. 
    hDuplicateKey = CryptDuplicateKey(hOriginalKey) 

    // Encrypt the block with the duplicate key. 
    CryptEncrypt(hDuplicateKey, block) 

    // Destroy the duplicate key. Its feedback register has been 
    // modified by the CryptEncrypt function, so it cannot be used 
    // again. It will be re-duplicated in the next iteration of the 
    // loop. 
    CryptDestroyKey(hDuplicateKey) 
} 

、2つの新しい行で更新されたコードです追加:

HCRYPTKEY hDuplicateKey; 
boolean final; 

while (aesblocks.quot != 0) 
{ 
    CryptDuplicateKey(hOriginalKey, NULL, 0, &hDuplicateKey); 
    IV_len = IV_SIZE; 
    memmove(tIV, nonceIV, IV_len); 
    final = (aesblocks.quot == 1 && aesblocks.rem == 0) ? TRUE : FALSE; 
    CryptEncrypt(hDuplicateKey, 0, final, 0, (BYTE *)tIV, &IV_len, sizeof(tIV)); 
    XOR(bufIn, tIV, AES_BLOCK_SIZE); 
    IncrementCounterByOne(nonceIV); 
    bufIn += AES_BLOCK_SIZE; 
    aesblocks.quot--; 
    CryptDestroyKey(hDuplicateKey); 
} 

if (aesblocks.rem != 0) 
{ 
    CryptDuplicateKey(hOriginalKey, NULL, 0, &hDuplicateKey); 
    final = TRUE; 
    memmove(tIV, nonceIV, IV_SIZE); 
    CryptEncrypt(hDuplicateKey, 0, final, 0, (BYTE *)tIV, &IV_len, sizeof(tIV)); 
    XOR(bufIn, tIV, aesblocks.rem); 
    CryptDestroyKey(hDuplicateKey); 
} 
+0

おそらく[openssl c EVP_BytesToKey](https://www.google.com/search?q=openssl+c+EVP_BytesToKey)が必要です。私はWinCryptのコンテキストで(まだ) 'EVP_BytesToKey'に関する質問を思い出していません。 – jww

答えて

2

私は、MicrosoftのAPIに慣れていないんだけど、私はCryptEncrypt()は、デフォルトではCBCモードを使用していることを信じている - ので、暗号化の最初のブロックからの出力が自動的にFされています2番目のブロックの入力に入力します。自分でCTRモードを構築しています(これは一般的にはお勧めできません - あなた自身の暗号化ロールではなく暗号ライブラリの機能を使うべきです)。期待される出力を得るには、おそらくCryptEncryptをECBモードでAESを使用する必要があります - 私はCryptptSetKeyParam(https://msdn.microsoft.com/en-us/library/aa380272.aspx)を使用して実行でき、KP_MODEをCRYPT_MODE_ECBに設定できると信じています。

+0

ヒントをありがとう。 CryptEncrypt()ドキュメントを再訪し、M $がこれを示唆していることがわかりました。 "元のキーのIVを設定します。鍵の フィードバックレジスタが変更され、変更できないため、元の鍵を の暗号化または復号化に使用しないでください。 – vengy

0

入力ファイルに改行などの余分な文字が含まれていないことを確認してください。Opensslには、暗号化中の余分な文字が含まれます。

関連する問題