|
@@ -0,0 +1,131 @@
|
|
1
|
+/*
|
|
2
|
+ * The ARC4 stream cipher.
|
|
3
|
+ *
|
|
4
|
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
|
|
5
|
+ *
|
|
6
|
+ * This program is free software; you can redistribute it and/or
|
|
7
|
+ * modify it under the terms of the GNU General Public License as
|
|
8
|
+ * published by the Free Software Foundation; either version 2 of the
|
|
9
|
+ * License, or any later version.
|
|
10
|
+ *
|
|
11
|
+ * This program is distributed in the hope that it will be useful, but
|
|
12
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
14
|
+ * General Public License for more details.
|
|
15
|
+ *
|
|
16
|
+ * You should have received a copy of the GNU General Public License
|
|
17
|
+ * along with this program; if not, write to the Free Software
|
|
18
|
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
19
|
+ */
|
|
20
|
+
|
|
21
|
+FILE_LICENCE ( GPL2_OR_LATER );
|
|
22
|
+
|
|
23
|
+#include <gpxe/crypto.h>
|
|
24
|
+#include <gpxe/arc4.h>
|
|
25
|
+
|
|
26
|
+#define SWAP( ary, i, j ) \
|
|
27
|
+ ({ u8 temp = ary[i]; ary[i] = ary[j]; ary[j] = temp; })
|
|
28
|
+
|
|
29
|
+/**
|
|
30
|
+ * Set ARC4 key
|
|
31
|
+ *
|
|
32
|
+ * @v ctxv ARC4 encryption context
|
|
33
|
+ * @v keyv Key to set
|
|
34
|
+ * @v keylen Length of key
|
|
35
|
+ *
|
|
36
|
+ * If an initialisation vector is to be used, it should be prepended
|
|
37
|
+ * to the key; ARC4 does not implement the @c setiv function because
|
|
38
|
+ * there is no standard length for an initialisation vector in the
|
|
39
|
+ * cipher.
|
|
40
|
+ */
|
|
41
|
+static int arc4_setkey ( void *ctxv, const void *keyv, size_t keylen )
|
|
42
|
+{
|
|
43
|
+ struct arc4_ctx *ctx = ctxv;
|
|
44
|
+ const u8 *key = keyv;
|
|
45
|
+ u8 *S = ctx->state;
|
|
46
|
+ int i, j;
|
|
47
|
+
|
|
48
|
+ for ( i = 0; i < 256; i++ ) {
|
|
49
|
+ S[i] = i;
|
|
50
|
+ }
|
|
51
|
+
|
|
52
|
+ for ( i = j = 0; i < 256; i++ ) {
|
|
53
|
+ j = ( j + S[i] + key[i % keylen] ) & 0xff;
|
|
54
|
+ SWAP ( S, i, j );
|
|
55
|
+ }
|
|
56
|
+
|
|
57
|
+ ctx->i = ctx->j = 0;
|
|
58
|
+ return 0;
|
|
59
|
+}
|
|
60
|
+
|
|
61
|
+/**
|
|
62
|
+ * Perform ARC4 encryption or decryption
|
|
63
|
+ *
|
|
64
|
+ * @v ctxv ARC4 encryption context
|
|
65
|
+ * @v srcv Data to encrypt or decrypt
|
|
66
|
+ * @v dstv Location to store encrypted or decrypted data
|
|
67
|
+ * @v len Length of data to operate on
|
|
68
|
+ *
|
|
69
|
+ * ARC4 is a stream cipher that works by generating a stream of PRNG
|
|
70
|
+ * data based on the key, and XOR'ing it with the data to be
|
|
71
|
+ * encrypted. Since XOR is symmetric, encryption and decryption in
|
|
72
|
+ * ARC4 are the same operation.
|
|
73
|
+ *
|
|
74
|
+ * If you pass a @c NULL source or destination pointer, @a len
|
|
75
|
+ * keystream bytes will be consumed without encrypting any data.
|
|
76
|
+ */
|
|
77
|
+static void arc4_xor ( void *ctxv, const void *srcv, void *dstv,
|
|
78
|
+ size_t len )
|
|
79
|
+{
|
|
80
|
+ struct arc4_ctx *ctx = ctxv;
|
|
81
|
+ const u8 *src = srcv;
|
|
82
|
+ u8 *dst = dstv;
|
|
83
|
+ u8 *S = ctx->state;
|
|
84
|
+ int i = ctx->i, j = ctx->j;
|
|
85
|
+
|
|
86
|
+ while ( len-- ) {
|
|
87
|
+ i = ( i + 1 ) & 0xff;
|
|
88
|
+ j = ( j + S[i] ) & 0xff;
|
|
89
|
+ SWAP ( S, i, j );
|
|
90
|
+ if ( srcv && dstv )
|
|
91
|
+ *dst++ = *src++ ^ S[(S[i] + S[j]) & 0xff];
|
|
92
|
+ }
|
|
93
|
+
|
|
94
|
+ ctx->i = i;
|
|
95
|
+ ctx->j = j;
|
|
96
|
+}
|
|
97
|
+
|
|
98
|
+static void arc4_setiv ( void *ctx __unused, const void *iv __unused )
|
|
99
|
+{
|
|
100
|
+ /* ARC4 does not use a fixed-length IV */
|
|
101
|
+}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+/**
|
|
105
|
+ * Perform ARC4 encryption or decryption, skipping initial keystream bytes
|
|
106
|
+ *
|
|
107
|
+ * @v key ARC4 encryption key
|
|
108
|
+ * @v keylen Key length
|
|
109
|
+ * @v skip Number of bytes of keystream to skip
|
|
110
|
+ * @v src Message to encrypt or decrypt
|
|
111
|
+ * @v msglen Length of message
|
|
112
|
+ * @ret dst Encrypted or decrypted message
|
|
113
|
+ */
|
|
114
|
+void arc4_skip ( const void *key, size_t keylen, size_t skip,
|
|
115
|
+ const void *src, void *dst, size_t msglen )
|
|
116
|
+{
|
|
117
|
+ struct arc4_ctx ctx;
|
|
118
|
+ arc4_setkey ( &ctx, key, keylen );
|
|
119
|
+ arc4_xor ( &ctx, NULL, NULL, skip );
|
|
120
|
+ arc4_xor ( &ctx, src, dst, msglen );
|
|
121
|
+}
|
|
122
|
+
|
|
123
|
+struct cipher_algorithm arc4_algorithm = {
|
|
124
|
+ .name = "ARC4",
|
|
125
|
+ .ctxsize = ARC4_CTX_SIZE,
|
|
126
|
+ .blocksize = 1,
|
|
127
|
+ .setkey = arc4_setkey,
|
|
128
|
+ .setiv = arc4_setiv,
|
|
129
|
+ .encrypt = arc4_xor,
|
|
130
|
+ .decrypt = arc4_xor,
|
|
131
|
+};
|