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 }