/src/libgcrypt/cipher/arcfour.c
Line | Count | Source (jump to first uncovered line) |
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 | | #include "cipher-internal.h" |
34 | | |
35 | | /* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ |
36 | | #undef USE_AMD64_ASM |
37 | | #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ |
38 | | defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) |
39 | | # define USE_AMD64_ASM 1 |
40 | | #endif |
41 | | |
42 | | static const char *selftest(void); |
43 | | |
44 | | #ifdef USE_AMD64_ASM |
45 | | |
46 | | typedef struct { |
47 | | u32 sbox[256]; |
48 | | u32 idx_i, idx_j; |
49 | | } ARCFOUR_context; |
50 | | |
51 | | void _gcry_arcfour_amd64(void *key, size_t len, const byte *indata, |
52 | | byte *outdata); |
53 | | |
54 | | static void |
55 | | encrypt_stream (void *context, |
56 | | byte *outbuf, const byte *inbuf, size_t length) |
57 | 0 | { |
58 | 0 | _gcry_arcfour_amd64 (context, length, inbuf, outbuf ); |
59 | 0 | } |
60 | | |
61 | | #else /*!USE_AMD64_ASM*/ |
62 | | |
63 | | typedef struct { |
64 | | byte sbox[256]; |
65 | | int idx_i, idx_j; |
66 | | } ARCFOUR_context; |
67 | | |
68 | | static void |
69 | | do_encrypt_stream( ARCFOUR_context *ctx, |
70 | | byte *outbuf, const byte *inbuf, size_t length ) |
71 | | { |
72 | | #ifndef __i386__ |
73 | | register unsigned int i = ctx->idx_i; |
74 | | register byte j = ctx->idx_j; |
75 | | register byte *sbox = ctx->sbox; |
76 | | register byte t, u; |
77 | | |
78 | | while ( length-- ) |
79 | | { |
80 | | i++; |
81 | | t = sbox[(byte)i]; |
82 | | j += t; |
83 | | u = sbox[j]; |
84 | | sbox[(byte)i] = u; |
85 | | u += t; |
86 | | sbox[j] = t; |
87 | | *outbuf++ = sbox[u] ^ *inbuf++; |
88 | | } |
89 | | |
90 | | ctx->idx_i = (byte)i; |
91 | | ctx->idx_j = (byte)j; |
92 | | #else /*__i386__*/ |
93 | | /* Old implementation of arcfour is faster on i386 than the version above. |
94 | | * This is because version above increases register pressure which on i386 |
95 | | * would push some of the variables to memory/stack. Therefore keep this |
96 | | * version for i386 to avoid regressing performance. */ |
97 | | register int i = ctx->idx_i; |
98 | | register int j = ctx->idx_j; |
99 | | register byte *sbox = ctx->sbox; |
100 | | register int t; |
101 | | |
102 | | while ( length-- ) |
103 | | { |
104 | | i++; |
105 | | i = i & 255; /* The and-op seems to be faster than the mod-op. */ |
106 | | j += sbox[i]; |
107 | | j &= 255; |
108 | | t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t; |
109 | | *outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255]; |
110 | | } |
111 | | |
112 | | ctx->idx_i = i; |
113 | | ctx->idx_j = j; |
114 | | #endif |
115 | | } |
116 | | |
117 | | static void |
118 | | encrypt_stream (void *context, |
119 | | byte *outbuf, const byte *inbuf, size_t length) |
120 | | { |
121 | | ARCFOUR_context *ctx = (ARCFOUR_context *) context; |
122 | | do_encrypt_stream (ctx, outbuf, inbuf, length ); |
123 | | _gcry_burn_stack (64); |
124 | | } |
125 | | |
126 | | #endif /*!USE_AMD64_ASM*/ |
127 | | |
128 | | |
129 | | static gcry_err_code_t |
130 | | do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) |
131 | 0 | { |
132 | 0 | static int initialized; |
133 | 0 | static const char* selftest_failed; |
134 | 0 | int i, j; |
135 | 0 | byte karr[256]; |
136 | 0 | ARCFOUR_context *ctx = (ARCFOUR_context *) context; |
137 | |
|
138 | 0 | if (!initialized ) |
139 | 0 | { |
140 | 0 | initialized = 1; |
141 | 0 | selftest_failed = selftest(); |
142 | 0 | if( selftest_failed ) |
143 | 0 | log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed ); |
144 | 0 | } |
145 | 0 | if( selftest_failed ) |
146 | 0 | return GPG_ERR_SELFTEST_FAILED; |
147 | | |
148 | 0 | if( keylen < 40/8 ) /* we want at least 40 bits */ |
149 | 0 | return GPG_ERR_INV_KEYLEN; |
150 | | |
151 | 0 | ctx->idx_i = ctx->idx_j = 0; |
152 | 0 | for (i=0; i < 256; i++ ) |
153 | 0 | ctx->sbox[i] = i; |
154 | 0 | for (i=j=0; i < 256; i++,j++ ) |
155 | 0 | { |
156 | 0 | if (j >= keylen) |
157 | 0 | j = 0; |
158 | 0 | karr[i] = key[j]; |
159 | 0 | } |
160 | 0 | for (i=j=0; i < 256; i++ ) |
161 | 0 | { |
162 | 0 | int t; |
163 | 0 | j = (j + ctx->sbox[i] + karr[i]) & 255; |
164 | 0 | t = ctx->sbox[i]; |
165 | 0 | ctx->sbox[i] = ctx->sbox[j]; |
166 | 0 | ctx->sbox[j] = t; |
167 | 0 | } |
168 | 0 | wipememory( karr, sizeof(karr) ); |
169 | |
|
170 | 0 | return GPG_ERR_NO_ERROR; |
171 | 0 | } |
172 | | |
173 | | static gcry_err_code_t |
174 | | arcfour_setkey ( void *context, const byte *key, unsigned int keylen, |
175 | | cipher_bulk_ops_t *bulk_ops ) |
176 | 0 | { |
177 | 0 | ARCFOUR_context *ctx = (ARCFOUR_context *) context; |
178 | 0 | gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen ); |
179 | 0 | (void)bulk_ops; |
180 | 0 | return rc; |
181 | 0 | } |
182 | | |
183 | | |
184 | | static const char* |
185 | | selftest(void) |
186 | 0 | { |
187 | 0 | ARCFOUR_context ctx; |
188 | 0 | byte scratch[16]; |
189 | | |
190 | | /* Test vector from Cryptlib labeled there: "from the |
191 | | State/Commerce Department". */ |
192 | 0 | static const byte key_1[] = |
193 | 0 | { 0x61, 0x8A, 0x63, 0xD2, 0xFB }; |
194 | 0 | static const byte plaintext_1[] = |
195 | 0 | { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C }; |
196 | 0 | static const byte ciphertext_1[] = |
197 | 0 | { 0xF1, 0x38, 0x29, 0xC9, 0xDE }; |
198 | |
|
199 | 0 | arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL); |
200 | 0 | encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1)); |
201 | 0 | if ( memcmp (scratch, ciphertext_1, sizeof (ciphertext_1))) |
202 | 0 | return "Arcfour encryption test 1 failed."; |
203 | 0 | arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL); |
204 | 0 | encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */ |
205 | 0 | if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1))) |
206 | 0 | return "Arcfour decryption test 1 failed."; |
207 | 0 | return NULL; |
208 | 0 | } |
209 | | |
210 | | |
211 | | gcry_cipher_spec_t _gcry_cipher_spec_arcfour = |
212 | | { |
213 | | GCRY_CIPHER_ARCFOUR, {0, 0}, |
214 | | "ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context), |
215 | | arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream, |
216 | | }; |