Botan
1.11.15
|
00001 /* 00002 * EAX Mode Encryption 00003 * (C) 1999-2007 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/eax.h> 00010 #include <botan/cmac.h> 00011 #include <botan/ctr.h> 00012 #include <botan/parsing.h> 00013 00014 namespace Botan { 00015 00016 BOTAN_REGISTER_BLOCK_CIPHER_MODE_LEN(EAX_Encryption, EAX_Decryption, 0); 00017 00018 namespace { 00019 00020 /* 00021 * EAX MAC-based PRF 00022 */ 00023 secure_vector<byte> eax_prf(byte tag, size_t block_size, 00024 MessageAuthenticationCode& mac, 00025 const byte in[], size_t length) 00026 { 00027 for(size_t i = 0; i != block_size - 1; ++i) 00028 mac.update(0); 00029 mac.update(tag); 00030 mac.update(in, length); 00031 return mac.final(); 00032 } 00033 00034 } 00035 00036 /* 00037 * EAX_Mode Constructor 00038 */ 00039 EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) : 00040 m_tag_size(tag_size ? tag_size : cipher->block_size()), 00041 m_cipher(cipher), 00042 m_ctr(new CTR_BE(m_cipher->clone())), 00043 m_cmac(new CMAC(m_cipher->clone())) 00044 { 00045 if(m_tag_size < 8 || m_tag_size > m_cmac->output_length()) 00046 throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size)); 00047 } 00048 00049 void EAX_Mode::clear() 00050 { 00051 m_cipher.reset(); 00052 m_ctr.reset(); 00053 m_cmac.reset(); 00054 zeroise(m_ad_mac); 00055 zeroise(m_nonce_mac); 00056 } 00057 00058 std::string EAX_Mode::name() const 00059 { 00060 return (m_cipher->name() + "/EAX"); 00061 } 00062 00063 size_t EAX_Mode::update_granularity() const 00064 { 00065 return 8 * m_cipher->parallel_bytes(); 00066 } 00067 00068 Key_Length_Specification EAX_Mode::key_spec() const 00069 { 00070 return m_cipher->key_spec(); 00071 } 00072 00073 /* 00074 * Set the EAX key 00075 */ 00076 void EAX_Mode::key_schedule(const byte key[], size_t length) 00077 { 00078 /* 00079 * These could share the key schedule, which is one nice part of EAX, 00080 * but it's much easier to ignore that here... 00081 */ 00082 m_ctr->set_key(key, length); 00083 m_cmac->set_key(key, length); 00084 00085 m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0); 00086 } 00087 00088 /* 00089 * Set the EAX associated data 00090 */ 00091 void EAX_Mode::set_associated_data(const byte ad[], size_t length) 00092 { 00093 m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length); 00094 } 00095 00096 secure_vector<byte> EAX_Mode::start_raw(const byte nonce[], size_t nonce_len) 00097 { 00098 if(!valid_nonce_length(nonce_len)) 00099 throw Invalid_IV_Length(name(), nonce_len); 00100 00101 m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len); 00102 00103 m_ctr->set_iv(&m_nonce_mac[0], m_nonce_mac.size()); 00104 00105 for(size_t i = 0; i != block_size() - 1; ++i) 00106 m_cmac->update(0); 00107 m_cmac->update(2); 00108 00109 return secure_vector<byte>(); 00110 } 00111 00112 void EAX_Encryption::update(secure_vector<byte>& buffer, size_t offset) 00113 { 00114 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00115 const size_t sz = buffer.size() - offset; 00116 byte* buf = &buffer[offset]; 00117 00118 m_ctr->cipher(buf, buf, sz); 00119 m_cmac->update(buf, sz); 00120 } 00121 00122 void EAX_Encryption::finish(secure_vector<byte>& buffer, size_t offset) 00123 { 00124 update(buffer, offset); 00125 00126 secure_vector<byte> data_mac = m_cmac->final(); 00127 xor_buf(data_mac, m_nonce_mac, data_mac.size()); 00128 xor_buf(data_mac, m_ad_mac, data_mac.size()); 00129 00130 buffer += std::make_pair(&data_mac[0], tag_size()); 00131 } 00132 00133 void EAX_Decryption::update(secure_vector<byte>& buffer, size_t offset) 00134 { 00135 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00136 const size_t sz = buffer.size() - offset; 00137 byte* buf = &buffer[offset]; 00138 00139 m_cmac->update(buf, sz); 00140 m_ctr->cipher(buf, buf, sz); 00141 } 00142 00143 void EAX_Decryption::finish(secure_vector<byte>& buffer, size_t offset) 00144 { 00145 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00146 const size_t sz = buffer.size() - offset; 00147 byte* buf = &buffer[offset]; 00148 00149 BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); 00150 00151 const size_t remaining = sz - tag_size(); 00152 00153 if(remaining) 00154 { 00155 m_cmac->update(buf, remaining); 00156 m_ctr->cipher(buf, buf, remaining); 00157 } 00158 00159 const byte* included_tag = &buf[remaining]; 00160 00161 secure_vector<byte> mac = m_cmac->final(); 00162 mac ^= m_nonce_mac; 00163 mac ^= m_ad_mac; 00164 00165 if(!same_mem(&mac[0], included_tag, tag_size())) 00166 throw Integrity_Failure("EAX tag check failed"); 00167 00168 buffer.resize(offset + remaining); 00169 } 00170 00171 }