How do I re-build django's password hashing in nim?

I'm rewriting my webapplication from Python (Django) to Nim (Prologue). I want to keep using Django's database that it has provided me with thus far, but I'm struggling how to re-build the way Django encrypts the password. That is, according to Django's own documentation:

By default, Django uses the PBKDF2 algorithm with a SHA256 hash

I found the nimcrypto library as a starting point, but given my lack of cryptographic knowledge a lot of the terminology in there and how to use the given procs goes completely over my head. How can I rebuild the Django encryption using it?


Solution 1:

Warning: As has been pointed out to me, it might be a better idea to use a nim-wrapper of libsodium for this, as it is the more established library. How you would do that is beyond me though, as libsodium has no obvious "pbkdf2" functions.

After researching this topic for a fair bit and going over the code in the django repo and the nimcrypto lib, I was able to reproduce the hashes I have in my database. The key here is, that nimcrypto has a pbkdf2 proc in a module of the same name, that you need to pass an HMAC type, which contains the sha256 algorithm as well as your server's secret key. You also need to be aware that the hashes stored in your database as strings will have the number of iterations and salt appended to them. They'll also be base64 encoded versions of the hash.

import nimcrypto
import nimcrypto/pbkdf2
import base64

var hctx: HMAC[sha256]
let serverSecretKey = "YourServersSecretKeyInDjangoFromSettings"
hctx.init(serverSecretKey)

let password = "thePasswordToHash"
let salt = "asalt" #<-- You have to get this one from the passwords entry in your database
var output: array[32, byte] # <-- 256 bits stored in 32 bytes
let iterations = 180000 # <-- You have to get this one from the passwords entry in your database

discard pbkdf2(hctx, password, salt, iterations, output) #The output of pbkdf2 is irrelevant, you care of the hash in the `output` byte array aka the digest

let newHash = encode(output) # This turns the byte.array into a base64 encoded string. That string should be identical to the hash-string you have in your database.