Botan  1.11.15
src/lib/modes/aead/eax/eax.cpp
Go to the documentation of this file.
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 }