1 // Written in the D programming language.
2 
3 module wrapper.sodium.crypto_pwhash;
4 
5 import wrapper.sodium.core; // assure sodium got initialized
6 
7 public
8 import  deimos.sodium.crypto_pwhash : crypto_pwhash_ALG_ARGON2I13,
9                                       crypto_pwhash_alg_argon2i13,
10                                       crypto_pwhash_ALG_DEFAULT,
11                                       crypto_pwhash_alg_default,
12                                       crypto_pwhash_BYTES_MIN,
13                                       crypto_pwhash_bytes_min,
14                                       crypto_pwhash_BYTES_MAX,
15                                       crypto_pwhash_bytes_max,
16                                       crypto_pwhash_PASSWD_MIN,
17                                       crypto_pwhash_passwd_min,
18                                       crypto_pwhash_PASSWD_MAX,
19                                       crypto_pwhash_passwd_max,
20                                       crypto_pwhash_SALTBYTES,
21                                       crypto_pwhash_saltbytes,
22                                       crypto_pwhash_STRBYTES,
23                                       crypto_pwhash_strbytes,
24                                       crypto_pwhash_STRPREFIX,
25 //                                    crypto_pwhash_strprefix,
26                                       crypto_pwhash_OPSLIMIT_MIN,
27                                       crypto_pwhash_opslimit_min,
28                                       crypto_pwhash_OPSLIMIT_MAX,
29                                       crypto_pwhash_opslimit_max,
30                                       crypto_pwhash_MEMLIMIT_MIN,
31                                       crypto_pwhash_memlimit_min,
32                                       crypto_pwhash_MEMLIMIT_MAX,
33                                       crypto_pwhash_memlimit_max,
34                                       crypto_pwhash_OPSLIMIT_INTERACTIVE,
35                                       crypto_pwhash_opslimit_interactive,
36                                       crypto_pwhash_MEMLIMIT_INTERACTIVE,
37                                       crypto_pwhash_memlimit_interactive,
38                                       crypto_pwhash_OPSLIMIT_MODERATE,
39                                       crypto_pwhash_opslimit_moderate,
40                                       crypto_pwhash_MEMLIMIT_MODERATE,
41                                       crypto_pwhash_memlimit_moderate,
42                                       crypto_pwhash_OPSLIMIT_SENSITIVE,
43                                       crypto_pwhash_opslimit_sensitive,
44                                       crypto_pwhash_MEMLIMIT_SENSITIVE,
45                                       crypto_pwhash_memlimit_sensitive,
46 //                                    crypto_pwhash,
47 //                                    crypto_pwhash_str,
48 //                                    crypto_pwhash_str_verify,
49                                       crypto_pwhash_PRIMITIVE;
50 //                                    crypto_pwhash_primitive;
51 
52 import std.exception : assertThrown;
53 import nogc.exception: enforce;
54 
55 string crypto_pwhash_strprefix() pure nothrow @nogc @trusted
56 {
57   import std.string : fromStringz;
58   static import deimos.sodium.crypto_pwhash;
59   const(char)[] c_arr;
60   try
61     c_arr = fromStringz(deimos.sodium.crypto_pwhash.crypto_pwhash_strprefix()); // strips terminating \0
62   catch (Exception e) { /* known not to throw */ }
63   return c_arr;
64 }
65 
66 string crypto_pwhash_primitive() pure nothrow @nogc @trusted
67 {
68   import std.string : fromStringz;
69   static import deimos.sodium.crypto_pwhash;
70   const(char)[] c_arr;
71   try
72     c_arr = fromStringz(deimos.sodium.crypto_pwhash.crypto_pwhash_primitive()); // strips terminating \0
73   catch (Exception e) { /* known not to throw */ }
74   return c_arr;
75 }
76 
77 // overload
78 
79 alias crypto_pwhash = deimos.sodium.crypto_pwhash.crypto_pwhash;
80 
81 /** Key derivation
82  */
83 bool crypto_pwhash(scope ubyte[] out_,
84                    scope const string passwd,
85                    const ubyte[crypto_pwhash_SALTBYTES] salt,
86                    ulong opslimit, size_t memlimit, int alg) @nogc @trusted
87 {
88 //  enforce(out_.length >= crypto_pwhash_BYTES_MIN, "Expected out_.length: ", out_.length, " to be greater_equal to crypto_pwhash_BYTES_MIN: ", crypto_pwhash_BYTES_MIN);
89   enforce(out_.length >= crypto_pwhash_BYTES_MIN, "Expected out_.length is not greater_equal to crypto_pwhash_BYTES_MIN");
90   return  crypto_pwhash(out_.ptr, out_.length, passwd.ptr, passwd.length, salt.ptr, opslimit, memlimit, alg) == 0;
91 }
92 
93 /** Password storage  hash generation (with same parameters as used for key derivation)
94  */
95 alias crypto_pwhash_str = deimos.sodium.crypto_pwhash.crypto_pwhash_str;
96 
97 pragma(inline, true)
98 bool crypto_pwhash_str(out char[crypto_pwhash_STRBYTES] out_,
99                        scope const string passwd,
100                        const ulong opslimit, const size_t memlimit) pure nothrow @nogc @trusted
101 {
102   return  crypto_pwhash_str(out_, passwd.ptr, passwd.length, opslimit, memlimit) == 0;
103 }
104 
105 
106 /** Password storage  hash verification
107  */
108 alias crypto_pwhash_str_verify = deimos.sodium.crypto_pwhash.crypto_pwhash_str_verify;
109 
110 pragma(inline, true)
111 bool crypto_pwhash_str_verify(const char[crypto_pwhash_STRBYTES] str, scope const string passwd) pure nothrow @nogc @trusted
112 {
113   return  crypto_pwhash_str_verify(str, passwd.ptr, passwd.length) == 0;
114 }
115 
116 
117 @safe
118 unittest {
119   import wrapper.sodium.randombytes : randombytes;
120   import wrapper.sodium.crypto_box  : crypto_box_SEEDBYTES;
121   import std.string: toStringz;
122   import std.stdio: writeln, writefln;
123   debug writeln("unittest block 1 from sodium.crypto_pwhash.d");
124 
125   assert(crypto_pwhash_alg_argon2i13()        == crypto_pwhash_ALG_ARGON2I13);
126   assert(crypto_pwhash_alg_default()          == crypto_pwhash_ALG_DEFAULT);
127   assert(crypto_pwhash_bytes_min()            == crypto_pwhash_BYTES_MIN);
128   assert(crypto_pwhash_bytes_max()            == crypto_pwhash_BYTES_MAX);
129   assert(crypto_pwhash_passwd_min()           == crypto_pwhash_PASSWD_MIN);
130   assert(crypto_pwhash_passwd_max()           == crypto_pwhash_PASSWD_MAX);
131   assert(crypto_pwhash_saltbytes()            == crypto_pwhash_SALTBYTES);
132   assert(crypto_pwhash_strbytes()             == crypto_pwhash_STRBYTES);
133   assert(crypto_pwhash_strprefix()            == crypto_pwhash_STRPREFIX);
134   assert(crypto_pwhash_opslimit_min()         == crypto_pwhash_OPSLIMIT_MIN); // 3
135   assert(crypto_pwhash_opslimit_max()         == crypto_pwhash_OPSLIMIT_MAX); // 4294967295
136   assert(crypto_pwhash_memlimit_min()         == crypto_pwhash_MEMLIMIT_MIN); // 8192
137   assert(crypto_pwhash_memlimit_max()         == crypto_pwhash_MEMLIMIT_MAX); // 4398046510080
138   assert(crypto_pwhash_opslimit_interactive() == crypto_pwhash_OPSLIMIT_INTERACTIVE); // 4
139   assert(crypto_pwhash_memlimit_interactive() == crypto_pwhash_MEMLIMIT_INTERACTIVE); // 33554432
140   assert(crypto_pwhash_opslimit_moderate()    == crypto_pwhash_OPSLIMIT_MODERATE);    // 6
141   assert(crypto_pwhash_memlimit_moderate()    == crypto_pwhash_MEMLIMIT_MODERATE);    // 134217728
142   assert(crypto_pwhash_opslimit_sensitive()   == crypto_pwhash_OPSLIMIT_SENSITIVE);   // 8
143   assert(crypto_pwhash_memlimit_sensitive()   == crypto_pwhash_MEMLIMIT_SENSITIVE);   // 536870912
144   assert(crypto_pwhash_primitive()            == crypto_pwhash_PRIMITIVE);
145 
146   enum password = "Correct Horse Battery Staple";
147   ubyte[crypto_pwhash_SALTBYTES] salt = void; // 16
148   randombytes(salt);
149   ubyte[crypto_box_SEEDBYTES]     key = void; // 32
150 
151   assertThrown(crypto_pwhash(key[0..15], password, salt, crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT));
152   assert(crypto_pwhash(key, password, salt, crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT));
153 //  writefln("crypto_pwhash key generated:    0x%(%02x%)", key);   // 0xddf58869c0523709d57f2b532f4b82105882093cd3eaf0ad1623740c44f34089
154 //  writefln("crypto_pwhash salt used:        0x%(%02x%)", salt);  // 0x7714bdc12f92efcadc9b8970394db0e5
155 
156   char[crypto_pwhash_STRBYTES] password_storage;
157   assert(crypto_pwhash_str(password_storage, password, crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE));
158 //  writeln("crypto_pwhash password_storage: ", password_storage); // $argon2i$v=19$m=32768,t=4,p=1$tfIofMr8IvXqKOwQt9iqcg$QGqBmFMcxeGptuTbq698i7KOC6oO8jw7VuVaPUWXeMQ
159   assert(crypto_pwhash_str_verify(password_storage, password));
160 }