Coverage Report

Created: 2022-12-08 06:10

/src/libgcrypt/cipher/rfc2268.c
Line
Count
Source (jump to first uncovered line)
1
/* rfc2268.c  - The cipher described in rfc2268; aka Ron's Cipher 2.
2
 * Copyright (C) 2003 Nikos Mavroyanopoulos
3
 * Copyright (C) 2004 Free Software Foundation, Inc.
4
 *
5
 * This file is part of Libgcrypt
6
 *
7
 * Libgcrypt is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser general Public License as
9
 * published by the Free Software Foundation; either version 2.1 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * Libgcrypt is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20
 */
21
22
/* This implementation was written by Nikos Mavroyanopoulos for GNUTLS
23
 * as a Libgcrypt module (gnutls/lib/x509/rc2.c) and later adapted for
24
 * direct use by Libgcrypt by Werner Koch.  This implementation is
25
 * only useful for pkcs#12 decryption.
26
 *
27
 * The implementation here is based on Peter Gutmann's RRC.2 paper.
28
 */
29
30
31
#include <config.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include "g10lib.h"
36
#include "types.h"
37
#include "cipher.h"
38
#include "cipher-internal.h"
39
40
#define RFC2268_BLOCKSIZE 8
41
42
typedef struct
43
{
44
  u16 S[64];
45
} RFC2268_context;
46
47
static const unsigned char rfc2268_sbox[] = {
48
  217, 120, 249, 196,  25, 221, 181, 237,
49
   40, 233, 253, 121,  74, 160, 216, 157,
50
  198, 126,  55, 131,  43, 118,  83, 142,
51
   98,  76, 100, 136,  68, 139, 251, 162,
52
   23, 154,  89, 245, 135, 179,  79,  19,
53
   97,  69, 109, 141,   9, 129, 125,  50,
54
  189, 143,  64, 235, 134, 183, 123,  11,
55
  240, 149,  33,  34,  92, 107,  78, 130,
56
   84, 214, 101, 147, 206,  96, 178,  28,
57
  115,  86, 192,  20, 167, 140, 241, 220,
58
   18, 117, 202,  31,  59, 190, 228, 209,
59
   66,  61, 212,  48, 163,  60, 182,  38,
60
  111, 191,  14, 218,  70, 105,   7,  87,
61
   39, 242,  29, 155, 188, 148,  67,   3,
62
  248,  17, 199, 246, 144, 239,  62, 231,
63
    6, 195, 213,  47, 200, 102,  30, 215,
64
    8, 232, 234, 222, 128,  82, 238, 247,
65
  132, 170, 114, 172,  53,  77, 106,  42,
66
  150,  26, 210, 113,  90,  21,  73, 116,
67
   75, 159, 208,  94,   4,  24, 164, 236,
68
  194, 224,  65, 110,  15,  81, 203, 204,
69
   36, 145, 175,  80, 161, 244, 112,  57,
70
  153, 124,  58, 133,  35, 184, 180, 122,
71
  252,   2,  54,  91,  37,  85, 151,  49,
72
   45,  93, 250, 152, 227, 138, 146, 174,
73
    5, 223,  41,  16, 103, 108, 186, 201,
74
  211,   0, 230, 207, 225, 158, 168,  44,
75
   99,  22,   1,  63,  88, 226, 137, 169,
76
   13,  56,  52,  27, 171,  51, 255, 176,
77
  187,  72,  12,  95, 185, 177, 205,  46,
78
  197, 243, 219,  71, 229, 165, 156, 119,
79
   10, 166,  32, 104, 254, 127, 193, 173
80
};
81
82
0
#define rotl16(x,n)   (((x) << ((u16)(n))) | ((x) >> (16 - (u16)(n))))
83
0
#define rotr16(x,n)   (((x) >> ((u16)(n))) | ((x) << (16 - (u16)(n))))
84
85
static const char *selftest (void);
86
87
88
static void
89
do_encrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf)
90
0
{
91
0
  RFC2268_context *ctx = context;
92
0
  register int i, j;
93
0
  u16 word0 = 0, word1 = 0, word2 = 0, word3 = 0;
94
95
0
  word0 = (word0 << 8) | inbuf[1];
96
0
  word0 = (word0 << 8) | inbuf[0];
97
0
  word1 = (word1 << 8) | inbuf[3];
98
0
  word1 = (word1 << 8) | inbuf[2];
99
0
  word2 = (word2 << 8) | inbuf[5];
100
0
  word2 = (word2 << 8) | inbuf[4];
101
0
  word3 = (word3 << 8) | inbuf[7];
102
0
  word3 = (word3 << 8) | inbuf[6];
103
104
0
  for (i = 0; i < 16; i++)
105
0
    {
106
0
      j = i * 4;
107
      /* For some reason I cannot combine those steps. */
108
0
      word0 += (word1 & ~word3) + (word2 & word3) + ctx->S[j];
109
0
      word0 = rotl16(word0, 1);
110
111
0
      word1 += (word2 & ~word0) + (word3 & word0) + ctx->S[j + 1];
112
0
      word1 = rotl16(word1, 2);
113
114
0
      word2 += (word3 & ~word1) + (word0 & word1) + ctx->S[j + 2];
115
0
      word2 = rotl16(word2, 3);
116
117
0
      word3 += (word0 & ~word2) + (word1 & word2) + ctx->S[j + 3];
118
0
      word3 = rotl16(word3, 5);
119
120
0
      if (i == 4 || i == 10)
121
0
        {
122
0
          word0 += ctx->S[word3 & 63];
123
0
          word1 += ctx->S[word0 & 63];
124
0
          word2 += ctx->S[word1 & 63];
125
0
          word3 += ctx->S[word2 & 63];
126
0
        }
127
128
0
    }
129
130
0
  outbuf[0] = word0 & 255;
131
0
  outbuf[1] = word0 >> 8;
132
0
  outbuf[2] = word1 & 255;
133
0
  outbuf[3] = word1 >> 8;
134
0
  outbuf[4] = word2 & 255;
135
0
  outbuf[5] = word2 >> 8;
136
0
  outbuf[6] = word3 & 255;
137
0
  outbuf[7] = word3 >> 8;
138
0
}
139
140
static unsigned int
141
encrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf)
142
0
{
143
0
  do_encrypt (context, outbuf, inbuf);
144
0
  return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4);
