...

Source file src/github.com/xdg-go/pbkdf2/pbkdf2.go

Documentation: github.com/xdg-go/pbkdf2

     1  // Copyright 2021 by David A. Golden. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  // Package pbkdf2 implements password-based key derivation using the PBKDF2
     8  // algorithm described in RFC 2898 and RFC 8018.
     9  //
    10  // It provides a drop-in replacement for `golang.org/x/crypto/pbkdf2`, with
    11  // the following benefits:
    12  //
    13  // - Released as a module with semantic versioning
    14  //
    15  // - Does not pull in dependencies for unrelated `x/crypto/*` packages
    16  //
    17  // - Supports Go 1.9+
    18  //
    19  // See https://tools.ietf.org/html/rfc8018#section-4 for security considerations
    20  // in the selection of a salt and iteration count.
    21  package pbkdf2
    22  
    23  import (
    24  	"crypto/hmac"
    25  	"encoding/binary"
    26  	"hash"
    27  )
    28  
    29  // Key generates a derived key from a password using the PBKDF2 algorithm. The
    30  // inputs include salt bytes, the iteration count, desired key length, and a
    31  // constructor for a hashing function.  For example, for a 32-byte key using
    32  // SHA-256:
    33  //
    34  //  key := Key([]byte("trustNo1"), salt, 10000, 32, sha256.New)
    35  func Key(password, salt []byte, iterCount, keyLen int, h func() hash.Hash) []byte {
    36  	prf := hmac.New(h, password)
    37  	hLen := prf.Size()
    38  	numBlocks := keyLen / hLen
    39  	// Get an extra block if keyLen is not an even number of hLen blocks.
    40  	if keyLen%hLen > 0 {
    41  		numBlocks++
    42  	}
    43  
    44  	Ti := make([]byte, hLen)
    45  	Uj := make([]byte, hLen)
    46  	dk := make([]byte, 0, hLen*numBlocks)
    47  	buf := make([]byte, 4)
    48  
    49  	for i := uint32(1); i <= uint32(numBlocks); i++ {
    50  		// Initialize Uj for j == 1 from salt and block index.
    51  		// Initialize Ti = U1.
    52  		binary.BigEndian.PutUint32(buf, i)
    53  		prf.Reset()
    54  		prf.Write(salt)
    55  		prf.Write(buf)
    56  		Uj = Uj[:0]
    57  		Uj = prf.Sum(Uj)
    58  
    59  		// Ti = U1 ^ U2 ^ ... ^ Ux
    60  		copy(Ti, Uj)
    61  		for j := 2; j <= iterCount; j++ {
    62  			prf.Reset()
    63  			prf.Write(Uj)
    64  			Uj = Uj[:0]
    65  			Uj = prf.Sum(Uj)
    66  			for k := range Uj {
    67  				Ti[k] ^= Uj[k]
    68  			}
    69  		}
    70  
    71  		// DK = concat(T1, T2, ... Tn)
    72  		dk = append(dk, Ti...)
    73  	}
    74  
    75  	return dk[0:keyLen]
    76  }
    77  

View as plain text