Files

109 lines
3.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package otp
import (
"testing"
"time"
)
// RFC 4226, Appendix D: ключ ASCII "12345678901234567890".
var rfc4226Key = []byte("12345678901234567890")
func TestHOTP_RFC4226(t *testing.T) {
want := []string{
"755224", "287082", "359152", "969429", "338314",
"254676", "287922", "162583", "399871", "520489",
}
c := Config{Secret: rfc4226Key, Digits: 6, Alg: SHA1, Step: DefaultStep}
for i, w := range want {
if got := c.HOTP(uint64(i)); got != w {
t.Errorf("HOTP(%d) = %s, ожидалось %s", i, got, w)
}
}
}
// RFC 6238, Appendix B. Ключи для SHA256/SHA512 — продолжение той же
// последовательности "12345678901234567890..." до размера блока хеша.
func seedRepeat(n int) []byte {
base := "12345678901234567890"
out := make([]byte, 0, n)
for len(out) < n {
out = append(out, base...)
}
return out[:n]
}
func TestTOTP_RFC6238(t *testing.T) {
cases := []struct {
unix int64
alg Algorithm
key []byte
want string
}{
{59, SHA1, seedRepeat(20), "94287082"},
{59, SHA256, seedRepeat(32), "46119246"},
{59, SHA512, seedRepeat(64), "90693936"},
{1111111109, SHA1, seedRepeat(20), "07081804"},
{1111111111, SHA1, seedRepeat(20), "14050471"},
{1234567890, SHA1, seedRepeat(20), "89005924"},
{2000000000, SHA1, seedRepeat(20), "69279037"},
{20000000000, SHA1, seedRepeat(20), "65353130"},
{1111111109, SHA256, seedRepeat(32), "68084774"},
{20000000000, SHA256, seedRepeat(32), "77737706"},
{1111111109, SHA512, seedRepeat(64), "25091201"},
{20000000000, SHA512, seedRepeat(64), "47863826"},
}
for _, tc := range cases {
c := Config{Secret: tc.key, Digits: 8, Alg: tc.alg, Step: DefaultStep}
got := c.TOTP(time.Unix(tc.unix, 0).UTC())
if got != tc.want {
t.Errorf("TOTP(%d, %s) = %s, ожидалось %s", tc.unix, tc.alg, got, tc.want)
}
}
}
func TestHOTP_LeadingZeros(t *testing.T) {
c := Config{Secret: rfc4226Key, Digits: 6, Alg: SHA1, Step: DefaultStep}
for i := uint64(0); i < 5000; i++ {
if got := c.HOTP(i); len(got) != 6 {
t.Fatalf("HOTP(%d) = %q: длина %d вместо 6", i, got, len(got))
}
}
}
func TestTimeStepAndStepStart(t *testing.T) {
c := Config{Secret: rfc4226Key, Digits: 6, Alg: SHA1, Step: DefaultStep}
if got := c.TimeStep(time.Unix(59, 0)); got != 1 {
t.Errorf("TimeStep(59) = %d, ожидалось 1", got)
}
if got := c.StepStart(1).Unix(); got != 30 {
t.Errorf("StepStart(1) = %d, ожидалось 30", got)
}
c60 := Config{Secret: rfc4226Key, Digits: 6, Alg: SHA1, Step: 60 * time.Second}
if got := c60.TimeStep(time.Unix(119, 0)); got != 1 {
t.Errorf("TimeStep(119, шаг 60с) = %d, ожидалось 1", got)
}
}
func TestValidate(t *testing.T) {
if err := (Config{Digits: 6, Step: DefaultStep}).Validate(); err == nil {
t.Error("пустой seed должен отвергаться")
}
if err := (Config{Secret: rfc4226Key, Digits: 4, Step: DefaultStep}).Validate(); err == nil {
t.Error("разрядность 4 должна отвергаться")
}
if err := (Config{Secret: rfc4226Key, Digits: 6}).Validate(); err == nil {
t.Error("нулевой шаг должен отвергаться")
}
}
func TestParseAlgorithm(t *testing.T) {
for _, s := range []string{"sha1", "SHA-1", ""} {
if a, err := ParseAlgorithm(s); err != nil || a != SHA1 {
t.Errorf("ParseAlgorithm(%q) = %v, %v", s, a, err)
}
}
if _, err := ParseAlgorithm("md5"); err == nil {
t.Error("md5 должен отвергаться")
}
}