Add limited implementation of GOST 28147-89 cipher
[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 /* This is an s-box from RFC4357, named GostR3411-94-TestParamSet
39  * For now it is the only s-box supported, as libgcrypt lacks mechanism
40  * for passing parameters to cipher in a usefull way. */
41 unsigned char test_sbox[16 * 8] = {
42   0x4, 0xE, 0x5, 0x7, 0x6, 0x4, 0xD, 0x1,
43   0xA, 0xB, 0x8, 0xD, 0xC, 0xB, 0xB, 0xF,
44   0x9, 0x4, 0x1, 0xA, 0x7, 0xA, 0x4, 0xD,
45   0x2, 0xC, 0xD, 0x1, 0x1, 0x0, 0x1, 0x0,
46
47   0xD, 0x6, 0xA, 0x0, 0x5, 0x7, 0x3, 0x5,
48   0x8, 0xD, 0x3, 0x8, 0xF, 0x2, 0xF, 0x7,
49   0x0, 0xF, 0x4, 0x9, 0xD, 0x1, 0x5, 0xA,
50   0xE, 0xA, 0x2, 0xF, 0x8, 0xD, 0x9, 0x4,
51
52   0x6, 0x2, 0xE, 0xE, 0x4, 0x3, 0x0, 0x9,
53   0xB, 0x3, 0xF, 0x4, 0xA, 0x6, 0xA, 0x2,
54   0x1, 0x8, 0xC, 0x6, 0x9, 0x8, 0xE, 0x3,
55   0xC, 0x1, 0x7, 0xC, 0xE, 0x5, 0x7, 0xE,
56
57   0x7, 0x0, 0x6, 0xB, 0x0, 0x9, 0x6, 0x6,
58   0xF, 0x7, 0x0, 0x2, 0x3, 0xC, 0x8, 0xB,
59   0x5, 0x5, 0x9, 0x5, 0xB, 0xF, 0x2, 0x8,
60   0x3, 0x9, 0xB, 0x3, 0x2, 0xE, 0xC, 0xC,
61 };
62
63 #include "gost.h"
64
65 static gcry_err_code_t
66 gost_setkey (void *c, const byte *key, unsigned keylen)
67 {
68   int i;
69   GOST28147_context *ctx = c;
70
71   if (keylen != 256 / 8)
72     return GPG_ERR_INV_KEYLEN;
73
74   for (i = 0; i < 8; i++)
75     {
76       ctx->key[i] = (key[4 * i + 3] << 24) |
77                     (key[4 * i + 2] << 16) |
78                     (key[4 * i + 1] <<  8) |
79                     (key[4 * i + 0] <<  0);
80     }
81   return GPG_ERR_NO_ERROR;
82 }
83
84 static void
85 gost_set_subst (GOST28147_context *ctx, unsigned char *sbox)
86 {
87   unsigned i, j;
88   for (i = 0; i < 4; i++)
89     {
90        for (j = 0; j < 256; j++)
91          {
92            ctx->subst[i][j] = sbox[ (j & 0xf) * 8 + 2 * i + 0] |
93                              (sbox[ (j >> 4)  * 8 + 2 * i + 1] << 4);
94          }
95     }
96   ctx->subst_set = 1;
97 }
98
99 static u32
100 gost_val (GOST28147_context *ctx, u32 cm1, int subkey)
101 {
102   cm1 += ctx->key[subkey];
103   cm1 = (ctx->subst[0][ (cm1 >>  0) & 0xff] <<  0) |
104         (ctx->subst[1][ (cm1 >>  8) & 0xff] <<  8) |
105         (ctx->subst[2][ (cm1 >> 16) & 0xff] << 16) |
106         (ctx->subst[3][ (cm1 >> 24) & 0xff] << 24);
107   return (cm1 << 11) | (cm1 >> 21);
108 }
109
110 static void
111 gost_encrypt_block (void *c, byte *outbuf, const byte *inbuf)
112 {
113   GOST28147_context *ctx = c;
114   u32 n1, n2;
115
116   if (!ctx->subst_set)
117     gost_set_subst (ctx, test_sbox);
118
119   n1 =  (inbuf[0] << 0) |
120         (inbuf[1] << 8) |
121         (inbuf[2] << 16) |
122         (inbuf[3] << 24);
123   n2 =  (inbuf[4] << 0) |
124         (inbuf[5] << 8) |
125         (inbuf[6] << 16) |
126         (inbuf[7] << 24);
127
128   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
129   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
130   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
131   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
132
133   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
134   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
135   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
136   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
137
138   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
139   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
140   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
141   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
142
143   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
144   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
145   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
146   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
147
148   outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff;
149   outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff;
150   outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff;
151   outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff;
152   outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff;
153   outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff;
154   outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff;
155   outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff;
156 }
157
158 void _gcry_gost_enc_one (GOST28147_context *c, const byte *key,
159     byte *out, byte *in)
160 {
161   gost_setkey (c, key, 32);
162   gost_encrypt_block (c, out, in);
163 }
164
165 static void
166 gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf)
167 {
168   GOST28147_context *ctx = c;
169   u32 n1, n2;
170
171   if (!ctx->subst_set)
172     gost_set_subst (ctx, test_sbox);
173
174   n1 =  (inbuf[0] << 0) |
175         (inbuf[1] << 8) |
176         (inbuf[2] << 16) |
177         (inbuf[3] << 24);
178   n2 =  (inbuf[4] << 0) |
179         (inbuf[5] << 8) |
180         (inbuf[6] << 16) |
181         (inbuf[7] << 24);
182
183   n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
184   n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
185   n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
186   n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
187
188   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
189   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
190   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
191   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
192
193   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
194   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
195   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
196   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
197
198   n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
199   n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
200   n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
201   n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
202
203   outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff;
204   outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff;
205   outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff;
206   outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff;
207   outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff;
208   outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff;
209   outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff;
210   outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff;
211 }
212
213 gcry_cipher_spec_t _gcry_cipher_spec_gost28147 =
214   {
215     "GOST28147", NULL, NULL, 8, 256,
216     sizeof (GOST28147_context),
217     gost_setkey,
218     gost_encrypt_block,
219     gost_decrypt_block,
220   };