Botan  1.11.15
src/lib/stream/salsa20/salsa20.cpp
Go to the documentation of this file.
00001 /*
00002 * Salsa20 / XSalsa20
00003 * (C) 1999-2010,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/salsa20.h>
00010 
00011 namespace Botan {
00012 
00013 BOTAN_REGISTER_STREAM_CIPHER_NOARGS(Salsa20);
00014 
00015 namespace {
00016 
00017 #define SALSA20_QUARTER_ROUND(x1, x2, x3, x4)    \
00018    do {                                          \
00019       x2 ^= rotate_left(x1 + x4,  7);            \
00020       x3 ^= rotate_left(x2 + x1,  9);            \
00021       x4 ^= rotate_left(x3 + x2, 13);            \
00022       x1 ^= rotate_left(x4 + x3, 18);            \
00023    } while(0)
00024 
00025 /*
00026 * Generate HSalsa20 cipher stream (for XSalsa20 IV setup)
00027 */
00028 void hsalsa20(u32bit output[8], const u32bit input[16])
00029    {
00030    u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
00031           x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
00032           x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
00033           x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
00034 
00035    for(size_t i = 0; i != 10; ++i)
00036       {
00037       SALSA20_QUARTER_ROUND(x00, x04, x08, x12);
00038       SALSA20_QUARTER_ROUND(x05, x09, x13, x01);
00039       SALSA20_QUARTER_ROUND(x10, x14, x02, x06);
00040       SALSA20_QUARTER_ROUND(x15, x03, x07, x11);
00041 
00042       SALSA20_QUARTER_ROUND(x00, x01, x02, x03);
00043       SALSA20_QUARTER_ROUND(x05, x06, x07, x04);
00044       SALSA20_QUARTER_ROUND(x10, x11, x08, x09);
00045       SALSA20_QUARTER_ROUND(x15, x12, x13, x14);
00046       }
00047 
00048    output[0] = x00;
00049    output[1] = x05;
00050    output[2] = x10;
00051    output[3] = x15;
00052    output[4] = x06;
00053    output[5] = x07;
00054    output[6] = x08;
00055    output[7] = x09;
00056    }
00057 
00058 /*
00059 * Generate Salsa20 cipher stream
00060 */
00061 void salsa20(byte output[64], const u32bit input[16])
00062    {
00063    u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
00064           x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
00065           x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
00066           x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
00067 
00068    for(size_t i = 0; i != 10; ++i)
00069       {
00070       SALSA20_QUARTER_ROUND(x00, x04, x08, x12);
00071       SALSA20_QUARTER_ROUND(x05, x09, x13, x01);
00072       SALSA20_QUARTER_ROUND(x10, x14, x02, x06);
00073       SALSA20_QUARTER_ROUND(x15, x03, x07, x11);
00074 
00075       SALSA20_QUARTER_ROUND(x00, x01, x02, x03);
00076       SALSA20_QUARTER_ROUND(x05, x06, x07, x04);
00077       SALSA20_QUARTER_ROUND(x10, x11, x08, x09);
00078       SALSA20_QUARTER_ROUND(x15, x12, x13, x14);
00079       }
00080 
00081    store_le(x00 + input[ 0], output + 4 *  0);
00082    store_le(x01 + input[ 1], output + 4 *  1);
00083    store_le(x02 + input[ 2], output + 4 *  2);
00084    store_le(x03 + input[ 3], output + 4 *  3);
00085    store_le(x04 + input[ 4], output + 4 *  4);
00086    store_le(x05 + input[ 5], output + 4 *  5);
00087    store_le(x06 + input[ 6], output + 4 *  6);
00088    store_le(x07 + input[ 7], output + 4 *  7);
00089    store_le(x08 + input[ 8], output + 4 *  8);
00090    store_le(x09 + input[ 9], output + 4 *  9);
00091    store_le(x10 + input[10], output + 4 * 10);
00092    store_le(x11 + input[11], output + 4 * 11);
00093    store_le(x12 + input[12], output + 4 * 12);
00094    store_le(x13 + input[13], output + 4 * 13);
00095    store_le(x14 + input[14], output + 4 * 14);
00096    store_le(x15 + input[15], output + 4 * 15);
00097    }
00098 
00099 }
00100 
00101 #undef SALSA20_QUARTER_ROUND
00102 
00103 /*
00104 * Combine cipher stream with message
00105 */
00106 void Salsa20::cipher(const byte in[], byte out[], size_t length)
00107    {
00108    while(length >= m_buffer.size() - m_position)
00109       {
00110       xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position);
00111       length -= (m_buffer.size() - m_position);
00112       in += (m_buffer.size() - m_position);
00113       out += (m_buffer.size() - m_position);
00114       salsa20(&m_buffer[0], &m_state[0]);
00115 
00116       ++m_state[8];
00117       m_state[9] += (m_state[8] == 0);
00118 
00119       m_position = 0;
00120       }
00121 
00122    xor_buf(out, in, &m_buffer[m_position], length);
00123 
00124    m_position += length;
00125    }
00126 
00127 /*
00128 * Salsa20 Key Schedule
00129 */
00130 void Salsa20::key_schedule(const byte key[], size_t length)
00131    {
00132    static const u32bit TAU[] =
00133       { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };
00134 
00135    static const u32bit SIGMA[] =
00136       { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
00137 
00138    const u32bit* CONSTANTS = (length == 16) ? TAU : SIGMA;
00139 
00140    m_state.resize(16);
00141    m_buffer.resize(64);
00142 
00143    m_state[0] = CONSTANTS[0];
00144    m_state[5] = CONSTANTS[1];
00145    m_state[10] = CONSTANTS[2];
00146    m_state[15] = CONSTANTS[3];
00147 
00148    m_state[1] = load_le<u32bit>(key, 0);
00149    m_state[2] = load_le<u32bit>(key, 1);
00150    m_state[3] = load_le<u32bit>(key, 2);
00151    m_state[4] = load_le<u32bit>(key, 3);
00152 
00153    if(length == 32)
00154       key += 16;
00155 
00156    m_state[11] = load_le<u32bit>(key, 0);
00157    m_state[12] = load_le<u32bit>(key, 1);
00158    m_state[13] = load_le<u32bit>(key, 2);
00159    m_state[14] = load_le<u32bit>(key, 3);
00160 
00161    m_position = 0;
00162 
00163    const byte ZERO[8] = { 0 };
00164    set_iv(ZERO, sizeof(ZERO));
00165    }
00166 
00167 /*
00168 * Return the name of this type
00169 */
00170 void Salsa20::set_iv(const byte iv[], size_t length)
00171    {
00172    if(!valid_iv_length(length))
00173       throw Invalid_IV_Length(name(), length);
00174 
00175    if(length == 8)
00176       {
00177       // Salsa20
00178       m_state[6] = load_le<u32bit>(iv, 0);
00179       m_state[7] = load_le<u32bit>(iv, 1);
00180       }
00181    else
00182       {
00183       // XSalsa20
00184       m_state[6] = load_le<u32bit>(iv, 0);
00185       m_state[7] = load_le<u32bit>(iv, 1);
00186       m_state[8] = load_le<u32bit>(iv, 2);
00187       m_state[9] = load_le<u32bit>(iv, 3);
00188 
00189       secure_vector<u32bit> hsalsa(8);
00190       hsalsa20(&hsalsa[0], &m_state[0]);
00191 
00192       m_state[ 1] = hsalsa[0];
00193       m_state[ 2] = hsalsa[1];
00194       m_state[ 3] = hsalsa[2];
00195       m_state[ 4] = hsalsa[3];
00196       m_state[ 6] = load_le<u32bit>(iv, 4);
00197       m_state[ 7] = load_le<u32bit>(iv, 5);
00198       m_state[11] = hsalsa[4];
00199       m_state[12] = hsalsa[5];
00200       m_state[13] = hsalsa[6];
00201       m_state[14] = hsalsa[7];
00202       }
00203 
00204    m_state[8] = 0;
00205    m_state[9] = 0;
00206 
00207    salsa20(&m_buffer[0], &m_state[0]);
00208    ++m_state[8];
00209    m_state[9] += (m_state[8] == 0);
00210 
00211    m_position = 0;
00212    }
00213 
00214 /*
00215 * Return the name of this type
00216 */
00217 std::string Salsa20::name() const
00218    {
00219    return "Salsa20";
00220    }
00221 
00222 /*
00223 * Clear memory of sensitive data
00224 */
00225 void Salsa20::clear()
00226    {
00227    zap(m_state);
00228    zap(m_buffer);
00229    m_position = 0;
00230    }
00231 
00232 }