1 /** 2 * CFB mode 3 * 4 * Copyright: 5 * (C) 1999-2007,2013 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.modes.cfb; 12 13 import botan.constants; 14 static if (BOTAN_HAS_MODE_CFB): 15 16 import botan.modes.cipher_mode; 17 import botan.block.block_cipher; 18 import botan.modes.mode_pad; 19 import botan.utils.parsing; 20 import botan.utils.xor_buf; 21 import botan.utils.types; 22 import botan.utils.mem_ops; 23 import std.conv : to; 24 import std.algorithm : min; 25 26 /** 27 * CFB Mode 28 */ 29 abstract class CFBMode : CipherMode, Transformation 30 { 31 public: 32 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) 33 { 34 if (!validNonceLength(nonce_len)) 35 throw new InvalidIVLength(name, nonce_len); 36 37 m_shift_register[] = nonce[0 .. nonce_len]; 38 m_keystream_buf.length = m_shift_register.length; 39 cipher().encrypt(m_shift_register, m_keystream_buf); 40 41 return SecureVector!ubyte(); 42 } 43 44 override @property string name() const 45 { 46 if (feedback() == cipher().blockSize()) 47 return cipher().name ~ "/CFB"; 48 else 49 return cipher().name ~ "/CFB(" ~ to!string(feedback()*8) ~ ")"; 50 } 51 52 override size_t updateGranularity() const 53 { 54 return feedback(); 55 } 56 57 override size_t minimumFinalSize() const 58 { 59 return 0; 60 } 61 62 override KeyLengthSpecification keySpec() const 63 { 64 return cipher().keySpec(); 65 } 66 67 override size_t outputLength(size_t input_length) const 68 { 69 return input_length; 70 } 71 72 override size_t defaultNonceLength() const 73 { 74 return cipher().blockSize(); 75 } 76 77 override bool validNonceLength(size_t n) const 78 { 79 return (n == cipher().blockSize()); 80 } 81 82 override void clear() 83 { 84 m_cipher.clear(); 85 m_shift_register.clear(); 86 } 87 88 override bool authenticated() const { return true; } 89 protected: 90 this(BlockCipher cipher, size_t feedback_bits) 91 { 92 m_cipher = cipher; 93 m_feedback_bytes = feedback_bits ? feedback_bits / 8 : m_cipher.blockSize(); 94 if (feedback_bits % 8 || feedback() > m_cipher.blockSize()) 95 throw new InvalidArgument(name() ~ ": feedback bits " ~ 96 to!string(feedback_bits) ~ " not supported"); 97 } 98 99 final BlockCipher cipher() const { return cast()*m_cipher; } 100 101 final size_t feedback() const { return m_feedback_bytes; } 102 103 final ref SecureVector!ubyte shiftRegister() { return m_shift_register; } 104 105 final ref SecureVector!ubyte keystreamBuf() { return m_keystream_buf; } 106 107 protected: 108 final override void keySchedule(const(ubyte)* key, size_t length) 109 { 110 m_cipher.setKey(key, length); 111 } 112 113 Unique!BlockCipher m_cipher; 114 SecureVector!ubyte m_shift_register; 115 SecureVector!ubyte m_keystream_buf; 116 size_t m_feedback_bytes; 117 } 118 119 /** 120 * CFB Encryption 121 */ 122 final class CFBEncryption : CFBMode, Transformation 123 { 124 public: 125 this(BlockCipher cipher, size_t feedback_bits) 126 { 127 super(cipher, feedback_bits); 128 } 129 130 override void update(ref SecureVector!ubyte buffer, size_t offset = 0) 131 { 132 assert(buffer.length >= offset, "Offset is sane"); 133 size_t sz = buffer.length - offset; 134 ubyte* buf = buffer.ptr + offset; 135 136 const size_t BS = cipher().blockSize(); 137 138 SecureVector!ubyte* state = &shiftRegister(); 139 const size_t shift = feedback(); 140 141 while (sz) 142 { 143 const size_t took = min(shift, sz); 144 xorBuf(buf, &keystreamBuf()[0], took); 145 // Assumes feedback-sized block except for last input 146 if (BS - shift > 0) copyMem(state.ptr, &(*state)[shift], BS - shift); 147 copyMem(&(*state)[BS-shift], buf, took); 148 cipher().encrypt(*state, keystreamBuf()); 149 150 buf += took; 151 sz -= took; 152 } 153 } 154 155 156 override void finish(ref SecureVector!ubyte buffer, size_t offset = 0) 157 { 158 update(buffer, offset); 159 } 160 161 // Interface fallthrough 162 override string provider() const { return "core"; } 163 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); } 164 override size_t updateGranularity() const { return super.updateGranularity(); } 165 override size_t defaultNonceLength() const { return super.defaultNonceLength(); } 166 override @property string name() const { return super.name; } 167 override void clear() { return super.clear(); } 168 override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); } 169 override size_t minimumFinalSize() const { return super.minimumFinalSize(); } 170 override bool validNonceLength(size_t n) const { 171 return super.validNonceLength(n); 172 } 173 } 174 175 /** 176 * CFB Decryption 177 */ 178 final class CFBDecryption : CFBMode, Transformation 179 { 180 public: 181 this(BlockCipher cipher, size_t feedback_bits) 182 { 183 super(cipher, feedback_bits); 184 } 185 186 override void update(ref SecureVector!ubyte buffer, size_t offset = 0) 187 { 188 assert(buffer.length >= offset, "Offset is sane"); 189 size_t sz = buffer.length - offset; 190 ubyte* buf = buffer.ptr + offset; 191 192 const size_t BS = cipher().blockSize(); 193 194 SecureVector!ubyte* state = &shiftRegister(); 195 const size_t shift = feedback(); 196 197 while (sz) 198 { 199 const size_t took = min(shift, sz); 200 201 // first update shift register with ciphertext 202 if (BS - shift > 0) copyMem(state.ptr, &(*state)[shift], BS - shift); 203 copyMem(&(*state)[BS-shift], buf, took); 204 205 // then decrypt 206 xorBuf(buf, &keystreamBuf()[0], took); 207 208 // then update keystream 209 cipher().encrypt(*state, keystreamBuf()); 210 211 buf += took; 212 sz -= took; 213 } 214 } 215 216 override void finish(ref SecureVector!ubyte buffer, size_t offset = 0) 217 { 218 update(buffer, offset); 219 } 220 221 // Interface fallthrough 222 override string provider() const { return "core"; } 223 override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); } 224 override size_t updateGranularity() const { return super.updateGranularity(); } 225 override size_t defaultNonceLength() const { return super.defaultNonceLength(); } 226 override @property string name() const { return super.name; } 227 override void clear() { return super.clear(); } 228 override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); } 229 override size_t minimumFinalSize() const { return super.minimumFinalSize(); } 230 override bool validNonceLength(size_t n) const { 231 return super.validNonceLength(n); 232 } 233 }