1 /**
2 * PBKDF1
3 * 
4 * Copyright:
5 * (C) 1999-2007 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.pbkdf1;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_PBKDF1):
15 
16 import botan.pbkdf.pbkdf;
17 import botan.hash.hash;
18 import std.datetime;
19 import botan.utils.exceptn;
20 import botan.utils.types;
21 import botan.algo_base.symkey;
22 import std.algorithm : min;
23 
24 /**
25 * PKCS #5 v1 PBKDF, aka PBKDF1
26 * Can only generate a key up to the size of the hash output.
27 * Unless needed for backwards compatability, use PKCS5_PBKDF2
28 */
29 final class PKCS5_PBKDF1 : PBKDF
30 {
31 public:
32     /**
33     * Create a PKCS #5 instance using the specified hash function.
34     *
35     * Params:
36     *  hash_input = pointer to a hash function object to use
37     */
38     this(HashFunction hash_input)
39     {
40         m_hash = hash_input;
41     }
42 
43     override @property string name() const
44     {
45         return "PBKDF1(" ~ m_hash.name ~ ")";
46     }
47 
48     override PBKDF clone() const
49     {
50         return new PKCS5_PBKDF1(m_hash.clone());
51     }
52 
53     /*
54     * Return a PKCS#5 PBKDF1 derived key
55     */
56     override Pair!(size_t, OctetString) keyDerivation(size_t key_len,
57                                                       in string passphrase,
58                                                       const(ubyte)* salt, size_t salt_len,
59                                                       size_t iterations,
60                                                       Duration loop_for) const
61     {
62         if (key_len > m_hash.outputLength)
63             throw new InvalidArgument("PKCS5_PBKDF1: Requested output length too long");
64         Unique!HashFunction hash = m_hash.clone();
65         hash.update(passphrase);
66         hash.update(salt, salt_len);
67         SecureVector!ubyte key = hash.finished();
68 
69         const start = Clock.currTime(UTC());
70         size_t iterations_performed = 1;
71         
72         while (true)
73         {
74             if (iterations == 0)
75             {
76                 if (iterations_performed % 10000 == 0)
77                 {
78                     auto time_taken = Clock.currTime(UTC()) - start;
79                     if (time_taken > loop_for)
80                         break;
81                 }
82             }
83             else if (iterations_performed == iterations)
84                 break;
85             
86             hash.update(key);
87             hash.flushInto(key.ptr);
88             
89             ++iterations_performed;
90         }
91         
92         return makePair(iterations_performed, OctetString(key.ptr, min(key_len, key.length)));
93     }
94 private:
95     Unique!HashFunction m_hash;
96 }
97