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 34static const char *selftest(void); 35 36typedef struct { 37 int idx_i, idx_j; 38 byte sbox[256]; 39} ARCFOUR_context; 40 41static void 42do_encrypt_stream( ARCFOUR_context *ctx, 43 byte *outbuf, const byte *inbuf, unsigned int length ) 44{ 45 register int i = ctx->idx_i; 46 register int j = ctx->idx_j; 47 register byte *sbox = ctx->sbox; 48 register int t; 49 50 while ( length-- ) 51 { 52 i++; 53 i = i & 255; /* The and-op seems to be faster than the mod-op. */ 54 j += sbox[i]; 55 j &= 255; 56 t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t; 57 *outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255]; 58 } 59 60 ctx->idx_i = i; 61 ctx->idx_j = j; 62} 63 64static void 65encrypt_stream (void *context, 66 byte *outbuf, const byte *inbuf, unsigned int length) 67{ 68 ARCFOUR_context *ctx = (ARCFOUR_context *) context; 69 do_encrypt_stream (ctx, outbuf, inbuf, length ); 70 _gcry_burn_stack (64); 71} 72 73 74static gcry_err_code_t 75do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) 76{ 77 static int initialized; 78 static const char* selftest_failed; 79 int i, j; 80 byte karr[256]; 81 ARCFOUR_context *ctx = (ARCFOUR_context *) context; 82 83 if (!initialized ) 84 { 85 initialized = 1; 86 selftest_failed = selftest(); 87 if( selftest_failed ) 88 log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed ); 89 } 90 if( selftest_failed ) 91 return GPG_ERR_SELFTEST_FAILED; 92 93 if( keylen < 40/8 ) /* we want at least 40 bits */ 94 return GPG_ERR_INV_KEYLEN; 95 96 ctx->idx_i = ctx->idx_j = 0; 97 for (i=0; i < 256; i++ ) 98 ctx->sbox[i] = i; 99 for (i=0; i < 256; i++ ) 100 karr[i] = key[i%keylen]; 101 for (i=j=0; i < 256; i++ ) 102 { 103 int t; 104 j = (j + ctx->sbox[i] + karr[i]) % 256; 105 t = ctx->sbox[i]; 106 ctx->sbox[i] = ctx->sbox[j]; 107 ctx->sbox[j] = t; 108 } 109 memset( karr, 0, 256 ); 110 111 return GPG_ERR_NO_ERROR; 112} 113 114static gcry_err_code_t 115arcfour_setkey ( void *context, const byte *key, unsigned int keylen ) 116{ 117 ARCFOUR_context *ctx = (ARCFOUR_context *) context; 118 gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen ); 119 _gcry_burn_stack (300); 120 return rc; 121} 122 123 124static const char* 125selftest(void) 126{ 127 ARCFOUR_context ctx; 128 byte scratch[16]; 129 130 /* Test vector from Cryptlib labeled there: "from the 131 State/Commerce Department". */ 132 static byte key_1[] = 133 { 0x61, 0x8A, 0x63, 0xD2, 0xFB }; 134 static byte plaintext_1[] = 135 { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C }; 136 static const byte ciphertext_1[] = 137 { 0xF1, 0x38, 0x29, 0xC9, 0xDE }; 138 139 arcfour_setkey( &ctx, key_1, sizeof(key_1)); 140 encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1)); 141 if ( memcmp (scratch, ciphertext_1, sizeof (ciphertext_1))) 142 return "Arcfour encryption test 1 failed."; 143 arcfour_setkey( &ctx, key_1, sizeof(key_1)); 144 encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */ 145 if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1))) 146 return "Arcfour decryption test 1 failed."; 147 return NULL; 148} 149 150 151gcry_cipher_spec_t _gcry_cipher_spec_arcfour = 152 { 153 "ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context), 154 arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream, 155 }; 156