From d32e9d1e4a140d569b6f72028d43ccde70fe9df5 Mon Sep 17 00:00:00 2001 From: Matteo Pierro Date: Sat, 17 Aug 2024 19:30:35 +0300 Subject: [PATCH] implement HS512 as instance of Hmac --- lib/jwt/jwa/hmac.rb | 43 +++++++++++++++++++++++++++--- lib/jwt/jwa/signature_algorithm.rb | 6 +++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/jwt/jwa/hmac.rb b/lib/jwt/jwa/hmac.rb index a304035c..5dea08af 100644 --- a/lib/jwt/jwa/hmac.rb +++ b/lib/jwt/jwa/hmac.rb @@ -2,17 +2,54 @@ module JWT module JWA - module Hmac + class Hmac include JWT::JWA::SignatureAlgorithm DIGEST_MAPPING = { 'HS256' => OpenSSL::Digest::SHA256, - 'HS384' => OpenSSL::Digest::SHA384, - 'HS512' => OpenSSL::Digest::SHA512 + 'HS384' => OpenSSL::Digest::SHA384 }.freeze register_algorithm(*DIGEST_MAPPING.keys) + def initialize(alg, digest) + @alg = alg + @digest = digest + end + + def valid_alg?(alg_to_check) + alg&.casecmp(alg_to_check)&.zero? == true + end + + def sign(data:, signing_key:) + signing_key ||= '' + + raise JWT::DecodeError, 'HMAC key expected to be a String' unless signing_key.is_a?(String) + + OpenSSL::HMAC.digest(digest.new, signing_key, data) + rescue OpenSSL::HMACError => e + if key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure' + raise JWT::DecodeError, 'OpenSSL 3.0 does not support nil or empty hmac_secret' + end + + raise e + end + + def verify(data:, signature:, verification_key:) + SecurityUtils.secure_compare(signature, sign(data: data, signing_key: verification_key)) + end + + def header(*) + { 'alg' => alg } + end + + HS512 = Hmac.new('HS512', OpenSSL::Digest::SHA512) + ::JWT::JWA.register_algorithm_v2(HS512, 'HS512') + + private + + attr_reader :alg, :digest + class << self def sign(algorithm, msg, key) key ||= '' diff --git a/lib/jwt/jwa/signature_algorithm.rb b/lib/jwt/jwa/signature_algorithm.rb index d410da7a..d4d6162a 100644 --- a/lib/jwt/jwa/signature_algorithm.rb +++ b/lib/jwt/jwa/signature_algorithm.rb @@ -35,6 +35,12 @@ def register_algorithm(klass, *algos) end end + def register_algorithm_v2(klass, *algos) + algos.each do |algo| + algorithms[algo.to_s.downcase] = klass + end + end + def find(algo) algorithms[algo.to_s.downcase] end