Botan
1.11.15
|
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 }