init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+176
View File
@@ -0,0 +1,176 @@
package pbkd
import (
"encoding/asn1"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
"xdx.jelly/xgcl/gerrors"
)
// id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
//
// The parameters field associated with this OID in an
// AlgorithmIdentifier shall have type PBES2-params:
//
// PBES2-params ::= SEQUENCE {
// keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
// encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
// }
//
// PBKDF2-params ::= SEQUENCE {
// salt CHOICE {
// specified OCTET STRING,
// otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
// },
// iterationCount INTEGER (1..MAX),
// keyLength INTEGER (1..MAX) OPTIONAL,
// prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
var (
// oidHmacWithSHA1 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 401, 2}
IdHmacWithSm3 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 401, 2} //SM3密码杂凑算法,有密钥使用
IdEncSM4CBC = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 104, 2} // SM4-CBC
IdPkcs5PBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} // pkcs5PBKDF2 (PKCS #5 v2.0)
IdPkcs5PBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} // pkcs5PBES2 (PKCS #5 v2.0)
)
func MarshalASN1PBKDF2(salt []byte, iterationCount int, keyLength int) ([]byte, error) {
pbkdf2 := &PBKDF2{
ObjectIdentifier: IdPkcs5PBKDF2,
}
pbkdf2.Param.Salt = salt
pbkdf2.Param.IterationCount = iterationCount
pbkdf2.Param.KeyLength = new(int)
*pbkdf2.Param.KeyLength = keyLength
pbkdf2.Param.Prf.ObjectIdentifier = IdHmacWithSm3
return pbkdf2.MarshalASN1()
}
type PBKDF2 struct {
// Salt only support OCTET STRING
asn1.ObjectIdentifier
Param struct {
Salt []byte
IterationCount int
KeyLength *int
Prf struct {
asn1.ObjectIdentifier // always be idHmacWithSm3
}
}
}
func (p *PBKDF2) MarshalASN1() ([]byte, error) {
var b cryptobyte.Builder
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1OctetString(p.Param.Salt)
b.AddASN1Int64(int64(p.Param.IterationCount))
if p.Param.KeyLength != nil {
b.AddASN1Int64(int64(*p.Param.KeyLength))
}
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1ObjectIdentifier(p.Param.Prf.ObjectIdentifier)
})
})
return b.Bytes()
}
func (p *PBKDF2) UnmarshalASN1(data []byte) (rest []byte, err error) {
input := cryptobyte.String(data)
var inner cryptobyte.String
var paramString cryptobyte.String
var algIdString cryptobyte.String
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
!inner.ReadASN1ObjectIdentifier(&p.ObjectIdentifier) ||
!inner.ReadASN1(&paramString, cryptobyte_asn1.SEQUENCE) ||
!inner.Empty() ||
!paramString.ReadASN1Bytes(&p.Param.Salt, cryptobyte_asn1.OCTET_STRING) ||
!paramString.ReadASN1Integer(&p.Param.IterationCount) {
return data, gerrors.WithAnnotating(ErrInvalidInput, "read ASN.1 SEQUENCE failed")
}
if paramString.PeekASN1Tag(cryptobyte_asn1.INTEGER) {
keyLength := 0
if !paramString.ReadASN1Integer(&keyLength) {
return data, gerrors.WithAnnotating(ErrInvalidInput, "read ASN.1 SEQUENCE failed")
}
if p.Param.KeyLength == nil {
p.Param.KeyLength = new(int)
}
*p.Param.KeyLength = keyLength
}
if !paramString.ReadASN1(&algIdString, cryptobyte_asn1.SEQUENCE) ||
!paramString.Empty() ||
!algIdString.ReadASN1ObjectIdentifier(&p.Param.Prf.ObjectIdentifier) ||
!algIdString.Empty() {
return data, gerrors.WithAnnotating(ErrInvalidInput, "read ASN.1 SEQUENCE failed")
}
return input, nil
}
type PBES2 struct {
asn1.ObjectIdentifier
Param struct {
KeyDerivationFunc PBKDF2
EncryptionScheme struct {
asn1.ObjectIdentifier // 1.2.156.10197.1.104.2 (SM4_CBC, GmSSL, but not the same with GM/T 0091)
iv []byte // The IV, always 16 bytes
}
}
}
func (p *PBES2) Salt() []byte {
return p.Param.KeyDerivationFunc.Param.Salt
}
func (p *PBES2) IterationCount() int {
return p.Param.KeyDerivationFunc.Param.IterationCount
}
func (p *PBES2) IV() []byte {
return p.Param.EncryptionScheme.iv
}
func (p *PBES2) MarshalASN1() ([]byte, error) {
var b cryptobyte.Builder
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1ObjectIdentifier(p.ObjectIdentifier)
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.MarshalASN1(&p.Param.KeyDerivationFunc)
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1ObjectIdentifier(p.Param.EncryptionScheme.ObjectIdentifier)
b.AddASN1OctetString(p.Param.EncryptionScheme.iv)
})
})
})
return b.Bytes()
}
func (p *PBES2) UnmarshalASN1(data []byte) ([]byte, error) {
input := cryptobyte.String(data)
var inner cryptobyte.String
var paramInner cryptobyte.String
var encryptionSchemeString cryptobyte.String
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
!inner.ReadASN1ObjectIdentifier(&p.ObjectIdentifier) ||
!inner.ReadASN1(&paramInner, cryptobyte_asn1.SEQUENCE) ||
!inner.Empty() {
return data, gerrors.WithAnnotating(ErrInvalidInput, "read ASN.1 SEQUENCE failed")
}
rest, err := p.Param.KeyDerivationFunc.UnmarshalASN1(paramInner)
if err != nil {
return data, gerrors.WithAnnotating(ErrInvalidInput, "read ASN.1 SEQUENCE failed")
}
encryptionSchemeString = cryptobyte.String(rest)
if !encryptionSchemeString.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
!encryptionSchemeString.Empty() ||
!inner.ReadASN1ObjectIdentifier(&p.Param.EncryptionScheme.ObjectIdentifier) ||
!inner.ReadASN1Bytes(&p.Param.EncryptionScheme.iv, cryptobyte_asn1.OCTET_STRING) ||
!inner.Empty() {
return data, gerrors.WithAnnotating(ErrInvalidInput, "read ASN.1 SEQUENCE failed")
}
return input, nil
}
+18
View File
@@ -0,0 +1,18 @@
package pbkd
import (
"encoding/base64"
"fmt"
"testing"
)
func TestAsn1PBES(t *testing.T) {
pbes2 := &PBES2{}
b, _ := base64.StdEncoding.DecodeString("MIIBBjBhBgkqhkiG9w0BBQ0wVDA0BgkqhkiG9w0BBQwwJwQQEiukKZfizsctUAskE9BkMAIDAQAAAgEQMAsGCSqBHM9VAYMRAjAcBggqgRzPVQFoAgQQQXzB+gsKqJnFi6VdlujFjASBoL42sUnOuvsa5SFIlbHJSn9/M40yvOL7/9jpGDZi4T+ikgk2TdsfjUGLaF/8H6D1qEm37SabTws0B5HaYTtYNpE21lgb7DlSmHspMenQ5aCYVT62n5vml2kyPMKkSyGGRgYa3pg/m5KifqafRMyIrFVga80n5CcRgUny/C/OEnIFWTlXH8WX/U3KttTl+y7udrxWyOd9EG/zggqi4bmOuWc=")
fmt.Printf("%x\n", b)
_, err := pbes2.UnmarshalASN1(b[4:])
if err != nil {
t.Fatal()
}
fmt.Println(pbes2.Param.KeyDerivationFunc.Param.IterationCount)
}
+6
View File
@@ -0,0 +1,6 @@
package pbkd
/*
package pbkd is the "Password-based key drivation specification"
GM/T 0091
*/
+15
View File
@@ -0,0 +1,15 @@
package pbkd
import "xdx.jelly/xgcl/gerrors"
//go:generate stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go
type ErrorCode gerrors.ErrorCode
func (e ErrorCode) Error() string {
return gerrors.Format(uint32(e), e.String())
}
// error codes
const (
ErrInvalidInput ErrorCode = 0x0100e000 + iota //输入不合法
)
+24
View File
@@ -0,0 +1,24 @@
// Code generated by "stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go"; DO NOT EDIT.
package pbkd
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ErrInvalidInput-16834560]
}
const _ErrorCode_name = "输入不合法"
var _ErrorCode_index = [...]uint8{0, 15}
func (i ErrorCode) String() string {
i -= 16834560
if i >= ErrorCode(len(_ErrorCode_index)-1) {
return "ErrorCode(" + strconv.FormatInt(int64(i+16834560), 10) + ")"
}
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
}
+84
View File
@@ -0,0 +1,84 @@
package pbkd
import (
"errors"
"xdx.jelly/xgcl/sm/sm4"
"xdx.jelly/xgcl/utils/padding"
)
const (
ENCRYPT = iota
DECRYPT
)
type Pbeser interface {
// EncryptBlocks
EncryptBlocks(dst, src []byte) ([]byte, error)
DecryptBlocks(dst, src []byte) ([]byte, error)
EncryptWithPadding(src []byte) ([]byte, error)
DecryptWithPadding(src []byte) ([]byte, error)
ResetIv(iv []byte) error
}
type PbesWithSm4Cbc struct {
key []byte
iv []byte
}
var errOperation = errors.New("error operation")
var errInvalidIV = errors.New("invalid iv length")
func NewPbesWithSm4Cbc(password, salt []byte, count int, iv []byte) (Pbeser, error) {
key, err := PbkdfWithHmacSm3(password, salt, count, int64(sm4.BlockSize))
if err != nil {
return nil, err
}
if len(iv) != sm4.BlockSize {
return nil, errInvalidIV
}
myIv := make([]byte, sm4.BlockSize)
copy(myIv, iv)
return &PbesWithSm4Cbc{
key: key,
iv: myIv,
}, nil
}
func (pbes *PbesWithSm4Cbc) EncryptBlocks(dst, src []byte) ([]byte, error) {
return sm4.EncryptCBC(dst, pbes.iv, pbes.key, src)
}
func (pbes *PbesWithSm4Cbc) DecryptBlocks(dst, src []byte) ([]byte, error) {
return sm4.EncryptCBC(dst, pbes.iv, pbes.key, src)
}
func (pbes *PbesWithSm4Cbc) EncryptWithPadding(src []byte) ([]byte, error) {
pad := padding.P7.Pad(src, sm4.BlockSize)
return sm4.EncryptCBC(nil, pbes.iv, pbes.key, pad)
}
func (pbes *PbesWithSm4Cbc) DecryptWithPadding(src []byte) ([]byte, error) {
dst, err := sm4.DecryptCBC(nil, pbes.iv, pbes.key, src)
if err != nil {
return nil, err
}
dst, err = padding.P7.Unpad(dst, sm4.BlockSize)
if err != nil {
return nil, err
}
return dst, nil
}
func (pbes *PbesWithSm4Cbc) ResetIv(iv []byte) error {
if len(iv) != sm4.BlockSize {
return errInvalidIV
}
copy(pbes.iv, iv)
return nil
}
+112
View File
@@ -0,0 +1,112 @@
package pbkd
import (
"bytes"
"fmt"
"testing"
"golang.org/x/crypto/pbkdf2"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/sm/sm3"
)
func TestPbkdfHF(t *testing.T) {
password := "1234567812345678"
salt := []byte("12345678")
key, err := kdf(newPrfHmacSm3([]byte(password)), salt, 1000, 16)
if err != nil {
t.Fatal("PBKD failed")
}
fmt.Printf("%x\n", key)
}
func TestPbkdf2(t *testing.T) {
password := "12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678"
salt := []byte("12345678")
key, err := PbkdfWithHmacSm3([]byte(password), salt, 1000, 16)
if err != nil {
t.Fatal("PBKD failed")
}
key2 := pbkdf2.Key([]byte(password), salt, 1000, 16, sm3.New)
if !bytes.Equal(key, key2) {
t.Logf("%x\n", key)
t.Logf("%x\n", key2)
}
}
func TestPbkdf(t *testing.T) {
password := "passsword"
salt := []byte("12345678")
key, err := PbkdfWithHmacSm3([]byte(password), salt, 1000, 16)
key2 := pbkdf2.Key([]byte(password), salt, 1000, 16, sm3.New)
if err != nil {
t.Fatal("PBKD failed")
}
t.Logf("%x\n", key) //b30fea078d13ba4e2199936a2f593f9d
t.Logf("%x\n", key2) //b30fea078d13ba4e2199936a2f593f9d
}
func TestPbes(t *testing.T) {
password := []byte("12345678")
salt := grand.GetRandom(16)
data := []byte("abcdefghabcdefgh") // 16 bytes
iv := grand.GetRandom(16)
pbes, err := NewPbesWithSm4Cbc(password, salt, MildCount, iv)
if err != nil {
t.Fatal("pbes failed")
}
var buf bytes.Buffer
for i := 0; i < 2; i++ {
c, err := pbes.EncryptBlocks(nil, data)
if err != nil {
t.Fatal("pbes failed")
}
buf.Write(c)
}
// last block, padding
c, err := pbes.EncryptWithPadding(data)
if err != nil {
t.Fatal("pbes failed")
}
buf.Write(c)
cipherText := buf.Bytes()
fmt.Printf("CipherText = %02x\n", cipherText)
// decrypt - 需要重置IV
pbes.ResetIv(iv)
plainText, err := pbes.DecryptWithPadding(cipherText)
if err != nil {
t.Fatal("pbes failed")
}
fmt.Printf("plainText = %s\n", plainText)
for i := 0; i < len(plainText)/16; i++ {
if bytes.Compare(plainText[i*16:(i+1)*16], data) != 0 {
t.Fatal("pbes failed")
}
}
}
func TestPbmac(t *testing.T) {
password := []byte("12345678")
salt := grand.GetRandom(16)
data := []byte("abcdefgh")
pbmac, err := NewPbmacWithHmacSm3(password, salt, MildCount)
if err != nil {
t.Fatal("pbmac failed")
}
mac, err := pbmac.ComputeMAC(data)
if err != nil {
t.Fatal("compute mac failed")
}
fmt.Printf("Mac: %02x\n", mac)
err = pbmac.VerifyMAC(mac, data)
if err != nil {
t.Fatal("verify mac failed")
}
}
+144
View File
@@ -0,0 +1,144 @@
package pbkd
// pbkdf 实际应为pbkdf2
import (
"crypto/hmac"
"encoding/binary"
"errors"
"hash"
"golang.org/x/crypto/pbkdf2"
"xdx.jelly/xgcl/internal/xor"
"xdx.jelly/xgcl/sm/sm3"
)
const (
MinimumCount = 1024
MildCount = 100000
RecommendCount = 10000000
two32m1 int64 = 0xFFFFFFFF
)
var errDKLenTooLong = errors.New("dkLen too long")
// f 实现错误,正确应为f2
// 虎符中用的是f
func f(prfer prfer, salt_i []byte, count int) ([]byte, error) {
u, err := prfer.prf(salt_i)
if err != nil {
return nil, err
}
for i := 2; i <= count; i++ {
if out, err := prfer.prf(u); err != nil {
return nil, err
} else {
xor.XorBytes(u, u, out)
}
}
return u, nil
}
func kdf(prfer prfer, salt []byte, count int, dkLen int64) ([]byte, error) {
hLen := prfer.hLen()
if dkLen > two32m1*hLen {
return nil, errDKLenTooLong
}
n := (dkLen + hLen - 1) / hLen
dk := make([]byte, 0, n*hLen)
sLen := len(salt)
salt_i := make([]byte, sLen+4)
copy(salt_i, salt)
for i := uint32(1); int64(i) <= n; i++ {
binary.BigEndian.PutUint32(salt_i[sLen:], i)
if out, err := f(prfer, salt_i, count); err != nil {
return nil, err
} else {
dk = append(dk, out...)
}
}
return dk[:dkLen], nil
}
func f2(prfer prfer, salt_i []byte, count int) ([]byte, error) {
u, err := prfer.prf(salt_i)
if err != nil {
return nil, err
}
T := append([]byte(nil), u...)
for i := 2; i <= count; i++ {
if u, err = prfer.prf(u); err != nil {
return nil, err
} else {
xor.XorBytes(T, T, u)
}
}
return T, nil
}
func kdf2(prfer prfer, salt []byte, count int, dkLen int64) ([]byte, error) {
hLen := prfer.hLen()
if dkLen > two32m1*hLen {
return nil, errDKLenTooLong
}
n := (dkLen + hLen - 1) / hLen
dk := make([]byte, 0, n*hLen)
sLen := len(salt)
salt_i := make([]byte, sLen+4)
copy(salt_i, salt)
for i := uint32(1); int64(i) <= n; i++ {
binary.BigEndian.PutUint32(salt_i[sLen:], i)
if out, err := f2(prfer, salt_i, count); err != nil {
return nil, err
} else {
dk = append(dk, out...)
}
}
return dk[:dkLen], nil
}
// PbkdfWithHmacSm3 计算口令导出密钥。遵循GM/T 0091,使用SM3_HMAC作为PRF。
func PbkdfWithHmacSm3(password, salt []byte, count int, dkLen int64) ([]byte, error) {
return pbkdf2.Key([]byte(password), salt, count, int(dkLen), sm3.New), nil
// return kdf2(newPrfHmacSm3(password), salt, count, dkLen)
// return key([]byte(password), salt, count, int(dkLen), sm3.New), nil
}
// key 按GM/T 0091计算导出密钥。
func key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
prf := hmac.New(h, password)
hashLen := prf.Size()
numBlocks := (keyLen + hashLen - 1) / hashLen
var buf [4]byte
dk := make([]byte, 0, numBlocks*hashLen)
U := make([]byte, hashLen)
for block := 1; block <= numBlocks; block++ {
// N.B.: || means concatenation, ^ means XOR
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
// U_1 = PRF(password, salt || uint(i))
prf.Reset()
prf.Write(salt)
buf[0] = byte(block >> 24)
buf[1] = byte(block >> 16)
buf[2] = byte(block >> 8)
buf[3] = byte(block)
prf.Write(buf[:4])
dk = prf.Sum(dk)
T := dk[len(dk)-hashLen:]
copy(U, T)
// U_n = PRF(password, U_(n-1))
for n := 2; n <= iter; n++ {
prf.Reset()
prf.Write(U)
U = U[:0]
U = prf.Sum(U)
for x := range U {
T[x] ^= U[x]
}
}
}
return dk[:keyLen]
}
+38
View File
@@ -0,0 +1,38 @@
package pbkd
import (
"xdx.jelly/xgcl/mac"
)
type pbmacWithHmacSm3 struct {
mac mac.MAC
}
func NewPbmacWithHmacSm3(password, salt []byte, count int) (mac.MAC, error) {
key, err := PbkdfWithHmacSm3(password, salt, count, 16)
if err != nil {
return nil, err
}
mac, err := mac.NewHMacSm3(key, hmacSm3TagSize)
if err != nil {
return nil, err
}
return &pbmacWithHmacSm3{
mac: mac,
}, nil
}
// func PbmacWithHmacSm3(password, salt []byte, count int, dst, src, iv []byte, op int) ([]byte, error) {
// }
// ComputeMAC computes message authentication code (MAC) for code data.
func (p *pbmacWithHmacSm3) ComputeMAC(data []byte) ([]byte, error) {
return p.mac.ComputeMAC(data)
}
// Verify returns nil if mac is a correct authentication code (MAC) for data,
// otherwise it returns an error.
func (p *pbmacWithHmacSm3) VerifyMAC(mac, data []byte) error {
return p.mac.VerifyMAC(mac, data)
}
+32
View File
@@ -0,0 +1,32 @@
package pbkd
import "xdx.jelly/xgcl/mac"
type prfer interface {
prf(data []byte) ([]byte, error)
hLen() int64
}
const hmacSm3TagSize = 32
type hmacSm3 struct {
m mac.MAC
}
func newPrfHmacSm3(key []byte) prfer {
for i := len(key); i < 16; i++ {
key = append(key, 0)
}
m, _ := mac.NewHMacSm3(key, hmacSm3TagSize)
return &hmacSm3{
m: m,
}
}
func (h *hmacSm3) prf(data []byte) ([]byte, error) {
return h.m.ComputeMAC(data)
}
func (h *hmacSm3) hLen() int64 {
return hmacSm3TagSize
}
File diff suppressed because it is too large Load Diff