2bda868953f08682a3a1d452d69084f88b572efe
[libgcrypt.git] / cipher / gost28147.c
1 /* gost28147.c - GOST 28147-89 implementation for Libgcrypt
2  * Copyright (C) 2012 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* GOST 28147-89 defines several modes of encryption:
21  * - ECB which should be used only for key transfer
22  * - CFB mode
23  * - OFB-like mode with additional transformation on keystream
24  *   RFC 5830 names this 'counter encryption' mode
25  *   Original GOST text uses the term 'gammirovanie'
26  * - MAC mode
27  *
28  * This implementation handles ECB and CFB modes via usual libgcrypt handling.
29  * OFB-like and MAC modes are unsupported.
30  */
31
32 #include <config.h>
33 #include "types.h"
34 #include "g10lib.h"
35 #include "cipher.h"
36
37
38 #define max(a, b) (((a) > (b)) ? (a) : (b))
39
40
41 /* This is an s-box from RFC4357, named GostR3411-94-TestParamSet
42  * For now it is the only s-box supported, as libgcrypt lacks mechanism
43  * for passing parameters to cipher in a usefull way. */
44 unsigned char test_sbox[16 * 8] = {
45   0x4, 0xE, 0x5, 0x7, 0x6, 0x4, 0xD, 0x1,
46   0xA, 0xB, 0x8, 0xD, 0xC, 0xB, 0xB, 0xF,
47   0x9, 0x4, 0x1, 0xA, 0x7, 0xA, 0x4, 0xD,
48   0x2, 0xC, 0xD, 0x1, 0x1, 0x0, 0x1, 0x0,
49
50   0xD, 0x6, 0xA, 0x0, 0x5, 0x7, 0x3, 0x5,
51   0x8, 0xD, 0x3, 0x8, 0xF, 0x2, 0xF, 0x7,
52   0x0, 0xF, 0x4, 0x9, 0xD, 0x1, 0x5, 0xA,
53   0xE, 0xA, 0x2, 0xF, 0x8, 0xD, 0x9, 0x4,
54
55   0x6, 0x2, 0xE, 0xE, 0x4, 0x3, 0x0, 0x9,
56   0xB, 0x3, 0xF, 0x4, 0xA, 0x6, 0xA, 0x2,
57   0x1, 0x8, 0xC, 0x6, 0x9, 0x8, 0xE, 0x3,
58   0xC, 0x1, 0x7, 0xC, 0xE, 0x5, 0x7, 0xE,
59
60   0x7, 0x0, 0x6, 0xB, 0x0, 0x9, 0x6, 0x6,
61   0xF, 0x7, 0x0, 0x2, 0x3, 0xC, 0x8, 0xB,
62   0x5, 0x5, 0x9, 0x5, 0xB, 0xF, 0x2, 0x8,
63   0x3, 0x9, 0xB, 0x3, 0x2, 0xE, 0xC, 0xC,
64 };
65
66 #include "gost.h"
67
68 static gcry_err_code_t
69 gost_setkey (void *c, const byte *key, unsigned keylen)
70 {
71   int i;
72   GOST28147_context *ctx = c;
73
74   if (keylen != 256 / 8)
75     return GPG_ERR_INV_KEYLEN;
76
77   for (i = 0; i < 8; i++)
78     {
79       ctx->key[i] = (key[4 * i + 3] << 24) |
80                     (key[4 * i + 2] << 16) |
81                     (key[4 * i + 1] <<  8) |
82                     (key[4 * i + 0] <<  0);
83     }
84   return GPG_ERR_NO_ERROR;
85 }
86
87 static void
88 gost_set_subst (GOST28147_context *ctx, unsigned char *sbox)
89 {
90   unsigned i, j;
91   for (i = 0; i < 4; i++)
92     {
93        for (j = 0; j < 256; j++)
94          {
95            ctx->subst[i][j] = sbox[ (j & 0xf) * 8 + 2 * i + 0] |
96                              (sbox[ (j >> 4)  * 8 + 2 * i + 1] << 4);
97          }
98     }
99   ctx->subst_set = 1;
100 }
101
102 static u32
103 gost_val (GOST28147_context *ctx, u32 cm1, int subkey)
104 {
105   cm1 += ctx->key[subkey];
106   cm1 = (ctx->subst[0][ (cm1 >>  0) & 0xff] <<  0) |
107         (ctx->subst[1][ (cm1 >>  8) & 0xff] <<  8) |
108         (ctx->subst[2][ (cm1 >> 16) & 0xff] << 16) |
109         (ctx->subst[3][ (cm1 >> 24) & 0xff] << 24);
110   return (cm1 << 11) | (cm1 >> 21);
111 }
112
113 static unsigned int
114 gost_encrypt_block (void *c, byte *outbuf, const byte *inbuf)
115 {
116   GOST28147_context *ctx = c;
117   u32 n1, n2;
118
119   if (!ctx->subst_set)
120     gost_set_subst (ctx, test_sbox);
121
122   n1 =  (inbuf[0] << 0) |
123         (inbuf[1] << 8) |
124         (inbuf[2] << 16) |
125         (inbuf[3] << 24);
126   n2 =  (inbuf[4] << 0) |
127         (inbuf[5] << 8) |
128         (inbuf[6] << 16) |
129         (inbuf[7] << 24);
130
131   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
132   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
133   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
134   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
135
136   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
137   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
138   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
139   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
140
141   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
142   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
143   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
144   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
145
146   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
147   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
148   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
149   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
150
151   outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff;
152   outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff;
153   outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff;
154   outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff;
155   outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff;
156   outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff;
157   outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff;
158   outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff;
159
160   return /* burn_stack */ 4*sizeof(void*) /* func call */ +
161                           3*sizeof(void*) /* stack */ +
162                           max( 4*sizeof(void*) /* gost_val call */,
163                                3*sizeof(void*) /* gost_set_subst call */ +
164                                2*sizeof(void*) /* gost_set subst stack*/ );
165 }
166
167 unsigned int _gcry_gost_enc_one (GOST28147_context *c, const byte *key,
168     byte *out, byte *in)
169 {
170   gost_setkey (c, key, 32);
171   return gost_encrypt_block (c, out, in) + 5 * sizeof(void *);
172 }
173
174 static unsigned int
175 gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf)
176 {
177   GOST28147_context *ctx = c;
178   u32 n1, n2;
179
180   if (!ctx->subst_set)
181     gost_set_subst (ctx, test_sbox);
182
183   n1 =  (inbuf[0] << 0) |
184         (inbuf[1] << 8) |
185         (inbuf[2] << 16) |
186         (inbuf[3] << 24);
187   n2 =  (inbuf[4] << 0) |
188         (inbuf[5] << 8) |
189         (inbuf[6] << 16) |
190         (inbuf[7] << 24);
191
192   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
193   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
194   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
195   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
196
197   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
198   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
199   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
200   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
201
202   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
203   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
204   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
205   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
206
207   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
208   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
209   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
210   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
211
212   outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff;
213   outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff;
214   outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff;
215   outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff;
216   outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff;
217   outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff;
218   outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff;
219   outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff;
220
221   return /* burn_stack */ 4*sizeof(void*) /* func call */ +
222                           3*sizeof(void*) /* stack */ +
223                           max( 4*sizeof(void*) /* gost_val call */,
224                                3*sizeof(void*) /* gost_set_subst call */ +
225                                2*sizeof(void*) /* gost_set subst stack*/ );
226 }
227
228 gcry_cipher_spec_t _gcry_cipher_spec_gost28147 =
229   {
230     GCRY_CIPHER_GOST28147, {0, 0},
231     "GOST28147", NULL, NULL, 8, 256,
232     sizeof (GOST28147_context),
233     gost_setkey,
234     gost_encrypt_block,
235     gost_decrypt_block,
236   };