Botan
1.11.15
|
00001 /* 00002 * ChaCha 00003 * (C) 2014 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/internal/stream_utils.h> 00009 #include <botan/chacha.h> 00010 00011 namespace Botan { 00012 00013 BOTAN_REGISTER_STREAM_CIPHER_NOARGS(ChaCha); 00014 00015 void ChaCha::chacha(byte output[64], const u32bit input[16]) 00016 { 00017 u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], 00018 x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], 00019 x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], 00020 x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; 00021 00022 #define CHACHA_QUARTER_ROUND(a, b, c, d) \ 00023 do { \ 00024 a += b; d ^= a; d = rotate_left(d, 16); \ 00025 c += d; b ^= c; b = rotate_left(b, 12); \ 00026 a += b; d ^= a; d = rotate_left(d, 8); \ 00027 c += d; b ^= c; b = rotate_left(b, 7); \ 00028 } while(0) 00029 00030 for(size_t i = 0; i != 10; ++i) 00031 { 00032 CHACHA_QUARTER_ROUND(x00, x04, x08, x12); 00033 CHACHA_QUARTER_ROUND(x01, x05, x09, x13); 00034 CHACHA_QUARTER_ROUND(x02, x06, x10, x14); 00035 CHACHA_QUARTER_ROUND(x03, x07, x11, x15); 00036 00037 CHACHA_QUARTER_ROUND(x00, x05, x10, x15); 00038 CHACHA_QUARTER_ROUND(x01, x06, x11, x12); 00039 CHACHA_QUARTER_ROUND(x02, x07, x08, x13); 00040 CHACHA_QUARTER_ROUND(x03, x04, x09, x14); 00041 } 00042 00043 #undef CHACHA_QUARTER_ROUND 00044 00045 store_le(x00 + input[ 0], output + 4 * 0); 00046 store_le(x01 + input[ 1], output + 4 * 1); 00047 store_le(x02 + input[ 2], output + 4 * 2); 00048 store_le(x03 + input[ 3], output + 4 * 3); 00049 store_le(x04 + input[ 4], output + 4 * 4); 00050 store_le(x05 + input[ 5], output + 4 * 5); 00051 store_le(x06 + input[ 6], output + 4 * 6); 00052 store_le(x07 + input[ 7], output + 4 * 7); 00053 store_le(x08 + input[ 8], output + 4 * 8); 00054 store_le(x09 + input[ 9], output + 4 * 9); 00055 store_le(x10 + input[10], output + 4 * 10); 00056 store_le(x11 + input[11], output + 4 * 11); 00057 store_le(x12 + input[12], output + 4 * 12); 00058 store_le(x13 + input[13], output + 4 * 13); 00059 store_le(x14 + input[14], output + 4 * 14); 00060 store_le(x15 + input[15], output + 4 * 15); 00061 } 00062 00063 /* 00064 * Combine cipher stream with message 00065 */ 00066 void ChaCha::cipher(const byte in[], byte out[], size_t length) 00067 { 00068 while(length >= m_buffer.size() - m_position) 00069 { 00070 xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); 00071 length -= (m_buffer.size() - m_position); 00072 in += (m_buffer.size() - m_position); 00073 out += (m_buffer.size() - m_position); 00074 chacha(&m_buffer[0], &m_state[0]); 00075 00076 ++m_state[12]; 00077 m_state[13] += (m_state[12] == 0); 00078 00079 m_position = 0; 00080 } 00081 00082 xor_buf(out, in, &m_buffer[m_position], length); 00083 00084 m_position += length; 00085 } 00086 00087 /* 00088 * ChaCha Key Schedule 00089 */ 00090 void ChaCha::key_schedule(const byte key[], size_t length) 00091 { 00092 static const u32bit TAU[] = 00093 { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; 00094 00095 static const u32bit SIGMA[] = 00096 { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; 00097 00098 const u32bit* CONSTANTS = (length == 16) ? TAU : SIGMA; 00099 00100 m_state.resize(16); 00101 m_buffer.resize(64); 00102 00103 m_state[0] = CONSTANTS[0]; 00104 m_state[1] = CONSTANTS[1]; 00105 m_state[2] = CONSTANTS[2]; 00106 m_state[3] = CONSTANTS[3]; 00107 00108 m_state[4] = load_le<u32bit>(key, 0); 00109 m_state[5] = load_le<u32bit>(key, 1); 00110 m_state[6] = load_le<u32bit>(key, 2); 00111 m_state[7] = load_le<u32bit>(key, 3); 00112 00113 if(length == 32) 00114 key += 16; 00115 00116 m_state[8] = load_le<u32bit>(key, 0); 00117 m_state[9] = load_le<u32bit>(key, 1); 00118 m_state[10] = load_le<u32bit>(key, 2); 00119 m_state[11] = load_le<u32bit>(key, 3); 00120 00121 m_position = 0; 00122 00123 const byte ZERO[8] = { 0 }; 00124 set_iv(ZERO, sizeof(ZERO)); 00125 } 00126 00127 void ChaCha::set_iv(const byte iv[], size_t length) 00128 { 00129 if(!valid_iv_length(length)) 00130 throw Invalid_IV_Length(name(), length); 00131 00132 m_state[12] = 0; 00133 m_state[13] = 0; 00134 00135 if(length == 8) 00136 { 00137 m_state[14] = load_le<u32bit>(iv, 0); 00138 m_state[15] = load_le<u32bit>(iv, 1); 00139 } 00140 else if(length == 12) 00141 { 00142 m_state[13] = load_le<u32bit>(iv, 0); 00143 m_state[14] = load_le<u32bit>(iv, 1); 00144 m_state[15] = load_le<u32bit>(iv, 2); 00145 } 00146 00147 chacha(&m_buffer[0], &m_state[0]); 00148 ++m_state[12]; 00149 m_state[13] += (m_state[12] == 0); 00150 00151 m_position = 0; 00152 } 00153 00154 void ChaCha::clear() 00155 { 00156 zap(m_state); 00157 zap(m_buffer); 00158 m_position = 0; 00159 } 00160 00161 }