Botan  1.11.15
src/lib/modes/aead/ocb/ocb.cpp
Go to the documentation of this file.
00001 /*
00002 * OCB Mode
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/ocb.h>
00010 #include <botan/cmac.h>
00011 
00012 namespace Botan {
00013 
00014 BOTAN_REGISTER_BLOCK_CIPHER_MODE_LEN(OCB_Encryption, OCB_Decryption, 16);
00015 
00016 // Has to be in Botan namespace so unique_ptr can reference it
00017 class L_computer
00018    {
00019    public:
00020       L_computer(const BlockCipher& cipher)
00021          {
00022          m_L_star.resize(cipher.block_size());
00023          cipher.encrypt(m_L_star);
00024          m_L_dollar = poly_double(star());
00025          m_L.push_back(poly_double(dollar()));
00026          }
00027 
00028       const secure_vector<byte>& star() const { return m_L_star; }
00029 
00030       const secure_vector<byte>& dollar() const { return m_L_dollar; }
00031 
00032       const secure_vector<byte>& operator()(size_t i) const { return get(i); }
00033 
00034       const secure_vector<byte>& compute_offsets(secure_vector<byte>& offset,
00035                                                  size_t block_index,
00036                                                  size_t blocks) const
00037          {
00038          const size_t BS = m_L_star.size();
00039          m_offset_buf.resize(blocks * BS);
00040 
00041          for(size_t i = 0; i != blocks; ++i)
00042             { // could be done in parallel
00043             offset ^= get(ctz(block_index + 1 + i));
00044             copy_mem(&m_offset_buf[BS*i], &offset[0], BS);
00045             }
00046 
00047          return m_offset_buf;
00048          }
00049 
00050    private:
00051       const secure_vector<byte>& get(size_t i) const
00052          {
00053          while(m_L.size() <= i)
00054             m_L.push_back(poly_double(m_L.back()));
00055 
00056          return m_L.at(i);
00057          }
00058 
00059       secure_vector<byte> poly_double(const secure_vector<byte>& in) const
00060          {
00061          return CMAC::poly_double(in);
00062          }
00063 
00064       secure_vector<byte> m_L_dollar, m_L_star;
00065       mutable std::vector<secure_vector<byte>> m_L;
00066       mutable secure_vector<byte> m_offset_buf;
00067    };
00068 
00069 namespace {
00070 
00071 /*
00072 * OCB's HASH
00073 */
00074 secure_vector<byte> ocb_hash(const L_computer& L,
00075                              const BlockCipher& cipher,
00076                              const byte ad[], size_t ad_len)
00077    {
00078    const size_t BS = cipher.block_size();
00079 
00080    secure_vector<byte> sum(BS);
00081    secure_vector<byte> offset(BS);
00082 
00083    secure_vector<byte> buf(BS);
00084 
00085    const size_t ad_blocks = (ad_len / BS);
00086    const size_t ad_remainder = (ad_len % BS);
00087 
00088    for(size_t i = 0; i != ad_blocks; ++i)
00089       {
00090       // this loop could run in parallel
00091       offset ^= L(ctz(i+1));
00092 
00093       buf = offset;
00094       xor_buf(&buf[0], &ad[BS*i], BS);
00095 
00096       cipher.encrypt(buf);
00097 
00098       sum ^= buf;
00099       }
00100 
00101    if(ad_remainder)
00102       {
00103       offset ^= L.star();
00104 
00105       buf = offset;
00106       xor_buf(&buf[0], &ad[BS*ad_blocks], ad_remainder);
00107       buf[ad_len % BS] ^= 0x80;
00108 
00109       cipher.encrypt(buf);
00110 
00111       sum ^= buf;
00112       }
00113 
00114    return sum;
00115    }
00116 
00117 }
00118 
00119 OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) :
00120    m_cipher(cipher),
00121    m_BS(m_cipher->block_size()),
00122    m_checksum(m_cipher->parallel_bytes()),
00123    m_offset(m_BS),
00124    m_ad_hash(m_BS),
00125    m_tag_size(tag_size)
00126    {
00127    if(BS() != 16)
00128       throw std::invalid_argument("OCB is not compatible with " + m_cipher->name());
00129 
00130    if(m_tag_size % 4 != 0 || m_tag_size < 8 || m_tag_size > BS())
00131       throw std::invalid_argument("OCB cannot produce a " + std::to_string(m_tag_size) +
00132                                   " byte tag");
00133 
00134    }
00135 
00136 OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ }
00137 
00138 void OCB_Mode::clear()
00139    {
00140    m_cipher.reset();
00141    m_L.reset();
00142 
00143    zeroise(m_ad_hash);
00144    zeroise(m_offset);
00145    zeroise(m_checksum);
00146    }
00147 
00148 bool OCB_Mode::valid_nonce_length(size_t length) const
00149    {
00150    return (length > 0 && length < m_cipher->block_size());
00151    }
00152 
00153 std::string OCB_Mode::name() const
00154    {
00155    return m_cipher->name() + "/OCB"; // include tag size
00156    }
00157 
00158 size_t OCB_Mode::update_granularity() const
00159    {
00160    return m_cipher->parallel_bytes();
00161    }
00162 
00163 Key_Length_Specification OCB_Mode::key_spec() const
00164    {
00165    return m_cipher->key_spec();
00166    }
00167 
00168 void OCB_Mode::key_schedule(const byte key[], size_t length)
00169    {
00170    m_cipher->set_key(key, length);
00171    m_L.reset(new L_computer(*m_cipher));
00172    }
00173 
00174 void OCB_Mode::set_associated_data(const byte ad[], size_t ad_len)
00175    {
00176    BOTAN_ASSERT(m_L, "A key was set");
00177    m_ad_hash = ocb_hash(*m_L, *m_cipher, &ad[0], ad_len);
00178    }
00179 
00180 secure_vector<byte>
00181 OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
00182    {
00183    BOTAN_ASSERT(nonce_len < BS(), "OCB nonce is less than cipher block size");
00184 
00185    secure_vector<byte> nonce_buf(BS());
00186 
00187    copy_mem(&nonce_buf[BS() - nonce_len], nonce, nonce_len);
00188    nonce_buf[0] = ((tag_size() * 8) % 128) << 1;
00189    nonce_buf[BS() - nonce_len - 1] = 1;
00190 
00191    const byte bottom = nonce_buf[BS()-1] & 0x3F;
00192    nonce_buf[BS()-1] &= 0xC0;
00193 
00194    const bool need_new_stretch = (m_last_nonce != nonce_buf);
00195 
00196    if(need_new_stretch)
00197       {
00198       m_last_nonce = nonce_buf;
00199 
00200       m_cipher->encrypt(nonce_buf);
00201 
00202       for(size_t i = 0; i != BS() / 2; ++i)
00203          nonce_buf.push_back(nonce_buf[i] ^ nonce_buf[i+1]);
00204 
00205       m_stretch = nonce_buf;
00206       }
00207 
00208    // now set the offset from stretch and bottom
00209 
00210    const size_t shift_bytes = bottom / 8;
00211    const size_t shift_bits  = bottom % 8;
00212 
00213    secure_vector<byte> offset(BS());
00214    for(size_t i = 0; i != BS(); ++i)
00215       {
00216       offset[i]  = (m_stretch[i+shift_bytes] << shift_bits);
00217       offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits));
00218       }
00219 
00220    return offset;
00221    }
00222 
00223 secure_vector<byte> OCB_Mode::start_raw(const byte nonce[], size_t nonce_len)
00224    {
00225    if(!valid_nonce_length(nonce_len))
00226       throw Invalid_IV_Length(name(), nonce_len);
00227 
00228    BOTAN_ASSERT(m_L, "A key was set");
00229 
00230    m_offset = update_nonce(nonce, nonce_len);
00231    zeroise(m_checksum);
00232    m_block_index = 0;
00233 
00234    return secure_vector<byte>();
00235    }
00236 
00237 void OCB_Encryption::encrypt(byte buffer[], size_t blocks)
00238    {
00239    const size_t par_blocks = m_checksum.size() / BS();
00240 
00241    while(blocks)
00242       {
00243       const size_t proc_blocks = std::min(blocks, par_blocks);
00244       const size_t proc_bytes = proc_blocks * BS();
00245 
00246       const auto& offsets = m_L->compute_offsets(m_offset, m_block_index, proc_blocks);
00247 
00248       xor_buf(&m_checksum[0], &buffer[0], proc_bytes);
00249 
00250       xor_buf(&buffer[0], &offsets[0], proc_bytes);
00251       m_cipher->encrypt_n(&buffer[0], &buffer[0], proc_blocks);
00252       xor_buf(&buffer[0], &offsets[0], proc_bytes);
00253 
00254       buffer += proc_bytes;
00255       blocks -= proc_blocks;
00256       m_block_index += proc_blocks;
00257       }
00258    }
00259 
00260 void OCB_Encryption::update(secure_vector<byte>& buffer, size_t offset)
00261    {
00262    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
00263    const size_t sz = buffer.size() - offset;
00264    byte* buf = &buffer[offset];
00265 
00266    BOTAN_ASSERT(sz % BS() == 0, "Input length is an even number of blocks");
00267    encrypt(buf, sz / BS());
00268    }
00269 
00270 void OCB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
00271    {
00272    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
00273    const size_t sz = buffer.size() - offset;
00274    byte* buf = &buffer[offset];
00275 
00276    if(sz)
00277       {
00278       const size_t final_full_blocks = sz / BS();
00279       const size_t remainder_bytes = sz - (final_full_blocks * BS());
00280 
00281       encrypt(buf, final_full_blocks);
00282 
00283       if(remainder_bytes)
00284          {
00285          BOTAN_ASSERT(remainder_bytes < BS(), "Only a partial block left");
00286          byte* remainder = &buf[sz - remainder_bytes];
00287 
00288          xor_buf(&m_checksum[0], &remainder[0], remainder_bytes);
00289          m_checksum[remainder_bytes] ^= 0x80;
00290 
00291          m_offset ^= m_L->star(); // Offset_*
00292 
00293          secure_vector<byte> zeros(BS());
00294          m_cipher->encrypt(m_offset, zeros);
00295          xor_buf(&remainder[0], &zeros[0], remainder_bytes);
00296          }
00297       }
00298 
00299    secure_vector<byte> checksum(BS());
00300 
00301    // fold checksum
00302    for(size_t i = 0; i != m_checksum.size(); ++i)
00303       checksum[i % checksum.size()] ^= m_checksum[i];
00304 
00305    // now compute the tag
00306    secure_vector<byte> mac = m_offset;
00307    mac ^= checksum;
00308    mac ^= m_L->dollar();
00309 
00310    m_cipher->encrypt(mac);
00311 
00312    mac ^= m_ad_hash;
00313 
00314    buffer += std::make_pair(&mac[0], tag_size());
00315 
00316    zeroise(m_checksum);
00317    zeroise(m_offset);
00318    m_block_index = 0;
00319    }
00320 
00321 void OCB_Decryption::decrypt(byte buffer[], size_t blocks)
00322    {
00323    const size_t par_bytes = m_cipher->parallel_bytes();
00324 
00325    BOTAN_ASSERT(par_bytes % BS() == 0, "Cipher is parallel in full blocks");
00326 
00327    const size_t par_blocks = par_bytes / BS();
00328 
00329    while(blocks)
00330       {
00331       const size_t proc_blocks = std::min(blocks, par_blocks);
00332       const size_t proc_bytes = proc_blocks * BS();
00333 
00334       const auto& offsets = m_L->compute_offsets(m_offset, m_block_index, proc_blocks);
00335 
00336       xor_buf(&buffer[0], &offsets[0], proc_bytes);
00337       m_cipher->decrypt_n(&buffer[0], &buffer[0], proc_blocks);
00338       xor_buf(&buffer[0], &offsets[0], proc_bytes);
00339 
00340       xor_buf(&m_checksum[0], &buffer[0], proc_bytes);
00341 
00342       buffer += proc_bytes;
00343       blocks -= proc_blocks;
00344       m_block_index += proc_blocks;
00345       }
00346    }
00347 
00348 void OCB_Decryption::update(secure_vector<byte>& buffer, size_t offset)
00349    {
00350    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
00351    const size_t sz = buffer.size() - offset;
00352    byte* buf = &buffer[offset];
00353 
00354    BOTAN_ASSERT(sz % BS() == 0, "Input length is an even number of blocks");
00355 
00356    decrypt(buf, sz / BS());
00357    }
00358 
00359 void OCB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
00360    {
00361    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
00362    const size_t sz = buffer.size() - offset;
00363    byte* buf = &buffer[offset];
00364 
00365    BOTAN_ASSERT(sz >= tag_size(), "We have the tag");
00366 
00367    const size_t remaining = sz - tag_size();
00368 
00369    if(remaining)
00370       {
00371       const size_t final_full_blocks = remaining / BS();
00372       const size_t final_bytes = remaining - (final_full_blocks * BS());
00373 
00374       decrypt(&buf[0], final_full_blocks);
00375 
00376       if(final_bytes)
00377          {
00378          BOTAN_ASSERT(final_bytes < BS(), "Only a partial block left");
00379 
00380          byte* remainder = &buf[remaining - final_bytes];
00381 
00382          m_offset ^= m_L->star(); // Offset_*
00383 
00384          secure_vector<byte> pad(BS());
00385          m_cipher->encrypt(m_offset, pad); // P_*
00386 
00387          xor_buf(&remainder[0], &pad[0], final_bytes);
00388 
00389          xor_buf(&m_checksum[0], &remainder[0], final_bytes);
00390          m_checksum[final_bytes] ^= 0x80;
00391          }
00392       }
00393 
00394    secure_vector<byte> checksum(BS());
00395 
00396    // fold checksum
00397    for(size_t i = 0; i != m_checksum.size(); ++i)
00398       checksum[i % checksum.size()] ^= m_checksum[i];
00399 
00400    // compute the mac
00401    secure_vector<byte> mac = m_offset;
00402    mac ^= checksum;
00403    mac ^= m_L->dollar();
00404 
00405    m_cipher->encrypt(mac);
00406 
00407    mac ^= m_ad_hash;
00408 
00409    // reset state
00410    zeroise(m_checksum);
00411    zeroise(m_offset);
00412    m_block_index = 0;
00413 
00414    // compare mac
00415    const byte* included_tag = &buf[remaining];
00416 
00417    if(!same_mem(&mac[0], included_tag, tag_size()))
00418       throw Integrity_Failure("OCB tag check failed");
00419 
00420    // remove tag from end of message
00421    buffer.resize(remaining + offset);
00422    }
00423 
00424 }