X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=sshblowf.c;h=353116a6604fdc8334d774f4004999e934f9d321;hb=ca8876f0044c2eb7dbc5a61a432e799973e7e51c;hp=d6e6731f5c86f50acec01ba259f75794a4656733;hpb=36a499a7f16065b08988063c1be063fd89dcf4d6;p=PuTTY.git diff --git a/sshblowf.c b/sshblowf.c index d6e6731f..353116a6 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -7,27 +7,37 @@ #include #include #include "ssh.h" +#include "sshblowf.h" -typedef struct { +struct BlowfishContext { word32 S0[256], S1[256], S2[256], S3[256], P[18]; word32 iv0, iv1; /* for CBC mode */ -} BlowfishContext; - -#define GET_32BIT_LSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[0]) | \ - ((unsigned long)(unsigned char)(cp)[1] << 8) | \ - ((unsigned long)(unsigned char)(cp)[2] << 16) | \ - ((unsigned long)(unsigned char)(cp)[3] << 24)) - -#define PUT_32BIT_LSB_FIRST(cp, value) do { \ - (cp)[0] = (value); \ - (cp)[1] = (value) >> 8; \ - (cp)[2] = (value) >> 16; \ - (cp)[3] = (value) >> 24; } while (0) +}; /* * The Blowfish init data: hex digits of the fractional part of pi. * (ie pi as a hex fraction is 3.243F6A8885A308D3...) + * + * If you have Simon Tatham's 'spigot' exact real calculator + * available, or any other method of generating 8336 fractional hex + * digits of pi on standard output, you can regenerate these tables + * exactly as below using the following Perl script (adjusting the + * first line or two if your pi-generator is not spigot). + +open my $spig, "spigot -n -B16 -d8336 pi |"; +read $spig, $ignore, 2; # throw away the leading "3." +for my $name ("parray", "sbox0".."sbox3") { + print "static const word32 ${name}[] = {\n"; + my $len = $name eq "parray" ? 18 : 256; + for my $i (1..$len) { + read $spig, $word, 8; + printf "%s0x%s,", ($i%6==1 ? " " : " "), uc $word; + print "\n" if ($i == $len || $i%6 == 0); + } + print "};\n\n"; +} +close $spig; + */ static const word32 parray[] = { 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, @@ -223,8 +233,9 @@ static const word32 sbox3[] = { #define F(x) Fprime( ((x>>24)&0xFF), ((x>>16)&0xFF), ((x>>8)&0xFF), (x&0xFF) ) #define ROUND(n) ( xL ^= P[n], t = xL, xL = F(xL) ^ xR, xR = t ) -static void blowfish_encrypt(word32 xL, word32 xR, word32 *output, - BlowfishContext *ctx) { +static void blowfish_encrypt(word32 xL, word32 xR, word32 * output, + BlowfishContext * ctx) +{ word32 *S0 = ctx->S0; word32 *S1 = ctx->S1; word32 *S2 = ctx->S2; @@ -255,8 +266,9 @@ static void blowfish_encrypt(word32 xL, word32 xR, word32 *output, output[1] = xL; } -static void blowfish_decrypt(word32 xL, word32 xR, word32 *output, - BlowfishContext *ctx) { +static void blowfish_decrypt(word32 xL, word32 xR, word32 * output, + BlowfishContext * ctx) +{ word32 *S0 = ctx->S0; word32 *S1 = ctx->S1; word32 *S2 = ctx->S2; @@ -287,160 +299,368 @@ static void blowfish_decrypt(word32 xL, word32 xR, word32 *output, output[1] = xL; } -static void blowfish_encrypt_cbc(unsigned char *blk, int len, - BlowfishContext *ctx) { +static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len, + BlowfishContext * ctx) +{ word32 xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); - iv0 = ctx->iv0; iv1 = ctx->iv1; + iv0 = ctx->iv0; + iv1 = ctx->iv1; while (len > 0) { - xL = GET_32BIT_LSB_FIRST(blk); - xR = GET_32BIT_LSB_FIRST(blk+4); - iv0 ^= xL; - iv1 ^= xR; - blowfish_encrypt(iv0, iv1, out, ctx); - iv0 = out[0]; - iv1 = out[1]; - PUT_32BIT_LSB_FIRST(blk, iv0); - PUT_32BIT_LSB_FIRST(blk+4, iv1); - blk += 8; - len -= 8; + xL = GET_32BIT_LSB_FIRST(blk); + xR = GET_32BIT_LSB_FIRST(blk + 4); + iv0 ^= xL; + iv1 ^= xR; + blowfish_encrypt(iv0, iv1, out, ctx); + iv0 = out[0]; + iv1 = out[1]; + PUT_32BIT_LSB_FIRST(blk, iv0); + PUT_32BIT_LSB_FIRST(blk + 4, iv1); + blk += 8; + len -= 8; } - ctx->iv0 = iv0; ctx->iv1 = iv1; + ctx->iv0 = iv0; + ctx->iv1 = iv1; +} + +void blowfish_lsb_encrypt_ecb(unsigned char *blk, int len, + BlowfishContext * ctx) +{ + word32 xL, xR, out[2]; + + assert((len & 7) == 0); + + while (len > 0) { + xL = GET_32BIT_LSB_FIRST(blk); + xR = GET_32BIT_LSB_FIRST(blk + 4); + blowfish_encrypt(xL, xR, out, ctx); + PUT_32BIT_LSB_FIRST(blk, out[0]); + PUT_32BIT_LSB_FIRST(blk + 4, out[1]); + blk += 8; + len -= 8; + } } -static void blowfish_decrypt_cbc(unsigned char *blk, int len, - BlowfishContext *ctx) { +static void blowfish_lsb_decrypt_cbc(unsigned char *blk, int len, + BlowfishContext * ctx) +{ word32 xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); - iv0 = ctx->iv0; iv1 = ctx->iv1; + iv0 = ctx->iv0; + iv1 = ctx->iv1; while (len > 0) { - xL = GET_32BIT_LSB_FIRST(blk); - xR = GET_32BIT_LSB_FIRST(blk+4); - blowfish_decrypt(xL, xR, out, ctx); - iv0 ^= out[0]; - iv1 ^= out[1]; - PUT_32BIT_LSB_FIRST(blk, iv0); - PUT_32BIT_LSB_FIRST(blk+4, iv1); - iv0 = xL; - iv1 = xR; - blk += 8; - len -= 8; + xL = GET_32BIT_LSB_FIRST(blk); + xR = GET_32BIT_LSB_FIRST(blk + 4); + blowfish_decrypt(xL, xR, out, ctx); + iv0 ^= out[0]; + iv1 ^= out[1]; + PUT_32BIT_LSB_FIRST(blk, iv0); + PUT_32BIT_LSB_FIRST(blk + 4, iv1); + iv0 = xL; + iv1 = xR; + blk += 8; + len -= 8; } - ctx->iv0 = iv0; ctx->iv1 = iv1; + ctx->iv0 = iv0; + ctx->iv1 = iv1; } -static void blowfish_setkey(BlowfishContext *ctx, - const unsigned char *key, short keybytes) { +static void blowfish_msb_encrypt_cbc(unsigned char *blk, int len, + BlowfishContext * ctx) +{ + word32 xL, xR, out[2], iv0, iv1; + + assert((len & 7) == 0); + + iv0 = ctx->iv0; + iv1 = ctx->iv1; + + while (len > 0) { + xL = GET_32BIT_MSB_FIRST(blk); + xR = GET_32BIT_MSB_FIRST(blk + 4); + iv0 ^= xL; + iv1 ^= xR; + blowfish_encrypt(iv0, iv1, out, ctx); + iv0 = out[0]; + iv1 = out[1]; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk + 4, iv1); + blk += 8; + len -= 8; + } + + ctx->iv0 = iv0; + ctx->iv1 = iv1; +} + +static void blowfish_msb_decrypt_cbc(unsigned char *blk, int len, + BlowfishContext * ctx) +{ + word32 xL, xR, out[2], iv0, iv1; + + assert((len & 7) == 0); + + iv0 = ctx->iv0; + iv1 = ctx->iv1; + + while (len > 0) { + xL = GET_32BIT_MSB_FIRST(blk); + xR = GET_32BIT_MSB_FIRST(blk + 4); + blowfish_decrypt(xL, xR, out, ctx); + iv0 ^= out[0]; + iv1 ^= out[1]; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk + 4, iv1); + iv0 = xL; + iv1 = xR; + blk += 8; + len -= 8; + } + + ctx->iv0 = iv0; + ctx->iv1 = iv1; +} + +static void blowfish_msb_sdctr(unsigned char *blk, int len, + BlowfishContext * ctx) +{ + word32 b[2], iv0, iv1, tmp; + + assert((len & 7) == 0); + + iv0 = ctx->iv0; + iv1 = ctx->iv1; + + while (len > 0) { + blowfish_encrypt(iv0, iv1, b, ctx); + tmp = GET_32BIT_MSB_FIRST(blk); + PUT_32BIT_MSB_FIRST(blk, tmp ^ b[0]); + tmp = GET_32BIT_MSB_FIRST(blk + 4); + PUT_32BIT_MSB_FIRST(blk + 4, tmp ^ b[1]); + if ((iv1 = (iv1 + 1) & 0xffffffff) == 0) + iv0 = (iv0 + 1) & 0xffffffff; + blk += 8; + len -= 8; + } + + ctx->iv0 = iv0; + ctx->iv1 = iv1; +} + +void blowfish_initkey(BlowfishContext *ctx) +{ + int i; + + for (i = 0; i < 18; i++) { + ctx->P[i] = parray[i]; + } + + for (i = 0; i < 256; i++) { + ctx->S0[i] = sbox0[i]; + ctx->S1[i] = sbox1[i]; + ctx->S2[i] = sbox2[i]; + ctx->S3[i] = sbox3[i]; + } +} + +void blowfish_expandkey(BlowfishContext * ctx, + const unsigned char *key, short keybytes, + const unsigned char *salt, short saltbytes) +{ word32 *S0 = ctx->S0; word32 *S1 = ctx->S1; word32 *S2 = ctx->S2; word32 *S3 = ctx->S3; word32 *P = ctx->P; word32 str[2]; - int i; - - for (i = 0; i < 18; i++) { - P[i] = parray[i]; - P[i] ^= ((word32)(unsigned char)(key[ (i*4+0) % keybytes ])) << 24; - P[i] ^= ((word32)(unsigned char)(key[ (i*4+1) % keybytes ])) << 16; - P[i] ^= ((word32)(unsigned char)(key[ (i*4+2) % keybytes ])) << 8; - P[i] ^= ((word32)(unsigned char)(key[ (i*4+3) % keybytes ])); + int i, j; + int saltpos; + unsigned char dummysalt[1]; + + saltpos = 0; + if (!salt) { + saltbytes = 1; + salt = dummysalt; + dummysalt[0] = 0; } - for (i = 0; i < 256; i++) { - S0[i] = sbox0[i]; - S1[i] = sbox1[i]; - S2[i] = sbox2[i]; - S3[i] = sbox3[i]; + for (i = 0; i < 18; i++) { + P[i] ^= + ((word32) (unsigned char) (key[(i * 4 + 0) % keybytes])) << 24; + P[i] ^= + ((word32) (unsigned char) (key[(i * 4 + 1) % keybytes])) << 16; + P[i] ^= + ((word32) (unsigned char) (key[(i * 4 + 2) % keybytes])) << 8; + P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 3) % keybytes])); } str[0] = str[1] = 0; for (i = 0; i < 18; i += 2) { - blowfish_encrypt(str[0], str[1], str, ctx); - P[i] = str[0]; P[i+1] = str[1]; + for (j = 0; j < 8; j++) + str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + + blowfish_encrypt(str[0], str[1], str, ctx); + P[i] = str[0]; + P[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { - blowfish_encrypt(str[0], str[1], str, ctx); - S0[i] = str[0]; S0[i+1] = str[1]; + for (j = 0; j < 8; j++) + str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + blowfish_encrypt(str[0], str[1], str, ctx); + S0[i] = str[0]; + S0[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { - blowfish_encrypt(str[0], str[1], str, ctx); - S1[i] = str[0]; S1[i+1] = str[1]; + for (j = 0; j < 8; j++) + str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + blowfish_encrypt(str[0], str[1], str, ctx); + S1[i] = str[0]; + S1[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { - blowfish_encrypt(str[0], str[1], str, ctx); - S2[i] = str[0]; S2[i+1] = str[1]; + for (j = 0; j < 8; j++) + str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + blowfish_encrypt(str[0], str[1], str, ctx); + S2[i] = str[0]; + S2[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { - blowfish_encrypt(str[0], str[1], str, ctx); - S3[i] = str[0]; S3[i+1] = str[1]; + for (j = 0; j < 8; j++) + str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); + blowfish_encrypt(str[0], str[1], str, ctx); + S3[i] = str[0]; + S3[i + 1] = str[1]; } } +static void blowfish_setkey(BlowfishContext *ctx, + const unsigned char *key, short keybytes) +{ + blowfish_initkey(ctx); + blowfish_expandkey(ctx, key, keybytes, NULL, 0); +} + /* -- Interface with PuTTY -- */ #define SSH_SESSION_KEY_LENGTH 32 -static BlowfishContext ectx, dctx; -static void blowfish_cskey(unsigned char *key) +void *blowfish_make_context(void) +{ + return snew(BlowfishContext); +} + +static void *blowfish_ssh1_make_context(void) +{ + /* In SSH-1, need one key for each direction */ + return snewn(2, BlowfishContext); +} + +void blowfish_free_context(void *handle) +{ + sfree(handle); +} + +static void blowfish_key(void *handle, unsigned char *key) +{ + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_setkey(ctx, key, 16); +} + +static void blowfish256_key(void *handle, unsigned char *key) +{ + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_setkey(ctx, key, 32); +} + +static void blowfish_iv(void *handle, unsigned char *key) { - blowfish_setkey(&ectx, key, 16); - logevent("Initialised Blowfish client->server encryption"); + BlowfishContext *ctx = (BlowfishContext *)handle; + ctx->iv0 = GET_32BIT_MSB_FIRST(key); + ctx->iv1 = GET_32BIT_MSB_FIRST(key + 4); } -static void blowfish_sckey(unsigned char *key) +static void blowfish_sesskey(void *handle, unsigned char *key) { - blowfish_setkey(&dctx, key, 16); - logevent("Initialised Blowfish server->client encryption"); + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_setkey(ctx, key, SSH_SESSION_KEY_LENGTH); + ctx->iv0 = 0; + ctx->iv1 = 0; + ctx[1] = ctx[0]; /* structure copy */ } -static void blowfish_csiv(unsigned char *key) +static void blowfish_ssh1_encrypt_blk(void *handle, unsigned char *blk, + int len) { - ectx.iv0 = GET_32BIT_LSB_FIRST(key); - ectx.iv1 = GET_32BIT_LSB_FIRST(key+4); + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_lsb_encrypt_cbc(blk, len, ctx); } -static void blowfish_sciv(unsigned char *key) +static void blowfish_ssh1_decrypt_blk(void *handle, unsigned char *blk, + int len) { - dctx.iv0 = GET_32BIT_LSB_FIRST(key); - dctx.iv1 = GET_32BIT_LSB_FIRST(key+4); + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_lsb_decrypt_cbc(blk, len, ctx+1); } -static void blowfish_sesskey(unsigned char *key) +static void blowfish_ssh2_encrypt_blk(void *handle, unsigned char *blk, + int len) { - blowfish_setkey(&ectx, key, SSH_SESSION_KEY_LENGTH); - ectx.iv0 = 0; - ectx.iv1 = 0; - dctx = ectx; - logevent("Initialised Blowfish encryption"); + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_msb_encrypt_cbc(blk, len, ctx); } -static void blowfish_encrypt_blk(unsigned char *blk, int len) +static void blowfish_ssh2_decrypt_blk(void *handle, unsigned char *blk, + int len) { - blowfish_encrypt_cbc(blk, len, &ectx); + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_msb_decrypt_cbc(blk, len, ctx); } -static void blowfish_decrypt_blk(unsigned char *blk, int len) +static void blowfish_ssh2_sdctr(void *handle, unsigned char *blk, + int len) { - blowfish_decrypt_cbc(blk, len, &dctx); + BlowfishContext *ctx = (BlowfishContext *)handle; + blowfish_msb_sdctr(blk, len, ctx); } -struct ssh_cipher ssh_blowfish = { - blowfish_sesskey, - blowfish_csiv, blowfish_cskey, - blowfish_sciv, blowfish_sckey, - blowfish_encrypt_blk, - blowfish_decrypt_blk, +const struct ssh_cipher ssh_blowfish_ssh1 = { + blowfish_ssh1_make_context, blowfish_free_context, blowfish_sesskey, + blowfish_ssh1_encrypt_blk, blowfish_ssh1_decrypt_blk, + 8, "Blowfish-128 CBC" +}; + +static const struct ssh2_cipher ssh_blowfish_ssh2 = { + blowfish_make_context, blowfish_free_context, blowfish_iv, blowfish_key, + blowfish_ssh2_encrypt_blk, blowfish_ssh2_decrypt_blk, NULL, NULL, "blowfish-cbc", - 8 + 8, 128, 16, SSH_CIPHER_IS_CBC, "Blowfish-128 CBC", + NULL +}; + +static const struct ssh2_cipher ssh_blowfish_ssh2_ctr = { + blowfish_make_context, blowfish_free_context, blowfish_iv, blowfish256_key, + blowfish_ssh2_sdctr, blowfish_ssh2_sdctr, NULL, NULL, + "blowfish-ctr", + 8, 256, 32, 0, "Blowfish-256 SDCTR", + NULL +}; + +static const struct ssh2_cipher *const blowfish_list[] = { + &ssh_blowfish_ssh2_ctr, + &ssh_blowfish_ssh2 +}; + +const struct ssh2_ciphers ssh2_blowfish = { + sizeof(blowfish_list) / sizeof(*blowfish_list), + blowfish_list };