1 (edited by johnot 2023-03-16 22:54:34)

Topic: Exchanging enc Data with BoringSSL [UPDATED]

Hi there,

I'm trying to replicate the functions

 EVP_AEAD_CTX_seal 

and

 EVP_AEAD_CTX_open 

in order to send (and receive) data to a server using BoringSSL. However, the server fails to decrypt the data. It seems like wolfSSL doesn't have any directly compatible functions. Here's my approach:

[UPDATE]: I posted decryption code earlier instead of encryption code, my bad.

// Original code using BoringSSL
size_t Encrypt(bssl::ScopedEVP_AEAD_CTX context, const uint8_t* in, size_t in_len, uint8_t* out, size_t out_len)
{
    size_t written_sz;
    std::vector<uint8_t> nonce(EVP_AEAD_nonce_length(EVP_AEAD_CTX_aead(context.get())), 0);

    if (!EVP_AEAD_CTX_seal(context.get(), out, &written_sz, out_len, nonce.data(),
                                        nonce.size(), in, in_len, nullptr, 0)) {
        std::cerr  << "Failed to encrypt" << std::endl;
        return 0;
    }
    
    return written_sz;
}

and

// Code ported to use wolfSSL
// key_g = { preset key }
size_t Decrypt(wolfssl::UniquePtr<WOLFSSL_EVP_CIPHER_CTX> encryptContext,
                                   const uint8_t* in, size_t in_len, uint8_t* out, size_t out_len)
{
    int written_sz, ret, taglen = 16;
    std::vector<uint8_t> nonce(EVP_CIPHER_iv_length(EVP_aes_128_gcm()), 0);

    ret = EVP_EncryptInit(encryptContext.get(), EVP_aes_128_gcm(), key_g, nonce.data());

    assert(ret == SSL_SUCCESS))

    ret = EVP_EncryptUpdate(encryptContext.get(), out, &written_sz, in, (int)in_len);

    if (ret != WOLFSSL_SUCCESS){
        std::cerr  << "Failed to encrypt" << std::endl;
        return 0;
    }

    ret = EVP_EncryptFinal(encryptContext.get(), out, &written_sz);

    if (ret != WOLFSSL_SUCCESS || written_sz != in_len){
        std::cerr  << "Failed to encrypt" << std::endl;
        return 0;
    }

    unsigned char tag[taglen]
    // the last 16 bytes are the tag. Copy the tag into those last 16 bytes as boringssl does
    assert((in_len + taglen) == out_len);
    assert(EVP_CIPHER_CTX_ctrl(encryptContext.get(), EVP_CTRL_GCM_GET_TAG, taglen, (void*)tag) == SSL_SUCCESS);
    memcpy((void*)(out + in_len), tag, taglen);

    return written_sz + taglen; // bssl returns sizeof(encryptedData) + taglen
}

I tried analyzing the encrypted data for bssl and figured out that authTag, which is 16 bytes (depending on cipher I suppose), is appended to the end of the encryption data. I tried following a similar scheme since wolfSSL didn't have the functions out of the box.

However, the server fails to decrypt the data. Can anybody help out?

Thanks in advance

Share

Re: Exchanging enc Data with BoringSSL [UPDATED]

Hi johnot,

your ported code looks almost correct. The only thing you are missing is the AAD. Even though your AAD is 0-length, it still needs to be applied. To do this, you need to add this step after the Init but before the first Update.

EVP_EncryptUpdate(encryptContext.get(), nullptr, &written_sz, nullptr, 0);

This will apply the 0-length AAD and you should achieve the correct output.

Sincerely
Juliusz

Share

Re: Exchanging enc Data with BoringSSL [UPDATED]

After further testing and investigation, I've discovered that the encryption and decryption works just fine. I'm actually trying to port parts of this code from adb to wolfssl:
https://cs.android.com/android/platform … 28_gcm.cpp

I've zeroed down the problem to my copy pasta of SPAKE2 from boringssl, needed for pairing authentication in adb. The encryption/decryption must be failing because the key received from SPAKE2_process_msg is wrong.

Share