mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
43be90e287
The revamp of key generation in commit e460f3083
made the assumption
that you could decide how many bytes of key material to generate by
converting cipher->keylen from bits to bytes. This is a good
assumption for all ciphers except DES/3DES: since the SSH DES key
setup ignores one bit in every byte of key material it's given, you
need more bytes than its keylen field would have you believe. So
currently the DES ciphers aren't being keyed correctly.
The original keylen field is used for deciding how big a DH group to
request, and on that basis I think it still makes sense to keep it
reflecting the true entropy of a cipher key. So it turns out we need
two _separate_ key length fields per cipher - one for the real
entropy, and one for the much more obvious purpose of knowing how much
data to ask for from ssh2_mkkey.
A compensatory advantage, though, is that we can now measure the
latter directly in bytes rather than bits, so we no longer have to
faff about with dividing by 8 and rounding up.
126 lines
2.8 KiB
C
126 lines
2.8 KiB
C
/*
|
|
* Arcfour (RC4) implementation for PuTTY.
|
|
*
|
|
* Coded from Schneier.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include "ssh.h"
|
|
|
|
typedef struct {
|
|
unsigned char i, j, s[256];
|
|
} ArcfourContext;
|
|
|
|
static void arcfour_block(void *handle, unsigned char *blk, int len)
|
|
{
|
|
ArcfourContext *ctx = (ArcfourContext *)handle;
|
|
unsigned k;
|
|
unsigned char tmp, i, j, *s;
|
|
|
|
s = ctx->s;
|
|
i = ctx->i; j = ctx->j;
|
|
for (k = 0; (int)k < len; k++) {
|
|
i = (i + 1) & 0xff;
|
|
j = (j + s[i]) & 0xff;
|
|
tmp = s[i]; s[i] = s[j]; s[j] = tmp;
|
|
blk[k] ^= s[(s[i]+s[j]) & 0xff];
|
|
}
|
|
ctx->i = i; ctx->j = j;
|
|
}
|
|
|
|
static void arcfour_setkey(ArcfourContext *ctx, unsigned char const *key,
|
|
unsigned keybytes)
|
|
{
|
|
unsigned char tmp, k[256], *s;
|
|
unsigned i, j;
|
|
|
|
s = ctx->s;
|
|
assert(keybytes <= 256);
|
|
ctx->i = ctx->j = 0;
|
|
for (i = 0; i < 256; i++) {
|
|
s[i] = i;
|
|
k[i] = key[i % keybytes];
|
|
}
|
|
j = 0;
|
|
for (i = 0; i < 256; i++) {
|
|
j = (j + s[i] + k[i]) & 0xff;
|
|
tmp = s[i]; s[i] = s[j]; s[j] = tmp;
|
|
}
|
|
}
|
|
|
|
/* -- Interface with PuTTY -- */
|
|
|
|
/*
|
|
* We don't implement Arcfour in SSH-1 because it's utterly insecure in
|
|
* several ways. See CERT Vulnerability Notes VU#25309, VU#665372,
|
|
* and VU#565052.
|
|
*
|
|
* We don't implement the "arcfour" algorithm in SSH-2 because it doesn't
|
|
* stir the cipher state before emitting keystream, and hence is likely
|
|
* to leak data about the key.
|
|
*/
|
|
|
|
static void *arcfour_make_context(void)
|
|
{
|
|
return snew(ArcfourContext);
|
|
}
|
|
|
|
static void arcfour_free_context(void *handle)
|
|
{
|
|
sfree(handle);
|
|
}
|
|
|
|
static void arcfour_stir(ArcfourContext *ctx)
|
|
{
|
|
unsigned char *junk = snewn(1536, unsigned char);
|
|
memset(junk, 0, 1536);
|
|
arcfour_block(ctx, junk, 1536);
|
|
smemclr(junk, 1536);
|
|
sfree(junk);
|
|
}
|
|
|
|
static void arcfour128_key(void *handle, unsigned char *key)
|
|
{
|
|
ArcfourContext *ctx = (ArcfourContext *)handle;
|
|
arcfour_setkey(ctx, key, 16);
|
|
arcfour_stir(ctx);
|
|
}
|
|
|
|
static void arcfour256_key(void *handle, unsigned char *key)
|
|
{
|
|
ArcfourContext *ctx = (ArcfourContext *)handle;
|
|
arcfour_setkey(ctx, key, 32);
|
|
arcfour_stir(ctx);
|
|
}
|
|
|
|
static void arcfour_iv(void *handle, unsigned char *key)
|
|
{
|
|
|
|
}
|
|
|
|
const struct ssh2_cipher ssh_arcfour128_ssh2 = {
|
|
arcfour_make_context, arcfour_free_context, arcfour_iv, arcfour128_key,
|
|
arcfour_block, arcfour_block, NULL, NULL,
|
|
"arcfour128",
|
|
1, 128, 16, 0, "Arcfour-128",
|
|
NULL
|
|
};
|
|
|
|
const struct ssh2_cipher ssh_arcfour256_ssh2 = {
|
|
arcfour_make_context, arcfour_free_context, arcfour_iv, arcfour256_key,
|
|
arcfour_block, arcfour_block, NULL, NULL,
|
|
"arcfour256",
|
|
1, 256, 32, 0, "Arcfour-256",
|
|
NULL
|
|
};
|
|
|
|
static const struct ssh2_cipher *const arcfour_list[] = {
|
|
&ssh_arcfour256_ssh2,
|
|
&ssh_arcfour128_ssh2,
|
|
};
|
|
|
|
const struct ssh2_ciphers ssh2_arcfour = {
|
|
sizeof(arcfour_list) / sizeof(*arcfour_list),
|
|
arcfour_list
|
|
};
|