Botan 2.19.3
Crypto and TLS for C&
gost_28147.cpp
Go to the documentation of this file.
1/*
2* GOST 28147-89
3* (C) 1999-2009,2011 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/gost_28147.h>
9#include <botan/exceptn.h>
10#include <botan/loadstor.h>
11#include <botan/rotate.h>
12
13namespace Botan {
14
15uint8_t GOST_28147_89_Params::sbox_entry(size_t row, size_t col) const
16 {
17 const uint8_t x = m_sboxes[4 * col + (row / 2)];
18 return (row % 2 == 0) ? (x >> 4) : (x & 0x0F);
19 }
20
21uint8_t GOST_28147_89_Params::sbox_pair(size_t row, size_t col) const
22 {
23 const uint8_t x = m_sboxes[4 * (col % 16) + row];
24 const uint8_t y = m_sboxes[4 * (col / 16) + row];
25 return (x >> 4) | (y << 4);
26 }
27
28GOST_28147_89_Params::GOST_28147_89_Params(const std::string& n) : m_name(n)
29 {
30 // Encoded in the packed fromat from RFC 4357
31
32 // GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0)
33 static const uint8_t GOST_R_3411_TEST_PARAMS[64] = {
34 0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A,
35 0x4D, 0x2C, 0xD1, 0x10, 0x10, 0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38,
36 0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94, 0x62,
37 0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3,
38 0xC1, 0x7C, 0xE5, 0x7E, 0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C,
39 0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC };
40
41 // GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1)
42 static const uint8_t GOST_R_3411_CRYPTOPRO_PARAMS[64] = {
43 0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42,
44 0x4A, 0x60, 0xEC, 0xB4, 0x19, 0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F,
45 0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF, 0xD1,
46 0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87,
47 0x03, 0x25, 0xEB, 0xFE, 0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE,
48 0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC };
49
50 if(m_name == "R3411_94_TestParam")
51 m_sboxes = GOST_R_3411_TEST_PARAMS;
52 else if(m_name == "R3411_CryptoPro")
53 m_sboxes = GOST_R_3411_CRYPTOPRO_PARAMS;
54 else
55 throw Invalid_Argument("GOST_28147_89_Params: Unknown " + m_name);
56 }
57
58/*
59* GOST Constructor
60*/
62 {
63 // Convert the parallel 4x4 sboxes into larger word-based sboxes
64
65 for(size_t i = 0; i != 256; ++i)
66 {
67 m_SBOX[i ] = rotl<11, uint32_t>(param.sbox_pair(0, i));
68 m_SBOX[i+256] = rotl<19, uint32_t>(param.sbox_pair(1, i));
69 m_SBOX[i+512] = rotl<27, uint32_t>(param.sbox_pair(2, i));
70 m_SBOX[i+768] = rotl< 3, uint32_t>(param.sbox_pair(3, i));
71 }
72 }
73
74std::string GOST_28147_89::name() const
75 {
76 /*
77 'Guess' the right name for the sbox on the basis of the values.
78 This would need to be updated if support for other sbox parameters
79 is added. Preferably, we would just store the string value in the
80 constructor, but can't break binary compat.
81 */
82 std::string sbox_name = "";
83 if(m_SBOX[0] == 0x00072000)
84 sbox_name = "R3411_94_TestParam";
85 else if(m_SBOX[0] == 0x0002D000)
86 sbox_name = "R3411_CryptoPro";
87 else
88 throw Internal_Error("GOST-28147 unrecognized sbox value");
89
90 return "GOST-28147-89(" + sbox_name + ")";
91 }
92
93/*
94* Two rounds of GOST
95*/
96#define GOST_2ROUND(N1, N2, R1, R2) \
97 do { \
98 uint32_t T0 = N1 + m_EK[R1]; \
99 N2 ^= m_SBOX[get_byte(3, T0)] | \
100 m_SBOX[get_byte(2, T0)+256] | \
101 m_SBOX[get_byte(1, T0)+512] | \
102 m_SBOX[get_byte(0, T0)+768]; \
103 \
104 uint32_t T1 = N2 + m_EK[R2]; \
105 N1 ^= m_SBOX[get_byte(3, T1)] | \
106 m_SBOX[get_byte(2, T1)+256] | \
107 m_SBOX[get_byte(1, T1)+512] | \
108 m_SBOX[get_byte(0, T1)+768]; \
109 } while(0)
110
111/*
112* GOST Encryption
113*/
114void GOST_28147_89::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
115 {
116 verify_key_set(m_EK.empty() == false);
117
118 for(size_t i = 0; i != blocks; ++i)
119 {
120 uint32_t N1 = load_le<uint32_t>(in, 0);
121 uint32_t N2 = load_le<uint32_t>(in, 1);
122
123 for(size_t j = 0; j != 3; ++j)
124 {
125 GOST_2ROUND(N1, N2, 0, 1);
126 GOST_2ROUND(N1, N2, 2, 3);
127 GOST_2ROUND(N1, N2, 4, 5);
128 GOST_2ROUND(N1, N2, 6, 7);
129 }
130
131 GOST_2ROUND(N1, N2, 7, 6);
132 GOST_2ROUND(N1, N2, 5, 4);
133 GOST_2ROUND(N1, N2, 3, 2);
134 GOST_2ROUND(N1, N2, 1, 0);
135
136 store_le(out, N2, N1);
137
138 in += BLOCK_SIZE;
139 out += BLOCK_SIZE;
140 }
141 }
142
143/*
144* GOST Decryption
145*/
146void GOST_28147_89::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
147 {
148 verify_key_set(m_EK.empty() == false);
149
150 for(size_t i = 0; i != blocks; ++i)
151 {
152 uint32_t N1 = load_le<uint32_t>(in, 0);
153 uint32_t N2 = load_le<uint32_t>(in, 1);
154
155 GOST_2ROUND(N1, N2, 0, 1);
156 GOST_2ROUND(N1, N2, 2, 3);
157 GOST_2ROUND(N1, N2, 4, 5);
158 GOST_2ROUND(N1, N2, 6, 7);
159
160 for(size_t j = 0; j != 3; ++j)
161 {
162 GOST_2ROUND(N1, N2, 7, 6);
163 GOST_2ROUND(N1, N2, 5, 4);
164 GOST_2ROUND(N1, N2, 3, 2);
165 GOST_2ROUND(N1, N2, 1, 0);
166 }
167
168 store_le(out, N2, N1);
169 in += BLOCK_SIZE;
170 out += BLOCK_SIZE;
171 }
172 }
173
174/*
175* GOST Key Schedule
176*/
177void GOST_28147_89::key_schedule(const uint8_t key[], size_t)
178 {
179 m_EK.resize(8);
180 for(size_t i = 0; i != 8; ++i)
181 m_EK[i] = load_le<uint32_t>(key, i);
182 }
183
185 {
186 zap(m_EK);
187 }
188
189}
uint8_t sbox_pair(size_t row, size_t col) const
uint8_t sbox_entry(size_t row, size_t col) const
GOST_28147_89_Params(const std::string &name="R3411_94_TestParam")
void clear() override
void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
std::string name() const override
GOST_28147_89(const GOST_28147_89_Params &params)
void verify_key_set(bool cond) const
Definition sym_algo.h:171
#define GOST_2ROUND(N1, N2, R1, R2)
void zap(std::vector< T, Alloc > &vec)
Definition secmem.h:124
uint32_t load_le< uint32_t >(const uint8_t in[], size_t off)
Definition loadstor.h:198
void store_le(uint16_t in, uint8_t out[2])
Definition loadstor.h:454