JuliaCrypto / Nettle.jl

Julia wrapper around nettle cryptographic hashing/encryption library providing MD5, SHA1, SHA2 hashing and HMAC functionality, as well as AES encryption/decryption

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PBKDF2

synxroform opened this issue · comments

commented

Can you help me with PBKDF2 function ? Can't find it in your library. It will be helpful for web frameworks.

This implements a 1-round PBKDF2 with SHA256. Something to start with anyway.

(from my https://github.com/BioTurboNick/Scrypt.jl)

const HASH_LENGTH = 256 ÷ 8

function pbkdf2_sha256_1(key, salt::Vector{UInt8}, derivedkeylength)
    blockcount = cld(derivedkeylength, HASH_LENGTH)
    lastblockbytes = derivedkeylength - (blockcount - 1) * HASH_LENGTH
    
    salt = [salt; zeros(UInt8, 4)]
    salttail = view(salt, length(salt) - 3:length(salt))
    
    derivedkey = Matrix{UInt8}(undef, HASH_LENGTH, blockcount)

    for i ∈ 1:blockcount
        salttail[:] = reinterpret(UInt8, [UInt32(i)]) |> reverse
        derivedkey[:, i] = digest("sha256", key, salt)
    end

    derivedkey = reshape(derivedkey, blockcount * HASH_LENGTH)[1:derivedkeylength]
    return derivedkey
end

Hi @BioTurboNick I'm trying to implement pbkdf2 using hmac sha512 with multiple iterations. I looked at your script and start from it. Also looking at the documentation to implement it.
At the moment this is the code I got

using SHA

function pbkdf2(key::AbstractString, salt::String, iterations::Int, dklen::Int)::Vector{UInt8}
    hlen = trunc(Int, dklen / 8)
    @assert dklen % hlen === 0
    nblocks = convert(Int, round(dklen / hlen))
    derived_key = Matrix{UInt8}(undef, hlen, nblocks)
    salt_bytes = Vector{UInt8}(salt)

    for i in 1:nblocks
        derived_key[:, i] = pbkdf2_block(key, salt_bytes, iterations, i)
    end
    
    derived_key = reshape(derived_key, nblocks * hlen)[1:dklen]
    return derived_key
end

function pbkdf2_block(key::AbstractString, salt::Vector{UInt8}, iterations::Int, i::Int)::Vector{UInt8}
    salt = [salt; zeros(UInt8, 4)]
    salt_tail = view(salt, length(salt) - 3:length(salt))
    salt_tail[:] = reinterpret(UInt8, [UInt32(i)]) |> reverse

    U1 = hmac_sha2_512(Vector{UInt8}(key), salt)
    Un = U1
    for i in 2:iterations
        Un = Un .⊻ hmac_sha2_512(Vector{UInt8}(key), Un)
    end

    return Un
end

By the way this doesn't seems to return the right result. I'm not a cryptography expert and this is the only thread I've found about PBKDF2 in Julia. Do you have any suggestion?

I'm afraid this isn't really my area. However, I find a good place to start is to try copying a known-good function in another language as close as possible (e.g. don't use broadcasting etc.) so it provides the correct result, and then apply Julia-style to it. Also inspect each step by executing in the REPL to make sure it's doing exactly what you expect it to. At least that'll show you where the problem starts. That's how I would approach solving your issue.