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  }