使用OpenSSL解密TLS 1.2 GCM

时间:2016-10-18 21:10:51

标签: c++ ssl encryption openssl

我正在编写C ++代码以获取TLS 1.x加密的pcap并将数据包解密为未加密的缓冲区。到目前为止,除了TLS 1.2 AEAD密码之外,我已经取得了成功。鉴于已知的premaster,我似乎无法推断出如何正确使用OpenSSL来解密每个TLS记录。 OpenSSL文档还有很多不足之处,因此我将代码简化为单一功能,希望有人可以对我做错的事情有所了解。

您应该假设TLS握手已完成并且我有premaster密钥并从prf计算了4字节隐式nonce(作为saltIV传递)。

任何帮助将不胜感激!我已经好几天了,而且感到很沮丧。

using bytes = std::vector<std::uint8_t>;

// input is the fragment part of TLSCiphertext from the TLS 1.2 RFC
void decryptGCM(bytes premaster, bytes saltIV, bytes input)
{
    EVP_CIPHER_CTX evp;
    EVP_CIPHER_CTX_init(&evp);

    EVP_DecryptInit_ex(&evp, EVP_aes_128_gcm(), nullptr, premaster.data(), nullptr);

    std::uint8_t nonce[12] = { 0 };
    /*
    struct {
            opaque nonce_explicit[SecurityParameters.record_iv_length];
            aead-ciphered struct {
                opaque content[TLSCompressed.length];
        };
    } GenericAEADCipher;
    */
    // The first 8 bytes of a TLS 1.2 record is the explicit nonce
    // Create nonce from implicit (generated from prf) and explicit parts
    assert(saltIV.size() == 4);
    memcpy(nonce, saltIV.data(), saltIV.size());
    memcpy(nonce + saltIV.size(), input.data(), EVP_GCM_TLS_EXPLICIT_IV_LEN); // EVP_GCM_TLS_EXPLICIT_IV_LEN == 8

    EVP_CIPHER_CTX_ctrl(&evp, EVP_CTRL_GCM_SET_IVLEN, sizeof(nonce), 0);
    EVP_CIPHER_CTX_ctrl(&evp, EVP_CTRL_GCM_SET_IV_FIXED, -1, nonce);

    /*
    Note that each of these AEAD algorithms uses a 128-bit authentication tag with GCM (in
    particular, as described in Section 3.5 of [RFC4366]
    */
    // Tag is the last 16 bytes of the input buffer, set below
    std::uint8_t tag[16];
    memcpy(tag, (input.data() + input.size() - sizeof(tag)), sizeof(tag));
    EVP_CIPHER_CTX_ctrl(&evp, EVP_CTRL_GCM_SET_TAG, sizeof(tag), tag);

    n_uint64     sequence(1);
    n_uint8      ct(22);
    n_uint16     size(static_cast<std::uint16_t>(input.size()));

    size = size - EVP_GCM_TLS_EXPLICIT_IV_LEN - static_cast<n_uint16>(sizeof(tag));

    // additional authenticated data
    output_byte_stream aad;
    aad << sequence << ct << tls1_2version << size;

    /*
        aad becomes this byte sequence
        [0] 0 '\0'  unsigned char
        [1] 0 '\0'  unsigned char
        [2] 0 '\0'  unsigned char
        [3] 0 '\0'  unsigned char
        [4] 0 '\0'  unsigned char
        [5] 0 '\0'  unsigned char
        [6] 0 '\0'  unsigned char
        [7] 1 '\x1' unsigned char
        [8] 22 '\x16'   unsigned char
        [9] 3 '\x3' unsigned char
        [10]    3 '\x3' unsigned char
        [11]    0 '\0'  unsigned char
        [12]    16 '\x10'   unsigned char
    */

    int outlen = 0;
    if (!EVP_DecryptUpdate(&evp, nullptr, &outlen, aad.buffer().data(), (unsigned int)aad.buffer().size()))
    {
        std::cout << "EVP_DecryptUpdate Failed" << std::endl;
    }

    bytes out;
    out.resize(input.size() + 1024);

    if (!EVP_DecryptUpdate(&evp, &out[0], &outlen, input.data() + EVP_GCM_TLS_EXPLICIT_IV_LEN, (unsigned int)size))
    {
        std::cout << "EVP_DecryptUpdate Failed" << std::endl;
    }

    // Check the tag
    if (!EVP_DecryptFinal(&evp, &out[0] + outlen, &outlen))
    {
        std::cout << "EVP_DecryptFinal Failed" << std::endl;
    }
}

0 个答案:

没有答案