Botan
1.11.15
|
00001 /* 00002 * XTS Mode 00003 * (C) 2009,2013 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/internal/mode_utils.h> 00009 #include <botan/xts.h> 00010 00011 namespace Botan { 00012 00013 BOTAN_REGISTER_BLOCK_CIPHER_MODE(XTS_Encryption, XTS_Decryption); 00014 00015 namespace { 00016 00017 void poly_double_128(byte out[], const byte in[]) 00018 { 00019 u64bit X0 = load_le<u64bit>(in, 0); 00020 u64bit X1 = load_le<u64bit>(in, 1); 00021 00022 const bool carry = (X1 >> 63); 00023 00024 X1 = (X1 << 1) | (X0 >> 63); 00025 X0 = (X0 << 1); 00026 00027 if(carry) 00028 X0 ^= 0x87; 00029 00030 store_le(out, X0, X1); 00031 } 00032 00033 void poly_double_64(byte out[], const byte in[]) 00034 { 00035 u64bit X = load_le<u64bit>(in, 0); 00036 const bool carry = (X >> 63); 00037 X <<= 1; 00038 if(carry) 00039 X ^= 0x1B; 00040 store_le(X, out); 00041 } 00042 00043 inline void poly_double(byte out[], const byte in[], size_t size) 00044 { 00045 if(size == 8) 00046 poly_double_64(out, in); 00047 else 00048 poly_double_128(out, in); 00049 } 00050 00051 } 00052 00053 XTS_Mode::XTS_Mode(BlockCipher* cipher) : m_cipher(cipher) 00054 { 00055 if(m_cipher->block_size() != 8 && m_cipher->block_size() != 16) 00056 throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); 00057 00058 m_tweak_cipher.reset(m_cipher->clone()); 00059 m_tweak.resize(update_granularity()); 00060 } 00061 00062 void XTS_Mode::clear() 00063 { 00064 m_cipher->clear(); 00065 m_tweak_cipher->clear(); 00066 zeroise(m_tweak); 00067 } 00068 00069 std::string XTS_Mode::name() const 00070 { 00071 return cipher().name() + "/XTS"; 00072 } 00073 00074 size_t XTS_Mode::update_granularity() const 00075 { 00076 return cipher().parallel_bytes(); 00077 } 00078 00079 size_t XTS_Mode::minimum_final_size() const 00080 { 00081 return cipher().block_size() + 1; 00082 } 00083 00084 Key_Length_Specification XTS_Mode::key_spec() const 00085 { 00086 return cipher().key_spec().multiple(2); 00087 } 00088 00089 size_t XTS_Mode::default_nonce_length() const 00090 { 00091 return cipher().block_size(); 00092 } 00093 00094 bool XTS_Mode::valid_nonce_length(size_t n) const 00095 { 00096 return cipher().block_size() == n; 00097 } 00098 00099 void XTS_Mode::key_schedule(const byte key[], size_t length) 00100 { 00101 const size_t key_half = length / 2; 00102 00103 if(length % 2 == 1 || !m_cipher->valid_keylength(key_half)) 00104 throw Invalid_Key_Length(name(), length); 00105 00106 m_cipher->set_key(&key[0], key_half); 00107 m_tweak_cipher->set_key(&key[key_half], key_half); 00108 } 00109 00110 secure_vector<byte> XTS_Mode::start_raw(const byte nonce[], size_t nonce_len) 00111 { 00112 if(!valid_nonce_length(nonce_len)) 00113 throw Invalid_IV_Length(name(), nonce_len); 00114 00115 copy_mem(&m_tweak[0], nonce, nonce_len); 00116 m_tweak_cipher->encrypt(&m_tweak[0]); 00117 00118 update_tweak(0); 00119 00120 return secure_vector<byte>(); 00121 } 00122 00123 void XTS_Mode::update_tweak(size_t which) 00124 { 00125 const size_t BS = m_tweak_cipher->block_size(); 00126 00127 if(which > 0) 00128 poly_double(&m_tweak[0], &m_tweak[(which-1)*BS], BS); 00129 00130 const size_t blocks_in_tweak = update_granularity() / BS; 00131 00132 for(size_t i = 1; i < blocks_in_tweak; ++i) 00133 poly_double(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS); 00134 } 00135 00136 size_t XTS_Encryption::output_length(size_t input_length) const 00137 { 00138 return round_up(input_length, cipher().block_size()); 00139 } 00140 00141 void XTS_Encryption::update(secure_vector<byte>& buffer, size_t offset) 00142 { 00143 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00144 const size_t sz = buffer.size() - offset; 00145 byte* buf = &buffer[offset]; 00146 00147 const size_t BS = cipher().block_size(); 00148 00149 BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); 00150 size_t blocks = sz / BS; 00151 00152 const size_t blocks_in_tweak = update_granularity() / BS; 00153 00154 while(blocks) 00155 { 00156 const size_t to_proc = std::min(blocks, blocks_in_tweak); 00157 const size_t to_proc_bytes = to_proc * BS; 00158 00159 xor_buf(buf, tweak(), to_proc_bytes); 00160 cipher().encrypt_n(buf, buf, to_proc); 00161 xor_buf(buf, tweak(), to_proc_bytes); 00162 00163 buf += to_proc * BS; 00164 blocks -= to_proc; 00165 00166 update_tweak(to_proc); 00167 } 00168 } 00169 00170 void XTS_Encryption::finish(secure_vector<byte>& buffer, size_t offset) 00171 { 00172 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00173 const size_t sz = buffer.size() - offset; 00174 byte* buf = &buffer[offset]; 00175 00176 BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input"); 00177 00178 const size_t BS = cipher().block_size(); 00179 00180 if(sz % BS == 0) 00181 { 00182 update(buffer, offset); 00183 } 00184 else 00185 { 00186 // steal ciphertext 00187 const size_t full_blocks = ((sz / BS) - 1) * BS; 00188 const size_t final_bytes = sz - full_blocks; 00189 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); 00190 00191 secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes); 00192 buffer.resize(full_blocks + offset); 00193 update(buffer, offset); 00194 00195 xor_buf(last, tweak(), BS); 00196 cipher().encrypt(last); 00197 xor_buf(last, tweak(), BS); 00198 00199 for(size_t i = 0; i != final_bytes - BS; ++i) 00200 { 00201 last[i] ^= last[i + BS]; 00202 last[i + BS] ^= last[i]; 00203 last[i] ^= last[i + BS]; 00204 } 00205 00206 xor_buf(last, tweak() + BS, BS); 00207 cipher().encrypt(last); 00208 xor_buf(last, tweak() + BS, BS); 00209 00210 buffer += last; 00211 } 00212 } 00213 00214 size_t XTS_Decryption::output_length(size_t input_length) const 00215 { 00216 // might be less 00217 return input_length; 00218 } 00219 00220 void XTS_Decryption::update(secure_vector<byte>& buffer, size_t offset) 00221 { 00222 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00223 const size_t sz = buffer.size() - offset; 00224 byte* buf = &buffer[offset]; 00225 00226 const size_t BS = cipher().block_size(); 00227 00228 BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); 00229 size_t blocks = sz / BS; 00230 00231 const size_t blocks_in_tweak = update_granularity() / BS; 00232 00233 while(blocks) 00234 { 00235 const size_t to_proc = std::min(blocks, blocks_in_tweak); 00236 const size_t to_proc_bytes = to_proc * BS; 00237 00238 xor_buf(buf, tweak(), to_proc_bytes); 00239 cipher().decrypt_n(buf, buf, to_proc); 00240 xor_buf(buf, tweak(), to_proc_bytes); 00241 00242 buf += to_proc * BS; 00243 blocks -= to_proc; 00244 00245 update_tweak(to_proc); 00246 } 00247 } 00248 00249 void XTS_Decryption::finish(secure_vector<byte>& buffer, size_t offset) 00250 { 00251 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00252 const size_t sz = buffer.size() - offset; 00253 byte* buf = &buffer[offset]; 00254 00255 BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input"); 00256 00257 const size_t BS = cipher().block_size(); 00258 00259 if(sz % BS == 0) 00260 { 00261 update(buffer, offset); 00262 } 00263 else 00264 { 00265 // steal ciphertext 00266 const size_t full_blocks = ((sz / BS) - 1) * BS; 00267 const size_t final_bytes = sz - full_blocks; 00268 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); 00269 00270 secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes); 00271 buffer.resize(full_blocks + offset); 00272 update(buffer, offset); 00273 00274 xor_buf(last, tweak() + BS, BS); 00275 cipher().decrypt(last); 00276 xor_buf(last, tweak() + BS, BS); 00277 00278 for(size_t i = 0; i != final_bytes - BS; ++i) 00279 { 00280 last[i] ^= last[i + BS]; 00281 last[i + BS] ^= last[i]; 00282 last[i] ^= last[i + BS]; 00283 } 00284 00285 xor_buf(last, tweak(), BS); 00286 cipher().decrypt(last); 00287 xor_buf(last, tweak(), BS); 00288 00289 buffer += last; 00290 } 00291 } 00292 00293 }