145
0
}
146
147
static void
148
do_decrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf)
149
0
{
150
0
  RFC2268_context *ctx = context;
151
0
  register int i, j;
152
0
  u16 word0 = 0, word1 = 0, word2 = 0, word3 = 0;
153
154
0
  word0 = (word0 << 8) | inbuf[1];
155
0
  word0 = (word0 << 8) | inbuf[0];
156
0
  word1 = (word1 << 8) | inbuf[3];
157
0
  word1 = (word1 << 8) | inbuf[2];
158
0
  word2 = (word2 << 8) | inbuf[5];
159
0
  word2 = (word2 << 8) | inbuf[4];
160
0
  word3 = (word3 << 8) | inbuf[7];
161
0
  word3 = (word3 << 8) | inbuf[6];
162
163
0
  for (i = 15; i >= 0; i--)
164
0
    {
165
0
      j = i * 4;
166
167
0
      word3 = rotr16(word3, 5);
168
0
      word3 -= (word0 & ~word2) + (word1 & word2) + ctx->S[j + 3];
169
170
0
      word2 = rotr16(word2, 3);
171
0
      word2 -= (word3 & ~word1) + (word0 & word1) + ctx->S[j + 2];
172
173
0
      word1 = rotr16(word1, 2);
174
0
      word1 -= (word2 & ~word0) + (word3 & word0) + ctx->S[j + 1];
175
176
0
      word0 = rotr16(word0, 1);
177
0
      word0 -= (word1 & ~word3) + (word2 & word3) + ctx->S[j];
178
179
0
      if (i == 5 || i == 11)
180
0
        {
181
0
          word3 = word3 - ctx->S[word2 & 63];
182
0
          word2 = word2 - ctx->S[word1 & 63];
183
0
          word1 = word1 - ctx->S[word0 & 63];
184
0
          word0 = word0 - ctx->S[word3 & 63];
185
0
        }
186
187
0
    }
188
189
0
  outbuf[0] = word0 & 255;
190
0
  outbuf[1] = word0 >> 8;
191
0
  outbuf[2] = word1 & 255;
192
0
  outbuf[3] = word1 >> 8;
193
0
  outbuf[4] = word2 & 255;
194
0
  outbuf[5] = word2 >> 8;
195
0
  outbuf[6] = word3 & 255;
196
0
  outbuf[7] = word3 >> 8;
197
0
}
198
199
static unsigned int
200
decrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf)
201
0
{
202
0
  do_decrypt (context, outbuf, inbuf);
203
0
  return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4);
