openvpn-mgt/crypto.go

73 lines
1.5 KiB
Go

package main
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base32"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"hash"
"math"
"math/rand"
"strings"
"time"
)
func NewSalt() string {
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]rune, 4)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
func ComputeHmac256(message string, secret string) []byte {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(message))
return h.Sum(nil)
}
func encode64(secret []byte) string {
return strings.TrimRight(base64.StdEncoding.EncodeToString(secret), "=")
}
func encodeSecret(secret []byte) string {
return strings.TrimRight(base32.StdEncoding.EncodeToString(secret), "=")
}
func GenericTotpCode(secret string, t time.Time, algo string, digits int, period int) (string, error) {
var mac hash.Hash
var format string
now := [8]byte{}
binary.BigEndian.PutUint64(now[:], uint64(math.Floor(float64(t.Unix())/float64(period))))
binsecret, _ := base32.StdEncoding.DecodeString(secret)
switch algo {
case "sha1":
mac = hmac.New(sha1.New, binsecret)
case "sha256":
mac = hmac.New(sha256.New, binsecret)
default:
return "", errors.New("unsupported algorithm")
}
switch digits {
case 6:
format = "%06d"
case 8:
format = "%08d"
default:
return "", errors.New("unsupported code size")
}
mac.Write(now[:])
sum := mac.Sum(nil)
return fmt.Sprintf(format, (binary.BigEndian.Uint32(sum[sum[len(sum)-1]&0xf:])&0x7fffffff)%1000000), nil
}