τau / crypto/hmac /

hmac.tau

source
/Users/niconex/Documents/tau/stdlib/crypto/hmac/hmac.tau
1# hmac - the keyed hash of RFC 2104, over SHA-256.2#3#	hmac = import("crypto/hmac")4#5#	tag = hmac.Hex(key, "the message")6#	if !hmac.Equal(tag, expected) { ... }7#8# A signature is checked with Equal rather than with ==, which stops as soon9# as two bytes differ and so says something about the key by how long it took.1011sha256 = import("crypto/sha256")12hex = import("encoding/hex")1314# toBytes takes a string or bytes and gives bytes.15toBytes = fn(data) {16	if type(data) == "bytes" {17		return data18	}19	return bytes(string(data))20}2122# padded returns the key stretched to one block: a long key is hashed first, a23# short one is filled with zeroes, as RFC 2104 says.24padded = fn(key) {25	if failed(key = toBytes(key)) {26		return key27	}28	if len(key) > sha256.BlockSize {29		key = sha256.Sum(key)30	}3132	out = []33	for i = 0; i < len(key); ++i {34		out = append(out, key[i])35	}36	for i = len(out); i < sha256.BlockSize; ++i {37		out = append(out, 0)38	}39	return out40}4142# Sum returns the 32 bytes signing msg with key.43Sum = fn(key, msg) {44	if failed(k = padded(key)) {45		return k46	}47	if failed(msg = toBytes(msg)) {48		return msg49	}5051	# The inner hash is over the key with 0x36 through it and the message, the52	# outer one over the key with 0x5c through it and that digest.53	inner = []54	outer = []55	for i = 0; i < sha256.BlockSize; ++i {56		inner = append(inner, k[i] ^ 0x36)57		outer = append(outer, k[i] ^ 0x5c)58	}5960	for i = 0; i < len(msg); ++i {61		inner = append(inner, msg[i])62	}6364	digest = sha256.Sum(bytes(inner))65	for i = 0; i < len(digest); ++i {66		outer = append(outer, digest[i])67	}68	return sha256.Sum(bytes(outer))69}7071# Hex returns the signature of msg as hexadecimal digits.72Hex = fn(key, msg) { hex.EncodeToString(Sum(key, msg)) }7374# Equal reports whether two signatures are the same, taking the same time75# whether they differ in the first byte or in the last.76Equal = fn(a, b) {77	if failed(a = toBytes(a)) {78		return false79	}80	if failed(b = toBytes(b)) {81		return false82	}83	if len(a) != len(b) {84		return false85	}8687	diff = 088	for i = 0; i < len(a); ++i {89		diff = diff | (a[i] ^ b[i])90	}91	return diff == 092}