Botan  1.11.15
src/lib/modes/aead/siv/siv.cpp
Go to the documentation of this file.
00001 /*
00002 * SIV Mode Encryption
00003 * (C) 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/siv.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(SIV_Encryption, SIV_Decryption);
00017 
00018 SIV_Mode::SIV_Mode(BlockCipher* cipher) :
00019    m_name(cipher->name() + "/SIV"),
00020    m_ctr(new CTR_BE(cipher->clone())),
00021    m_cmac(new CMAC(cipher))
00022    {
00023    }
00024 
00025 void SIV_Mode::clear()
00026    {
00027    m_ctr.reset();
00028    m_nonce.clear();
00029    m_msg_buf.clear();
00030    m_ad_macs.clear();
00031    }
00032 
00033 std::string SIV_Mode::name() const
00034    {
00035    return m_name;
00036    }
00037 
00038 bool SIV_Mode::valid_nonce_length(size_t) const
00039    {
00040    return true;
00041    }
00042 
00043 size_t SIV_Mode::update_granularity() const
00044    {
00045    /*
00046    This value does not particularly matter as regardless SIV_Mode::update
00047    buffers all input, so in theory this could be 1. However as for instance
00048    Transform_Filter creates update_granularity() byte buffers, use a
00049    somewhat large size to avoid bouncing on a tiny buffer.
00050    */
00051    return 128;
00052    }
00053 
00054 Key_Length_Specification SIV_Mode::key_spec() const
00055    {
00056    return m_cmac->key_spec().multiple(2);
00057    }
00058 
00059 void SIV_Mode::key_schedule(const byte key[], size_t length)
00060    {
00061    const size_t keylen = length / 2;
00062    m_cmac->set_key(key, keylen);
00063    m_ctr->set_key(key + keylen, keylen);
00064    m_ad_macs.clear();
00065    }
00066 
00067 void SIV_Mode::set_associated_data_n(size_t n, const byte ad[], size_t length)
00068    {
00069    if(n >= m_ad_macs.size())
00070       m_ad_macs.resize(n+1);
00071 
00072    m_ad_macs[n] = m_cmac->process(ad, length);
00073    }
00074 
00075 secure_vector<byte> SIV_Mode::start_raw(const byte nonce[], size_t nonce_len)
00076    {
00077    if(!valid_nonce_length(nonce_len))
00078       throw Invalid_IV_Length(name(), nonce_len);
00079 
00080    if(nonce_len)
00081       m_nonce = m_cmac->process(nonce, nonce_len);
00082    else
00083       m_nonce.clear();
00084 
00085    m_msg_buf.clear();
00086 
00087    return secure_vector<byte>();
00088    }
00089 
00090 void SIV_Mode::update(secure_vector<byte>& buffer, size_t offset)
00091    {
00092    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
00093    const size_t sz = buffer.size() - offset;
00094    byte* buf = &buffer[offset];
00095 
00096    m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
00097    buffer.resize(offset); // truncate msg
00098    }
00099 
00100 secure_vector<byte> SIV_Mode::S2V(const byte* text, size_t text_len)
00101    {
00102    const byte zero[16] = { 0 };
00103 
00104    secure_vector<byte> V = m_cmac->process(zero, 16);
00105 
00106    for(size_t i = 0; i != m_ad_macs.size(); ++i)
00107       {
00108       V = CMAC::poly_double(V);
00109       V ^= m_ad_macs[i];
00110       }
00111 
00112    if(m_nonce.size())
00113       {
00114       V = CMAC::poly_double(V);
00115       V ^= m_nonce;
00116       }
00117 
00118    if(text_len < 16)
00119       {
00120       V = CMAC::poly_double(V);
00121       xor_buf(&V[0], text, text_len);
00122       V[text_len] ^= 0x80;
00123       return m_cmac->process(V);
00124       }
00125 
00126    m_cmac->update(text, text_len - 16);
00127    xor_buf(&V[0], &text[text_len - 16], 16);
00128    m_cmac->update(V);
00129 
00130    return m_cmac->final();
00131    }
00132 
00133 void SIV_Mode::set_ctr_iv(secure_vector<byte> V)
00134    {
00135    V[8] &= 0x7F;
00136    V[12] &= 0x7F;
00137 
00138    ctr().set_iv(&V[0], V.size());
00139    }
00140 
00141 void SIV_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
00142    {
00143    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
00144 
00145    buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
00146 
00147    secure_vector<byte> V = S2V(&buffer[offset], buffer.size() - offset);
00148 
00149    buffer.insert(buffer.begin() + offset, V.begin(), V.end());
00150 
00151    set_ctr_iv(V);
00152    ctr().cipher1(&buffer[offset + V.size()], buffer.size() - offset - V.size());
00153    }
00154 
00155 void SIV_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
00156    {
00157    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
00158 
00159    buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
00160 
00161    const size_t sz = buffer.size() - offset;
00162 
00163    BOTAN_ASSERT(sz >= tag_size(), "We have the tag");
00164 
00165    secure_vector<byte> V(&buffer[offset], &buffer[offset + 16]);
00166 
00167    set_ctr_iv(V);
00168 
00169    ctr().cipher(&buffer[offset + V.size()],
00170                 &buffer[offset],
00171                 buffer.size() - offset - V.size());
00172 
00173    secure_vector<byte> T = S2V(&buffer[offset], buffer.size() - offset - V.size());
00174 
00175    if(T != V)
00176       throw Integrity_Failure("SIV tag check failed");
00177 
00178    buffer.resize(buffer.size() - tag_size());
00179    }
00180 
00181 }