hmac.gno
1.02 Kb · 38 lines
1package wesh
2
3import "crypto/sha256"
4
5// blockSize is SHA-256's internal block size, the padding width HMAC uses.
6const blockSize = 64
7
8// HMACSHA256 computes HMAC-SHA256 as specified in RFC 2104.
9//
10// gno's standard library exposes sha256.Sum256 but no streaming hash.Hash and
11// no crypto/hmac, so the construction is spelled out here:
12//
13// HMAC(K, m) = H((K' ⊕ opad) ‖ H((K' ⊕ ipad) ‖ m))
14//
15// with K' the key hashed down when longer than the block size, then
16// zero-padded up to it. This is the primitive weshnet's rendezvous point
17// derivation is built on, so it has to agree byte-for-byte; see
18// [RendezvousPoint].
19func HMACSHA256(key, msg []byte) []byte {
20 k := key
21 if len(k) > blockSize {
22 sum := sha256.Sum256(k)
23 k = sum[:]
24 }
25
26 ipad := make([]byte, blockSize)
27 opad := make([]byte, blockSize)
28 copy(ipad, k)
29 copy(opad, k)
30 for i := 0; i < blockSize; i++ {
31 ipad[i] ^= 0x36
32 opad[i] ^= 0x5c
33 }
34
35 inner := sha256.Sum256(append(ipad, msg...))
36 outer := sha256.Sum256(append(opad, inner[:]...))
37 return outer[:]
38}