summaryrefslogtreecommitdiff
path: root/cipher.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>1999-10-27 13:42:43 +1000
committerDamien Miller <djm@mindrot.org>1999-10-27 13:42:43 +1000
commitd4a8b7e34dd619a4debf9a206c81db26d1402ea6 (patch)
treea47d770a2f790f40d18b0982d4e55fa7cfb1fa3b /cipher.c
Initial revision
Diffstat (limited to 'cipher.c')
-rw-r--r--cipher.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/cipher.c b/cipher.c
new file mode 100644
index 000000000..b47e7ecd8
--- /dev/null
+++ b/cipher.c
@@ -0,0 +1,304 @@
1/*
2
3cipher.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10Created: Wed Apr 19 17:41:39 1995 ylo
11
12*/
13
14#include "includes.h"
15RCSID("$Id: cipher.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
16
17#include "ssh.h"
18#include "cipher.h"
19
20#include <openssl/md5.h>
21
22/*
23 * What kind of tripple DES are these 2 routines?
24 *
25 * Why is there a redundant initialization vector?
26 *
27 * If only iv3 was used, then, this would till effect have been
28 * outer-cbc. However, there is also a private iv1 == iv2 which
29 * perhaps makes differential analysis easier. On the other hand, the
30 * private iv1 probably makes the CRC-32 attack ineffective. This is a
31 * result of that there is no longer any known iv1 to use when
32 * choosing the X block.
33 */
34void
35SSH_3CBC_ENCRYPT(des_key_schedule ks1,
36 des_key_schedule ks2, des_cblock *iv2,
37 des_key_schedule ks3, des_cblock *iv3,
38 void *dest, void *src,
39 unsigned int len)
40{
41 des_cblock iv1;
42
43 memcpy(&iv1, iv2, 8);
44
45 des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
46 memcpy(&iv1, dest + len - 8, 8);
47
48 des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
49 memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
50
51 des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
52 memcpy(iv3, dest + len - 8, 8);
53}
54
55void
56SSH_3CBC_DECRYPT(des_key_schedule ks1,
57 des_key_schedule ks2, des_cblock *iv2,
58 des_key_schedule ks3, des_cblock *iv3,
59 void *dest, void *src,
60 unsigned int len)
61{
62 des_cblock iv1;
63
64 memcpy(&iv1, iv2, 8);
65
66 des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
67 memcpy(iv3, src + len - 8, 8);
68
69 des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
70 memcpy(iv2, dest + len - 8, 8);
71
72 des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
73 /* memcpy(&iv1, iv2, 8); */ /* Note how iv1 == iv2 on entry and exit. */
74}
75
76/*
77 * SSH uses a variation on Blowfish, all bytes must be swapped before
78 * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
79 */
80static
81void
82swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
83{
84 u_int32_t *dst = (u_int32_t *)dst_; /* dst must be properly aligned. */
85 union {
86 u_int32_t i;
87 char c[4];
88 } t;
89
90 /* assert((n & 7) == 0); */
91
92 /* Process 8 bytes every lap. */
93 for (n = n / 8; n > 0; n--)
94 {
95 t.c[3] = *src++;
96 t.c[2] = *src++;
97 t.c[1] = *src++;
98 t.c[0] = *src++;
99 *dst++ = t.i;
100
101 t.c[3] = *src++;
102 t.c[2] = *src++;
103 t.c[1] = *src++;
104 t.c[0] = *src++;
105 *dst++ = t.i;
106 }
107}
108
109void (*cipher_attack_detected)(const char *fmt, ...) = fatal;
110
111static inline
112void
113detect_cbc_attack(const unsigned char *src,
114 unsigned int len)
115{
116 return;
117
118 log("CRC-32 CBC insertion attack detected");
119 cipher_attack_detected("CRC-32 CBC insertion attack detected");
120}
121
122/* Names of all encryption algorithms. These must match the numbers defined
123 int cipher.h. */
124static char *cipher_names[] =
125{
126 "none",
127 "idea",
128 "des",
129 "3des",
130 "tss",
131 "rc4",
132 "blowfish"
133};
134
135/* Returns a bit mask indicating which ciphers are supported by this
136 implementation. The bit mask has the corresponding bit set of each
137 supported cipher. */
138
139unsigned int cipher_mask()
140{
141 unsigned int mask = 0;
142 mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
143 mask |= 1 << SSH_CIPHER_BLOWFISH;
144 return mask;
145}
146
147/* Returns the name of the cipher. */
148
149const
150char *cipher_name(int cipher)
151{
152 if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
153 cipher_names[cipher] == NULL)
154 fatal("cipher_name: bad cipher number: %d", cipher);
155 return cipher_names[cipher];
156}
157
158/* Parses the name of the cipher. Returns the number of the corresponding
159 cipher, or -1 on error. */
160
161int
162cipher_number(const char *name)
163{
164 int i;
165 for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
166 if (strcmp(cipher_names[i], name) == 0 &&
167 (cipher_mask() & (1 << i)))
168 return i;
169 return -1;
170}
171
172/* Selects the cipher, and keys if by computing the MD5 checksum of the
173 passphrase and using the resulting 16 bytes as the key. */
174
175void cipher_set_key_string(CipherContext *context, int cipher,
176 const char *passphrase, int for_encryption)
177{
178 MD5_CTX md;
179 unsigned char digest[16];
180
181 MD5_Init(&md);
182 MD5_Update(&md, (const unsigned char *)passphrase, strlen(passphrase));
183 MD5_Final(digest, &md);
184
185 cipher_set_key(context, cipher, digest, 16, for_encryption);
186
187 memset(digest, 0, sizeof(digest));
188 memset(&md, 0, sizeof(md));
189}
190
191/* Selects the cipher to use and sets the key. */
192
193void cipher_set_key(CipherContext *context, int cipher,
194 const unsigned char *key, int keylen, int for_encryption)
195{
196 unsigned char padded[32];
197
198 /* Set cipher type. */
199 context->type = cipher;
200
201 /* Get 32 bytes of key data. Pad if necessary. (So that code below does
202 not need to worry about key size). */
203 memset(padded, 0, sizeof(padded));
204 memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
205
206 /* Initialize the initialization vector. */
207 switch (cipher)
208 {
209 case SSH_CIPHER_NONE:
210 /* Has to stay for authfile saving of private key with no passphrase */
211 break;
212
213 case SSH_CIPHER_3DES:
214 /* Note: the least significant bit of each byte of key is parity,
215 and must be ignored by the implementation. 16 bytes of key are
216 used (first and last keys are the same). */
217 if (keylen < 16)
218 error("Key length %d is insufficient for 3DES.", keylen);
219 des_set_key((void*)padded, context->u.des3.key1);
220 des_set_key((void*)(padded + 8), context->u.des3.key2);
221 if (keylen <= 16)
222 des_set_key((void*)padded, context->u.des3.key3);
223 else
224 des_set_key((void*)(padded + 16), context->u.des3.key3);
225 memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
226 memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
227 break;
228
229 case SSH_CIPHER_BLOWFISH:
230 BF_set_key(&context->u.bf.key, keylen, padded);
231 memset(context->u.bf.iv, 0, 8);
232 break;
233
234 default:
235 fatal("cipher_set_key: unknown cipher: %d", cipher);
236 }
237 memset(padded, 0, sizeof(padded));
238}
239
240/* Encrypts data using the cipher. */
241
242void cipher_encrypt(CipherContext *context, unsigned char *dest,
243 const unsigned char *src, unsigned int len)
244{
245 assert((len & 7) == 0);
246
247 switch (context->type)
248 {
249 case SSH_CIPHER_NONE:
250 memcpy(dest, src, len);
251 break;
252
253 case SSH_CIPHER_3DES:
254 SSH_3CBC_ENCRYPT(context->u.des3.key1,
255 context->u.des3.key2, &context->u.des3.iv2,
256 context->u.des3.key3, &context->u.des3.iv3,
257 dest, (void*)src, len);
258 break;
259
260 case SSH_CIPHER_BLOWFISH:
261 swap_bytes(src, dest, len);
262 BF_cbc_encrypt(dest, dest, len,
263 &context->u.bf.key, context->u.bf.iv, BF_ENCRYPT);
264 swap_bytes(dest, dest, len);
265 break;
266
267 default:
268 fatal("cipher_encrypt: unknown cipher: %d", context->type);
269 }
270}
271
272/* Decrypts data using the cipher. */
273
274void cipher_decrypt(CipherContext *context, unsigned char *dest,
275 const unsigned char *src, unsigned int len)
276{
277 assert((len & 7) == 0);
278
279 switch (context->type)
280 {
281 case SSH_CIPHER_NONE:
282 memcpy(dest, src, len);
283 break;
284
285 case SSH_CIPHER_3DES:
286 /* CRC-32 attack? */
287 SSH_3CBC_DECRYPT(context->u.des3.key1,
288 context->u.des3.key2, &context->u.des3.iv2,
289 context->u.des3.key3, &context->u.des3.iv3,
290 dest, (void*)src, len);
291 break;
292
293 case SSH_CIPHER_BLOWFISH:
294 detect_cbc_attack(src, len);
295 swap_bytes(src, dest, len);
296 BF_cbc_encrypt((void*)dest, dest, len,
297 &context->u.bf.key, context->u.bf.iv, BF_DECRYPT);
298 swap_bytes(dest, dest, len);
299 break;
300
301 default:
302 fatal("cipher_decrypt: unknown cipher: %d", context->type);
303 }
304}