Botan  1.11.15
src/lib/block/gost_28147/gost_28147.cpp
Go to the documentation of this file.
00001 /*
00002 * GOST 28147-89
00003 * (C) 1999-2009,2011 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/internal/block_utils.h>
00009 #include <botan/gost_28147.h>
00010 
00011 namespace Botan {
00012 
00013 BOTAN_REGISTER_BLOCK_CIPHER_NAMED_1STR(GOST_28147_89, "GOST-28147-89", "R3411_94_TestParam");
00014 
00015 byte GOST_28147_89_Params::sbox_entry(size_t row, size_t col) const
00016    {
00017    byte x = sboxes[4 * col + (row / 2)];
00018 
00019    return (row % 2 == 0) ? (x >> 4) : (x & 0x0F);
00020    }
00021 
00022 GOST_28147_89_Params::GOST_28147_89_Params(const std::string& n) : name(n)
00023    {
00024    // Encoded in the packed fromat from RFC 4357
00025 
00026    // GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0)
00027    static const byte GOST_R_3411_TEST_PARAMS[64] = {
00028       0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A,
00029       0x4D, 0x2C, 0xD1, 0x10, 0x10, 0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38,
00030       0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94, 0x62,
00031       0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3,
00032       0xC1, 0x7C, 0xE5, 0x7E, 0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C,
00033       0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC };
00034 
00035    // GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1)
00036    static const byte GOST_R_3411_CRYPTOPRO_PARAMS[64] = {
00037       0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42,
00038       0x4A, 0x60, 0xEC, 0xB4, 0x19, 0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F,
00039       0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF, 0xD1,
00040       0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87,
00041       0x03, 0x25, 0xEB, 0xFE, 0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE,
00042       0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC };
00043 
00044    if(name == "R3411_94_TestParam")
00045       sboxes = GOST_R_3411_TEST_PARAMS;
00046    else if(name == "R3411_CryptoPro")
00047       sboxes = GOST_R_3411_CRYPTOPRO_PARAMS;
00048    else
00049       throw Invalid_Argument("GOST_28147_89_Params: Unknown " + name);
00050    }
00051 
00052 /*
00053 * GOST Constructor
00054 */
00055 GOST_28147_89::GOST_28147_89(const GOST_28147_89_Params& param) : SBOX(1024)
00056    {
00057    // Convert the parallel 4x4 sboxes into larger word-based sboxes
00058    for(size_t i = 0; i != 4; ++i)
00059       for(size_t j = 0; j != 256; ++j)
00060          {
00061          const u32bit T = (param.sbox_entry(2*i  , j % 16)) |
00062                           (param.sbox_entry(2*i+1, j / 16) << 4);
00063          SBOX[256*i+j] = rotate_left(T, (11+8*i) % 32);
00064          }
00065    }
00066 
00067 std::string GOST_28147_89::name() const
00068    {
00069    /*
00070    'Guess' the right name for the sbox on the basis of the values.
00071    This would need to be updated if support for other sbox parameters
00072    is added. Preferably, we would just store the string value in the
00073    constructor, but can't break binary compat.
00074    */
00075    std::string sbox_name = "";
00076    if(SBOX[0] == 0x00072000)
00077       sbox_name = "R3411_94_TestParam";
00078    else if(SBOX[0] == 0x0002D000)
00079       sbox_name = "R3411_CryptoPro";
00080    else
00081       throw Internal_Error("GOST-28147 unrecognized sbox value");
00082 
00083    return "GOST-28147-89(" + sbox_name + ")";
00084    }
00085 
00086 /*
00087 * Two rounds of GOST
00088 */
00089 #define GOST_2ROUND(N1, N2, R1, R2)   \
00090    do {                               \
00091    u32bit T0 = N1 + EK[R1];           \
00092    N2 ^= SBOX[get_byte(3, T0)] |      \
00093          SBOX[get_byte(2, T0)+256] |  \
00094          SBOX[get_byte(1, T0)+512] |  \
00095          SBOX[get_byte(0, T0)+768];   \
00096                                       \
00097    u32bit T1 = N2 + EK[R2];           \
00098    N1 ^= SBOX[get_byte(3, T1)] |      \
00099          SBOX[get_byte(2, T1)+256] |  \
00100          SBOX[get_byte(1, T1)+512] |  \
00101          SBOX[get_byte(0, T1)+768];   \
00102    } while(0)
00103 
00104 /*
00105 * GOST Encryption
00106 */
00107 void GOST_28147_89::encrypt_n(const byte in[], byte out[], size_t blocks) const
00108    {
00109    for(size_t i = 0; i != blocks; ++i)
00110       {
00111       u32bit N1 = load_le<u32bit>(in, 0);
00112       u32bit N2 = load_le<u32bit>(in, 1);
00113 
00114       for(size_t j = 0; j != 3; ++j)
00115          {
00116          GOST_2ROUND(N1, N2, 0, 1);
00117          GOST_2ROUND(N1, N2, 2, 3);
00118          GOST_2ROUND(N1, N2, 4, 5);
00119          GOST_2ROUND(N1, N2, 6, 7);
00120          }
00121 
00122       GOST_2ROUND(N1, N2, 7, 6);
00123       GOST_2ROUND(N1, N2, 5, 4);
00124       GOST_2ROUND(N1, N2, 3, 2);
00125       GOST_2ROUND(N1, N2, 1, 0);
00126 
00127       store_le(out, N2, N1);
00128 
00129       in += BLOCK_SIZE;
00130       out += BLOCK_SIZE;
00131       }
00132    }
00133 
00134 /*
00135 * GOST Decryption
00136 */
00137 void GOST_28147_89::decrypt_n(const byte in[], byte out[], size_t blocks) const
00138    {
00139    for(size_t i = 0; i != blocks; ++i)
00140       {
00141       u32bit N1 = load_le<u32bit>(in, 0);
00142       u32bit N2 = load_le<u32bit>(in, 1);
00143 
00144       GOST_2ROUND(N1, N2, 0, 1);
00145       GOST_2ROUND(N1, N2, 2, 3);
00146       GOST_2ROUND(N1, N2, 4, 5);
00147       GOST_2ROUND(N1, N2, 6, 7);
00148 
00149       for(size_t j = 0; j != 3; ++j)
00150          {
00151          GOST_2ROUND(N1, N2, 7, 6);
00152          GOST_2ROUND(N1, N2, 5, 4);
00153          GOST_2ROUND(N1, N2, 3, 2);
00154          GOST_2ROUND(N1, N2, 1, 0);
00155          }
00156 
00157       store_le(out, N2, N1);
00158       in += BLOCK_SIZE;
00159       out += BLOCK_SIZE;
00160       }
00161    }
00162 
00163 /*
00164 * GOST Key Schedule
00165 */
00166 void GOST_28147_89::key_schedule(const byte key[], size_t)
00167    {
00168    EK.resize(8);
00169    for(size_t i = 0; i != 8; ++i)
00170       EK[i] = load_le<u32bit>(key, i);
00171    }
00172 
00173 void GOST_28147_89::clear()
00174    {
00175    zap(EK);
00176    }
00177 
00178 }