diff --git a/src/OpenSSL.jl b/src/OpenSSL.jl index eb78254..30c64ca 100644 --- a/src/OpenSSL.jl +++ b/src/OpenSSL.jl @@ -30,7 +30,7 @@ export TLSv12ClientMethod, TLSv12ServerMethod, EvpEncNull, EvpBlowFishCBC, EvpBlowFishECB, EvpBlowFishCFB, EvpBlowFishOFB, EvpAES128CBC, EvpAES128ECB, EvpAES128CFB, EvpAES128OFB, EvpMDNull, EvpMD2, EvpMD5, EvpSHA1, EvpDSS1, encrypt_init, cipher, add_extension, add_extensions, decrypt_init, digest_init, digest_update, digest_final, - digest, random_bytes, rsa_generate_key, dsa_generate_key, add_entry, sign_certificate, sign_request, adjust, + digest, hmac, random_bytes, rsa_generate_key, dsa_generate_key, add_entry, sign_certificate, sign_request, adjust, add_cert, unpack, eof, isreadable, iswritable, bytesavailable, read, unsafe_write, connect, get_peer_certificate, free, HTTP2_ALPN, UPDATE_HTTP2_ALPN, version @@ -1291,6 +1291,34 @@ function digest(evp_digest::EvpDigest, io::IO) return result end + +""" + Compute the hash-based message authentication code of the given data using a key and a hash function. +""" +function hmac(evp_digest::EvpDigest, in_data::AbstractVector{UInt8}, key::AbstractVector{UInt8})::Vector{UInt8} + out_data = Vector{UInt8}(undef, EVP_MAX_MD_SIZE) + out_length = Ref{UInt32}(0) + GC.@preserve key in_data out_data out_length begin + if ccall( + (:HMAC, libcrypto), + Ptr{Cchar}, + (EvpDigest, Ptr{Cvoid}, Cint, Ptr{Cchar}, Csize_t, Ptr{Cchar}, Ptr{Cuint}), + evp_digest, + pointer(key), length(key), + pointer(in_data), length(in_data), + pointer(out_data), pointer_from_objref(out_length)) == C_NULL + throw(OpenSSLError()) + end + end + resize!(out_data, out_length.x) + return out_data +end + +hmac(evp_digest::EvpDigest, in_data::AbstractString, key::AbstractString)::Vector{UInt8} = hmac(evp_digest, codeunits(in_data), codeunits(key)) +hmac(evp_digest::EvpDigest, in_data::AbstractString, key::AbstractVector{UInt8})::Vector{UInt8} = hmac(evp_digest, codeunits(in_data), key) + + + """ RSA structure. The RSA structure consists of several BIGNUM components. @@ -1454,7 +1482,7 @@ end """ ec_generate_key(nid) - + Generate EC key pair from a curve identifier. See ec_builtin_curves(). """ @@ -1954,7 +1982,7 @@ mutable struct EvpPKey function EvpPKey(ec::EC)::EvpPKey evp_pkey = EvpPKey() - + if ccall( (:EVP_PKEY_assign, libcrypto), Cint, (EvpPKey, Cint, EC), @@ -1963,7 +1991,7 @@ mutable struct EvpPKey ec) != 1 throw(OpenSSLError()) end - + ec.ec = C_NULL return evp_pkey end diff --git a/test/runtests.jl b/test/runtests.jl index 5be468a..c7fdf93 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -277,6 +277,17 @@ end @test bytes2hex(digest(OpenSSL.EvpRIPEMD160(), IOBuffer("abc"))) == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" end +@testset "HMAC" begin + # echo -n "Hello world" | openssl dgst -sha256 -mac hmac -macopt hexkey:01020304 + @test bytes2hex(hmac(OpenSSL.EvpSHA256(), "Hello world", hex2bytes("01020304"))) == "760e94f3d42452f372885f22d3ed5915ffa5a7d6ddf38716331f9c2786f21e5a" + + # echo -n "Hello world" | openssl dgst -sha512 -hmac "Σλ" + @test bytes2hex(hmac(OpenSSL.EvpSHA512(), "Hello world", "Σλ")) == "dfe48de81d0f5f8976d20e10c6fa2f82ff3cc28ae5060b396f70e26d45563a4cfa446d53d5fbea377018b54dac1ec368c979fb2b4a99f642cb0a2d8422c3bfa6" + + # echo -n "Hello world" | openssl dgst -sha256 -hmac "" + @test bytes2hex(hmac(OpenSSL.EvpSHA256(), [0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64], b"")) == "c50d316a00f927059322a898ea2fa7321fdb4d32eb749656ea7ba7775a870dc0" +end + @testset "SelfSignedCertificate" begin x509_certificate = X509Certificate() @@ -675,8 +686,8 @@ end @testset "CACertsLoading" begin certs_dir = joinpath(@__DIR__, "certs") - certs_path = joinpath(certs_dir, "ca-certificates.crt") - + certs_path = joinpath(certs_dir, "ca-certificates.crt") + ssl_method = OpenSSL.TLSClientMethod() ctx = OpenSSL.SSLContext(ssl_method, certs_path) @test typeof(ctx) == OpenSSL.SSLContext