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/

Reply via email to