LCOV - code coverage report
Current view: top level - cipher - arcfour.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 42 0.0 %
Date: 2016-12-15 12:59:22 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /* arcfour.c  -  The arcfour stream cipher
       2             :  *      Copyright (C) 2000, 2001, 2002, 2003 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, write to the Free Software
      18             :  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
      19             :  *
      20             :  * For a description of the algorithm, see:
      21             :  *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
      22             :  *   ISBN 0-471-11709-9. Pages 397 ff.
      23             :  */
      24             : 
      25             : 
      26             : #include <config.h>
      27             : #include <stdio.h>
      28             : #include <stdlib.h>
      29             : #include <string.h>
      30             : #include "types.h"
      31             : #include "g10lib.h"
      32             : #include "cipher.h"
      33             : 
      34             : /* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
      35             : #undef USE_AMD64_ASM
      36             : #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
      37             :     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
      38             : # define USE_AMD64_ASM 1
      39             : #endif
      40             : 
      41             : static const char *selftest(void);
      42             : 
      43             : #ifdef USE_AMD64_ASM
      44             : 
      45             : typedef struct {
      46             :     u32 sbox[256];
      47             :     u32 idx_i, idx_j;
      48             : } ARCFOUR_context;
      49             : 
      50             : void _gcry_arcfour_amd64(void *key, size_t len, const byte *indata,
      51             :                          byte *outdata);
      52             : 
      53             : static void
      54           0 : encrypt_stream (void *context,
      55             :                 byte *outbuf, const byte *inbuf, size_t length)
      56             : {
      57             : #ifdef HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS
      58             :   const void *fn = _gcry_arcfour_amd64;
      59             :   /* Call SystemV ABI function without storing non-volatile XMM registers,
      60             :    * as target function does not use vector instruction sets. */
      61             :   asm volatile ("callq *%0\n\t"
      62             :                 : "+a" (fn),
      63             :                   "+D" (context),
      64             :                   "+S" (length),
      65             :                   "+d" (inbuf),
      66             :                   "+c" (outbuf)
      67             :                 :
      68             :                 : "cc", "memory", "r8", "r9", "r10", "r11");
      69             : #else
      70           0 :   _gcry_arcfour_amd64 (context, length, inbuf, outbuf );
      71             : #endif
      72           0 : }
      73             : 
      74             : #else /*!USE_AMD64_ASM*/
      75             : 
      76             : typedef struct {
      77             :     byte sbox[256];
      78             :     int idx_i, idx_j;
      79             : } ARCFOUR_context;
      80             : 
      81             : static void
      82             : do_encrypt_stream( ARCFOUR_context *ctx,
      83             :                    byte *outbuf, const byte *inbuf, size_t length )
      84             : {
      85             : #ifndef __i386__
      86             :   register unsigned int i = ctx->idx_i;
      87             :   register byte j = ctx->idx_j;
      88             :   register byte *sbox = ctx->sbox;
      89             :   register byte t, u;
      90             : 
      91             :   while ( length-- )
      92             :     {
      93             :       i++;
      94             :       t = sbox[(byte)i];
      95             :       j += t;
      96             :       u = sbox[j];
      97             :       sbox[(byte)i] = u;
      98             :       u += t;
      99             :       sbox[j] = t;
     100             :       *outbuf++ = sbox[u] ^ *inbuf++;
     101             :     }
     102             : 
     103             :   ctx->idx_i = (byte)i;
     104             :   ctx->idx_j = (byte)j;
     105             : #else /*__i386__*/
     106             :   /* Old implementation of arcfour is faster on i386 than the version above.
     107             :    * This is because version above increases register pressure which on i386
     108             :    * would push some of the variables to memory/stack.  Therefore keep this
     109             :    * version for i386 to avoid regressing performance.  */
     110             :   register int i = ctx->idx_i;
     111             :   register int j = ctx->idx_j;
     112             :   register byte *sbox = ctx->sbox;
     113             :   register int t;
     114             : 
     115             :   while ( length-- )
     116             :     {
     117             :       i++;
     118             :       i = i & 255; /* The and-op seems to be faster than the mod-op. */
     119             :       j += sbox[i];
     120             :       j &= 255;
     121             :       t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t;
     122             :       *outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255];
     123             :     }
     124             : 
     125             :   ctx->idx_i = i;
     126             :   ctx->idx_j = j;
     127             : #endif
     128             : }
     129             : 
     130             : static void
     131             : encrypt_stream (void *context,
     132             :                 byte *outbuf, const byte *inbuf, size_t length)
     133             : {
     134             :   ARCFOUR_context *ctx = (ARCFOUR_context *) context;
     135             :   do_encrypt_stream (ctx, outbuf, inbuf, length );
     136             :   _gcry_burn_stack (64);
     137             : }
     138             : 
     139             : #endif /*!USE_AMD64_ASM*/
     140             : 
     141             : 
     142             : static gcry_err_code_t
     143           0 : do_arcfour_setkey (void *context, const byte *key, unsigned int keylen)
     144             : {
     145             :   static int initialized;
     146             :   static const char* selftest_failed;
     147             :   int i, j;
     148             :   byte karr[256];
     149           0 :   ARCFOUR_context *ctx = (ARCFOUR_context *) context;
     150             : 
     151           0 :   if (!initialized )
     152             :     {
     153           0 :       initialized = 1;
     154           0 :       selftest_failed = selftest();
     155           0 :       if( selftest_failed )
     156           0 :         log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed );
     157             :     }
     158           0 :   if( selftest_failed )
     159           0 :     return GPG_ERR_SELFTEST_FAILED;
     160             : 
     161           0 :   if( keylen < 40/8 ) /* we want at least 40 bits */
     162           0 :     return GPG_ERR_INV_KEYLEN;
     163             : 
     164           0 :   ctx->idx_i = ctx->idx_j = 0;
     165           0 :   for (i=0; i < 256; i++ )
     166           0 :     ctx->sbox[i] = i;
     167           0 :   for (i=j=0; i < 256; i++,j++ )
     168             :     {
     169           0 :       if (j >= keylen)
     170           0 :         j = 0;
     171           0 :       karr[i] = key[j];
     172             :     }
     173           0 :   for (i=j=0; i < 256; i++ )
     174             :     {
     175             :       int t;
     176           0 :       j = (j + ctx->sbox[i] + karr[i]) & 255;
     177           0 :       t = ctx->sbox[i];
     178           0 :       ctx->sbox[i] = ctx->sbox[j];
     179           0 :       ctx->sbox[j] = t;
     180             :     }
     181           0 :   wipememory( karr, sizeof(karr) );
     182             : 
     183           0 :   return GPG_ERR_NO_ERROR;
     184             : }
     185             : 
     186             : static gcry_err_code_t
     187           0 : arcfour_setkey ( void *context, const byte *key, unsigned int keylen )
     188             : {
     189           0 :   ARCFOUR_context *ctx = (ARCFOUR_context *) context;
     190           0 :   gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen );
     191           0 :   return rc;
     192             : }
     193             : 
     194             : 
     195             : static const char*
     196           0 : selftest(void)
     197             : {
     198             :   ARCFOUR_context ctx;
     199             :   byte scratch[16];
     200             : 
     201             :   /* Test vector from Cryptlib labeled there: "from the
     202             :      State/Commerce Department". */
     203             :   static const byte key_1[] =
     204             :     { 0x61, 0x8A, 0x63, 0xD2, 0xFB };
     205             :   static const byte plaintext_1[] =
     206             :     { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C };
     207             :   static const byte ciphertext_1[] =
     208             :     { 0xF1, 0x38, 0x29, 0xC9, 0xDE };
     209             : 
     210           0 :   arcfour_setkey( &ctx, key_1, sizeof(key_1));
     211           0 :   encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1));
     212           0 :   if ( memcmp (scratch, ciphertext_1, sizeof (ciphertext_1)))
     213           0 :     return "Arcfour encryption test 1 failed.";
     214           0 :   arcfour_setkey( &ctx, key_1, sizeof(key_1));
     215           0 :   encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */
     216           0 :   if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1)))
     217           0 :     return "Arcfour decryption test 1 failed.";
     218           0 :   return NULL;
     219             : }
     220             : 
     221             : 
     222             : gcry_cipher_spec_t _gcry_cipher_spec_arcfour =
     223             :   {
     224             :     GCRY_CIPHER_ARCFOUR, {0, 0},
     225             :     "ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context),
     226             :     arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream,
     227             :   };

Generated by: LCOV version 1.12