Создание пакета ESP с использованием C openssl шифрование AES-GCM приводит к неправильному ICV - PullRequest
0 голосов
/ 24 июня 2019

Я пытаюсь зашифровать свой ICMP-пакет с помощью AES128-CCM16. Я использовал библиотеку c openssl для шифрования. Но зашифрованный результат неверен!

Я использовал две виртуальные машины Linux 18.04 для имитации пакета ESP с помощью IPS strongswan. Я захватил пакет ESP и распечатал все мои переменные в моей функции расшифровки.

static bool _aes_ccm_encrypt(uint8_t* payload, uint16_t payload_len, uint8_t* key, uint16_t key_len, uint8_t* iv, uint8_t iv_len, uint8_t* aad, uint8_t aad_len, uint8_t* icv, uint8_t icv_len) {
    EVP_CIPHER_CTX *ctx = NULL;
    int len;
    uint8_t salt_len = 3;
    uint8_t new_iv[iv_len + salt_len];

    EVP_CIPHER *cipher = NULL;
    switch(key_len) {
        case 19: cipher = EVP_aes_128_ccm(); break;
        case 27: cipher = EVP_aes_192_ccm(); break;
        case 35: cipher = EVP_aes_256_ccm(); break;
        default: break;
    }   

    // Add salt to IV
    memcpy(new_iv, key + (key_len - salt_len), salt_len);
    memcpy(new_iv + salt_len, iv, iv_len);
    iv = new_iv;
    iv_len += salt_len;

    ctx = EVP_CIPHER_CTX_new();
    if(1 != EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL)
            || 1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, NULL)
            || 1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) 
            || 1 != EVP_EncryptUpdate(ctx, NULL, &len, NULL, payload_len)
            || 1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)
            || 1 != EVP_EncryptUpdate(ctx, payload, &len, payload, payload_len)
            || 1 != EVP_EncryptFinal_ex(ctx, payload+len, &len))
        goto failure;

    EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, icv_len, icv);
    print_hex("icv", icv, icv_len);
    EVP_CIPHER_CTX_free(ctx);
    return true;

failure:
    ZF_LOGE("AES CCM Encryption failed");
    if(ctx)
        EVP_CIPHER_CTX_free(ctx);
    return false;
}

Это мой перехваченный пакет

tcpdump: listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
08:48:00.686858 IP (tos 0x0, ttl 64, id 3134, offset 0, flags [none], proto ESP (50), length 140)
    10.10.10.100 > pc2: ESP(spi=0xc8ee6879,seq=0x0), length 120
        0x0000:  ffff ffff ffff ffff ffff ffff 0800 4500
        0x0010:  008c 0c3e 0000 4032 4526 0a0a 0a64 0a0a
        0x0020:  0a65 c8ee 6879 0000 0000 0a0a 0a64 0a0a
        0x0030:  0a65 c8df 30c2 3f71 282b 1ee8 73de 411f
        0x0040:  a937 fbe2 dd3a ee2d 77fd 8b5f 83d6 2523
        0x0050:  8b7c 22d0 6af3 2fb7 1af3 6182 e263 caa4
        0x0060:  6a43 12b5 fc84 52d7 1daa 2437 86a7 9dce
        0x0070:  028e ee0c febe 543d 49f8 e6ca 96c1 e83b
        0x0080:  6514 f23a b916 ba23 58fb 3f52 a522 bd6a
        0x0090:  33e5 0739 0462 0000 0000

А это мои печатные переменные

Оригинальная полезная нагрузка

payload_o(88):
0x0x105790806:  4500 0054 0c3e 0000 4001 44a4 0a00 0a64
0x0x105790816:  0a00 0b64 0000 45be 1910 0001 408e 105d
0x0x105790826:  0000 0000 8772 0a00 0000 0000 1011 1213
0x0x105790836:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
0x0x105790846:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
0x0x105790856:  3435 3637 0000 0204

ключ

key(19):
0x0x7ff8a400215c:  f2e2 66ad ebca 5110 6110 3d29 4900 263d
0x0x7ff8a400216c:  650a 19

IV

iv(11):
0x0x7ffda9dbcc90:  650a 190a 0a0a 640a 0a0a 65

AAD

aad(8):
0x0x1057907f6:  c8ee 6879 0000 0000

ICV

icv(16):
0x0x10579085e:  3f52 a522 bd6a 33e5 0739 0462 0000 0000

Зашифрованная полезная нагрузка

payload_e(88):
0x0x105790806:  c8df 30c2 3f71 282b 1ee8 73de 411f a937
0x0x105790816:  fbe2 dd3a ee2d 77fd 8b5f 83d6 2523 8b7c
0x0x105790826:  22d0 6af3 2fb7 1af3 6182 e263 caa4 6a43
0x0x105790836:  12b5 fc84 52d7 1daa 2437 86a7 9dce 028e
0x0x105790846:  ee0c febe 543d 49f8 e6ca 96c1 e83b 6514
0x0x105790856:  f23a b916 ba23 58fb

Я отправил эти пакеты с заполненным нулями ICV, но Linux IPsec отбросил эти пакеты. Есть ли какие-то опции openssl, которые я пропустил?

Я использовал

EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, icv_len, icv);

с параметрами icv_len = 16, но он создает только 12-байтовый ICV.

1 Ответ

0 голосов
/ 25 июня 2019

Я решил проблему. Так ответь себе

Перед EVP_EncryptInit_ex(...), ниже код должен быть вставлен.

EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, icv_len, NULL)

Финальный код должен быть таким

static bool _aes_ccm_encrypt(uint8_t* payload, uint16_t payload_len, uint8_t* key, uint16_t key_len, uint8_t* iv, uint8_t iv_len, uint8_t* aad, uint8_t aad_len, uint8_t* icv, uint8_t icv_len) {
    EVP_CIPHER_CTX *ctx = NULL;
    int len;
    uint8_t salt_len = 3;
    uint8_t new_iv[iv_len + salt_len];

    EVP_CIPHER *cipher = NULL;
    switch(key_len) {
        case 19: cipher = EVP_aes_128_ccm(); break;
        case 27: cipher = EVP_aes_192_ccm(); break;
        case 35: cipher = EVP_aes_256_ccm(); break;
        default: break;
    }   

    // Add salt to IV
    memcpy(new_iv, key + (key_len - salt_len), salt_len);
    memcpy(new_iv + salt_len, iv, iv_len);
    iv = new_iv;
    iv_len += salt_len;

    print_hex("payload_o", payload, payload_len);
    print_hex("key", key, key_len);
    print_hex("iv", iv, iv_len);
    print_hex("aad", aad, aad_len);

    ctx = EVP_CIPHER_CTX_new();
    if(1 != EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL)
            || 1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, NULL)
            || 1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, icv_len, NULL)
            || 1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) 
            || 1 != EVP_EncryptUpdate(ctx, NULL, &len, NULL, payload_len)
            || 1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)
            || 1 != EVP_EncryptUpdate(ctx, payload, &len, payload, payload_len)
            || 1 != EVP_EncryptFinal_ex(ctx, payload+len, &len))
        goto failure;

    EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, icv_len, icv);

    print_hex("icv", icv, icv_len);
    print_hex("payload_e", payload, payload_len);

    EVP_CIPHER_CTX_free(ctx);
    return true;

failure:
    ZF_LOGE("AES CCM Encryption failed");
    if(ctx)
        EVP_CIPHER_CTX_free(ctx);
    return false;
}
...