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}