forked from randomstate/openssl_ext
-
Notifications
You must be signed in to change notification settings - Fork 14
Open
Description
Problem
Crystal's OpenSSL::Cipher doesn't expose methods needed for authenticated encryption modes (AEAD) like AES-GCM. Specifically:
- No way to set Additional Authenticated Data (AAD)
- No way to retrieve/set authentication tags
- No ECDH key agreement support
Use Cases
I've encountered this limitation in two separate production projects:
1. JWE (JSON Web Encryption) with AES-128-GCM
- Implements RFC 7516 for secure token generation
- Requires AAD support to authenticate the JWT header alongside the encrypted payload
- Currently binding LibCrypto directly to call
EVP_EncryptUpdatewith AAD and retrieve tags viaEVP_CIPHER_CTX_ctrl
2. Web Push (RFC 8291) - see github.com/russ/vapid
- Implements Web Push message encryption
- Requires ECDH key agreement (
ECDH_compute_key) and GCM authentication tags - Also binding LibCrypto directly
Current Workaround
Both projects duplicate these LibCrypto bindings:
From internal JWE project:
@[Link("crypto")]
lib LibCrypto
fun evp_aes_128_gcm = EVP_aes_128_gcm : Void*
fun evp_cipher_ctx_new = EVP_CIPHER_CTX_new : Void*
fun evp_cipher_ctx_free = EVP_CIPHER_CTX_free(ctx : Void*)
fun evp_encryptinit_ex = EVP_EncryptInit_ex(ctx : Void*, type : Void*, impl : Void*, key : UInt8*, iv : UInt8*) : Int32
fun evp_encryptupdate = EVP_EncryptUpdate(ctx : Void*, out : UInt8*, outl : Int32*, in : UInt8*, inl : Int32) : Int32
fun evp_encryptfinal_ex = EVP_EncryptFinal_ex(ctx : Void*, out : UInt8*, outl : Int32*) : Int32
fun evp_cipher_ctx_ctrl = EVP_CIPHER_CTX_ctrl(ctx : Void*, type : Int32, arg : Int32, ptr : Void*) : Int32
EVP_CTRL_GCM_SET_IVLEN = 0x9
EVP_CTRL_GCM_GET_TAG = 0x10
end
From github.com/russ/vapid:
lib LibCrypto
fun ecdh_compute_key = ECDH_compute_key(out : UInt8*, outlen : LibC::SizeT, pub_key : Void*, ecdh : Void*, kdf : Void*) : LibC::Int
fun ec_group_get_degree = EC_GROUP_get_degree(group : Void*) : LibC::Int
# EVP cipher functions
fun evp_cipher_ctx_new = EVP_CIPHER_CTX_new : Void*
fun evp_cipher_ctx_free = EVP_CIPHER_CTX_free(ctx : Void*)
fun evp_get_cipherbyname = EVP_get_cipherbyname(name : LibC::Char*) : Void*
fun evp_encryptinit_ex = EVP_EncryptInit_ex(ctx : Void*, type : Void*, impl : Void*, key : UInt8*, iv : UInt8*) : LibC::Int
fun evp_encryptupdate = EVP_EncryptUpdate(ctx : Void*, out : UInt8*, outl : LibC::Int*, in : UInt8*, inl : LibC::Int) : LibC::Int
fun evp_encryptfinal_ex = EVP_EncryptFinal_ex(ctx : Void*, out : UInt8*, outl : LibC::Int*) : LibC::Int
fun evp_cipher_ctx_ctrl = EVP_CIPHER_CTX_ctrl(ctx : Void*, type : LibC::Int, arg : LibC::Int, ptr : Void*) : LibC::Int
# GCM control constants
EVP_CTRL_GCM_SET_IVLEN = 0x9
EVP_CTRL_GCM_GET_TAG = 0x10
endNotes
- This code is admittedly over my head, but it does work in production environments
Would this be something that makes sense to add to openssl_ext?
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels