kdf_pbkdf2.go raw

   1  package pkcs8
   2  
   3  import (
   4  	"crypto"
   5  	"crypto/sha1"
   6  	"crypto/sha256"
   7  	"crypto/x509/pkix"
   8  	"encoding/asn1"
   9  	"errors"
  10  	"hash"
  11  
  12  	"golang.org/x/crypto/pbkdf2"
  13  )
  14  
  15  var (
  16  	oidPKCS5PBKDF2        = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12}
  17  	oidHMACWithSHA1       = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7}
  18  	oidHMACWithSHA256     = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9}
  19  )
  20  
  21  func init() {
  22  	RegisterKDF(oidPKCS5PBKDF2, func() KDFParameters {
  23  		return new(pbkdf2Params)
  24  	})
  25  }
  26  
  27  func newHashFromPRF(ai pkix.AlgorithmIdentifier) (func() hash.Hash, error) {
  28  	switch {
  29  	case len(ai.Algorithm) == 0 || ai.Algorithm.Equal(oidHMACWithSHA1):
  30  		return sha1.New, nil
  31  	case ai.Algorithm.Equal(oidHMACWithSHA256):
  32  		return sha256.New, nil
  33  	default:
  34  		return nil, errors.New("pkcs8: unsupported hash function")
  35  	}
  36  }
  37  
  38  func newPRFParamFromHash(h crypto.Hash) (pkix.AlgorithmIdentifier, error) {
  39  	switch h {
  40  	case crypto.SHA1:
  41  		return pkix.AlgorithmIdentifier{
  42  			Algorithm:  oidHMACWithSHA1,
  43  			Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil
  44  	case crypto.SHA256:
  45  		return pkix.AlgorithmIdentifier{
  46  			Algorithm:  oidHMACWithSHA256,
  47  			Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil
  48  	}
  49  	return pkix.AlgorithmIdentifier{}, errors.New("pkcs8: unsupported hash function")
  50  }
  51  
  52  type pbkdf2Params struct {
  53  	Salt           []byte
  54  	IterationCount int
  55  	PRF            pkix.AlgorithmIdentifier `asn1:"optional"`
  56  }
  57  
  58  func (p pbkdf2Params) DeriveKey(password []byte, size int) (key []byte, err error) {
  59  	h, err := newHashFromPRF(p.PRF)
  60  	if err != nil {
  61  		return nil, err
  62  	}
  63  	return pbkdf2.Key(password, p.Salt, p.IterationCount, size, h), nil
  64  }
  65  
  66  // PBKDF2Opts contains options for the PBKDF2 key derivation function.
  67  type PBKDF2Opts struct {
  68  	SaltSize       int
  69  	IterationCount int
  70  	HMACHash       crypto.Hash
  71  }
  72  
  73  func (p PBKDF2Opts) DeriveKey(password, salt []byte, size int) (
  74  	key []byte, params KDFParameters, err error) {
  75  
  76  	key = pbkdf2.Key(password, salt, p.IterationCount, size, p.HMACHash.New)
  77  	prfParam, err := newPRFParamFromHash(p.HMACHash)
  78  	if err != nil {
  79  		return nil, nil, err
  80  	}
  81  	params = pbkdf2Params{salt, p.IterationCount, prfParam}
  82  	return key, params, nil
  83  }
  84  
  85  func (p PBKDF2Opts) GetSaltSize() int {
  86  	return p.SaltSize
  87  }
  88  
  89  func (p PBKDF2Opts) OID() asn1.ObjectIdentifier {
  90  	return oidPKCS5PBKDF2
  91  }
  92