HMAC Generator — Ruby source
Generate a keyed-hash HMAC (SHA-1/256/384/512) for a message and secret. Runs entirely in your browser via Web Crypto, with a shareable link to your exact input.
This is the Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.
# hmac-generator — RFC 2104 keyed-hash HMAC of a UTF-8 message, hex output.
#
# Language: Ruby 3.2 (bundled library: openssl)
# Source: CosmoDev polyglot showcase port of the `hmac-generator` tool,
# ported from src/lib/hmac.ts (the canonical TypeScript lib).
# License: display source — part of CosmoDev's polyglot tool pages.
#
# Keyed HMAC via Ruby's bundled `openssl` library — a default-gem C extension
# shipped with the Ruby distribution, so no gems need to be installed.
# OpenSSL::HMAC implements RFC 2104 on top of the same vetted OpenSSL digests
# the `hash` tool's Ruby port reaches through `digest`, and `hexdigest`
# returns exactly the lowercase hex the TypeScript reference produces.
#
# Behavior mirrors the TypeScript reference: UTF-8 inputs, lowercase hex
# output, SHA-256 by default, and rejection of empty secrets and unknown
# algorithms. A Ruby String is a byte sequence with an encoding, so a UTF-8
# message and secret hash as their own bytes — the same byte sequence a
# browser hands to crypto.subtle.sign. The empty-secret rejection keeps
# parity with SubtleCrypto, which refuses a zero-length key that
# OpenSSL::HMAC would otherwise accept. SHA-1 is offered for legacy
# compatibility only; it is not collision-resistant.
require 'openssl'
module HmacTool
# Canonical algorithm names. The spellings match the TypeScript union so
# the same string works across every port.
SHA1 = 'SHA-1'
SHA256 = 'SHA-256' # default algorithm
SHA384 = 'SHA-384'
SHA512 = 'SHA-512'
# Dispatch table: canonical name -> OpenSSL digest name. Module-level so
# the supported set is visible in one place and easy to extend (the same
# shape as the Python port's _HASH_CONSTRUCTORS).
ALGORITHMS = {
SHA1 => 'SHA1',
SHA256 => 'SHA256',
SHA384 => 'SHA384',
SHA512 => 'SHA512'
}.freeze
module_function
# Computes HMAC(`message`, `secret`) under the named algorithm and returns
# it as lowercase hex.
#
# A nil or empty `algorithm` selects SHA-256 — the optional-parameter
# default the TypeScript reference declares. An empty `secret` and an
# unknown algorithm name both raise ArgumentError (not KeyError), matching
# the Python port's ValueError and the two arms of the Rust port's
# HmacError enum.
def hmac_hex(message, secret, algorithm = SHA256)
name = algorithm.to_s.empty? ? SHA256 : algorithm
raise ArgumentError, 'HMAC secret must not be empty' if secret.empty?
digest_name = ALGORITHMS.fetch(name) do
raise ArgumentError, "Unsupported HMAC algorithm: #{name}"
end
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new(digest_name), secret, message)
end
end
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →