mirror of https://github.com/ginuerzh/gost
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
2.3 KiB
100 lines
2.3 KiB
package gost
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha1"
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math/rand"
|
|
"time"
|
|
)
|
|
|
|
func VerifyOTP(secret, pass string) bool {
|
|
now := time.Now().UTC().Unix()
|
|
skew := config.Auth.DynamicSkew
|
|
period := config.Auth.DynamicPeriod
|
|
for i := -skew; i <= skew; i++ {
|
|
t := (now / period) + int64(i)
|
|
code := generateTOTP(secret, t)
|
|
if code == pass {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func generateTOTP(secret string, counter int64) string {
|
|
key := []byte(secret)
|
|
var buf [8]byte
|
|
binary.BigEndian.PutUint64(buf[:], uint64(counter))
|
|
h := hmac.New(sha1.New, key)
|
|
h.Write(buf[:])
|
|
hash := h.Sum(nil)
|
|
offset := hash[len(hash)-1] & 0x0f
|
|
truncated :=
|
|
(binary.BigEndian.Uint32(hash[offset:offset+4]) & 0x7fffffff) % 1000000
|
|
return fmt.Sprintf("%06d", truncated)
|
|
}
|
|
|
|
func generateSecret(ip, user string) string {
|
|
src := ip + ":" + user + ":" + config.Auth.Secret
|
|
hash := sha256.Sum256([]byte(src))
|
|
return hex.EncodeToString(hash[:])
|
|
}
|
|
|
|
func verifyOTP(secret, pass string) (bool, int64) {
|
|
now := time.Now().UTC().Unix()
|
|
skew := config.Auth.DynamicSkew
|
|
period := config.Auth.DynamicPeriod
|
|
for i := -skew; i <= skew; i++ {
|
|
counter := (now / period) + int64(i)
|
|
code := generateTOTP(secret, counter)
|
|
if code == pass {
|
|
return true, counter
|
|
}
|
|
}
|
|
return false, 0
|
|
}
|
|
|
|
func GeneratePassword(ip, user string) string {
|
|
src := ip + user + config.Auth.Secret
|
|
hash := sha256.New()
|
|
hash.Write([]byte(src))
|
|
hashedSrc := hash.Sum(nil)
|
|
hashedSrcHex := hex.EncodeToString(hashedSrc)
|
|
return hashedSrcHex
|
|
}
|
|
|
|
func GenerateShortOTP(key string) string {
|
|
data := make([]byte, 8)
|
|
binary.BigEndian.PutUint32(data[:4], rand.Uint32())
|
|
binary.BigEndian.PutUint32(data[4:], uint32(time.Now().Unix()))
|
|
|
|
encryptData := Encrypt(data, []byte(key))
|
|
|
|
return fmt.Sprintf("%x", encryptData)
|
|
}
|
|
|
|
func VerifyShortOTP(key string, otp string, maxAge int64) bool {
|
|
var encryptData []byte
|
|
_, err := fmt.Sscanf(otp, "%x", &encryptData)
|
|
if err != nil || len(encryptData) == 0 {
|
|
return false
|
|
}
|
|
|
|
decryptData := Decrypt(encryptData, []byte(key))
|
|
if len(decryptData) != 8 {
|
|
return false
|
|
}
|
|
|
|
timestamp := int64(binary.BigEndian.Uint32(decryptData[4:]))
|
|
|
|
now := time.Now().Unix()
|
|
if now-timestamp > maxAge || timestamp > now+5 {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|