1 /* 2 * CBC mode 3 * (C) 1999-2007,2013 Jack Lloyd 4 * (C) 2014-2015 Etienne Cimon 5 * 6 * License: 7 * Botan is released under the Simplified BSD License (see LICENSE.md) 8 */ 9 module botan.modes.cbc; 10 11 import botan.constants; 12 static if (BOTAN_HAS_MODE_CBC): 13 14 import botan.modes.cipher_mode; 15 import botan.block.block_cipher; 16 import botan.modes.mode_pad; 17 import botan.utils.loadstor; 18 import botan.utils.xor_buf; 19 import botan.utils.rounding; 20 import botan.utils.mem_ops; 21 import std.algorithm : min, swap; 22 23 /** 24 * CBC Mode 25 */ 26 abstract class CBCMode : CipherMode, Transformation 27 { 28 public: 29 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) 30 { 31 if (!validNonceLength(nonce_len)) 32 throw new InvalidIVLength(name(), nonce_len); 33 34 /* 35 * A nonce of zero length means carry the last ciphertext value over 36 * as the new IV, as unfortunately some protocols require this. If 37 * this is the first message then we use an IV of all zeros. 38 */ 39 if (nonce_len) 40 m_state[] = nonce[0 .. nonce_len]; 41 42 return SecureVector!ubyte(); 43 } 44 45 override @property string name() const 46 { 47 if (m_padding) 48 return cipher().name ~ "/CBC/" ~ padding().name; 49 else 50 return cipher().name ~ "/CBC/CTS"; 51 } 52 53 override size_t updateGranularity() const 54 { 55 return cipher().parallelBytes(); 56 } 57 58 override KeyLengthSpecification keySpec() const 59 { 60 return cipher().keySpec(); 61 } 62 63 override size_t defaultNonceLength() const 64 { 65 return cipher().blockSize(); 66 } 67 68 override bool validNonceLength(size_t n) const 69 { 70 return (n == 0 || n == cipher().blockSize()); 71 } 72 73 override void clear() 74 { 75 m_cipher.clear(); 76 m_state.clear(); 77 } 78 79 final override bool authenticated() const { return true; } 80 protected: 81 this(BlockCipher cipher, BlockCipherModePaddingMethod padding) 82 { 83 m_cipher = cipher; 84 m_padding = padding; 85 m_state = SecureVector!ubyte(m_cipher.blockSize()); 86 if (!m_padding.isEmpty && !m_padding.validBlocksize(m_cipher.blockSize())) 87 throw new InvalidArgument("Padding " ~ m_padding.name ~ " cannot be used with " ~ m_cipher.name ~ "/CBC"); 88 } 89 90 final BlockCipher cipher() const { return cast()*m_cipher; } 91 92 final const(BlockCipherModePaddingMethod) padding() const 93 { 94 assert(m_padding, "No padding defined"); 95 return *m_padding; 96 } 97 98 final ref SecureVector!ubyte state() { return m_state; } 99 100 final ubyte* statePtr() { return m_state.ptr; } 101 102 final override void keySchedule(const(ubyte)* key, size_t length) 103 { 104 m_cipher.setKey(key, length); 105 } 106 107 private: 108 Unique!BlockCipher m_cipher; 109 Unique!BlockCipherModePaddingMethod m_padding; 110 SecureVector!ubyte m_state; 111 } 112 113 /** 114 * CBC Encryption 115 */ 116 class CBCEncryption : CBCMode, Transformation 117 { 118 public: 119 this(BlockCipher cipher, BlockCipherModePaddingMethod padding) 120 { 121 super(cipher, padding); 122 } 123 124 override void update(ref SecureVector!ubyte buffer, size_t offset = 0) 125 { 126 assert(buffer.length >= offset, "Offset is sane"); 127 const size_t sz = buffer.length - offset; 128 ubyte* buf = buffer.ptr + offset; 129 130 const size_t BS = cipher().blockSize(); 131 132 assert(sz % BS == 0, "CBC input is full blocks"); 133 const size_t blocks = sz / BS; 134 135 const(ubyte)* prev_block = statePtr(); 136 137 if (blocks) 138 { 139 foreach (size_t i; 0 .. blocks) 140 { 141 assert(buffer.length >= BS*i); 142 xorBuf(buf + BS*i, prev_block, BS); 143 cipher().encrypt(buf + BS*i); 144 prev_block = buf + BS*i; 145 } 146 147 assert(buffer.length >= BS*blocks); 148 state()[] = buf[BS*(blocks-1) .. BS*blocks]; 149 } 150 151 } 152 153 154 override void finish(ref SecureVector!ubyte buffer, size_t offset = 0) 155 { 156 assert(buffer.length >= offset, "Offset is sane"); 157 158 const size_t BS = cipher().blockSize(); 159 160 const size_t bytes_in_final_block = (buffer.length-offset) % BS; 161 162 padding().addPadding(buffer, bytes_in_final_block, BS); 163 164 if ((buffer.length-offset) % BS) 165 throw new Exception("Did not pad to full block size in " ~ name); 166 167 update(buffer, offset); 168 } 169 170 override size_t outputLength(size_t input_length) const 171 { 172 return roundUp(input_length, cipher().blockSize()); 173 } 174 175 override size_t minimumFinalSize() const 176 { 177 return 0; 178 } 179 180 // Interface fallthrough 181 override string provider() const { return "core"; } 182 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); } 183 override size_t updateGranularity() const { return super.updateGranularity(); } 184 override size_t defaultNonceLength() const { return super.defaultNonceLength(); } 185 override bool validNonceLength(size_t nonce_len) const { return super.validNonceLength(nonce_len); } 186 override @property string name() const { return super.name; } 187 override void clear() { return super.clear(); } 188 } 189 190 /** 191 * CBC Encryption with ciphertext stealing (CBC-CS3 variant) 192 */ 193 final class CTSEncryption : CBCEncryption 194 { 195 public: 196 this(BlockCipher cipher) 197 { 198 super(cipher, null); 199 } 200 201 override size_t outputLength(size_t input_length) const 202 { 203 return input_length; // no ciphertext expansion in CTS 204 } 205 206 override void finish(ref SecureVector!ubyte buffer, size_t offset = 0) 207 { 208 assert(buffer.length >= offset, "Offset is sane"); 209 ubyte* buf = buffer.ptr + offset; 210 const size_t sz = buffer.length - offset; 211 212 const size_t BS = cipher().blockSize(); 213 214 if (sz < BS + 1) 215 throw new EncodingError(name() ~ ": insufficient data to encrypt"); 216 217 if (sz % BS == 0) 218 { 219 update(buffer, offset); 220 221 // swap last two blocks 222 foreach (size_t i; 0 .. BS) 223 swap(buffer[buffer.length-BS+i], buffer[buffer.length-2*BS+i]); 224 } 225 else 226 { 227 const size_t full_blocks = ((sz / BS) - 1) * BS; 228 const size_t final_bytes = sz - full_blocks; 229 assert(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); 230 assert(buffer.length >= full_blocks+final_bytes); 231 SecureVector!ubyte last = SecureVector!ubyte(buf[full_blocks .. full_blocks + final_bytes]); 232 buffer.resize(full_blocks + offset); 233 update(buffer, offset); 234 235 xorBuf(last.ptr, statePtr(), BS); 236 cipher().encrypt(last.ptr); 237 238 foreach (size_t i; 0 .. (final_bytes - BS)) 239 { 240 last[i] ^= last[i + BS]; 241 last[i + BS] ^= last[i]; 242 } 243 244 cipher().encrypt(last.ptr); 245 246 buffer ~= last[]; 247 } 248 } 249 250 override size_t minimumFinalSize() const 251 { 252 return cipher().blockSize() + 1; 253 } 254 255 override bool validNonceLength(size_t n) const 256 { 257 return (n == cipher().blockSize()); 258 } 259 260 // Interface fallthrough 261 override string provider() const { return "core"; } 262 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); } 263 override void update(ref SecureVector!ubyte blocks, size_t offset = 0) { super.update(blocks, offset); } 264 override size_t updateGranularity() const { return super.updateGranularity(); } 265 override size_t defaultNonceLength() const { return super.defaultNonceLength(); } 266 override @property string name() const { return super.name; } 267 override void clear() { return super.clear(); } 268 269 } 270 271 /** 272 * CBC Decryption 273 */ 274 class CBCDecryption : CBCMode, Transformation 275 { 276 public: 277 this(BlockCipher cipher, BlockCipherModePaddingMethod padding) 278 { 279 super(cipher, padding); 280 m_tempbuf = SecureVector!ubyte(updateGranularity()); 281 } 282 283 override void update(ref SecureVector!ubyte buffer, size_t offset) 284 { 285 assert(buffer.length >= offset, "Offset is sane"); 286 const size_t sz = buffer.length - offset; 287 ubyte* buf = buffer.ptr + offset; 288 289 const size_t BS = cipher().blockSize(); 290 291 assert(sz % BS == 0, "Input is full blocks"); 292 size_t blocks = sz / BS; 293 294 while (blocks) 295 { 296 const size_t to_proc = min(BS * blocks, m_tempbuf.length); 297 cipher().decryptN(buf, m_tempbuf.ptr, to_proc / BS); 298 299 assert(m_tempbuf.length >= BS); 300 xorBuf(m_tempbuf.ptr, statePtr(), BS); 301 xorBuf(m_tempbuf.ptr + BS, buf, to_proc - BS); 302 303 assert(state().length >= BS); 304 copyMem(statePtr(), buf + (to_proc - BS), BS); 305 306 assert(buffer.length >= to_proc); 307 copyMem(buf, m_tempbuf.ptr, to_proc); 308 309 buf += to_proc; 310 blocks -= to_proc / BS; 311 } 312 } 313 314 override void finish(ref SecureVector!ubyte buffer, size_t offset = 0) 315 { 316 assert(buffer.length >= offset, "Offset is sane"); 317 const size_t sz = buffer.length - offset; 318 319 const size_t BS = cipher().blockSize(); 320 321 if (sz == 0 || sz % BS) 322 throw new DecodingError(name() ~ ": Ciphertext not a multiple of block size"); 323 324 update(buffer, offset); 325 assert(buffer.length >= BS); 326 const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.length-BS], BS); 327 buffer.resize(buffer.length - pad_bytes); // remove padding 328 } 329 330 override size_t outputLength(size_t input_length) const 331 { 332 return input_length; // precise for CTS, worst case otherwise 333 } 334 335 override size_t minimumFinalSize() const 336 { 337 return cipher().blockSize(); 338 } 339 340 // Interface fallthrough 341 override string provider() const { return "core"; } 342 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); } 343 override size_t updateGranularity() const { return super.updateGranularity(); } 344 override size_t defaultNonceLength() const { return super.defaultNonceLength(); } 345 override bool validNonceLength(size_t nonce_len) const { return super.validNonceLength(nonce_len); } 346 override @property string name() const { return super.name; } 347 override void clear() { return super.clear(); } 348 private: 349 SecureVector!ubyte m_tempbuf; 350 } 351 352 /** 353 * CBC Decryption with ciphertext stealing (CBC-CS3 variant) 354 */ 355 final class CTSDecryption : CBCDecryption, Transformation 356 { 357 public: 358 this(BlockCipher cipher) 359 { 360 super(cipher, null); 361 } 362 363 override void finish(ref SecureVector!ubyte buffer, size_t offset = 0) 364 { 365 assert(buffer.length >= offset, "Offset is sane"); 366 const size_t sz = buffer.length - offset; 367 ubyte* buf = buffer.ptr + offset; 368 369 const size_t BS = cipher().blockSize(); 370 371 if (sz < BS + 1) 372 throw new EncodingError(name() ~ ": insufficient data to decrypt"); 373 374 if (sz % BS == 0) 375 { 376 // swap last two blocks 377 378 foreach (size_t i; 0 .. BS) 379 swap(buffer[buffer.length-BS+i], buffer[buffer.length-2*BS+i]); 380 381 update(buffer, offset); 382 } 383 else 384 { 385 const size_t full_blocks = ((sz / BS) - 1) * BS; 386 const size_t final_bytes = sz - full_blocks; 387 assert(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); 388 389 SecureVector!ubyte last = SecureVector!ubyte(buf[full_blocks .. full_blocks + final_bytes]); 390 buffer.resize(full_blocks + offset); 391 update(buffer, offset); 392 393 cipher().decrypt(last.ptr); 394 395 xorBuf(last.ptr, &last[BS], final_bytes - BS); 396 397 foreach (size_t i; 0 .. (final_bytes - BS)) 398 swap(last[i], last[i + BS]); 399 400 cipher().decrypt(last.ptr); 401 xorBuf(last.ptr, statePtr(), BS); 402 403 buffer ~= last; 404 } 405 } 406 407 override size_t minimumFinalSize() const 408 { 409 return cipher().blockSize() + 1; 410 } 411 412 override bool validNonceLength(size_t n) const 413 { 414 return (n == cipher().blockSize()); 415 } 416 417 // Interface fallthrough 418 override string provider() const { return "core"; } 419 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); } 420 override void update(ref SecureVector!ubyte blocks, size_t offset = 0) { super.update(blocks, offset); } 421 override size_t updateGranularity() const { return super.updateGranularity(); } 422 override size_t defaultNonceLength() const { return super.defaultNonceLength(); } 423 override @property string name() const { return super.name; } 424 override void clear() { return super.clear(); } 425 override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); } 426 }