init: v1.0.0
This commit is contained in:
+176
@@ -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(¶mString, 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(¶mInner, 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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package pbkd
|
||||
|
||||
/*
|
||||
package pbkd is the "Password-based key drivation specification"
|
||||
GM/T 0091
|
||||
*/
|
||||
@@ -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 //输入不合法
|
||||
)
|
||||
@@ -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]]
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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]
|
||||
}
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user