Botan  1.11.15
src/lib/hash/skein/skein_512.cpp
Go to the documentation of this file.
00001 /*
00002 * The Skein-512 hash function
00003 * (C) 2009,2010,2014 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/internal/hash_utils.h>
00009 #include <botan/skein_512.h>
00010 #include <botan/parsing.h>
00011 #include <botan/exceptn.h>
00012 #include <botan/internal/xor_buf.h>
00013 #include <algorithm>
00014 
00015 namespace Botan {
00016 
00017 BOTAN_REGISTER_NAMED_T(HashFunction, "Skein-512", Skein_512, Skein_512::make);
00018 
00019 Skein_512* Skein_512::make(const Spec& spec)
00020    {
00021    return new Skein_512(spec.arg_as_integer(0, 512), spec.arg(1, ""));
00022    }
00023 
00024 Skein_512::Skein_512(size_t arg_output_bits,
00025                      const std::string& arg_personalization) :
00026    personalization(arg_personalization),
00027    output_bits(arg_output_bits),
00028    m_threefish(new Threefish_512),
00029    T(2), buffer(64), buf_pos(0)
00030    {
00031    if(output_bits == 0 || output_bits % 8 != 0 || output_bits > 512)
00032       throw Invalid_Argument("Bad output bits size for Skein-512");
00033 
00034    initial_block();
00035    }
00036 
00037 std::string Skein_512::name() const
00038    {
00039    if(personalization != "")
00040       return "Skein-512(" + std::to_string(output_bits) + "," +
00041                             personalization + ")";
00042    return "Skein-512(" + std::to_string(output_bits) + ")";
00043    }
00044 
00045 HashFunction* Skein_512::clone() const
00046    {
00047    return new Skein_512(output_bits, personalization);
00048    }
00049 
00050 void Skein_512::clear()
00051    {
00052    zeroise(buffer);
00053    buf_pos = 0;
00054 
00055    initial_block();
00056    }
00057 
00058 void Skein_512::reset_tweak(type_code type, bool final)
00059    {
00060    T[0] = 0;
00061 
00062    T[1] = (static_cast<u64bit>(type) << 56) |
00063           (static_cast<u64bit>(1) << 62) |
00064           (static_cast<u64bit>(final) << 63);
00065    }
00066 
00067 void Skein_512::initial_block()
00068    {
00069    const byte zeros[64] = { 0 };
00070 
00071    m_threefish->set_key(zeros, sizeof(zeros));
00072 
00073    // ASCII("SHA3") followed by version (0x0001) code
00074    byte config_str[32] = { 0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0 };
00075    store_le(u32bit(output_bits), config_str + 8);
00076 
00077    reset_tweak(SKEIN_CONFIG, true);
00078    ubi_512(config_str, sizeof(config_str));
00079 
00080    if(personalization != "")
00081       {
00082       /*
00083         This is a limitation of this implementation, and not of the
00084         algorithm specification. Could be fixed relatively easily, but
00085         doesn't seem worth the trouble.
00086       */
00087       if(personalization.length() > 64)
00088          throw Invalid_Argument("Skein personalization must be less than 64 bytes");
00089 
00090       const byte* bits = reinterpret_cast<const byte*>(personalization.data());
00091       reset_tweak(SKEIN_PERSONALIZATION, true);
00092       ubi_512(bits, personalization.length());
00093       }
00094 
00095    reset_tweak(SKEIN_MSG, false);
00096    }
00097 
00098 void Skein_512::ubi_512(const byte msg[], size_t msg_len)
00099    {
00100    secure_vector<u64bit> M(8);
00101 
00102    do
00103       {
00104       const size_t to_proc = std::min<size_t>(msg_len, 64);
00105       T[0] += to_proc;
00106 
00107       load_le(&M[0], msg, to_proc / 8);
00108 
00109       if(to_proc % 8)
00110          {
00111          for(size_t j = 0; j != to_proc % 8; ++j)
00112            M[to_proc/8] |= static_cast<u64bit>(msg[8*(to_proc/8)+j]) << (8*j);
00113          }
00114 
00115       m_threefish->skein_feedfwd(M, T);
00116 
00117       // clear first flag if set
00118       T[1] &= ~(static_cast<u64bit>(1) << 62);
00119 
00120       msg_len -= to_proc;
00121       msg += to_proc;
00122       } while(msg_len);
00123    }
00124 
00125 void Skein_512::add_data(const byte input[], size_t length)
00126    {
00127    if(length == 0)
00128       return;
00129 
00130    if(buf_pos)
00131       {
00132       buffer_insert(buffer, buf_pos, input, length);
00133       if(buf_pos + length > 64)
00134          {
00135          ubi_512(&buffer[0], buffer.size());
00136 
00137          input += (64 - buf_pos);
00138          length -= (64 - buf_pos);
00139          buf_pos = 0;
00140          }
00141       }
00142 
00143    const size_t full_blocks = (length - 1) / 64;
00144 
00145    if(full_blocks)
00146       ubi_512(input, 64*full_blocks);
00147 
00148    length -= full_blocks * 64;
00149 
00150    buffer_insert(buffer, buf_pos, input + full_blocks * 64, length);
00151    buf_pos += length;
00152    }
00153 
00154 void Skein_512::final_result(byte out[])
00155    {
00156    T[1] |= (static_cast<u64bit>(1) << 63); // final block flag
00157 
00158    for(size_t i = buf_pos; i != buffer.size(); ++i)
00159       buffer[i] = 0;
00160 
00161    ubi_512(&buffer[0], buf_pos);
00162 
00163    const byte counter[8] = { 0 };
00164 
00165    reset_tweak(SKEIN_OUTPUT, true);
00166    ubi_512(counter, sizeof(counter));
00167 
00168    copy_out_vec_le(out, output_bits / 8, m_threefish->m_K);
00169 
00170    buf_pos = 0;
00171    initial_block();
00172    }
00173 
00174 }