1 module tagion.crypto.aes.AESCrypto; 2 3 import tagion.basic.Debug : __format; 4 5 alias AES128 = AESCrypto!128; 6 alias AES196 = AESCrypto!192; 7 alias AES256 = AESCrypto!256; 8 9 struct AESCrypto(int KEY_LENGTH) { 10 static assert((KEY_LENGTH is 128) || (KEY_LENGTH is 192) || (KEY_LENGTH is 256), 11 format("The KEYLENGTH of the %s must be 128, 196 or 256 not %d", AESCrypto.stringof, KEY_LENGTH)); 12 13 @disable this(); 14 15 static size_t enclength(const size_t inputlength) pure nothrow { 16 return ((inputlength / BLOCK_SIZE) + ((inputlength % BLOCK_SIZE == 0) ? 0 : 1)) * BLOCK_SIZE; 17 } 18 19 import tagion.crypto.aes.tiny_aes.tiny_aes; 20 21 alias AES = Tiny_AES!(KEY_LENGTH, Mode.CBC); 22 enum BLOCK_SIZE = AES.BLOCK_SIZE; 23 enum KEY_SIZE = AES.KEY_SIZE; 24 static void crypt_parse(bool ENCRYPT = true)( 25 const(ubyte[]) key, 26 ubyte[BLOCK_SIZE] iv, 27 ref ubyte[] data) nothrow 28 in (data) 29 in (data.length % BLOCK_SIZE == 0, 30 __format("Data must be an equal number of %d bytes but is %d", BLOCK_SIZE, data.length)) 31 in (key.length is KEY_SIZE, 32 __format("The key size must be %d bytes not %d", KEY_SIZE, key.length)) 33 do { 34 scope aes = AES(key[0 .. KEY_SIZE], iv); 35 scope (exit) { 36 aes = aes.init; 37 } 38 static if (ENCRYPT) { 39 aes.encrypt(data); 40 } 41 else { 42 aes.decrypt(data); 43 } 44 } 45 46 static void crypt(bool ENCRYPT = true)( 47 scope const(ubyte[]) key, 48 scope const(ubyte[]) iv, 49 return scope const(ubyte[]) indata, ref ubyte[] outdata) pure nothrow @safe 50 in { 51 if (outdata.length) { 52 assert(enclength(indata.length) == outdata.length, 53 __format("Output data must be an equal number of %d bytes", BLOCK_SIZE)); 54 assert(iv.length is BLOCK_SIZE, 55 __format("The iv size must be %d bytes not %d", BLOCK_SIZE, iv.length)); 56 } 57 } 58 do { 59 if (outdata.length < indata.length) { 60 outdata = indata.dup; 61 } 62 else if (&outdata[0]!is &indata[0]) { 63 outdata[0 .. $] = indata[0 .. $]; 64 } 65 size_t old_length; 66 if (outdata.length % BLOCK_SIZE !is 0) { 67 old_length = outdata.length; 68 outdata.length = enclength(outdata.length); 69 } 70 scope (exit) { 71 if (old_length) { 72 outdata.length = old_length; 73 } 74 } 75 ubyte[BLOCK_SIZE] temp_iv = iv[0 .. BLOCK_SIZE]; 76 crypt_parse!ENCRYPT(key, temp_iv, outdata); 77 } 78 79 alias encrypt = crypt!true; 80 alias decrypt = crypt!false; 81 82 unittest { 83 import std.algorithm.iteration : map; 84 import std.array : array; 85 import std.range : iota; 86 import tagion.utils.Random; 87 88 { // Encrypt 89 immutable(ubyte[]) indata = [ 90 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 91 0x11, 0x73, 0x93, 0x17, 0x2a, 92 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 93 0xac, 0x45, 0xaf, 0x8e, 0x51, 94 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 95 0x19, 0x1a, 0x0a, 0x52, 0xef, 96 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 97 0x7b, 0xe6, 0x6c, 0x37, 0x10 98 ]; 99 static if (KEY_LENGTH is 256) { 100 immutable(ubyte[KEY_SIZE]) key = [ 101 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 102 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 103 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 104 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 105 ]; 106 immutable(ubyte[64]) outdata = [ 107 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 108 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, 109 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 110 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, 111 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 112 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, 113 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 114 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b 115 ]; 116 } 117 else static if (KEY_LENGTH is 192) { 118 immutable(ubyte[KEY_SIZE]) key = [ 119 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 120 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 121 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b 122 ]; 123 immutable(ubyte[64]) outdata = [ 124 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 125 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8, 126 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 127 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a, 128 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 129 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0, 130 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 131 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd 132 ]; 133 } 134 else static if (KEY_LENGTH is 128) { 135 immutable(ubyte[KEY_SIZE]) key = [ 136 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 137 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c 138 ]; 139 immutable(ubyte[64]) outdata = [ 140 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 141 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, 142 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 143 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, 144 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 145 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, 146 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 147 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 148 ]; 149 } 150 ubyte[BLOCK_SIZE] iv = [ 151 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 152 0x0b, 0x0c, 0x0d, 0x0e, 0x0f 153 ]; 154 155 ubyte[] enc_output; 156 AESCrypto.encrypt(key, iv, indata, enc_output); 157 } 158 159 { // Decrypt 160 static if (KEY_LENGTH is 256) { 161 immutable(ubyte[KEY_SIZE]) key = [ 162 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 163 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 164 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 165 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 166 ]; 167 immutable(ubyte[64]) indata = [ 168 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 169 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, 170 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 171 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, 172 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 173 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, 174 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 175 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b 176 ]; 177 } 178 else static if (KEY_LENGTH is 192) { 179 immutable(ubyte[KEY_SIZE]) key = [ 180 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 181 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 182 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b 183 ]; 184 immutable(ubyte[64]) indata = [ 185 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 186 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8, 187 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 188 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a, 189 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 190 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0, 191 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 192 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd 193 ]; 194 } 195 else static if (KEY_LENGTH is 128) { 196 immutable(ubyte[KEY_SIZE]) key = [ 197 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 198 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c 199 ]; 200 immutable(ubyte[64]) indata = [ 201 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 202 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, 203 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 204 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, 205 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 206 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, 207 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 208 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 209 ]; 210 } 211 ubyte[BLOCK_SIZE] iv = [ 212 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 213 0x0b, 0x0c, 0x0d, 0x0e, 0x0f 214 ]; 215 immutable(ubyte[]) outdata = [ 216 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 217 0x11, 0x73, 0x93, 0x17, 0x2a, 218 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 219 0xac, 0x45, 0xaf, 0x8e, 0x51, 220 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 221 0x19, 0x1a, 0x0a, 0x52, 0xef, 222 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 223 0x7b, 0xe6, 0x6c, 0x37, 0x10 224 ]; 225 226 ubyte[] dec_output; 227 auto temp_iv = iv; 228 AESCrypto.decrypt(key, temp_iv, indata, dec_output); 229 assert(dec_output == outdata); 230 } 231 232 } 233 } 234 235 unittest { 236 static foreach (key_size; [128, 192, 256]) { 237 { 238 alias AES = AESCrypto!key_size; 239 } 240 } 241 }