HMAC Generator — Go 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 Go implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Package hmacgenerator is the Go twin of CosmoDev's src/lib/hmac.ts (dual
// source: the web lib is TypeScript, the CLI lib is Go — kept in lock-step).
// Pure + deterministic, never panics. The table-driven tests in
// hmac-generator_test.go share vectors with src/lib/hmac.test.ts so the two
// implementations are held to the same contract.
//
// The TS lib computes keyed-hash HMAC through the WebCrypto API
// (crypto.subtle / SubtleCrypto); this twin maps that to the Go stdlib
// (crypto/hmac + crypto/sha1, crypto/sha256, crypto/sha512), producing the
// identical bytes and then lowercasing them to hex — the same surface as
// hmacHex() in the TS lib. Inputs are UTF-8 encoded, matching TextEncoder.
package hmacgenerator
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"errors"
"fmt"
"hash"
)
// Algorithm is the hash used for HMAC. It mirrors the TS HmacAlgorithm union
// ('SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512') as an int enum so the zero
// value carries the default (SHA256) — a string type could not, since its zero
// value would be "". This is the same pattern slugify uses for its Case union.
type Algorithm int
const (
// SHA256 is the default algorithm (zero value), matching the TS lib's
// default 'SHA-256'.
SHA256 Algorithm = iota
SHA1
SHA384
SHA512
)
// String returns the TS-style algorithm name (e.g. "SHA-256"), useful for error
// messages and the eventual cosmodev CLI surface.
func (a Algorithm) String() string {
switch a {
case SHA256:
return "SHA-256"
case SHA1:
return "SHA-1"
case SHA384:
return "SHA-384"
case SHA512:
return "SHA-512"
default:
return fmt.Sprintf("SHA-(%d)", int(a))
}
}
// newHasher returns a fresh hash.Hash factory for the algorithm, or an error if
// the algorithm is unsupported — mirroring SubtleCrypto rejecting an unknown
// hash name.
func newHasher(a Algorithm) (func() hash.Hash, error) {
switch a {
case SHA256:
return sha256.New, nil
case SHA1:
return sha1.New, nil
case SHA384:
return sha512.New384, nil
case SHA512:
return sha512.New, nil
default:
return nil, fmt.Errorf("hmac: unsupported algorithm %s", a)
}
}
// HmacHex computes the HMAC of message under secret and returns it as lowercase
// hex. It is the Go twin of hmacHex() in src/lib/hmac.ts and must agree with it
// on every shared vector. Both inputs are UTF-8 encoded, exactly like the TS
// lib's TextEncoder. The zero-value algorithm (SHA256) is the default.
//
// An empty secret returns an error — SubtleCrypto rejects a zero-length key in
// the TS lib, and the twin mirrors that contract. An unsupported algorithm
// likewise returns an error rather than panicking.
func HmacHex(message, secret string, alg Algorithm) (string, error) {
if secret == "" {
return "", errors.New("hmac: secret must be non-empty")
}
hasher, err := newHasher(alg)
if err != nil {
return "", err
}
mac := hmac.New(hasher, []byte(secret))
mac.Write([]byte(message))
return hex.EncodeToString(mac.Sum(nil)), nil
}
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 →