LCOV - code coverage report
Current view: top level - cipher - rfc2268.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 124 133 93.2 %
Date: 2017-03-02 16:44:37 Functions: 7 7 100.0 %

          Line data    Source code
       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             : 
      39             : #define RFC2268_BLOCKSIZE 8
      40             : 
      41             : typedef struct
      42             : {
      43             :   u16 S[64];
      44             : } RFC2268_context;
      45             : 
      46             : static const unsigned char rfc2268_sbox[] = {
      47             :   217, 120, 249, 196,  25, 221, 181, 237,
      48             :    40, 233, 253, 121,  74, 160, 216, 157,
      49             :   198, 126,  55, 131,  43, 118,  83, 142,
      50             :    98,  76, 100, 136,  68, 139, 251, 162,
      51             :    23, 154,  89, 245, 135, 179,  79,  19,
      52             :    97,  69, 109, 141,   9, 129, 125,  50,
      53             :   189, 143,  64, 235, 134, 183, 123,  11,
      54             :   240, 149,  33,  34,  92, 107,  78, 130,
      55             :    84, 214, 101, 147, 206,  96, 178,  28,
      56             :   115,  86, 192,  20, 167, 140, 241, 220,
      57             :    18, 117, 202,  31,  59, 190, 228, 209,
      58             :    66,  61, 212,  48, 163,  60, 182,  38,
      59             :   111, 191,  14, 218,  70, 105,   7,  87,
      60             :    39, 242,  29, 155, 188, 148,  67,   3,
      61             :   248,  17, 199, 246, 144, 239,  62, 231,
      62             :     6, 195, 213,  47, 200, 102,  30, 215,
      63             :     8, 232, 234, 222, 128,  82, 238, 247,
      64             :   132, 170, 114, 172,  53,  77, 106,  42,
      65             :   150,  26, 210, 113,  90,  21,  73, 116,
      66             :    75, 159, 208,  94,   4,  24, 164, 236,
      67             :   194, 224,  65, 110,  15,  81, 203, 204,
      68             :    36, 145, 175,  80, 161, 244, 112,  57,
      69             :   153, 124,  58, 133,  35, 184, 180, 122,
      70             :   252,   2,  54,  91,  37,  85, 151,  49,
      71             :    45,  93, 250, 152, 227, 138, 146, 174,
      72             :     5, 223,  41,  16, 103, 108, 186, 201,
      73             :   211,   0, 230, 207, 225, 158, 168,  44,
      74             :    99,  22,   1,  63,  88, 226, 137, 169,
      75             :    13,  56,  52,  27, 171,  51, 255, 176,
      76             :   187,  72,  12,  95, 185, 177, 205,  46,
      77             :   197, 243, 219,  71, 229, 165, 156, 119,
      78             :    10, 166,  32, 104, 254, 127, 193, 173
      79             : };
      80             : 
      81             : #define rotl16(x,n)   (((x) << ((u16)(n))) | ((x) >> (16 - (u16)(n))))
      82             : #define rotr16(x,n)   (((x) >> ((u16)(n))) | ((x) << (16 - (u16)(n))))
      83             : 
      84             : static const char *selftest (void);
      85             : 
      86             : 
      87             : static void
      88     5791646 : do_encrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf)
      89             : {
      90     5791646 :   RFC2268_context *ctx = context;
      91             :   register int i, j;
      92     5791646 :   u16 word0 = 0, word1 = 0, word2 = 0, word3 = 0;
      93             : 
      94     5791646 :   word0 = (word0 << 8) | inbuf[1];
      95     5791646 :   word0 = (word0 << 8) | inbuf[0];
      96     5791646 :   word1 = (word1 << 8) | inbuf[3];
      97     5791646 :   word1 = (word1 << 8) | inbuf[2];
      98     5791646 :   word2 = (word2 << 8) | inbuf[5];
      99     5791646 :   word2 = (word2 << 8) | inbuf[4];
     100     5791646 :   word3 = (word3 << 8) | inbuf[7];
     101     5791646 :   word3 = (word3 << 8) | inbuf[6];
     102             : 
     103    98457982 :   for (i = 0; i < 16; i++)
     104             :     {
     105    92666336 :       j = i * 4;
     106             :       /* For some reason I cannot combine those steps. */
     107    92666336 :       word0 += (word1 & ~word3) + (word2 & word3) + ctx->S[j];
     108    92666336 :       word0 = rotl16(word0, 1);
     109             : 
     110    92666336 :       word1 += (word2 & ~word0) + (word3 & word0) + ctx->S[j + 1];
     111    92666336 :       word1 = rotl16(word1, 2);
     112             : 
     113    92666336 :       word2 += (word3 & ~word1) + (word0 & word1) + ctx->S[j + 2];
     114    92666336 :       word2 = rotl16(word2, 3);
     115             : 
     116    92666336 :       word3 += (word0 & ~word2) + (word1 & word2) + ctx->S[j + 3];
     117    92666336 :       word3 = rotl16(word3, 5);
     118             : 
     119    92666336 :       if (i == 4 || i == 10)
     120             :         {
     121    11583292 :           word0 += ctx->S[word3 & 63];
     122    11583292 :           word1 += ctx->S[word0 & 63];
     123    11583292 :           word2 += ctx->S[word1 & 63];
     124    11583292 :           word3 += ctx->S[word2 & 63];
     125             :         }
     126             : 
     127             :     }
     128             : 
     129     5791646 :   outbuf[0] = word0 & 255;
     130     5791646 :   outbuf[1] = word0 >> 8;
     131     5791646 :   outbuf[2] = word1 & 255;
     132     5791646 :   outbuf[3] = word1 >> 8;
     133     5791646 :   outbuf[4] = word2 & 255;
     134     5791646 :   outbuf[5] = word2 >> 8;
     135     5791646 :   outbuf[6] = word3 & 255;
     136     5791646 :   outbuf[7] = word3 >> 8;
     137     5791646 : }
     138             : 
     139             : static unsigned int
     140     5791634 : encrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf)
     141             : {
     142     5791634 :   do_encrypt (context, outbuf, inbuf);
     143     5791634 :   return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4);
     144             : }
     145             : 
     146             : static void
     147     1434364 : do_decrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf)
     148             : {
     149     1434364 :   RFC2268_context *ctx = context;
     150             :   register int i, j;
     151     1434364 :   u16 word0 = 0, word1 = 0, word2 = 0, word3 = 0;
     152             : 
     153     1434364 :   word0 = (word0 << 8) | inbuf[1];
     154     1434364 :   word0 = (word0 << 8) | inbuf[0];
     155     1434364 :   word1 = (word1 << 8) | inbuf[3];
     156     1434364 :   word1 = (word1 << 8) | inbuf[2];
     157     1434364 :   word2 = (word2 << 8) | inbuf[5];
     158     1434364 :   word2 = (word2 << 8) | inbuf[4];
     159     1434364 :   word3 = (word3 << 8) | inbuf[7];
     160     1434364 :   word3 = (word3 << 8) | inbuf[6];
     161             : 
     162    24384188 :   for (i = 15; i >= 0; i--)
     163             :     {
     164    22949824 :       j = i * 4;
     165             : 
     166    22949824 :       word3 = rotr16(word3, 5);
     167    22949824 :       word3 -= (word0 & ~word2) + (word1 & word2) + ctx->S[j + 3];
     168             : 
     169    22949824 :       word2 = rotr16(word2, 3);
     170    22949824 :       word2 -= (word3 & ~word1) + (word0 & word1) + ctx->S[j + 2];
     171             : 
     172    22949824 :       word1 = rotr16(word1, 2);
     173    22949824 :       word1 -= (word2 & ~word0) + (word3 & word0) + ctx->S[j + 1];
     174             : 
     175    22949824 :       word0 = rotr16(word0, 1);
     176    22949824 :       word0 -= (word1 & ~word3) + (word2 & word3) + ctx->S[j];
     177             : 
     178    22949824 :       if (i == 5 || i == 11)
     179             :         {
     180     2868728 :           word3 = word3 - ctx->S[word2 & 63];
     181     2868728 :           word2 = word2 - ctx->S[word1 & 63];
     182     2868728 :           word1 = word1 - ctx->S[word0 & 63];
     183     2868728 :           word0 = word0 - ctx->S[word3 & 63];
     184             :         }
     185             : 
     186             :     }
     187             : 
     188     1434364 :   outbuf[0] = word0 & 255;
     189     1434364 :   outbuf[1] = word0 >> 8;
     190     1434364 :   outbuf[2] = word1 & 255;
     191     1434364 :   outbuf[3] = word1 >> 8;
     192     1434364 :   outbuf[4] = word2 & 255;
     193     1434364 :   outbuf[5] = word2 >> 8;
     194     1434364 :   outbuf[6] = word3 & 255;
     195     1434364 :   outbuf[7] = word3 >> 8;
     196     1434364 : }
     197             : 
     198             : static unsigned int
     199     1434352 : decrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf)
     200             : {
     201     1434352 :   do_decrypt (context, outbuf, inbuf);
     202     1434352 :   return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4);
     203             : }
     204             : 
     205             : 
     206             : static gpg_err_code_t
     207         290 : setkey_core (void *context, const unsigned char *key, unsigned int keylen, int with_phase2)
     208             : {
     209             :   static int initialized;
     210             :   static const char *selftest_failed;
     211         290 :   RFC2268_context *ctx = context;
     212             :   unsigned int i;
     213             :   unsigned char *S, x;
     214             :   int len;
     215         290 :   int bits = keylen * 8;
     216             : 
     217         290 :   if (!initialized)
     218             :     {
     219           4 :       initialized = 1;
     220           4 :       selftest_failed = selftest ();
     221           4 :       if (selftest_failed)
     222           0 :         log_error ("RFC2268 selftest failed (%s).\n", selftest_failed);
     223             :     }
     224         290 :   if (selftest_failed)
     225           0 :     return GPG_ERR_SELFTEST_FAILED;
     226             : 
     227         290 :   if (keylen < 40 / 8)       /* We want at least 40 bits. */
     228           0 :     return GPG_ERR_INV_KEYLEN;
     229             : 
     230         290 :   S = (unsigned char *) ctx->S;
     231             : 
     232        2246 :   for (i = 0; i < keylen; i++)
     233        1956 :     S[i] = key[i];
     234             : 
     235       35454 :   for (i = keylen; i < 128; i++)
     236       35164 :     S[i] = rfc2268_sbox[(S[i - keylen] + S[i - 1]) & 255];
     237             : 
     238         290 :   S[0] = rfc2268_sbox[S[0]];
     239             : 
     240             :   /* Phase 2 - reduce effective key size to "bits". This was not
     241             :    * discussed in Gutmann's paper. I've copied that from the public
     242             :    * domain code posted in sci.crypt. */
     243         290 :   if (with_phase2)
     244             :     {
     245         266 :       len = (bits + 7) >> 3;
     246         266 :       i = 128 - len;
     247         266 :       x = rfc2268_sbox[S[i] & (255 >> (7 & -bits))];
     248         266 :       S[i] = x;
     249             : 
     250       33008 :       while (i--)
     251             :         {
     252       32476 :           x = rfc2268_sbox[x ^ S[i + len]];
     253       32476 :           S[i] = x;
     254             :         }
     255             :     }
     256             : 
     257             :   /* Make the expanded key, endian independent. */
     258       18850 :   for (i = 0; i < 64; i++)
     259       18560 :     ctx->S[i] = ( (u16) S[i * 2] | (((u16) S[i * 2 + 1]) << 8));
     260             : 
     261         290 :   return 0;
     262             : }
     263             : 
     264             : static gpg_err_code_t
     265         266 : do_setkey (void *context, const unsigned char *key, unsigned int keylen)
     266             : {
     267         266 :   return setkey_core (context, key, keylen, 1);
     268             : }
     269             : 
     270             : static const char *
     271           4 : selftest (void)
     272             : {
     273             :   RFC2268_context ctx;
     274             :   unsigned char scratch[16];
     275             : 
     276             :   /* Test vectors from Peter Gutmann's paper. */
     277             :   static unsigned char key_1[] =
     278             :     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     279             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     280             :     };
     281             :   static unsigned char plaintext_1[] =
     282             :     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
     283             :   static const unsigned char ciphertext_1[] =
     284             :     { 0x1C, 0x19, 0x8A, 0x83, 0x8D, 0xF0, 0x28, 0xB7 };
     285             : 
     286             :   static unsigned char key_2[] =
     287             :     { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     288             :       0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
     289             :     };
     290             :   static unsigned char plaintext_2[] =
     291             :     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
     292             :   static unsigned char ciphertext_2[] =
     293             :     { 0x50, 0xDC, 0x01, 0x62, 0xBD, 0x75, 0x7F, 0x31 };
     294             : 
     295             :   /* This one was checked against libmcrypt's RFC2268. */
     296             :   static unsigned char key_3[] =
     297             :     { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     298             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     299             :     };
     300             :   static unsigned char plaintext_3[] =
     301             :     { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
     302             :   static unsigned char ciphertext_3[] =
     303             :     { 0x8f, 0xd1, 0x03, 0x89, 0x33, 0x6b, 0xf9, 0x5e };
     304             : 
     305             : 
     306             :   /* First test. */
     307           4 :   setkey_core (&ctx, key_1, sizeof(key_1), 0);
     308           4 :   do_encrypt (&ctx, scratch, plaintext_1);
     309             : 
     310           4 :   if (memcmp (scratch, ciphertext_1, sizeof(ciphertext_1)))
     311           0 :     return "RFC2268 encryption test 1 failed.";
     312             : 
     313           4 :   setkey_core (&ctx, key_1, sizeof(key_1), 0);
     314           4 :   do_decrypt (&ctx, scratch, scratch);
     315           4 :   if (memcmp (scratch, plaintext_1, sizeof(plaintext_1)))
     316           0 :     return "RFC2268 decryption test 1 failed.";
     317             : 
     318             :   /* Second test. */
     319           4 :   setkey_core (&ctx, key_2, sizeof(key_2), 0);
     320           4 :   do_encrypt (&ctx, scratch, plaintext_2);
     321           4 :   if (memcmp (scratch, ciphertext_2, sizeof(ciphertext_2)))
     322           0 :     return "RFC2268 encryption test 2 failed.";
     323             : 
     324           4 :   setkey_core (&ctx, key_2, sizeof(key_2), 0);
     325           4 :   do_decrypt (&ctx, scratch, scratch);
     326           4 :   if (memcmp (scratch, plaintext_2, sizeof(plaintext_2)))
     327           0 :     return "RFC2268 decryption test 2 failed.";
     328             : 
     329             :   /* Third test. */
     330           4 :   setkey_core(&ctx, key_3, sizeof(key_3), 0);
     331           4 :   do_encrypt(&ctx, scratch, plaintext_3);
     332             : 
     333           4 :   if (memcmp(scratch, ciphertext_3, sizeof(ciphertext_3)))
     334           0 :     return "RFC2268 encryption test 3 failed.";
     335             : 
     336           4 :   setkey_core (&ctx, key_3, sizeof(key_3), 0);
     337           4 :   do_decrypt (&ctx, scratch, scratch);
     338           4 :   if (memcmp(scratch, plaintext_3, sizeof(plaintext_3)))
     339           0 :     return "RFC2268 decryption test 3 failed.";
     340             : 
     341           4 :   return NULL;
     342             : }
     343             : 
     344             : 
     345             : 
     346             : static gcry_cipher_oid_spec_t oids_rfc2268_40[] =
     347             :   {
     348             :     /*{ "1.2.840.113549.3.2", GCRY_CIPHER_MODE_CBC },*/
     349             :     /* pbeWithSHAAnd40BitRC2_CBC */
     350             :     { "1.2.840.113549.1.12.1.6", GCRY_CIPHER_MODE_CBC },
     351             :     { NULL }
     352             :   };
     353             : 
     354             : static gcry_cipher_oid_spec_t oids_rfc2268_128[] =
     355             :   {
     356             :     /* pbeWithSHAAnd128BitRC2_CBC */
     357             :     { "1.2.840.113549.1.12.1.5", GCRY_CIPHER_MODE_CBC },
     358             :     { NULL }
     359             :   };
     360             : 
     361             : gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 =
     362             :   {
     363             :     GCRY_CIPHER_RFC2268_40, {0, 0},
     364             :     "RFC2268_40", NULL, oids_rfc2268_40,
     365             :     RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context),
     366             :     do_setkey, encrypt_block, decrypt_block
     367             :   };
     368             : 
     369             : gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 =
     370             :   {
     371             :     GCRY_CIPHER_RFC2268_128, {0, 0},
     372             :     "RFC2268_128", NULL, oids_rfc2268_128,
     373             :     RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context),
     374             :     do_setkey, encrypt_block, decrypt_block
     375             :   };

Generated by: LCOV version 1.13