1  
     2  
     3  
     4  
     5  package pbkdf2
     6  
     7  import (
     8  	"crypto/internal/fips140"
     9  	"crypto/internal/fips140/hmac"
    10  	"errors"
    11  	"hash"
    12  )
    13  
    14  
    15  
    16  
    17  
    18  
    19  func divRoundUp(x, y int) int {
    20  	return int((int64(x) + int64(y) - 1) / int64(y))
    21  }
    22  
    23  func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
    24  	setServiceIndicator(salt, keyLength)
    25  
    26  	if keyLength <= 0 {
    27  		return nil, errors.New("pkbdf2: keyLength must be larger than 0")
    28  	}
    29  
    30  	prf := hmac.New(h, []byte(password))
    31  	hmac.MarkAsUsedInKDF(prf)
    32  	hashLen := prf.Size()
    33  	numBlocks := divRoundUp(keyLength, hashLen)
    34  	const maxBlocks = int64(1<<32 - 1)
    35  	if keyLength+hashLen < keyLength || int64(numBlocks) > maxBlocks {
    36  		return nil, errors.New("pbkdf2: keyLength too long")
    37  	}
    38  
    39  	var buf [4]byte
    40  	dk := make([]byte, 0, numBlocks*hashLen)
    41  	U := make([]byte, hashLen)
    42  	for block := 1; block <= numBlocks; block++ {
    43  		
    44  		
    45  		
    46  		prf.Reset()
    47  		prf.Write(salt)
    48  		buf[0] = byte(block >> 24)
    49  		buf[1] = byte(block >> 16)
    50  		buf[2] = byte(block >> 8)
    51  		buf[3] = byte(block)
    52  		prf.Write(buf[:4])
    53  		dk = prf.Sum(dk)
    54  		T := dk[len(dk)-hashLen:]
    55  		copy(U, T)
    56  
    57  		
    58  		for n := 2; n <= iter; n++ {
    59  			prf.Reset()
    60  			prf.Write(U)
    61  			U = U[:0]
    62  			U = prf.Sum(U)
    63  			for x := range U {
    64  				T[x] ^= U[x]
    65  			}
    66  		}
    67  	}
    68  	return dk[:keyLength], nil
    69  }
    70  
    71  func setServiceIndicator(salt []byte, keyLength int) {
    72  	
    73  	
    74  	
    75  
    76  	
    77  	if len(salt) < 128/8 {
    78  		fips140.RecordNonApproved()
    79  	}
    80  
    81  	
    82  	
    83  	if keyLength < 112/8 {
    84  		fips140.RecordNonApproved()
    85  	}
    86  
    87  	fips140.RecordApproved()
    88  }
    89  
View as plain text