github.com/emmansun/gmsm@v0.29.1/pkcs/kdf_pbkdf2.go (about) 1 package pkcs 2 3 // 4 // Reference https://datatracker.ietf.org/doc/html/rfc8018#section-5.2 5 // 6 7 import ( 8 "crypto/sha1" 9 "crypto/sha256" 10 "crypto/sha512" 11 "crypto/x509/pkix" 12 "encoding/asn1" 13 "errors" 14 "hash" 15 16 "github.com/emmansun/gmsm/sm3" 17 "golang.org/x/crypto/pbkdf2" 18 ) 19 20 var ( 21 oidPKCS5PBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} 22 oidSMPBKDF = asn1.ObjectIdentifier{1, 2, 156, 10197, 6, 4, 1, 5, 1} 23 oidHMACWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7} 24 oidHMACWithSHA224 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 8} 25 oidHMACWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9} 26 oidHMACWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 10} 27 oidHMACWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 11} 28 oidHMACWithSHA512_224 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 12} 29 oidHMACWithSHA512_256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 13} 30 oidHMACWithSM3 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 401, 2} 31 ) 32 33 func init() { 34 RegisterKDF(oidPKCS5PBKDF2, func() KDFParameters { 35 return new(pbkdf2Params) 36 }) 37 RegisterKDF(oidSMPBKDF, func() KDFParameters { 38 return new(pbkdf2Params) 39 }) 40 } 41 42 func newHashFromPRF(oidKDF asn1.ObjectIdentifier, ai pkix.AlgorithmIdentifier) (func() hash.Hash, error) { 43 switch { 44 case len(ai.Algorithm) == 0: // handle default case 45 switch { 46 case oidKDF.Equal(oidSMPBKDF): 47 return sm3.New, nil 48 default: 49 return sha1.New, nil 50 } 51 case ai.Algorithm.Equal(oidHMACWithSHA1): 52 return sha1.New, nil 53 case ai.Algorithm.Equal(oidHMACWithSHA224): 54 return sha256.New224, nil 55 case ai.Algorithm.Equal(oidHMACWithSHA256): 56 return sha256.New, nil 57 case ai.Algorithm.Equal(oidHMACWithSHA384): 58 return sha512.New384, nil 59 case ai.Algorithm.Equal(oidHMACWithSHA512): 60 return sha512.New, nil 61 case ai.Algorithm.Equal(oidHMACWithSHA512_224): 62 return sha512.New512_224, nil 63 case ai.Algorithm.Equal(oidHMACWithSHA512_256): 64 return sha512.New512_256, nil 65 case ai.Algorithm.Equal(oidHMACWithSM3): 66 return sm3.New, nil 67 default: 68 return nil, errors.New("pbes/pbkdf2: unsupported hash function") 69 } 70 } 71 72 func newPRFParamFromHash(h Hash) (pkix.AlgorithmIdentifier, error) { 73 switch h { 74 case SHA1: 75 return pkix.AlgorithmIdentifier{ 76 Algorithm: oidHMACWithSHA1, 77 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 78 case SHA224: 79 return pkix.AlgorithmIdentifier{ 80 Algorithm: oidHMACWithSHA224, 81 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 82 case SHA256: 83 return pkix.AlgorithmIdentifier{ 84 Algorithm: oidHMACWithSHA256, 85 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 86 case SHA384: 87 return pkix.AlgorithmIdentifier{ 88 Algorithm: oidHMACWithSHA384, 89 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 90 case SHA512: 91 return pkix.AlgorithmIdentifier{ 92 Algorithm: oidHMACWithSHA512, 93 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 94 case SHA512_224: 95 return pkix.AlgorithmIdentifier{ 96 Algorithm: oidHMACWithSHA512_224, 97 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 98 case SHA512_256: 99 return pkix.AlgorithmIdentifier{ 100 Algorithm: oidHMACWithSHA512_256, 101 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 102 case SM3: 103 return pkix.AlgorithmIdentifier{ 104 Algorithm: oidHMACWithSM3, 105 Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil 106 107 } 108 return pkix.AlgorithmIdentifier{}, errors.New("pbes/pbkdf2: unsupported hash function") 109 } 110 111 // PBKDF2-params ::= SEQUENCE { 112 // salt CHOICE { 113 // specified OCTET STRING, 114 // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 115 // }, 116 // iterationCount INTEGER (1..MAX), 117 // keyLength INTEGER (1..MAX) OPTIONAL, 118 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 119 // } 120 type pbkdf2Params struct { 121 Salt []byte 122 IterationCount int 123 KeyLen int `asn1:"optional"` 124 PRF pkix.AlgorithmIdentifier `asn1:"optional"` 125 } 126 127 func (p pbkdf2Params) DeriveKey(oidKDF asn1.ObjectIdentifier, password []byte, size int) (key []byte, err error) { 128 h, err := newHashFromPRF(oidKDF, p.PRF) 129 if err != nil { 130 return nil, err 131 } 132 return pbkdf2.Key(password, p.Salt, p.IterationCount, size, h), nil 133 } 134 135 // KeyLength returns the length of the derived key. 136 func (p pbkdf2Params) KeyLength() int { 137 return p.KeyLen 138 } 139 140 // PBKDF2Opts contains options for the PBKDF2 key derivation function. 141 type PBKDF2Opts struct { 142 SaltSize int 143 IterationCount int 144 HMACHash Hash 145 pbkdfOID asn1.ObjectIdentifier 146 } 147 148 // NewPBKDF2Opts returns a new PBKDF2Opts with the specified parameters. 149 func NewPBKDF2Opts(hash Hash, saltSize, iterationCount int) PBKDF2Opts { 150 return PBKDF2Opts{ 151 SaltSize: saltSize, 152 IterationCount: iterationCount, 153 HMACHash: hash, 154 pbkdfOID: oidPKCS5PBKDF2, 155 } 156 } 157 158 // NewSMPBKDF2Opts returns a new PBKDF2Opts (ShangMi PBKDF) with the specified parameters. 159 func NewSMPBKDF2Opts(saltSize, iterationCount int) PBKDF2Opts { 160 return PBKDF2Opts{ 161 SaltSize: saltSize, 162 IterationCount: iterationCount, 163 HMACHash: SM3, 164 pbkdfOID: oidSMPBKDF, 165 } 166 } 167 168 func (p PBKDF2Opts) DeriveKey(password, salt []byte, size int) ( 169 key []byte, params KDFParameters, err error) { 170 171 key = pbkdf2.Key(password, salt, p.IterationCount, size, p.HMACHash.New) 172 prfParam, err := newPRFParamFromHash(p.HMACHash) 173 if err != nil { 174 return nil, nil, err 175 } 176 params = pbkdf2Params{salt, p.IterationCount, size, prfParam} 177 return key, params, nil 178 } 179 180 func (p PBKDF2Opts) GetSaltSize() int { 181 return p.SaltSize 182 } 183 184 func (p PBKDF2Opts) OID() asn1.ObjectIdentifier { 185 // If the OID is not set, use the default OID for PBKDF2 186 if p.pbkdfOID == nil { 187 return oidPKCS5PBKDF2 188 } 189 return p.pbkdfOID 190 }