1 /** 2 * Block Cipher Base Class 3 * 4 * Copyright: 5 * (C) 1999-2009 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.block.block_cipher; 12 13 import botan.constants; 14 public import botan.algo_base.transform; 15 public import botan.algo_base.sym_algo; 16 17 /** 18 * This class represents a block cipher object. 19 */ 20 interface BlockCipher : SymmetricAlgorithm 21 { 22 public: 23 24 /** 25 * Returns: block size of this algorithm 26 */ 27 abstract size_t blockSize() const; 28 29 /** 30 * Returns: native parallelism of this cipher in blocks 31 */ 32 abstract @property size_t parallelism() const; 33 34 /** 35 * Returns: prefererred parallelism of this cipher in bytes 36 */ 37 final size_t parallelBytes() const 38 { 39 return parallelism * this.blockSize() * BOTAN_BLOCK_CIPHER_PAR_MULT; 40 } 41 42 /** 43 * Encrypt a block. 44 * 45 * Params: 46 * input = The plaintext block to be encrypted as a ubyte array. 47 * output = The ubyte array designated to hold the encrypted block. 48 * 49 * Notes: Both arguments must be of length blockSize(). 50 */ 51 final void encrypt(const(ubyte)* input, ubyte* output) 52 { encryptN(input, output, 1); } 53 54 /** 55 * Decrypt a block. 56 * Params: 57 * input = The ciphertext block to be decypted as a ubyte array. 58 * output = The ubyte array designated to hold the decrypted block. 59 * Notes: Both parameters must be of length blockSize(). 60 */ 61 final void decrypt(const(ubyte)* input, ubyte* output) 62 { decryptN(input, output, 1); } 63 64 /** 65 * Encrypt a block. 66 * Params: 67 * block = the plaintext block to be encrypted 68 * Notes: Must be of length blockSize(). Will hold the result when the function 69 * has finished. 70 */ 71 final void encrypt(ubyte* block) { encryptN(cast(const(ubyte)*)block, block, 1); } 72 73 /** 74 * Decrypt a block. 75 * Params: 76 * block = the ciphertext block to be decrypted 77 * Notes: Must be of length blockSize(). Will hold the result when the function 78 * has finished. 79 */ 80 final void decrypt(ubyte* block) { decryptN(cast(const(ubyte)*)block, block, 1); } 81 82 /** 83 * Encrypt a block. 84 * Params: 85 * block = the plaintext block to be encrypted 86 * Notes: Must be of length blockSize(). Will hold the result when the function 87 * has finished. 88 */ 89 final void encrypt(ref ubyte[] block) 90 in { assert(block.length == this.blockSize()); } 91 do { encryptN(block.ptr, block.ptr, 1); } 92 93 /** 94 * Decrypt a block. 95 * Params: 96 * block = the ciphertext block to be decrypted 97 * Notes: Must be of length blockSize(). Will hold the result when the function 98 * has finished. 99 */ 100 final void decrypt(ref ubyte[] block) 101 in { assert(block.length >= this.blockSize()); } 102 do { decryptN(block.ptr, block.ptr, 1); } 103 104 /** 105 * Encrypt one or more blocks 106 * Params: 107 * block = the input/output buffer (multiple of blockSize()) 108 */ 109 final void encrypt(Alloc)(ref Vector!( ubyte, Alloc ) block) 110 in { assert(block.length >= this.blockSize()); } 111 do { 112 return encryptN(block.ptr, block.ptr, block.length / this.blockSize()); 113 } 114 115 /** 116 * Decrypt one or more blocks 117 * Params: 118 * block = the input/output buffer (multiple of blockSize()) 119 */ 120 final void decrypt(Alloc)(ref Vector!( ubyte, Alloc ) block) 121 in { assert(block.length >= this.blockSize()); } 122 do { 123 return decryptN(block.ptr, block.ptr, block.length / this.blockSize()); 124 } 125 126 /** 127 * Encrypt one or more blocks 128 * Params: 129 * input = the input buffer (multiple of blockSize()) 130 * output = the output buffer (same size as input) 131 */ 132 final void encrypt(Alloc, Alloc2)(auto const ref Vector!( ubyte, Alloc ) input, 133 ref Vector!( ubyte, Alloc2 ) output) 134 in { assert(input.length >= this.blockSize()); } 135 do { 136 return encryptN(input.ptr, output.ptr, input.length / this.blockSize()); 137 } 138 139 /** 140 * Decrypt one or more blocks 141 * Params: 142 * input = the input buffer (multiple of blockSize()) 143 * output = the output buffer (same size as input) 144 */ 145 final void decrypt(Alloc, Alloc2)(auto const ref Vector!( ubyte, Alloc ) input, 146 ref Vector!( ubyte, Alloc2 ) output) 147 in { assert(input.length >= this.blockSize()); } 148 do { 149 return decryptN(input.ptr, output.ptr, input.length / this.blockSize()); 150 } 151 /** 152 * Encrypt one or more blocks 153 * Params: 154 * input = the input buffer (multiple of blockSize()) 155 * output = the output buffer (same size as input) 156 */ 157 final void encrypt(ubyte[] input, ref ubyte[] output) 158 in { assert(input.length >= this.blockSize()); } 159 do { 160 return encryptN(input.ptr, output.ptr, input.length / blockSize()); 161 } 162 163 /** 164 * Decrypt one or more blocks 165 * Params: 166 * input = the input buffer (multiple of blockSize()) 167 * output = the output buffer (same size as input) 168 */ 169 final void decrypt(ubyte[] input, ref ubyte[] output) 170 in { assert(input.length >= this.blockSize()); } 171 do { 172 return decryptN(input.ptr, output.ptr, input.length / this.blockSize()); 173 } 174 175 /** 176 * Encrypt one or more blocks 177 * Params: 178 * input = the input buffer (multiple of blockSize()) 179 * output = the output buffer (same size as input) 180 * blocks = the number of blocks to process 181 */ 182 abstract void encryptN(const(ubyte)* input, ubyte* output, size_t blocks); 183 184 /** 185 * Decrypt one or more blocks 186 * Params: 187 * input = the input buffer (multiple of blockSize()) 188 * output = the output buffer (same size as input) 189 * blocks = the number of blocks to process 190 */ 191 abstract void decryptN(const(ubyte)* input, ubyte* output, size_t blocks); 192 193 /** 194 * Returns: new object representing the same algorithm as this 195 */ 196 abstract BlockCipher clone() const; 197 final @disable BlockCipher dup() const; 198 } 199 200 /** 201 * Represents a block cipher with a single fixed block size 202 */ 203 abstract class BlockCipherFixedParams(size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1) : BlockCipher, SymmetricAlgorithm 204 { 205 public: 206 enum { BLOCK_SIZE = BS } 207 override size_t blockSize() const { return BS; } 208 209 KeyLengthSpecification keySpec() const 210 { 211 return KeyLengthSpecification(KMIN, KMAX, KMOD); 212 } 213 214 abstract void clear(); 215 this() { clear(); } // TODO: Write some real constructors for each object. 216 } 217 218 static if (BOTAN_TEST): 219 220 import botan.test; 221 private import botan.libstate.libstate; 222 import botan.algo_factory.algo_factory; 223 import botan.codec.hex; 224 import core.atomic; 225 import memutils.hashmap; 226 227 shared size_t total_tests; 228 229 size_t blockTest(string algo, string key_hex, string in_hex, string out_hex) 230 { 231 const SecureVector!ubyte key = hexDecodeLocked(key_hex); 232 const SecureVector!ubyte pt = hexDecodeLocked(in_hex); 233 const SecureVector!ubyte ct = hexDecodeLocked(out_hex); 234 235 AlgorithmFactory af = globalState().algorithmFactory(); 236 237 const auto providers = af.providersOf(algo); 238 size_t fails = 0; 239 240 if (providers.empty) 241 throw new Exception("Unknown block cipher " ~ algo); 242 243 foreach (provider; providers[]) 244 { 245 246 atomicOp!"+="(total_tests, 1); 247 const BlockCipher proto = af.prototypeBlockCipher(algo, provider); 248 249 if (!proto) 250 { 251 logError("Unable to get " ~ algo ~ " from " ~ provider); 252 ++fails; 253 continue; 254 } 255 256 Unique!BlockCipher cipher = proto.clone(); 257 cipher.setKey(key); 258 SecureVector!ubyte buf = pt.clone; 259 260 cipher.encrypt(buf); 261 atomicOp!"+="(total_tests, 1); 262 if (buf != ct) 263 { 264 logTrace(buf[], " Real"); 265 logTrace(ct[], " Expected"); 266 ++fails; 267 buf = ct.clone; 268 } 269 270 cipher.decrypt(buf); 271 272 atomicOp!"+="(total_tests, 1); 273 if (buf != pt) 274 { 275 logTrace(buf[], " Real"); 276 logTrace(pt[], " Expected"); 277 ++fails; 278 } 279 } 280 //logTrace("Finished ", algo, " Fails: ", fails); 281 assert(fails == 0); 282 return fails; 283 } 284 285 static if (BOTAN_HAS_TESTS && !SKIP_BLOCK_TEST) unittest { 286 287 288 logDebug("Testing block_cipher.d ..."); 289 size_t test_bc(string input) 290 { 291 logDebug("Testing file `" ~ input ~ " ..."); 292 File vec = File(input, "r"); 293 return runTestsBb(vec, "BlockCipher", "Out", true, 294 (ref HashMap!(string, string) m) { 295 return blockTest(m["BlockCipher"], m["Key"], m["In"], m["Out"]); 296 }); 297 } 298 299 logTrace("Running tests ..."); 300 size_t fails = runTestsInDir("test_data/block", &test_bc); 301 302 303 testReport("block_cipher", total_tests, fails); 304 }