1 /** 2 * CTR-BE Mode 3 * 4 * Copyright: 5 * (C) 1999-2007 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.stream.ctr; 12 13 import botan.constants; 14 static if (BOTAN_HAS_CTR_BE): 15 16 import botan.block.block_cipher; 17 import botan.stream.stream_cipher; 18 import botan.utils.xor_buf; 19 import botan.utils.types; 20 import botan.utils.mem_ops; 21 22 /** 23 * CTR-BE (Counter mode, big-endian) 24 */ 25 final class CTRBE : StreamCipher, SymmetricAlgorithm 26 { 27 public: 28 override void cipher(const(ubyte)* input, ubyte* output, size_t length) 29 { 30 while (length >= m_pad.length - m_pad_pos) 31 { 32 xorBuf(output, input, &m_pad[m_pad_pos], m_pad.length - m_pad_pos); 33 length -= (m_pad.length - m_pad_pos); 34 input += (m_pad.length - m_pad_pos); 35 output += (m_pad.length - m_pad_pos); 36 increment_counter(); 37 } 38 xorBuf(output, input, &m_pad[m_pad_pos], length); 39 m_pad_pos += length; 40 } 41 42 43 override void setIv(const(ubyte)* iv, size_t iv_len) 44 { 45 if (!validIvLength(iv_len)) 46 throw new InvalidIVLength(name, iv_len); 47 48 const size_t bs = m_cipher.blockSize(); 49 50 zeroise(m_counter); 51 52 bufferInsert(m_counter, 0, iv, iv_len); 53 54 // Set m_counter blocks to IV, IV + 1, ... IV + 255 55 foreach (size_t i; 1 .. 256) 56 { 57 bufferInsert(m_counter, i*bs, &m_counter[(i-1)*bs], bs); 58 59 foreach (size_t j; 0 .. bs) 60 if (++(m_counter[i*bs + (bs - 1 - j)])) 61 break; 62 } 63 64 m_cipher.encryptN(m_counter.ptr, m_pad.ptr, 256); 65 m_pad_pos = 0; 66 } 67 68 override bool validIvLength(size_t iv_len) const 69 { return (iv_len <= m_cipher.blockSize()); } 70 71 KeyLengthSpecification keySpec() const 72 { 73 return m_cipher.keySpec(); 74 } 75 76 @property string name() const 77 { 78 return ("CTR-BE(" ~ m_cipher.name ~ ")"); 79 } 80 81 override CTRBE clone() const 82 { return new CTRBE(m_cipher.clone()); } 83 84 override void clear() 85 { 86 m_cipher.clear(); 87 zeroise(m_pad); 88 zeroise(m_counter); 89 m_pad_pos = 0; 90 } 91 92 /** 93 * Params: 94 * ciph = the underlying block cipher to use 95 */ 96 this(BlockCipher ciph) 97 { 98 m_cipher = ciph; 99 m_counter = 256 * m_cipher.blockSize(); 100 m_pad = m_counter.length; 101 m_pad_pos = 0; 102 } 103 protected: 104 override void keySchedule(const(ubyte)* key, size_t length) 105 { 106 m_cipher.setKey(key, length); 107 108 // Set a default all-zeros IV 109 setIv(null, 0); 110 } 111 112 /* 113 * Increment the counter and update the buffer 114 */ 115 void increment_counter() 116 { 117 const size_t bs = m_cipher.blockSize(); 118 119 /* 120 * Each counter value always needs to be incremented by 256, 121 * so we don't touch the lowest ubyte and instead treat it as 122 * an increment of one starting with the next ubyte. 123 */ 124 foreach (size_t i; 0 .. 256) 125 { 126 foreach (size_t j; 1 .. bs) 127 if (++(m_counter[i*bs + (bs - 1 - j)])) 128 break; 129 } 130 131 m_cipher.encryptN(m_counter.ptr, m_pad.ptr, 256); 132 m_pad_pos = 0; 133 } 134 135 Unique!BlockCipher m_cipher; 136 SecureVector!ubyte m_counter, m_pad; 137 size_t m_pad_pos; 138 }