204
0
}
205
206
207
static gpg_err_code_t
208
setkey_core (void *context, const unsigned char *key, unsigned int keylen, int with_phase2)
209
0
{
210
0
  static int initialized;
211
0
  static const char *selftest_failed;
212
0
  RFC2268_context *ctx = context;
213
0
  unsigned int i;
214
0
  unsigned char *S, x;
215
0
  int len;
216
0
  int bits = keylen * 8;
217
218
0
  if (!initialized)
219
0
    {
220
0
      initialized = 1;
221
0
      selftest_failed = selftest ();
222
0
      if (selftest_failed)
223
0
        log_error ("RFC2268 selftest failed (%s).\n", selftest_failed);
224
0
    }
225
0
  if (selftest_failed)
226
0
    return GPG_ERR_SELFTEST_FAILED;
227
228
0
  if (keylen < 40 / 8) /* We want at least 40 bits. */
229
0
    return GPG_ERR_INV_KEYLEN;
230
231
0
  if (keylen > 128)
232
0
    return GPG_ERR_INV_KEYLEN;
233
234
0
  S = (unsigned char *) ctx->S;
235
236
0
  for (i = 0; i < keylen; i++)
237
0
    S[i] = key[i];
238
239
0
  for (i = keylen; i < 128; i++)
240
0
    S[i] = rfc2268_sbox[(S[i - keylen] + S[i - 1]) & 255];
241
242
0
  S[0] = rfc2268_sbox[S[0]];
243
244
  /* Phase 2 - reduce effective key size to "bits". This was not
245
   * discussed in Gutmann's paper. I've copied that from the public
246
   * domain code posted in sci.crypt. */
247
0
  if (with_phase2)
248
0
    {
249
0
      len = (bits + 7) >> 3;
250
0
      i = 128 - len;
251
0
      x = rfc2268_sbox[S[i] & (255 >> (7 & -bits))];
252
0
      S[i] = x;
253
254
0
      while (i--)
255
0
        {
256
0
          x = rfc2268_sbox[x ^ S[i + len]];
257
0
          S[i] = x;
258
0
        }
259
0
    }
260
261
  /* Make the expanded key, endian independent. */
262
0
  for (i = 0; i < 64; i++)
263
0
    ctx->S[i] = ( (u16) S[i * 2] | (((u16) S[i * 2 + 1]) << 8));
264
265
0
  return 0;
266
0
}
267
268
static gpg_err_code_t
269
do_setkey (void *context, const unsigned char *key, unsigned int keylen,
270
           cipher_bulk_ops_t *bulk_ops)
271
0
{
272
0
  (void)bulk_ops;
273
0
  return setkey_core (context, key, keylen, 1);
274
0
}
275
276
static const char *
277
selftest (void)
278
0
{
279
0
  RFC2268_context ctx;
280
0
  unsigned char scratch[16];
281
282
  /* Test vectors from Peter Gutmann's paper. */
283
0
  static unsigned char key_1[] =
284
0
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285
0
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
286
0
    };
287
0
  static unsigned char plaintext_1[] =
288
0
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
289
0
  static const unsigned char ciphertext_1[] =
290
0
    { 0x1C, 0x19, 0x8A, 0x83, 0x8D, 0xF0, 0x28, 0xB7 };
291
292
0
  static unsigned char key_2[] =
