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 body { 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 body { 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 body { 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 body { 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 body { 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 body { 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 body { 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 body { 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 } 198 199 /** 200 * Represents a block cipher with a single fixed block size 201 */ 202 abstract class BlockCipherFixedParams(size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1) : BlockCipher, SymmetricAlgorithm 203 { 204 public: 205 enum { BLOCK_SIZE = BS } 206 override size_t blockSize() const { return BS; } 207 208 KeyLengthSpecification keySpec() const 209 { 210 return KeyLengthSpecification(KMIN, KMAX, KMOD); 211 } 212 213 abstract void clear(); 214 this() { clear(); } // TODO: Write some real constructors for each object. 215 } 216 217 static if (BOTAN_TEST): 218 219 import botan.test; 220 import botan.libstate.libstate; 221 import botan.algo_factory.algo_factory; 222 import botan.codec.hex; 223 import core.atomic; 224 import memutils.hashmap; 225 226 shared size_t total_tests; 227 228 size_t blockTest(string algo, string key_hex, string in_hex, string out_hex) 229 { 230 const SecureVector!ubyte key = hexDecodeLocked(key_hex); 231 const SecureVector!ubyte pt = hexDecodeLocked(in_hex); 232 const SecureVector!ubyte ct = hexDecodeLocked(out_hex); 233 234 AlgorithmFactory af = globalState().algorithmFactory(); 235 236 const auto providers = af.providersOf(algo); 237 size_t fails = 0; 238 239 if (providers.empty) 240 throw new Exception("Unknown block cipher " ~ algo); 241 242 foreach (provider; providers[]) 243 { 244 245 atomicOp!"+="(total_tests, 1); 246 const BlockCipher proto = af.prototypeBlockCipher(algo, provider); 247 248 if (!proto) 249 { 250 logError("Unable to get " ~ algo ~ " from " ~ provider); 251 ++fails; 252 continue; 253 } 254 255 Unique!BlockCipher cipher = proto.clone(); 256 cipher.setKey(key); 257 SecureVector!ubyte buf = pt.dup; 258 259 cipher.encrypt(buf); 260 atomicOp!"+="(total_tests, 1); 261 if (buf != ct) 262 { 263 logTrace(buf[], " Real"); 264 logTrace(ct[], " Expected"); 265 ++fails; 266 buf = ct.dup; 267 } 268 269 cipher.decrypt(buf); 270 271 atomicOp!"+="(total_tests, 1); 272 if (buf != pt) 273 { 274 logTrace(buf[], " Real"); 275 logTrace(pt[], " Expected"); 276 ++fails; 277 } 278 } 279 //logTrace("Finished ", algo, " Fails: ", fails); 280 assert(fails == 0); 281 return fails; 282 } 283 284 static if (BOTAN_HAS_TESTS && !SKIP_BLOCK_TEST) unittest { 285 286 287 logDebug("Testing block_cipher.d ..."); 288 size_t test_bc(string input) 289 { 290 logDebug("Testing file `" ~ input ~ " ..."); 291 File vec = File(input, "r"); 292 return runTestsBb(vec, "BlockCipher", "Out", true, 293 (ref HashMap!(string, string) m) { 294 return blockTest(m["BlockCipher"], m["Key"], m["In"], m["Out"]); 295 }); 296 } 297 298 logTrace("Running tests ..."); 299 size_t fails = runTestsInDir("../test_data/block", &test_bc); 300 301 302 testReport("block_cipher", total_tests, fails); 303 }