-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathderive_rfc4226_wasm.go
63 lines (53 loc) · 1.1 KB
/
derive_rfc4226_wasm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//go:build js && wasm
package otp
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/binary"
"hash"
"strconv"
)
// DeriveRFC4226Wasm generates a HOTP code (used by both HOTP/TOTP) safely for WebAssembly (js/wasm).
func DeriveRFC4226Wasm(secret []byte, counter uint64, digits int, algo Algorithm) (string, error) {
var h func() hash.Hash
switch algo {
case SHA1:
h = sha1.New
case SHA256:
h = sha256.New
case SHA512:
h = sha512.New
default:
return "", ErrUnsupportedAlgorithm
}
var buf [8]byte
binary.BigEndian.PutUint64(buf[:], counter)
mac := hmac.New(h, secret)
mac.Write(buf[:])
sum := mac.Sum(nil)
var mod uint64
if digits >= 1 && digits <= 9 {
mod = mod10[digits]
} else {
mod = pow10Wasm(digits)
}
code := truncate(sum, mod)
s := strconv.FormatUint(uint64(code), 10)
if len(s) < digits {
padding := make([]byte, digits-len(s))
for i := range padding {
padding[i] = '0'
}
s = string(padding) + s
}
return s, nil
}
func pow10Wasm(n int) uint64 {
var result uint64 = 1
for i := 0; i < n; i++ {
result *= 10
}
return result
}