OpenSSL AES_ctr128_encrypt() 的意外输出作为 RFC3711 (SRTP) 中密钥派生的伪随机函数

Unexpected output of OpenSSL AES_ctr128_encrypt() as pseudo-random function for key derivation in RFC3711 (SRTP)

我正在尝试实现 RFC3711(安全 RTP 协议) 中定义的伪随机函数的简单版本,它是计数器模式下的 AES使用 128 位主密钥

我正在使用 32 位 Intel Core2Duo CPU (LittleEndian) 和 OpenSSL v0.9.8AES_ctr128_encrypt()

按照 RFC3711 的指示进行密钥派生,我只需要调用一次 AES_ctr128_encrypt() 并提供:

  1. 已知的 112 位(14 字节)输入向量和初始化为零的 16 位(2 字节)计数器的串联
  2. 一个已知的 128 位主密钥

...产生恰好 16 个字节的密文(例如加密密钥)。

我正在使用 RFC3711 的附录 B.3 中提供的用于加密密钥派生的样本测试向量——在紧要关头,总结如下:

128 位主密钥:E1F97A0D3E018BE0D64FA32C06DE4139

112 位输入向量:0EC675AD498AFEEBB6960B3AABE6

16 位计数器:0000

当将 112 位输入向量和 16 位计数器的串联输入 AES_ctr128_encrypt() 时,我 NOT 得到的预期输出是 列出了 RFC3711 的附录 B.3

预期的密文输出(根据RFC3711的附录B.3)应该是:
C61E7A93744F39EE10734AFE3FF7A087

我的代码得到的实际密文输出是: C8D80F3E3DC5C705A6E541C49411A087

(注意 只有最后 16 位符合预期)。

这是为什么呢?我做错了什么?

这是我的代码:

// COMPILE WITH:
// g++ -o aesctr128 -lcrypto aesctr128_test.cpp

#include <openssl/aes.h>
#include <stdio.h>
#include <string.h>

struct counter_state 
{ 
    unsigned char ivec[16];   // ivec[0..13] (high-order bytes) is 'IV' / ivec[14..15] (low-order bytes) is 'counter'
    unsigned int num;         // Block byte offset
    unsigned char ecount[16]; 
}; 

int reset_state(struct counter_state *state, const unsigned char iv[14])
{   
    // aes_ctr128_encrypt() requires 'num' and 'ecount' to be set to zero on its first call
    state->num = 0; 
    memset(state->ecount, 0, 16);      

    // Clear BOTH 14 high-order bytes [0..13] for 'IV' *AND* 2 low-order bytes [14..15] for 'counter'
    memset(state->ivec, 0, 16);
    // Copy 'IV' into 14 high-order bytes [0..13] -- 2 low-order bytes [14..15] remain zero
    memcpy(state->ivec, iv, 14);

    return 0;
} 

int pseudorandom_function2()
{
    int rc = 0;
    AES_KEY aes_key;
    struct counter_state state;
    unsigned char key[16];         // Master key (16-byte -- 128 bits)
    unsigned char iv[14];          // Input vector (14-byte -- 112 bits)
    unsigned char x[16];           // 16-byte concatenation of 14-byte Input Vector and 2-byte counter (00)
    unsigned char out[16];         // 16-byte encrypted ciphertext

    memset(key, 0, sizeof(key));
    key[0] = 0xE1;
    key[1] = 0xF9;
    key[2] = 0x7A;
    key[3] = 0x0D;
    key[4] = 0x3E;
    key[5] = 0x01;
    key[6] = 0x8B;
    key[7] = 0xE0;
    key[8] = 0xD6;
    key[9] = 0x4F;
    key[10] = 0xA3;
    key[11] = 0x2C;
    key[12] = 0x06;
    key[13] = 0xDE;
    key[14] = 0x41;
    key[15] = 0x39;

    memset(iv, 0, sizeof(iv));
    iv[0] = 0x0E;
    iv[1] = 0xC6;
    iv[2] = 0x75;
    iv[3] = 0xAD;
    iv[4] = 0x49;
    iv[5] = 0x8A;
    iv[6] = 0xFE;
    iv[7] = 0xEB;
    iv[8] = 0xB6;
    iv[9] = 0x96;
    iv[10] = 0x0B;
    iv[11] = 0x3A;
    iv[12] = 0xAB;
    iv[13] = 0xE6;

    memset(x, 0, sizeof(x));
    memcpy(x, iv, 14);

    // Initialize encryption KEY
    rc = AES_set_encrypt_key(key, 128, &aes_key);
    if (rc < 0)
    {
        return -1;
    }

    reset_state(&state, iv);

    memset(out, 0, sizeof(out));

    printf("ivec BEFORE: ");
    for (int i = 0; i < 16; i++) {
      printf("%02x", state.ivec[i]);
    }
    printf("\n");

    // Encrypt given x input using key to out
    AES_ctr128_encrypt(x, out, AES_BLOCK_SIZE, &aes_key, state.ivec, state.ecount, &state.num);

    for (int k = 0; k < 16; k++) 
    {
        printf("pseudorandom_function2: out[%d] = %02x\n", k, out[k]);
    }

    printf("ivec  AFTER: ");
    for (int i = 0; i < 16; i++) {
      printf("%02x", state.ivec[i]);
    }
    printf("\n");

    return 0;
}

int main(int argc, char *argv[])
{  
    pseudorandom_function2();
    return 0;
}

我屏幕上的实际输出:

ivec BEFORE: 0ec675ad498afeebb6960b3aabe60000
pseudorandom_function2: out[0] = c8
pseudorandom_function2: out[1] = d8
pseudorandom_function2: out[2] = 0f
pseudorandom_function2: out[3] = 3e
pseudorandom_function2: out[4] = 3d
pseudorandom_function2: out[5] = c5
pseudorandom_function2: out[6] = c7
pseudorandom_function2: out[7] = 05
pseudorandom_function2: out[8] = a6
pseudorandom_function2: out[9] = e5
pseudorandom_function2: out[10] = 41
pseudorandom_function2: out[11] = c4
pseudorandom_function2: out[12] = 94
pseudorandom_function2: out[13] = 11
pseudorandom_function2: out[14] = a0
pseudorandom_function2: out[15] = 87
ivec  AFTER: 0ec675ad498afeebb6960b3aabe60001

这个:

memcpy(x, iv, 14);

不应该在那里。去掉它。这样做,将代码中的其他所有内容保持原样:

输出

ivec BEFORE: 0ec675ad498afeebb6960b3aabe60000
pseudorandom_function2: out[0] = c6
pseudorandom_function2: out[1] = 1e
pseudorandom_function2: out[2] = 7a
pseudorandom_function2: out[3] = 93
pseudorandom_function2: out[4] = 74
pseudorandom_function2: out[5] = 4f
pseudorandom_function2: out[6] = 39
pseudorandom_function2: out[7] = ee
pseudorandom_function2: out[8] = 10
pseudorandom_function2: out[9] = 73
pseudorandom_function2: out[10] = 4a
pseudorandom_function2: out[11] = fe
pseudorandom_function2: out[12] = 3f
pseudorandom_function2: out[13] = f7
pseudorandom_function2: out[14] = a0
pseudorandom_function2: out[15] = 87
ivec  AFTER: 0ec675ad498afeebb6960b3aabe60001