mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
229af2b5bf
This is more or less the same job as the SSH-1 case, only more extensive, because we have a wider range of ciphers. I'm a bit disappointed about the AES case, in particular, because I feel as if it ought to have been possible to arrange to combine this layer of vtable dispatch with the subsidiary one that selects between hardware and software implementations of the underlying cipher. I may come back later and have another try at that, in fact.
131 lines
3.2 KiB
C
131 lines
3.2 KiB
C
/*
|
|
* Arcfour (RC4) implementation for PuTTY.
|
|
*
|
|
* Coded from Schneier.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include "ssh.h"
|
|
|
|
typedef struct {
|
|
unsigned char i, j, s[256];
|
|
ssh2_cipher vt;
|
|
} ArcfourContext;
|
|
|
|
static void arcfour_block(void *handle, void *vblk, int len)
|
|
{
|
|
unsigned char *blk = (unsigned char *)vblk;
|
|
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 ssh2_cipher *arcfour_new(const struct ssh2_cipheralg *alg)
|
|
{
|
|
ArcfourContext *ctx = snew(ArcfourContext);
|
|
ctx->vt = alg;
|
|
return &ctx->vt;
|
|
}
|
|
|
|
static void arcfour_free(ssh2_cipher *cipher)
|
|
{
|
|
ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt);
|
|
smemclr(ctx, sizeof(*ctx));
|
|
sfree(ctx);
|
|
}
|
|
|
|
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 arcfour_ssh2_setiv(ssh2_cipher *cipher, const void *key)
|
|
{
|
|
/* As a pure stream cipher, Arcfour has no IV separate from the key */
|
|
}
|
|
|
|
static void arcfour_ssh2_setkey(ssh2_cipher *cipher, const void *key)
|
|
{
|
|
ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt);
|
|
arcfour_setkey(ctx, key, ctx->vt->padded_keybytes);
|
|
arcfour_stir(ctx);
|
|
}
|
|
|
|
static void arcfour_ssh2_block(ssh2_cipher *cipher, void *blk, int len)
|
|
{
|
|
ArcfourContext *ctx = FROMFIELD(cipher, ArcfourContext, vt);
|
|
arcfour_block(ctx, blk, len);
|
|
}
|
|
|
|
const struct ssh2_cipheralg ssh_arcfour128_ssh2 = {
|
|
arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey,
|
|
arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL,
|
|
"arcfour128",
|
|
1, 128, 16, 0, "Arcfour-128",
|
|
NULL
|
|
};
|
|
|
|
const struct ssh2_cipheralg ssh_arcfour256_ssh2 = {
|
|
arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey,
|
|
arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL,
|
|
"arcfour256",
|
|
1, 256, 32, 0, "Arcfour-256",
|
|
NULL
|
|
};
|
|
|
|
static const struct ssh2_cipheralg *const arcfour_list[] = {
|
|
&ssh_arcfour256_ssh2,
|
|
&ssh_arcfour128_ssh2,
|
|
};
|
|
|
|
const struct ssh2_ciphers ssh2_arcfour = {
|
|
sizeof(arcfour_list) / sizeof(*arcfour_list),
|
|
arcfour_list
|
|
};
|