293
0
    { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
294
0
      0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
295
0
    };
296
0
  static unsigned char plaintext_2[] =
297
0
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
298
0
  static unsigned char ciphertext_2[] =
299
0
    { 0x50, 0xDC, 0x01, 0x62, 0xBD, 0x75, 0x7F, 0x31 };
300
301
  /* This one was checked against libmcrypt's RFC2268. */
302
0
  static unsigned char key_3[] =
303
0
    { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304
0
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
305
0
    };
306
0
  static unsigned char plaintext_3[] =
307
0
    { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
308
0
  static unsigned char ciphertext_3[] =
309
0
    { 0x8f, 0xd1, 0x03, 0x89, 0x33, 0x6b, 0xf9, 0x5e };
310
311
312
  /* First test. */
313
0
  setkey_core (&ctx, key_1, sizeof(key_1), 0);
314
0
  do_encrypt (&ctx, scratch, plaintext_1);
315
316
0
  if (memcmp (scratch, ciphertext_1, sizeof(ciphertext_1)))
317
0
    return "RFC2268 encryption test 1 failed.";
318
319
0
  setkey_core (&ctx, key_1, sizeof(key_1), 0);
320
0
  do_decrypt (&ctx, scratch, scratch);
321
0
  if (memcmp (scratch, plaintext_1, sizeof(plaintext_1)))
322
0
    return "RFC2268 decryption test 1 failed.";
323
324
  /* Second test. */
325
0
  setkey_core (&ctx, key_2, sizeof(key_2), 0);
326
0
  do_encrypt (&ctx, scratch, plaintext_2);
327
0
  if (memcmp (scratch, ciphertext_2, sizeof(ciphertext_2)))
328
0
    return "RFC2268 encryption test 2 failed.";
329
330
0
  setkey_core (&ctx, key_2, sizeof(key_2), 0);
331
0
  do_decrypt (&ctx, scratch, scratch);
332
0
  if (memcmp (scratch, plaintext_2, sizeof(plaintext_2)))
333
0
    return "RFC2268 decryption test 2 failed.";
334
335
  /* Third test. */
336
0
  setkey_core(&ctx, key_3, sizeof(key_3), 0);
337
0
  do_encrypt(&ctx, scratch, plaintext_3);
338
339
0
  if (memcmp(scratch, ciphertext_3, sizeof(ciphertext_3)))
340
0
    return "RFC2268 encryption test 3 failed.";
341
342
0
  setkey_core (&ctx, key_3, sizeof(key_3), 0);
343
0
  do_decrypt (&ctx, scratch, scratch);
344
0
  if (memcmp(scratch, plaintext_3, sizeof(plaintext_3)))
345
0
    return "RFC2268 decryption test 3 failed.";
346
347
0
  return NULL;
348
0
}
349
350
351
352
static const gcry_cipher_oid_spec_t oids_rfc2268_40[] =
353
  {
354
    /*{ "1.2.840.113549.3.2", GCRY_CIPHER_MODE_CBC },*/
355
    /* pbeWithSHAAnd40BitRC2_CBC */
356
    { "1.2.840.113549.1.12.1.6", GCRY_CIPHER_MODE_CBC },
357
    { NULL }
358
  };
359
360
static const gcry_cipher_oid_spec_t oids_rfc2268_128[] =
361
  {
362
    /* pbeWithSHAAnd128BitRC2_CBC */
363
    { "1.2.840.113549.1.12.1.5", GCRY_CIPHER_MODE_CBC },
364
    { NULL }
365
  };
366
367
gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 =
368
  {
369
    GCRY_CIPHER_RFC2268_40, {0, 0},
370
    "RFC2268_40", NULL, oids_rfc2268_40,
371
    RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context),
372
    do_setkey, encrypt_block, decrypt_block
373
  };
374
375
gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 =
376
  {
377
    GCRY_CIPHER_RFC2268_128, {0, 0},
378
    "RFC2268_128", NULL, oids_rfc2268_128,
379
    RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context),
380
    do_setkey, encrypt_block, decrypt_block
381
  };