mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-12 00:16:37 +08:00
224 lines
4.5 KiB
Go
224 lines
4.5 KiB
Go
package helper
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"crypto/sha512"
|
|
"errors"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
SaltLenMin = 1
|
|
SaltLenMax = 16
|
|
RoundsMin = 1000
|
|
RoundsMax = 999999999
|
|
RoundsDefault = 5000
|
|
)
|
|
|
|
var _rounds = []byte("rounds=")
|
|
|
|
func Generate(key []byte) (string, error) {
|
|
var rounds int
|
|
var isRoundsDef bool
|
|
|
|
salt := generateWRounds()
|
|
magicPrefix := []byte("$6$")
|
|
if !bytes.HasPrefix(salt, magicPrefix) {
|
|
return "", errors.New("invalid magic prefix")
|
|
}
|
|
|
|
saltItem := bytes.Split(salt, []byte{'$'})
|
|
if len(saltItem) < 3 {
|
|
return "", errors.New("invalid salt format")
|
|
}
|
|
|
|
if bytes.HasPrefix(saltItem[2], _rounds) {
|
|
isRoundsDef = true
|
|
pr, err := strconv.ParseInt(string(saltItem[2][7:]), 10, 32)
|
|
if err != nil {
|
|
return "", errors.New("invalid rounds")
|
|
}
|
|
rounds = int(pr)
|
|
if rounds < RoundsMin {
|
|
rounds = RoundsMin
|
|
} else if rounds > RoundsMax {
|
|
rounds = RoundsMax
|
|
}
|
|
salt = saltItem[3]
|
|
} else {
|
|
rounds = RoundsDefault
|
|
salt = saltItem[2]
|
|
}
|
|
|
|
if len(salt) > SaltLenMax {
|
|
salt = salt[0:SaltLenMax]
|
|
}
|
|
|
|
Alternate := sha512.New()
|
|
Alternate.Write(key)
|
|
Alternate.Write(salt)
|
|
Alternate.Write(key)
|
|
AlternateSum := Alternate.Sum(nil)
|
|
|
|
A := sha512.New()
|
|
A.Write(key)
|
|
A.Write(salt)
|
|
i := len(key)
|
|
for ; i > 64; i -= 64 {
|
|
A.Write(AlternateSum)
|
|
}
|
|
A.Write(AlternateSum[0:i])
|
|
|
|
for i = len(key); i > 0; i >>= 1 {
|
|
if (i & 1) != 0 {
|
|
A.Write(AlternateSum)
|
|
} else {
|
|
A.Write(key)
|
|
}
|
|
}
|
|
A_sum := A.Sum(nil)
|
|
|
|
P := sha512.New()
|
|
for i = 0; i < len(key); i++ {
|
|
P.Write(key)
|
|
}
|
|
P_sum := P.Sum(nil)
|
|
P_seq := make([]byte, 0, len(key))
|
|
for i = len(key); i > 64; i -= 64 {
|
|
P_seq = append(P_seq, P_sum...)
|
|
}
|
|
P_seq = append(P_seq, P_sum[0:i]...)
|
|
|
|
S := sha512.New()
|
|
for i = 0; i < (16 + int(A_sum[0])); i++ {
|
|
S.Write(salt)
|
|
}
|
|
S_sum := S.Sum(nil)
|
|
S_seq := make([]byte, 0, len(salt))
|
|
for i = len(salt); i > 64; i -= 64 {
|
|
S_seq = append(S_seq, S_sum...)
|
|
}
|
|
S_seq = append(S_seq, S_sum[0:i]...)
|
|
|
|
C_sum := A_sum
|
|
|
|
for i = 0; i < rounds; i++ {
|
|
C := sha512.New()
|
|
if (i & 1) != 0 {
|
|
C.Write(P_seq)
|
|
} else {
|
|
C.Write(C_sum)
|
|
}
|
|
if (i % 3) != 0 {
|
|
C.Write(S_seq)
|
|
}
|
|
if (i % 7) != 0 {
|
|
C.Write(P_seq)
|
|
}
|
|
if (i & 1) != 0 {
|
|
C.Write(C_sum)
|
|
} else {
|
|
C.Write(P_seq)
|
|
}
|
|
|
|
C_sum = C.Sum(nil)
|
|
}
|
|
|
|
out := make([]byte, 0, 123)
|
|
out = append(out, magicPrefix...)
|
|
if isRoundsDef {
|
|
out = append(out, []byte("rounds="+strconv.Itoa(rounds)+"$")...)
|
|
}
|
|
out = append(out, salt...)
|
|
out = append(out, '$')
|
|
out = append(out, base64_24Bit([]byte{
|
|
C_sum[42], C_sum[21], C_sum[0],
|
|
C_sum[1], C_sum[43], C_sum[22],
|
|
C_sum[23], C_sum[2], C_sum[44],
|
|
C_sum[45], C_sum[24], C_sum[3],
|
|
C_sum[4], C_sum[46], C_sum[25],
|
|
C_sum[26], C_sum[5], C_sum[47],
|
|
C_sum[48], C_sum[27], C_sum[6],
|
|
C_sum[7], C_sum[49], C_sum[28],
|
|
C_sum[29], C_sum[8], C_sum[50],
|
|
C_sum[51], C_sum[30], C_sum[9],
|
|
C_sum[10], C_sum[52], C_sum[31],
|
|
C_sum[32], C_sum[11], C_sum[53],
|
|
C_sum[54], C_sum[33], C_sum[12],
|
|
C_sum[13], C_sum[55], C_sum[34],
|
|
C_sum[35], C_sum[14], C_sum[56],
|
|
C_sum[57], C_sum[36], C_sum[15],
|
|
C_sum[16], C_sum[58], C_sum[37],
|
|
C_sum[38], C_sum[17], C_sum[59],
|
|
C_sum[60], C_sum[39], C_sum[18],
|
|
C_sum[19], C_sum[61], C_sum[40],
|
|
C_sum[41], C_sum[20], C_sum[62],
|
|
C_sum[63],
|
|
})...)
|
|
|
|
A.Reset()
|
|
Alternate.Reset()
|
|
P.Reset()
|
|
for i = 0; i < len(A_sum); i++ {
|
|
A_sum[i] = 0
|
|
}
|
|
for i = 0; i < len(AlternateSum); i++ {
|
|
AlternateSum[i] = 0
|
|
}
|
|
for i = 0; i < len(P_seq); i++ {
|
|
P_seq[i] = 0
|
|
}
|
|
|
|
return string(out), nil
|
|
}
|
|
|
|
func generateWRounds() []byte {
|
|
salt := make([]byte, 16)
|
|
_, _ = rand.Read(salt)
|
|
|
|
magicPrefix := "$6$"
|
|
out := make([]byte, len(magicPrefix)+5000)
|
|
copy(out, magicPrefix)
|
|
copy(out[len(magicPrefix):], base64_24Bit(salt))
|
|
return out
|
|
}
|
|
|
|
func base64_24Bit(src []byte) (hash []byte) {
|
|
if len(src) == 0 {
|
|
return []byte{}
|
|
}
|
|
alphabet := "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
|
|
hashSize := (len(src) * 8) / 6
|
|
if (len(src) % 6) != 0 {
|
|
hashSize += 1
|
|
}
|
|
hash = make([]byte, hashSize)
|
|
|
|
dst := hash
|
|
for len(src) > 0 {
|
|
switch len(src) {
|
|
default:
|
|
dst[0] = alphabet[src[0]&0x3f]
|
|
dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f]
|
|
dst[2] = alphabet[((src[1]>>4)|(src[2]<<4))&0x3f]
|
|
dst[3] = alphabet[(src[2]>>2)&0x3f]
|
|
src = src[3:]
|
|
dst = dst[4:]
|
|
case 2:
|
|
dst[0] = alphabet[src[0]&0x3f]
|
|
dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f]
|
|
dst[2] = alphabet[(src[1]>>4)&0x3f]
|
|
src = src[2:]
|
|
dst = dst[3:]
|
|
case 1:
|
|
dst[0] = alphabet[src[0]&0x3f]
|
|
dst[1] = alphabet[(src[0]>>6)&0x3f]
|
|
src = src[1:]
|
|
dst = dst[2:]
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|