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 }