Vibe.d Password Verification

Matthew monkeytonk115 at gmail.com
Sat Feb 8 20:09:46 UTC 2025


On Wednesday, 5 February 2025 at 15:16:10 UTC, seany wrote:
> Is there any built in passowrd verification for Vibe.d? Such as 
> bcrypt.verifypassword(password , hash)?
> ...
> Thank you.

I would agree with Jonathan and use a C library. I was just 
looking for a password solution myself also for a vibe.d project. 
The OWASP [0] recommends argon2id [1] so I chose that but I'm 
sure similar applies to bcrypt or scrypt.

I have just written the following test program to check it works 
(and to check I understand how argon2id works).

I copied and pasted the definitions I needed from 
`/usr/include/argon2.h`. Mark them as `extern(C)`. I added two 
alias definitions because D doesn't have `uint32_t` or 
`argon2_type`.

Because they are C functions, they take the password, salt, and 
hash as pointers and length argument pairs, so for a D string we 
use password.ptr and password.length.

```D
import std.stdio;
import std.string;
import std.getopt;

alias uint32_t = size_t;
alias argon2_type = uint;

extern(C)
int argon2id_hash_encoded(
   const uint32_t t_cost,
   const uint32_t m_cost,
   const uint32_t parallelism,
   const void *pwd,
   const size_t pwdlen,
   const void *salt,
   const size_t saltlen,
   const size_t hashlen,
   char *encoded,
   const size_t encodedlen);

extern(C)
size_t argon2_encodedlen(
   uint32_t t_cost,
   uint32_t m_cost,
   uint32_t parallelism,
   uint32_t saltlen,
   uint32_t hashlen,
   argon2_type type);

enum Argon2_id = 2;
enum HASHLEN = 32;

void main(string[] args)
{
   // Bind arguments
   string salt;
   string password;
   uint t_cost;
   uint m_cost;
   uint p_cost;
   char[] encoded_hash;

   getopt(args,
     "salt", &salt,
     "password", &password,
     "t", &t_cost,
     "m", &m_cost,
     "p", &p_cost
   );

   // calculate and allocate space for the encoded hash string
   size_t encodedlen = argon2_encodedlen(t_cost, m_cost, p_cost, 
salt.length, HASHLEN, Argon2_id);
   encoded_hash = new char[encodedlen];

   int err = argon2id_hash_encoded(
     t_cost, m_cost, p_cost,
     password.ptr, password.length,
     salt.ptr, salt.length,
     HASHLEN,
     encoded_hash.ptr, encoded_hash.length
   );

   writefln("err: %d", err);
   writefln("password: %s", password);
   writefln("salt: %s", salt);
   writefln("hash: %s", encoded_hash);
}
```

I added argon2 to dub.json libs section
```json
{
   "authors": [
     "matthew"
   ],
   "copyright": "Copyright © 2025, matthew",
   "description": "A minimal D application.",
   "license": "proprietary",
   "name": "argon_test",
   "libs": [
     "argon2"
   ]
}
```

`dub build` and `ldd` shows it is dynamically linked to 
`/usr/lib/libargon2.so.1`.

```sh
> dub build
     Starting Performing "debug" build using /usr/bin/dmd for 
x86_64.
     Building argon_test ~master: building configuration 
[application]
      Linking argon_test
> ldd argon_test
         linux-vdso.so.1 (0x00007f393ed43000)
         libargon2.so.1 => /usr/lib/libargon2.so.1 
(0x00007f393ebd5000)
         libm.so.6 => /usr/lib/libm.so.6 (0x00007f393eae6000)
         libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 
(0x00007f393eab8000)
         libc.so.6 => /usr/lib/libc.so.6 (0x00007f393e8c7000)
         /lib64/ld-linux-x86-64.so.2 => 
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f393ed45000)
```

It gives the same encoded hash as the `argon2` command line 
utility so it's probably correct.

```sh
> ./argon_test --password 'password' --salt 'wipqozn123456789' -t
4 -m 163840 -p 2
err: 0
password: password
salt: wipqozn123456789
hash: 
$argon2id$v=19$m=163840,t=4,p=2$d2lwcW96bjEyMzQ1Njc4OQ$So4Z3TuftM1BZcnTpz96MqM/54W9zViOIhdfRwD1ZM4

> printf 'password' | argon2 'wipqozn123456789' -id -t 4 -k 
> 163840 -p 2
Type:           Argon2id
Iterations:     4
Memory:         163840 KiB
Parallelism:    2
Hash:           
4a8e19dd3b9fb4cd4165c9d3a73f7a32a33fe785bdcd588e22175f4700f564ce
Encoded:        
$argon2id$v=19$m=163840,t=4,p=2$d2lwcW96bjEyMzQ1Njc4OQ$So4Z3TuftM1BZcnTpz96MqM/54W9zViOIhdfRwD1ZM4
0.350 seconds
Verification ok
```

Wrap it into a nice D module with proper strings instead of 
`char*` then import it from your other file.
Verification of passwords with hashes and turning this into a 
vibe.d route is left as an excercise to the reader.

On my machine (arch btw) `/usr/include/argon2.h`, 
`/usr/lib/libargon2.so`, and `/usr/bin/argon2` are provided by 
the `argon2`[2] package. I can only asume BSD would have an 
argon2 package.

Hope this helps.

Regards,
Matthew

[0] 
https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
[1] https://github.com/P-H-C/phc-winner-argon2
[2] https://archlinux.org/packages/extra/x86_64/argon2/


More information about the Digitalmars-d-learn mailing list