v/vlib/crypto/pbkdf2/pbkdf2.v

67 lines
1.4 KiB
V

// Based off: https://golang.org/x/crypto/pbkdf2
module pbkdf2
import crypto.hmac
import crypto.sha256
import crypto.sha512
import hash
// key derives a key from the password, salt and iteration count
// example pbkdf2.key('test'.bytes(), '123456'.bytes(), 1000, 64, sha512.new())
pub fn key(password []u8, salt []u8, count int, key_length int, h hash.Hash) ![]u8 {
mut fun := fn (b []u8) []u8 {
return []u8{}
}
mut block_size := 0
mut size := 0
match h {
sha256.Digest {
block_size = h.block_size()
size = h.size()
if size == sha256.size224 {
fun = sha256.sum224
} else {
fun = sha256.sum256
}
}
sha512.Digest {
block_size = h.block_size()
size = h.size()
if size == sha512.size384 {
fun = sha512.sum384
} else {
fun = sha512.sum512
}
}
else {
panic('Unsupported hash')
}
}
hash_length := size
block_count := (key_length + hash_length - 1) / hash_length
mut output := []u8{}
mut last := []u8{}
mut buf := []u8{len: 4}
for i := 1; i <= block_count; i++ {
last.clear()
last << salt
buf[0] = u8(i >> 24)
buf[1] = u8(i >> 16)
buf[2] = u8(i >> 8)
buf[3] = u8(i)
last << buf
mut xorsum := hmac.new(password, last, fun, block_size)
mut last_hash := xorsum.clone()
for j := 1; j < count; j++ {
last_hash = hmac.new(password, last_hash, fun, block_size)
for k in 0 .. xorsum.len {
xorsum[k] ^= last_hash[k]
}
}
output << xorsum
}
return output[..key_length]
}