You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
2.1 KiB
76 lines
2.1 KiB
// Copyright 2021 by David A. Golden. All rights reserved. |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may |
|
// not use this file except in compliance with the License. You may obtain |
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
|
|
|
// Package pbkdf2 implements password-based key derivation using the PBKDF2 |
|
// algorithm described in RFC 2898 and RFC 8018. |
|
// |
|
// It provides a drop-in replacement for `golang.org/x/crypto/pbkdf2`, with |
|
// the following benefits: |
|
// |
|
// - Released as a module with semantic versioning |
|
// |
|
// - Does not pull in dependencies for unrelated `x/crypto/*` packages |
|
// |
|
// - Supports Go 1.9+ |
|
// |
|
// See https://tools.ietf.org/html/rfc8018#section-4 for security considerations |
|
// in the selection of a salt and iteration count. |
|
package pbkdf2 |
|
|
|
import ( |
|
"crypto/hmac" |
|
"encoding/binary" |
|
"hash" |
|
) |
|
|
|
// Key generates a derived key from a password using the PBKDF2 algorithm. The |
|
// inputs include salt bytes, the iteration count, desired key length, and a |
|
// constructor for a hashing function. For example, for a 32-byte key using |
|
// SHA-256: |
|
// |
|
// key := Key([]byte("trustNo1"), salt, 10000, 32, sha256.New) |
|
func Key(password, salt []byte, iterCount, keyLen int, h func() hash.Hash) []byte { |
|
prf := hmac.New(h, password) |
|
hLen := prf.Size() |
|
numBlocks := keyLen / hLen |
|
// Get an extra block if keyLen is not an even number of hLen blocks. |
|
if keyLen%hLen > 0 { |
|
numBlocks++ |
|
} |
|
|
|
Ti := make([]byte, hLen) |
|
Uj := make([]byte, hLen) |
|
dk := make([]byte, 0, hLen*numBlocks) |
|
buf := make([]byte, 4) |
|
|
|
for i := uint32(1); i <= uint32(numBlocks); i++ { |
|
// Initialize Uj for j == 1 from salt and block index. |
|
// Initialize Ti = U1. |
|
binary.BigEndian.PutUint32(buf, i) |
|
prf.Reset() |
|
prf.Write(salt) |
|
prf.Write(buf) |
|
Uj = Uj[:0] |
|
Uj = prf.Sum(Uj) |
|
|
|
// Ti = U1 ^ U2 ^ ... ^ Ux |
|
copy(Ti, Uj) |
|
for j := 2; j <= iterCount; j++ { |
|
prf.Reset() |
|
prf.Write(Uj) |
|
Uj = Uj[:0] |
|
Uj = prf.Sum(Uj) |
|
for k := range Uj { |
|
Ti[k] ^= Uj[k] |
|
} |
|
} |
|
|
|
// DK = concat(T1, T2, ... Tn) |
|
dk = append(dk, Ti...) |
|
} |
|
|
|
return dk[0:keyLen] |
|
}
|
|
|