1 module dcrypt.crypto.generators.pbe;
2 
3 public import dcrypt.crypto.params.keyparameter;
4 import std.conv: to;
5 import std.exception: enforce;
6 /**
7  * super class for all Password Based Encryption (PBE) parameter generator classes.
8  */
9 @safe
10 public abstract class PBEParametersGenerator
11 {
12 	protected const(ubyte)[]	password;
13 	protected const(ubyte)[]	salt;
14 	protected uint		iterationCount = 1;
15 	protected uint		iterTime;
16 	
17 	invariant() {
18 		assert(iterationCount > 0 || iterTime > 0, "either iterationCount or iterTime have to be > 0!");
19 	}
20 
21 	/**
22 	 * base constructor.
23 	 */
24 	protected this()
25 	{
26 	}
27 
28 	/**
29 	 * initialize the PBE generator.
30 	 *
31 	 * Params: password = the password converted into bytes (see below).
32 	 * 	 salt	=	the salt to be mixed with the password.
33 	 * 	 iterationCount	=	the (minimal) number of iterations in the "mixing" function
34 	 * is to be applied for.
35 	 * 	iterTime	=	spent at least iterTime milli seconds and at least iterationCount iterations to calculate the password
36 	 * getIterationCount() will return the number of iterations done in the specified time.
37 	 */
38 	public void init(in ubyte[] password, in ubyte[] salt, uint iterationCount, uint iterTime = 0) 
39 	{
40 		enforce(iterTime > 0 || iterationCount > 0, "either iterationCount or iterTime have to be > 0!");
41 		
42 		this.password = password;
43 		this.salt = salt;
44 		this.iterationCount = iterationCount;
45 		this.iterTime = iterTime;
46 	}
47 
48 	/**
49 	 * return the password byte array.
50 	 */
51 	public ubyte[] getPassword() pure nothrow
52 	{
53 		return password.dup;
54 	}
55 
56 	/**
57 	 * return the salt byte array.
58 	 */
59 	public ubyte[] getSalt() pure nothrow
60 	{
61 		return salt.dup;
62 	}
63 
64 	/**
65 	 * Returns: the number of iterations done for the last computation.
66 	 */
67 	public uint getIterationCount() pure nothrow
68 	{
69 		return iterationCount;
70 	}
71 
72 	/**
73 	 * generate derived parameters for a key of length keySize.
74 	 *
75 	 * Param: keySize the length, in bits, of the key required.
76 	 * Returns: a parameters object representing a key.
77 	 */
78 	public abstract KeyParameter generateDerivedParameters(uint keySize);
79 
80 	/**
81 	 * generate derived parameters for a key of length keySize, and
82 	 * an initialisation vector (IV) of length ivSize.
83 	 *
84 	 * Params: keySize = the length, in bits, of the key required.
85 	 * 		ivSize = the length, in bits, of the iv required.
86 	 * Returns: a parameters object representing a key and an IV.
87 	 */
88 	public abstract KeyParameter generateDerivedParameters(uint keySize, uint ivSize);
89 
90 	/**
91 	 * generate derived parameters for a key of length keySize, specifically
92 	 * for use with a MAC.
93 	 *
94 	 * Params: keySize = the length, in bits, of the key required.
95 	 * Returns: a parameters object representing a key.
96 	 */
97 	public abstract KeyParameter generateDerivedMacParameters(uint keySize);
98 
99 	public abstract string getAlgorithmName();
100 
101 }
102 
103 
104 /**
105  * converts a password to a byte array according to the scheme in
106  * PKCS5 (ascii, no padding)
107  *
108  * Params: password = a character array representing the password.
109  * Returns: a byte array representing the password.
110  */
111 @safe
112 public ubyte[] PKCS5PasswordToBytes(in char[] password) pure nothrow
113 {
114 	if (password != null)
115 	{
116 		ubyte[]  bytes = new ubyte[password.length];
117 		
118 		foreach (i; 0..password.length)
119 		{
120 			bytes[i] = cast (ubyte) password[i];
121 		}
122 		
123 		return bytes;
124 	}
125 	else
126 	{
127 		return new ubyte[0];
128 	}
129 }
130 
131 /// test PKCS5PasswordToUTF8Bytes
132 unittest {
133 	assert(PKCS5PasswordToBytes(null) == [], "PKCS5PasswordToBytes(null) failed");
134 	assert(PKCS5PasswordToBytes(x"61415f3021") == [0x61, 0x41, 0x5f, 0x30, 0x21]);
135 	assert(PKCS5PasswordToBytes(x"0061") == [0x00, 0x61]);
136 }
137 
138 
139 /**
140  * converts a password to a byte array according to the scheme in
141  * PKCS5 (UTF-8, no padding)
142  *
143  * Params: password = a character array representing the password.
144  * Returns: a byte array representing the password.
145  */
146 @safe
147 public ubyte[] PKCS5PasswordToUTF8Bytes(in char[] password) pure nothrow
148 {
149 	if(password is null) {
150 		return [];
151 	}
152 	return cast(ubyte[]) password.dup;
153 }
154 
155 
156 /// Test PKCS5PasswordToUTF8Bytes with some special cases.
157 unittest {
158 	assert(PKCS5PasswordToUTF8Bytes(null) == [], "PKCS5PasswordToBytes(null) failed");
159 	assert(PKCS5PasswordToUTF8Bytes(x"00 61 41 5f 30 21") == x"00 61 41 5f 30 21", "PKCS5PasswordToBytes failed");
160 	assert(PKCS5PasswordToUTF8Bytes("ä") == x"C3 A4", "PKCS5PasswordToBytes('ä') failed");
161 	assert(PKCS5PasswordToUTF8Bytes("€") == x"E2 82 AC", "PKCS5PasswordToBytes('€') failed");
162 	assert(PKCS5PasswordToUTF8Bytes("𝄞") == x"F0 9D 84 9E", "PKCS5PasswordToBytes failed");
163 	assert(PKCS5PasswordToUTF8Bytes("𝄞€ä") == x"F0 9D 84 9E E2 82 AC C3 A4", "PKCS5PasswordToBytes failed");
164 }
165 
166 
167 /**
168  * converts a password to a byte array according to the scheme in
169  * PKCS12 (unicode, big endian, 2 zero pad bytes at the end).
170  *
171  * Params: password = a character array representing the password.
172  * Returns: a byte array representing the password.
173  */
174 @safe
175 public ubyte[] PKCS12PasswordToBytes(in char[] password) pure nothrow
176 {
177 	if (password != null && password.length > 0)
178 	{
179 		// +1 for extra 2 pad bytes.
180 		ubyte[]  bytes = new ubyte[(password.length + 1) * 2];
181 		
182 		foreach (i; 0..password.length)
183 		{
184 			bytes[i * 2] = cast(ubyte)(password[i] >>> 8);
185 			bytes[i * 2 + 1] = cast(ubyte)password[i];
186 		}
187 		
188 		return bytes;
189 	}
190 	else
191 	{
192 		return [];
193 	}
194 }