1 /**
2 * PBKDF
3 * 
4 * Copyright:
5 * (C) 1999-2007,2012 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.pbkdf.pbkdf;
12 
13 import botan.constants;
14 import botan.algo_base.symkey;
15 import std.datetime;
16 import std.exception;
17 import botan.utils.types;
18 
19 /**
20 * Base class for PBKDF (password based key derivation function)
21 * implementations. Converts a password into a key using a salt
22 * and iterated hashing to make brute force attacks harder.
23 */
24 interface PBKDF
25 {
26 public:
27     /**
28     * Returns: new instance of this same algorithm
29     */
30     PBKDF clone() const;
31 
32     @property string name() const;
33 
34     /**
35     * Derive a key from a passphrase
36     * Params:
37     *  output_len = the desired length of the key to produce
38     *  passphrase = the password to derive the key from
39     *  salt = a randomly chosen salt
40     *  salt_len = length of salt in bytes
41     *  iterations = the number of iterations to use (use 10K or more)
42     */
43     final OctetString deriveKey(size_t output_len,
44                                 in string passphrase,
45                                 const(ubyte)* salt, size_t salt_len,
46                                 size_t iterations) const
47     {
48         if (iterations == 0)
49             throw new InvalidArgument(name ~ ": Invalid iteration count");
50         
51         auto derived = keyDerivation(output_len, passphrase,
52                                      salt, salt_len, iterations,
53                                      Duration.zero);
54         
55         assert(derived.first == iterations,
56                      "PBKDF used the correct number of iterations");
57         
58         return derived.second;
59     }
60 
61     /**
62     * Derive a key from a passphrase
63     * Params:
64     *  output_len = the desired length of the key to produce
65     *  passphrase = the password to derive the key from
66     *  salt = a randomly chosen salt
67     *  iterations = the number of iterations to use (use 10K or more)
68     */
69     final OctetString deriveKey(Alloc)(size_t output_len,
70                                        in string passphrase,
71                                        const ref Vector!( ubyte, Alloc ) salt,
72                                        size_t iterations) const
73     {
74         return deriveKey(output_len, passphrase, salt.ptr, salt.length, iterations);
75     }
76 
77     /**
78     * Derive a key from a passphrase
79     * Params:
80     *  output_len = the desired length of the key to produce
81     *  passphrase = the password to derive the key from
82     *  salt = a randomly chosen salt
83     *  salt_len = length of salt in bytes
84     *  loop_for = is how long to run the PBKDF
85     *  iterations = is set to the number of iterations used
86     */
87     final OctetString deriveKey(size_t output_len,
88                            in string passphrase,
89                            const(ubyte)* salt, size_t salt_len,
90                            Duration loop_for,
91                            ref size_t iterations) const
92     {
93         auto derived = keyDerivation(output_len, passphrase, salt, salt_len, 0, loop_for);
94         
95         iterations = derived.first;
96         
97         return derived.second;
98     }
99 
100     /**
101     * Derive a key from a passphrase using a certain amount of time
102     * Params:
103     *  output_len = the desired length of the key to produce
104     *  passphrase = the password to derive the key from
105     *  salt = a randomly chosen salt
106     *  loop_for = is how long to run the PBKDF
107     *  iterations = is set to the number of iterations used
108     */
109     final OctetString deriveKey(Alloc)(size_t output_len,
110                                        in string passphrase,
111                                        const ref Vector!( ubyte, Alloc ) salt,
112                                        Duration loop_for,
113                                        ref size_t iterations) const
114     {
115         return deriveKey(output_len, passphrase, salt.ptr, salt.length, loop_for, iterations);
116     }
117 
118     /**
119     * Derive a key from a passphrase for a number of iterations
120     * specified by either iterations or if iterations == 0 then
121     * running until seconds time has elapsed.
122     *
123     * Params:
124     *  output_len = the desired length of the key to produce
125     *  passphrase = the password to derive the key from
126     *  salt = a randomly chosen salt
127     *  salt_len = length of salt in bytes
128     *  iterations = the number of iterations to use (use 10K or more)
129     *  loop_for = if iterations is zero, then instead the PBKDF is
130     *          run until duration has passed.
131     * Returns: the number of iterations performed and the derived key
132     */
133     Pair!(size_t, OctetString)
134         keyDerivation(size_t output_len,
135                       in string passphrase,
136                       const(ubyte)* salt, size_t salt_len,
137                       size_t iterations,
138                       Duration loop_for) const;
139 }
140 
141 static if (BOTAN_HAS_TESTS && !SKIP_PBKDF_TEST) unittest {
142     logDebug("Testing pbkdf.d ...");
143     import botan.test;
144     import botan.codec.hex;
145     import memutils.hashmap;
146     int total_tests;
147     auto test = delegate(string input) {
148         return runTests(input, "PBKDF", "Output", true,
149              (ref HashMap!(string, string) vec) {
150                 total_tests += 1;
151                 Unique!PBKDF pbkdf = getPbkdf(vec["PBKDF"]);
152                 
153                 const size_t iterations = to!size_t(vec["Iterations"]);
154                 const size_t outlen = to!size_t(vec["OutputLen"]);
155                 const auto salt = hexDecode(vec["Salt"]);
156                 const string pass = vec["Passphrase"];
157                 
158                 const auto key = pbkdf.deriveKey(outlen, pass, salt.ptr, salt.length, iterations).bitsOf();
159                 return hexEncode(key);
160             });
161     };
162     
163     size_t fails = runTestsInDir("../test_data/pbkdf", test);
164 
165     testReport("pbkdf", total_tests, fails);
166 }