constexpr int PBKDF2_ITERATIONS = 4096;
constexpr uint32_t KEYCOMPONENT_VERSION = 2;
constexpr int OPENSSL_ENGINE_ERROR = -4;
+constexpr int AUTHENTICATION_ERROR = -5;
template<typename T>
RawBuffer toRawBuffer(const T &data)
if (!EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
return OPENSSL_ENGINE_ERROR;
- if (!EVP_EncryptInit_ex(ctx.get(), NULL, NULL, key, iv))
+ if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, MAX_IV_SIZE, NULL))
return OPENSSL_ENGINE_ERROR;
- if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, MAX_IV_SIZE, NULL))
+ if (!EVP_EncryptInit_ex(ctx.get(), NULL, NULL, key, iv))
return OPENSSL_ENGINE_ERROR;
if (!EVP_EncryptUpdate(ctx.get(), ciphertext, &len, plaintext, plaintext_len))
int ciphertext_len, unsigned char *tag, const unsigned char *key,
const unsigned char *iv, unsigned char *plaintext)
{
- int len;
- int plaintext_len;
- int ret;
+ auto decrypt = [&](size_t iv_len){
+ int len;
+ int plaintext_len;
+ int ret;
- auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
- if (!ctx)
- return OPENSSL_ENGINE_ERROR;
+ auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
+ if (!ctx)
+ return OPENSSL_ENGINE_ERROR;
- if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
- return OPENSSL_ENGINE_ERROR;
+ if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
+ return OPENSSL_ENGINE_ERROR;
- if (!EVP_DecryptInit_ex(ctx.get(), NULL, NULL, key, iv))
- return OPENSSL_ENGINE_ERROR;
+ if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
+ return OPENSSL_ENGINE_ERROR;
- if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, MAX_IV_SIZE, NULL))
- return OPENSSL_ENGINE_ERROR;
+ if (!EVP_DecryptInit_ex(ctx.get(), NULL, NULL, key, iv))
+ return OPENSSL_ENGINE_ERROR;
- if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, MAX_IV_SIZE, tag))
- return OPENSSL_ENGINE_ERROR;
+ if (!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext, ciphertext_len))
+ return OPENSSL_ENGINE_ERROR;
- if (!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext, ciphertext_len))
- return OPENSSL_ENGINE_ERROR;
+ plaintext_len = len;
- plaintext_len = len;
+ if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, MAX_IV_SIZE, tag))
+ return OPENSSL_ENGINE_ERROR;
- if (!(ret = EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)))
- return OPENSSL_ENGINE_ERROR;
+ if (!(ret = EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)))
+ return AUTHENTICATION_ERROR;
- if (ret > 0) {
- plaintext_len += len;
- return plaintext_len;
- } else {
- return -1;
- }
+ if (ret > 0) {
+ plaintext_len += len;
+ return plaintext_len;
+ } else {
+ return -1;
+ }
+ };
+
+ auto ret = decrypt(MAX_IV_SIZE);
+ if (ret == AUTHENTICATION_ERROR)
+ ret = decrypt(12); // retry with truncated IV
+
+ return ret;
}
typedef std::array<uint8_t, MAX_KEY_SIZE> KeyData;