mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Merge branch 'thirdparty_dev' into dev
# Conflicts: # source/putty/mpint.c # source/putty/ssh.h # source/putty/ssh2bpp.c # source/putty/sshaes.c Source commit: c448c97cc3320d5d66590b09dbc4d9ad75b3fa4e
This commit is contained in:
6
source/putty/defs.h
vendored
6
source/putty/defs.h
vendored
@@ -105,11 +105,9 @@ typedef struct ssh_compression_alg ssh_compression_alg;
|
||||
typedef struct ssh2_userkey ssh2_userkey;
|
||||
typedef struct ssh2_macalg ssh2_macalg;
|
||||
typedef struct ssh2_mac ssh2_mac;
|
||||
typedef struct ssh2_cipheralg ssh2_cipheralg;
|
||||
typedef struct ssh2_cipher ssh2_cipher;
|
||||
typedef struct ssh_cipheralg ssh_cipheralg;
|
||||
typedef struct ssh_cipher ssh_cipher;
|
||||
typedef struct ssh2_ciphers ssh2_ciphers;
|
||||
typedef struct ssh1_cipheralg ssh1_cipheralg;
|
||||
typedef struct ssh1_cipher ssh1_cipher;
|
||||
typedef struct dh_ctx dh_ctx;
|
||||
typedef struct ecdh_key ecdh_key;
|
||||
|
||||
|
||||
34
source/putty/import.c
vendored
34
source/putty/import.c
vendored
@@ -547,11 +547,11 @@ static ssh2_userkey *openssh_pem_read(
|
||||
des3_decrypt_pubkey_ossh(keybuf, key->iv,
|
||||
key->keyblob->u, key->keyblob->len);
|
||||
else {
|
||||
ssh2_cipher *cipher = ssh2_cipher_new(&ssh_aes128_cbc);
|
||||
ssh2_cipher_setkey(cipher, keybuf);
|
||||
ssh2_cipher_setiv(cipher, key->iv);
|
||||
ssh2_cipher_decrypt(cipher, key->keyblob->u, key->keyblob->len);
|
||||
ssh2_cipher_free(cipher);
|
||||
ssh_cipher *cipher = ssh_cipher_new(&ssh_aes128_cbc);
|
||||
ssh_cipher_setkey(cipher, keybuf);
|
||||
ssh_cipher_setiv(cipher, key->iv);
|
||||
ssh_cipher_decrypt(cipher, key->keyblob->u, key->keyblob->len);
|
||||
ssh_cipher_free(cipher);
|
||||
}
|
||||
|
||||
smemclr(&md5c, sizeof(md5c));
|
||||
@@ -1388,16 +1388,16 @@ static ssh2_userkey *openssh_new_read(
|
||||
goto error;
|
||||
}
|
||||
{
|
||||
ssh2_cipher *cipher = ssh2_cipher_new(
|
||||
ssh_cipher *cipher = ssh_cipher_new(
|
||||
key->cipher == ON_E_AES256CBC ?
|
||||
&ssh_aes256_cbc : &ssh_aes256_sdctr);
|
||||
ssh2_cipher_setkey(cipher, keybuf);
|
||||
ssh2_cipher_setiv(cipher, keybuf + 32);
|
||||
ssh_cipher_setkey(cipher, keybuf);
|
||||
ssh_cipher_setiv(cipher, keybuf + 32);
|
||||
/* Decrypt the private section in place, casting away
|
||||
* the const from key->private being a ptrlen */
|
||||
ssh2_cipher_decrypt(cipher, (char *)key->private.ptr,
|
||||
key->private.len);
|
||||
ssh2_cipher_free(cipher);
|
||||
ssh_cipher_decrypt(cipher, (char *)key->private.ptr,
|
||||
key->private.len);
|
||||
ssh_cipher_free(cipher);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1588,17 +1588,17 @@ static bool openssh_new_write(
|
||||
* material: 32 bytes AES key + 16 bytes iv.
|
||||
*/
|
||||
unsigned char keybuf[48];
|
||||
ssh2_cipher *cipher;
|
||||
ssh_cipher *cipher;
|
||||
|
||||
openssh_bcrypt(passphrase,
|
||||
bcrypt_salt, sizeof(bcrypt_salt), bcrypt_rounds,
|
||||
keybuf, sizeof(keybuf));
|
||||
|
||||
cipher = ssh2_cipher_new(&ssh_aes256_sdctr);
|
||||
ssh2_cipher_setkey(cipher, keybuf);
|
||||
ssh2_cipher_setiv(cipher, keybuf + 32);
|
||||
ssh2_cipher_encrypt(cipher, cpblob->u, cpblob->len);
|
||||
ssh2_cipher_free(cipher);
|
||||
cipher = ssh_cipher_new(&ssh_aes256_sdctr);
|
||||
ssh_cipher_setkey(cipher, keybuf);
|
||||
ssh_cipher_setiv(cipher, keybuf + 32);
|
||||
ssh_cipher_encrypt(cipher, cpblob->u, cpblob->len);
|
||||
ssh_cipher_free(cipher);
|
||||
|
||||
smemclr(keybuf, sizeof(keybuf));
|
||||
}
|
||||
|
||||
36
source/putty/mpint.c
vendored
36
source/putty/mpint.c
vendored
@@ -1172,25 +1172,16 @@ mp_int *mp_rshift_safe(mp_int *x, size_t bits)
|
||||
/*
|
||||
* That's done the shifting by words; now we do the shifting by
|
||||
* bits.
|
||||
*
|
||||
* I assume here that register-controlled right shifts are
|
||||
* time-constant. If they're not, I could replace this with
|
||||
* another loop over bit positions.
|
||||
*/
|
||||
{ // WINSCP
|
||||
size_t upshift = BIGNUM_INT_BITS - bitshift;
|
||||
size_t no_shift = (upshift >> BIGNUM_INT_BITS_BITS);
|
||||
upshift &= ~-(size_t)no_shift;
|
||||
{ // WINSCP
|
||||
BignumInt upshifted_mask = ~-(BignumInt)no_shift;
|
||||
|
||||
size_t i; // WINSCP
|
||||
for (i = 0; i < r->nw; i++) {
|
||||
r->w[i] = (r->w[i] >> bitshift) |
|
||||
((mp_word(r, i+1) << upshift) & upshifted_mask);
|
||||
for (bit = 0; bit < BIGNUM_INT_BITS_BITS; bit++) { // WINSCP
|
||||
unsigned shift = 1 << bit, upshift = BIGNUM_INT_BITS - shift;
|
||||
BignumInt mask = -(BignumInt)((bitshift >> bit) & 1);
|
||||
size_t i; // WINSCP
|
||||
for (i = 0; i < r->nw; i++) {
|
||||
BignumInt w = ((r->w[i] >> shift) | (mp_word(r, i+1) << upshift));
|
||||
r->w[i] ^= (r->w[i] ^ w) & mask;
|
||||
}
|
||||
}
|
||||
} // WINSCP
|
||||
} // WINSCP
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1964,12 +1955,11 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
|
||||
* actual input will be close to a fixed power of two regardless
|
||||
* of where the MSB was.
|
||||
*
|
||||
* I do this in another log n individual passes, not so much
|
||||
* because I'm worried about the time-invariance of the CPU's
|
||||
* register-controlled shift operation, but in case the compiler
|
||||
* code-generates uint64_t shifts out of a variable number of
|
||||
* smaller-word shift instructions, e.g. by splitting up into
|
||||
* cases.
|
||||
* I do this in another log n individual passes, partly in case
|
||||
* the CPU's register-controlled shift operation isn't
|
||||
* time-constant, and also in case the compiler code-generates
|
||||
* uint64_t shifts out of a variable number of smaller-word shift
|
||||
* instructions, e.g. by splitting up into cases.
|
||||
*/
|
||||
for (i = BIGNUM_INT_BITS_BITS; i-- > 0;) {
|
||||
size_t sl = 1 << i; /* left shift count */
|
||||
|
||||
144
source/putty/ssh.h
vendored
144
source/putty/ssh.h
vendored
@@ -520,15 +520,17 @@ void freersakey(RSAKey *key);
|
||||
#endif // WINSCP_VS
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
unsigned long crc32_compute(const void *s, size_t len);
|
||||
unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len);
|
||||
uint32_t crc32_rfc1662(ptrlen data);
|
||||
uint32_t crc32_ssh1(ptrlen data);
|
||||
uint32_t crc32_update(uint32_t crc_input, ptrlen data);
|
||||
|
||||
/* SSH CRC compensation attack detector */
|
||||
struct crcda_ctx;
|
||||
struct crcda_ctx *crcda_make_context(void);
|
||||
void crcda_free_context(struct crcda_ctx *ctx);
|
||||
bool detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32_t len,
|
||||
unsigned char *IV);
|
||||
bool detect_attack(struct crcda_ctx *ctx,
|
||||
const unsigned char *buf, uint32_t len,
|
||||
const unsigned char *IV);
|
||||
|
||||
/*
|
||||
* SSH2 RSA key exchange functions
|
||||
@@ -561,8 +563,8 @@ mp_int *dss_gen_k(const char *id_string,
|
||||
unsigned char *digest, int digest_len);
|
||||
#endif
|
||||
|
||||
struct ssh2_cipher {
|
||||
const ssh2_cipheralg *vt;
|
||||
struct ssh_cipher {
|
||||
const ssh_cipheralg *vt;
|
||||
};
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
@@ -645,41 +647,22 @@ void SHA384_Init(SHA384_State * s);
|
||||
void SHA384_Final(SHA384_State * s, unsigned char *output);
|
||||
void SHA384_Simple(const void *p, int len, unsigned char *output);
|
||||
|
||||
struct ssh1_cipher {
|
||||
const ssh1_cipheralg *vt;
|
||||
};
|
||||
|
||||
struct ssh1_cipheralg {
|
||||
ssh1_cipher *(*new)(void);
|
||||
void (*free)(ssh1_cipher *);
|
||||
void (*sesskey)(ssh1_cipher *, const void *key);
|
||||
void (*encrypt)(ssh1_cipher *, void *blk, int len);
|
||||
void (*decrypt)(ssh1_cipher *, void *blk, int len);
|
||||
int blksize;
|
||||
const char *text_name;
|
||||
};
|
||||
|
||||
#define ssh1_cipher_new(alg) ((alg)->new())
|
||||
#define ssh1_cipher_free(ctx) ((ctx)->vt->free(ctx))
|
||||
#define ssh1_cipher_sesskey(ctx, key) ((ctx)->vt->sesskey(ctx, key))
|
||||
#define ssh1_cipher_encrypt(ctx, blk, len) ((ctx)->vt->encrypt(ctx, blk, len))
|
||||
#define ssh1_cipher_decrypt(ctx, blk, len) ((ctx)->vt->decrypt(ctx, blk, len))
|
||||
|
||||
#endif
|
||||
|
||||
struct ssh2_cipheralg {
|
||||
ssh2_cipher *(*new)(const ssh2_cipheralg *alg);
|
||||
void (*free)(ssh2_cipher *);
|
||||
void (*setiv)(ssh2_cipher *, const void *iv);
|
||||
void (*setkey)(ssh2_cipher *, const void *key);
|
||||
void (*encrypt)(ssh2_cipher *, void *blk, int len);
|
||||
void (*decrypt)(ssh2_cipher *, void *blk, int len);
|
||||
struct ssh_cipheralg {
|
||||
ssh_cipher *(*new)(const ssh_cipheralg *alg);
|
||||
void (*free)(ssh_cipher *);
|
||||
void (*setiv)(ssh_cipher *, const void *iv);
|
||||
void (*setkey)(ssh_cipher *, const void *key);
|
||||
void (*encrypt)(ssh_cipher *, void *blk, int len);
|
||||
void (*decrypt)(ssh_cipher *, void *blk, int len);
|
||||
|
||||
/* Ignored unless SSH_CIPHER_SEPARATE_LENGTH flag set */
|
||||
void (*encrypt_length)(ssh2_cipher *, void *blk, int len,
|
||||
void (*encrypt_length)(ssh_cipher *, void *blk, int len,
|
||||
unsigned long seq);
|
||||
void (*decrypt_length)(ssh2_cipher *, void *blk, int len,
|
||||
void (*decrypt_length)(ssh_cipher *, void *blk, int len,
|
||||
unsigned long seq);
|
||||
const char *name;
|
||||
const char *ssh2_id;
|
||||
int blksize;
|
||||
/* real_keybits is the number of bits of entropy genuinely used by
|
||||
* the cipher scheme; it's used for deciding how big a
|
||||
@@ -707,21 +690,21 @@ struct ssh2_cipheralg {
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
|
||||
#define ssh2_cipher_new(alg) ((alg)->new(alg))
|
||||
#define ssh2_cipher_free(ctx) ((ctx)->vt->free(ctx))
|
||||
#define ssh2_cipher_setiv(ctx, iv) ((ctx)->vt->setiv(ctx, iv))
|
||||
#define ssh2_cipher_setkey(ctx, key) ((ctx)->vt->setkey(ctx, key))
|
||||
#define ssh2_cipher_encrypt(ctx, blk, len) ((ctx)->vt->encrypt(ctx, blk, len))
|
||||
#define ssh2_cipher_decrypt(ctx, blk, len) ((ctx)->vt->decrypt(ctx, blk, len))
|
||||
#define ssh2_cipher_encrypt_length(ctx, blk, len, seq) \
|
||||
#define ssh_cipher_new(alg) ((alg)->new(alg))
|
||||
#define ssh_cipher_free(ctx) ((ctx)->vt->free(ctx))
|
||||
#define ssh_cipher_setiv(ctx, iv) ((ctx)->vt->setiv(ctx, iv))
|
||||
#define ssh_cipher_setkey(ctx, key) ((ctx)->vt->setkey(ctx, key))
|
||||
#define ssh_cipher_encrypt(ctx, blk, len) ((ctx)->vt->encrypt(ctx, blk, len))
|
||||
#define ssh_cipher_decrypt(ctx, blk, len) ((ctx)->vt->decrypt(ctx, blk, len))
|
||||
#define ssh_cipher_encrypt_length(ctx, blk, len, seq) \
|
||||
((ctx)->vt->encrypt_length(ctx, blk, len, seq))
|
||||
#define ssh2_cipher_decrypt_length(ctx, blk, len, seq) \
|
||||
#define ssh_cipher_decrypt_length(ctx, blk, len, seq) \
|
||||
((ctx)->vt->decrypt_length(ctx, blk, len, seq))
|
||||
#define ssh2_cipher_alg(ctx) ((ctx)->vt)
|
||||
#define ssh_cipher_alg(ctx) ((ctx)->vt)
|
||||
|
||||
struct ssh2_ciphers {
|
||||
int nciphers;
|
||||
const ssh2_cipheralg *const *list;
|
||||
const ssh_cipheralg *const *list;
|
||||
};
|
||||
|
||||
struct ssh2_mac {
|
||||
@@ -731,7 +714,7 @@ struct ssh2_mac {
|
||||
|
||||
struct ssh2_macalg {
|
||||
/* Passes in the cipher context */
|
||||
ssh2_mac *(*new)(const ssh2_macalg *alg, ssh2_cipher *cipher);
|
||||
ssh2_mac *(*new)(const ssh2_macalg *alg, ssh_cipher *cipher);
|
||||
void (*free)(ssh2_mac *);
|
||||
void (*setkey)(ssh2_mac *, ptrlen key);
|
||||
void (*start)(ssh2_mac *);
|
||||
@@ -878,36 +861,35 @@ struct ssh2_userkey {
|
||||
/* The maximum length of any hash algorithm. (bytes) */
|
||||
#define MAX_HASH_LEN (64) /* longest is SHA-512 */
|
||||
|
||||
extern const ssh1_cipheralg ssh1_3des;
|
||||
extern const ssh1_cipheralg ssh1_des;
|
||||
extern const ssh1_cipheralg ssh1_blowfish;
|
||||
extern const ssh2_cipheralg ssh_3des_ssh2_ctr;
|
||||
extern const ssh2_cipheralg ssh_3des_ssh2;
|
||||
extern const ssh2_cipheralg ssh_des_ssh2;
|
||||
extern const ssh2_cipheralg ssh_des_sshcom_ssh2;
|
||||
extern const ssh2_cipheralg ssh_aes256_sdctr;
|
||||
extern const ssh2_cipheralg ssh_aes256_sdctr_hw;
|
||||
extern const ssh2_cipheralg ssh_aes256_sdctr_sw;
|
||||
extern const ssh2_cipheralg ssh_aes256_cbc;
|
||||
extern const ssh2_cipheralg ssh_aes256_cbc_hw;
|
||||
extern const ssh2_cipheralg ssh_aes256_cbc_sw;
|
||||
extern const ssh2_cipheralg ssh_aes192_sdctr;
|
||||
extern const ssh2_cipheralg ssh_aes192_sdctr_hw;
|
||||
extern const ssh2_cipheralg ssh_aes192_sdctr_sw;
|
||||
extern const ssh2_cipheralg ssh_aes192_cbc;
|
||||
extern const ssh2_cipheralg ssh_aes192_cbc_hw;
|
||||
extern const ssh2_cipheralg ssh_aes192_cbc_sw;
|
||||
extern const ssh2_cipheralg ssh_aes128_sdctr;
|
||||
extern const ssh2_cipheralg ssh_aes128_sdctr_hw;
|
||||
extern const ssh2_cipheralg ssh_aes128_sdctr_sw;
|
||||
extern const ssh2_cipheralg ssh_aes128_cbc;
|
||||
extern const ssh2_cipheralg ssh_aes128_cbc_hw;
|
||||
extern const ssh2_cipheralg ssh_aes128_cbc_sw;
|
||||
extern const ssh2_cipheralg ssh_blowfish_ssh2_ctr;
|
||||
extern const ssh2_cipheralg ssh_blowfish_ssh2;
|
||||
extern const ssh2_cipheralg ssh_arcfour256_ssh2;
|
||||
extern const ssh2_cipheralg ssh_arcfour128_ssh2;
|
||||
extern const ssh2_cipheralg ssh2_chacha20_poly1305;
|
||||
extern const ssh_cipheralg ssh_3des_ssh1;
|
||||
extern const ssh_cipheralg ssh_blowfish_ssh1;
|
||||
extern const ssh_cipheralg ssh_3des_ssh2_ctr;
|
||||
extern const ssh_cipheralg ssh_3des_ssh2;
|
||||
extern const ssh_cipheralg ssh_des;
|
||||
extern const ssh_cipheralg ssh_des_sshcom_ssh2;
|
||||
extern const ssh_cipheralg ssh_aes256_sdctr;
|
||||
extern const ssh_cipheralg ssh_aes256_sdctr_hw;
|
||||
extern const ssh_cipheralg ssh_aes256_sdctr_sw;
|
||||
extern const ssh_cipheralg ssh_aes256_cbc;
|
||||
extern const ssh_cipheralg ssh_aes256_cbc_hw;
|
||||
extern const ssh_cipheralg ssh_aes256_cbc_sw;
|
||||
extern const ssh_cipheralg ssh_aes192_sdctr;
|
||||
extern const ssh_cipheralg ssh_aes192_sdctr_hw;
|
||||
extern const ssh_cipheralg ssh_aes192_sdctr_sw;
|
||||
extern const ssh_cipheralg ssh_aes192_cbc;
|
||||
extern const ssh_cipheralg ssh_aes192_cbc_hw;
|
||||
extern const ssh_cipheralg ssh_aes192_cbc_sw;
|
||||
extern const ssh_cipheralg ssh_aes128_sdctr;
|
||||
extern const ssh_cipheralg ssh_aes128_sdctr_hw;
|
||||
extern const ssh_cipheralg ssh_aes128_sdctr_sw;
|
||||
extern const ssh_cipheralg ssh_aes128_cbc;
|
||||
extern const ssh_cipheralg ssh_aes128_cbc_hw;
|
||||
extern const ssh_cipheralg ssh_aes128_cbc_sw;
|
||||
extern const ssh_cipheralg ssh_blowfish_ssh2_ctr;
|
||||
extern const ssh_cipheralg ssh_blowfish_ssh2;
|
||||
extern const ssh_cipheralg ssh_arcfour256_ssh2;
|
||||
extern const ssh_cipheralg ssh_arcfour128_ssh2;
|
||||
extern const ssh_cipheralg ssh2_chacha20_poly1305;
|
||||
extern const ssh2_ciphers ssh2_3des;
|
||||
extern const ssh2_ciphers ssh2_des;
|
||||
extern const ssh2_ciphers ssh2_aes;
|
||||
@@ -944,6 +926,14 @@ extern const ssh2_macalg ssh_hmac_sha256;
|
||||
extern const ssh2_macalg ssh2_poly1305;
|
||||
extern const ssh_compression_alg ssh_zlib;
|
||||
|
||||
/*
|
||||
* On some systems, you have to detect hardware crypto acceleration by
|
||||
* asking the local OS API rather than OS-agnostically asking the CPU
|
||||
* itself. If so, then this function should be implemented in each
|
||||
* platform subdirectory.
|
||||
*/
|
||||
bool platform_aes_hw_available(void);
|
||||
|
||||
/*
|
||||
* PuTTY version number formatted as an SSH version string.
|
||||
*/
|
||||
|
||||
52
source/putty/ssh1bpp.c
vendored
52
source/putty/ssh1bpp.c
vendored
@@ -13,13 +13,14 @@ struct ssh1_bpp_state {
|
||||
int crState;
|
||||
long len, pad, biglen, length, maxlen;
|
||||
unsigned char *data;
|
||||
unsigned long realcrc, gotcrc;
|
||||
uint32_t realcrc, gotcrc;
|
||||
int chunk;
|
||||
PktIn *pktin;
|
||||
|
||||
ssh1_cipher *cipher;
|
||||
ssh_cipher *cipher_in, *cipher_out;
|
||||
|
||||
struct crcda_ctx *crcda_ctx;
|
||||
uint8_t iv[8]; /* for crcda */
|
||||
|
||||
bool pending_compression_request;
|
||||
ssh_compressor *compctx;
|
||||
@@ -56,8 +57,10 @@ BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx)
|
||||
static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp);
|
||||
if (s->cipher)
|
||||
ssh1_cipher_free(s->cipher);
|
||||
if (s->cipher_in)
|
||||
ssh_cipher_free(s->cipher_in);
|
||||
if (s->cipher_out)
|
||||
ssh_cipher_free(s->cipher_out);
|
||||
if (s->compctx)
|
||||
ssh_compressor_free(s->compctx);
|
||||
if (s->decompctx)
|
||||
@@ -69,23 +72,32 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
|
||||
}
|
||||
|
||||
void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
|
||||
const ssh1_cipheralg *cipher,
|
||||
const ssh_cipheralg *cipher,
|
||||
const void *session_key)
|
||||
{
|
||||
struct ssh1_bpp_state *s;
|
||||
assert(bpp->vt == &ssh1_bpp_vtable);
|
||||
s = container_of(bpp, struct ssh1_bpp_state, bpp);
|
||||
|
||||
assert(!s->cipher);
|
||||
assert(!s->cipher_in);
|
||||
assert(!s->cipher_out);
|
||||
|
||||
if (cipher) {
|
||||
s->cipher = ssh1_cipher_new(cipher);
|
||||
ssh1_cipher_sesskey(s->cipher, session_key);
|
||||
s->cipher_in = ssh_cipher_new(cipher);
|
||||
s->cipher_out = ssh_cipher_new(cipher);
|
||||
ssh_cipher_setkey(s->cipher_in, session_key);
|
||||
ssh_cipher_setkey(s->cipher_out, session_key);
|
||||
|
||||
assert(!s->crcda_ctx);
|
||||
s->crcda_ctx = crcda_make_context();
|
||||
|
||||
bpp_logevent("Initialised %s encryption", cipher->text_name);
|
||||
|
||||
memset(s->iv, 0, sizeof(s->iv));
|
||||
|
||||
assert(cipher->blksize <= sizeof(s->iv));
|
||||
ssh_cipher_setiv(s->cipher_in, s->iv);
|
||||
ssh_cipher_setiv(s->cipher_out, s->iv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,17 +166,21 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
|
||||
BPP_READ(s->data, s->biglen);
|
||||
|
||||
if (s->cipher && detect_attack(s->crcda_ctx,
|
||||
s->data, s->biglen, NULL)) {
|
||||
if (s->cipher_in && detect_attack(s->crcda_ctx,
|
||||
s->data, s->biglen, s->iv)) {
|
||||
ssh_sw_abort(s->bpp.ssh,
|
||||
"Network attack (CRC compensation) detected!");
|
||||
crStopV;
|
||||
}
|
||||
/* Save the last cipher block, to be passed to the next call
|
||||
* to detect_attack */
|
||||
assert(s->biglen >= 8);
|
||||
memcpy(s->iv, s->data + s->biglen - 8, sizeof(s->iv));
|
||||
|
||||
if (s->cipher)
|
||||
ssh1_cipher_decrypt(s->cipher, s->data, s->biglen);
|
||||
if (s->cipher_in)
|
||||
ssh_cipher_decrypt(s->cipher_in, s->data, s->biglen);
|
||||
|
||||
s->realcrc = crc32_compute(s->data, s->biglen - 4);
|
||||
s->realcrc = crc32_ssh1(make_ptrlen(s->data, s->biglen - 4));
|
||||
s->gotcrc = GET_32BIT(s->data + s->biglen - 4);
|
||||
if (s->gotcrc != s->realcrc) {
|
||||
ssh_sw_abort(s->bpp.ssh, "Incorrect CRC received on packet");
|
||||
@@ -280,7 +296,7 @@ static PktOut *ssh1_bpp_new_pktout(int pkt_type)
|
||||
static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt)
|
||||
{
|
||||
int pad, biglen, i, pktoffs;
|
||||
unsigned long crc;
|
||||
uint32_t crc;
|
||||
int len;
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
@@ -315,13 +331,13 @@ static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt)
|
||||
|
||||
for (i = pktoffs; i < 4+8; i++)
|
||||
pkt->data[i] = random_byte();
|
||||
crc = crc32_compute(pkt->data + pktoffs + 4,
|
||||
biglen - 4); /* all ex len */
|
||||
crc = crc32_ssh1(
|
||||
make_ptrlen(pkt->data + pktoffs + 4, biglen - 4)); /* all ex len */
|
||||
PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);
|
||||
PUT_32BIT(pkt->data + pktoffs, len);
|
||||
|
||||
if (s->cipher)
|
||||
ssh1_cipher_encrypt(s->cipher, pkt->data + pktoffs + 4, biglen);
|
||||
if (s->cipher_out)
|
||||
ssh_cipher_encrypt(s->cipher_out, pkt->data + pktoffs + 4, biglen);
|
||||
|
||||
bufchain_add(s->bpp.out_raw, pkt->data + pktoffs,
|
||||
biglen + 4); /* len(length+padding+type+data+CRC) */
|
||||
|
||||
1
source/putty/ssh1connection.h
vendored
1
source/putty/ssh1connection.h
vendored
@@ -50,6 +50,7 @@ struct ssh1_connection_state {
|
||||
struct outstanding_succfail *succfail_head, *succfail_tail;
|
||||
|
||||
bool compressing; /* used in server mode only */
|
||||
bool sent_exit_status; /* also for server mode */
|
||||
|
||||
ConnectionLayer cl;
|
||||
PacketProtocolLayer ppl;
|
||||
|
||||
6
source/putty/ssh1login.c
vendored
6
source/putty/ssh1login.c
vendored
@@ -362,9 +362,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
ssh_bpp_handle_output(s->ppl.bpp);
|
||||
|
||||
{
|
||||
const ssh1_cipheralg *cipher =
|
||||
(s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish :
|
||||
s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des);
|
||||
const ssh_cipheralg *cipher =
|
||||
(s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 :
|
||||
s->cipher_type == SSH_CIPHER_DES ? &ssh_des : &ssh_3des_ssh1);
|
||||
ssh1_bpp_new_cipher(s->ppl.bpp, cipher, s->session_key);
|
||||
}
|
||||
|
||||
|
||||
71
source/putty/ssh2bpp.c
vendored
71
source/putty/ssh2bpp.c
vendored
@@ -11,7 +11,7 @@
|
||||
|
||||
struct ssh2_bpp_direction {
|
||||
unsigned long sequence;
|
||||
ssh2_cipher *cipher;
|
||||
ssh_cipher *cipher;
|
||||
ssh2_mac *mac;
|
||||
bool etm_mode;
|
||||
const ssh_compression_alg *pending_compression;
|
||||
@@ -73,7 +73,7 @@ static void ssh2_bpp_free_outgoing_crypto(struct ssh2_bpp_state *s)
|
||||
* We must free the MAC before the cipher, because sometimes the
|
||||
* MAC is not actually separately allocated but just a different
|
||||
* facet of the same object as the cipher, in which case
|
||||
* ssh2_mac_free does nothing and ssh2_cipher_free does the actual
|
||||
* ssh2_mac_free does nothing and ssh_cipher_free does the actual
|
||||
* freeing. So if we freed the cipher first and then tried to
|
||||
* dereference the MAC's vtable pointer to find out how to free
|
||||
* that too, we'd be accessing freed memory.
|
||||
@@ -81,7 +81,7 @@ static void ssh2_bpp_free_outgoing_crypto(struct ssh2_bpp_state *s)
|
||||
if (s->out.mac)
|
||||
ssh2_mac_free(s->out.mac);
|
||||
if (s->out.cipher)
|
||||
ssh2_cipher_free(s->out.cipher);
|
||||
ssh_cipher_free(s->out.cipher);
|
||||
if (s->out_comp)
|
||||
ssh_compressor_free(s->out_comp);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ static void ssh2_bpp_free_incoming_crypto(struct ssh2_bpp_state *s)
|
||||
if (s->in.mac)
|
||||
ssh2_mac_free(s->in.mac);
|
||||
if (s->in.cipher)
|
||||
ssh2_cipher_free(s->in.cipher);
|
||||
ssh_cipher_free(s->in.cipher);
|
||||
if (s->in_decomp)
|
||||
ssh_decompressor_free(s->in_decomp);
|
||||
}
|
||||
@@ -109,7 +109,7 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
|
||||
|
||||
void ssh2_bpp_new_outgoing_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
|
||||
const ssh_compression_alg *compression, bool delayed_compression)
|
||||
{
|
||||
@@ -120,16 +120,16 @@ void ssh2_bpp_new_outgoing_crypto(
|
||||
ssh2_bpp_free_outgoing_crypto(s);
|
||||
|
||||
if (cipher) {
|
||||
s->out.cipher = ssh2_cipher_new(cipher);
|
||||
ssh2_cipher_setkey(s->out.cipher, ckey);
|
||||
ssh2_cipher_setiv(s->out.cipher, iv);
|
||||
s->out.cipher = ssh_cipher_new(cipher);
|
||||
ssh_cipher_setkey(s->out.cipher, ckey);
|
||||
ssh_cipher_setiv(s->out.cipher, iv);
|
||||
|
||||
s->cbc_ignore_workaround = (
|
||||
(ssh2_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_IS_CBC) &&
|
||||
(ssh_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_IS_CBC) &&
|
||||
!(s->bpp.remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE));
|
||||
|
||||
bpp_logevent("Initialised %s outbound encryption",
|
||||
ssh2_cipher_alg(s->out.cipher)->text_name);
|
||||
ssh_cipher_alg(s->out.cipher)->text_name);
|
||||
} else {
|
||||
s->out.cipher = NULL;
|
||||
s->cbc_ignore_workaround = false;
|
||||
@@ -143,7 +143,7 @@ void ssh2_bpp_new_outgoing_crypto(
|
||||
ssh2_mac_alg(s->out.mac)->text_name,
|
||||
etm_mode ? " (in ETM mode)" : "",
|
||||
(s->out.cipher &&
|
||||
ssh2_cipher_alg(s->out.cipher)->required_mac ?
|
||||
ssh_cipher_alg(s->out.cipher)->required_mac ?
|
||||
" (required by cipher)" : ""));
|
||||
} else {
|
||||
s->out.mac = NULL;
|
||||
@@ -171,7 +171,7 @@ void ssh2_bpp_new_outgoing_crypto(
|
||||
|
||||
void ssh2_bpp_new_incoming_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
|
||||
const ssh_compression_alg *compression, bool delayed_compression)
|
||||
{
|
||||
@@ -182,12 +182,12 @@ void ssh2_bpp_new_incoming_crypto(
|
||||
ssh2_bpp_free_incoming_crypto(s);
|
||||
|
||||
if (cipher) {
|
||||
s->in.cipher = ssh2_cipher_new(cipher);
|
||||
ssh2_cipher_setkey(s->in.cipher, ckey);
|
||||
ssh2_cipher_setiv(s->in.cipher, iv);
|
||||
s->in.cipher = ssh_cipher_new(cipher);
|
||||
ssh_cipher_setkey(s->in.cipher, ckey);
|
||||
ssh_cipher_setiv(s->in.cipher, iv);
|
||||
|
||||
bpp_logevent("Initialised %s inbound encryption",
|
||||
ssh2_cipher_alg(s->in.cipher)->text_name);
|
||||
ssh_cipher_alg(s->in.cipher)->text_name);
|
||||
} else {
|
||||
s->in.cipher = NULL;
|
||||
}
|
||||
@@ -200,7 +200,7 @@ void ssh2_bpp_new_incoming_crypto(
|
||||
ssh2_mac_alg(s->in.mac)->text_name,
|
||||
etm_mode ? " (in ETM mode)" : "",
|
||||
(s->in.cipher &&
|
||||
ssh2_cipher_alg(s->in.cipher)->required_mac ?
|
||||
ssh_cipher_alg(s->in.cipher)->required_mac ?
|
||||
" (required by cipher)" : ""));
|
||||
} else {
|
||||
s->in.mac = NULL;
|
||||
@@ -283,7 +283,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
s->maxlen = 0;
|
||||
s->length = 0;
|
||||
if (s->in.cipher)
|
||||
s->cipherblk = ssh2_cipher_alg(s->in.cipher)->blksize;
|
||||
s->cipherblk = ssh_cipher_alg(s->in.cipher)->blksize;
|
||||
else
|
||||
s->cipherblk = 8;
|
||||
if (s->cipherblk < 8)
|
||||
@@ -291,7 +291,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
s->maclen = s->in.mac ? ssh2_mac_alg(s->in.mac)->len : 0;
|
||||
|
||||
if (s->in.cipher &&
|
||||
(ssh2_cipher_alg(s->in.cipher)->flags & SSH_CIPHER_IS_CBC) &&
|
||||
(ssh_cipher_alg(s->in.cipher)->flags & SSH_CIPHER_IS_CBC) &&
|
||||
s->in.mac && !s->in.etm_mode) {
|
||||
/*
|
||||
* When dealing with a CBC-mode cipher, we want to avoid the
|
||||
@@ -333,8 +333,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
BPP_READ(s->buf + (s->packetlen + s->maclen), s->cipherblk);
|
||||
/* Decrypt one more block (a little further back in
|
||||
* the stream). */
|
||||
ssh2_cipher_decrypt(s->in.cipher,
|
||||
s->buf + s->packetlen, s->cipherblk);
|
||||
ssh_cipher_decrypt(s->in.cipher,
|
||||
s->buf + s->packetlen, s->cipherblk);
|
||||
|
||||
/* Feed that block to the MAC. */
|
||||
put_data(s->in.mac,
|
||||
@@ -376,12 +376,12 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
BPP_READ(s->buf, 4);
|
||||
|
||||
/* Cipher supports length decryption, so do it */
|
||||
if (s->in.cipher && (ssh2_cipher_alg(s->in.cipher)->flags &
|
||||
if (s->in.cipher && (ssh_cipher_alg(s->in.cipher)->flags &
|
||||
SSH_CIPHER_SEPARATE_LENGTH)) {
|
||||
/* Keep the packet the same though, so the MAC passes */
|
||||
unsigned char len[4];
|
||||
memcpy(len, s->buf, 4);
|
||||
ssh2_cipher_decrypt_length(
|
||||
ssh_cipher_decrypt_length(
|
||||
s->in.cipher, len, 4, s->in.sequence);
|
||||
s->len = toint(GET_32BIT(len));
|
||||
} else {
|
||||
@@ -430,7 +430,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
|
||||
/* Decrypt everything between the length field and the MAC. */
|
||||
if (s->in.cipher)
|
||||
ssh2_cipher_decrypt(
|
||||
ssh_cipher_decrypt(
|
||||
s->in.cipher, s->data + 4, s->packetlen - 4);
|
||||
} else {
|
||||
if (s->bufsize < s->cipherblk) {
|
||||
@@ -445,8 +445,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
BPP_READ(s->buf, s->cipherblk);
|
||||
|
||||
if (s->in.cipher)
|
||||
ssh2_cipher_decrypt(
|
||||
s->in.cipher, s->buf, s->cipherblk);
|
||||
ssh_cipher_decrypt(s->in.cipher, s->buf, s->cipherblk);
|
||||
|
||||
/*
|
||||
* Now get the length figure.
|
||||
@@ -488,7 +487,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
|
||||
/* Decrypt everything _except_ the MAC. */
|
||||
if (s->in.cipher)
|
||||
ssh2_cipher_decrypt(
|
||||
ssh_cipher_decrypt(
|
||||
s->in.cipher,
|
||||
s->data + s->cipherblk, s->packetlen - s->cipherblk);
|
||||
|
||||
@@ -684,7 +683,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
|
||||
pkt->downstream_id, pkt->additional_log_text);
|
||||
}
|
||||
|
||||
cipherblk = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 8;
|
||||
cipherblk = s->out.cipher ? ssh_cipher_alg(s->out.cipher)->blksize : 8;
|
||||
cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */
|
||||
|
||||
if (s->out_comp) {
|
||||
@@ -733,9 +732,9 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
|
||||
|
||||
/* Encrypt length if the scheme requires it */
|
||||
if (s->out.cipher &&
|
||||
(ssh2_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
|
||||
ssh2_cipher_encrypt_length(s->out.cipher, pkt->data, 4,
|
||||
s->out.sequence);
|
||||
(ssh_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
|
||||
ssh_cipher_encrypt_length(s->out.cipher, pkt->data, 4,
|
||||
s->out.sequence);
|
||||
}
|
||||
|
||||
put_padding(pkt, maclen, 0);
|
||||
@@ -745,8 +744,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
|
||||
* OpenSSH-defined encrypt-then-MAC protocol.
|
||||
*/
|
||||
if (s->out.cipher)
|
||||
ssh2_cipher_encrypt(s->out.cipher,
|
||||
pkt->data + 4, origlen + padding - 4);
|
||||
ssh_cipher_encrypt(s->out.cipher,
|
||||
pkt->data + 4, origlen + padding - 4);
|
||||
ssh2_mac_generate(s->out.mac, pkt->data, origlen + padding,
|
||||
s->out.sequence);
|
||||
} else {
|
||||
@@ -757,7 +756,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
|
||||
ssh2_mac_generate(s->out.mac, pkt->data, origlen + padding,
|
||||
s->out.sequence);
|
||||
if (s->out.cipher)
|
||||
ssh2_cipher_encrypt(s->out.cipher, pkt->data, origlen + padding);
|
||||
ssh_cipher_encrypt(s->out.cipher, pkt->data, origlen + padding);
|
||||
}
|
||||
|
||||
s->out.sequence++; /* whether or not we MACed */
|
||||
@@ -791,7 +790,7 @@ static void ssh2_bpp_format_packet(struct ssh2_bpp_state *s, PktOut *pkt)
|
||||
int block, length;
|
||||
PktOut *ignore_pkt;
|
||||
|
||||
block = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 0;
|
||||
block = s->out.cipher ? ssh_cipher_alg(s->out.cipher)->blksize : 0;
|
||||
if (block < 8)
|
||||
block = 8;
|
||||
length = pkt->length;
|
||||
@@ -874,7 +873,7 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp)
|
||||
* from out_raw).
|
||||
*/
|
||||
if (bufchain_size(s->bpp.out_raw) <
|
||||
(ssh2_cipher_alg(s->out.cipher)->blksize +
|
||||
(ssh_cipher_alg(s->out.cipher)->blksize +
|
||||
ssh2_mac_alg(s->out.mac)->len)) {
|
||||
/*
|
||||
* There's less data in out_raw than the MAC size plus the
|
||||
|
||||
6
source/putty/ssh2transport.c
vendored
6
source/putty/ssh2transport.c
vendored
@@ -657,7 +657,7 @@ static void ssh2_write_kexinit_lists(
|
||||
if (!c) warn = true;
|
||||
else for (j = 0; j < c->nciphers; j++) {
|
||||
alg = ssh2_kexinit_addalg(kexlists[k],
|
||||
c->list[j]->name);
|
||||
c->list[j]->ssh2_id);
|
||||
alg->u.cipher.cipher = c->list[j];
|
||||
alg->u.cipher.warn = warn;
|
||||
}
|
||||
@@ -1208,7 +1208,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
if (s->warn_cscipher) {
|
||||
s->dlgret = seat_confirm_weak_crypto_primitive(
|
||||
s->ppl.seat, "client-to-server cipher", s->out.cipher->name,
|
||||
s->ppl.seat, "client-to-server cipher", s->out.cipher->ssh2_id,
|
||||
ssh2_transport_dialog_callback, s);
|
||||
crMaybeWaitUntilV(s->dlgret >= 0);
|
||||
if (s->dlgret == 0) {
|
||||
@@ -1219,7 +1219,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
if (s->warn_sccipher) {
|
||||
s->dlgret = seat_confirm_weak_crypto_primitive(
|
||||
s->ppl.seat, "server-to-client cipher", s->in.cipher->name,
|
||||
s->ppl.seat, "server-to-client cipher", s->in.cipher->ssh2_id,
|
||||
ssh2_transport_dialog_callback, s);
|
||||
crMaybeWaitUntilV(s->dlgret >= 0);
|
||||
if (s->dlgret == 0) {
|
||||
|
||||
4
source/putty/ssh2transport.h
vendored
4
source/putty/ssh2transport.h
vendored
@@ -36,7 +36,7 @@ struct kexinit_algorithm {
|
||||
bool warn;
|
||||
} hk;
|
||||
struct {
|
||||
const ssh2_cipheralg *cipher;
|
||||
const ssh_cipheralg *cipher;
|
||||
bool warn;
|
||||
} cipher;
|
||||
struct {
|
||||
@@ -104,7 +104,7 @@ typedef enum RekeyClass {
|
||||
} RekeyClass;
|
||||
|
||||
typedef struct transport_direction {
|
||||
const ssh2_cipheralg *cipher;
|
||||
const ssh_cipheralg *cipher;
|
||||
const ssh2_macalg *mac;
|
||||
bool etm_mode;
|
||||
const ssh_compression_alg *comp;
|
||||
|
||||
501
source/putty/sshaes.c
vendored
501
source/putty/sshaes.c
vendored
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
#define HW_AES_NONE 0
|
||||
#define HW_AES_NI 1
|
||||
#define HW_AES_NEON 2
|
||||
|
||||
#ifdef _FORCE_AES_NI
|
||||
# define HW_AES HW_AES_NI
|
||||
@@ -34,6 +35,37 @@
|
||||
|
||||
#define HW_AES HW_AES_NI // WINSCP
|
||||
|
||||
#ifdef _FORCE_AES_NEON
|
||||
# define HW_AES HW_AES_NEON
|
||||
#elif defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
/* Arm can potentially support both endiannesses, but this code
|
||||
* hasn't been tested on anything but little. If anyone wants to
|
||||
* run big-endian, they'll need to fix it first. */
|
||||
#elif defined __ARM_FEATURE_CRYPTO
|
||||
/* If the Arm crypto extension is available already, we can
|
||||
* support NEON AES without having to enable anything by hand */
|
||||
# define HW_AES HW_AES_NEON
|
||||
#elif defined(__clang__)
|
||||
# if __has_attribute(target) && __has_include(<arm_neon.h>) && \
|
||||
(defined(__aarch64__))
|
||||
/* clang can enable the crypto extension in AArch64 using
|
||||
* __attribute__((target)) */
|
||||
# define HW_AES HW_AES_NEON
|
||||
# define USE_CLANG_ATTR_TARGET_AARCH64
|
||||
# endif
|
||||
#elif defined _MSC_VER
|
||||
/* Visual Studio supports the crypto extension when targeting
|
||||
* AArch64, but as of VS2017, the AArch32 header doesn't quite
|
||||
* manage it (declaring the aese/aesd intrinsics without a round
|
||||
* key operand). */
|
||||
# if defined _M_ARM64
|
||||
# define HW_AES HW_AES_NEON
|
||||
# if defined _M_ARM64
|
||||
# define USE_ARM64_NEON_H /* unusual header name in this case */
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined _FORCE_SOFTWARE_AES || !defined HW_AES
|
||||
# undef HW_AES
|
||||
# define HW_AES HW_AES_NONE
|
||||
@@ -41,6 +73,8 @@
|
||||
|
||||
#if HW_AES == HW_AES_NI
|
||||
#define HW_NAME_SUFFIX " (AES-NI accelerated)"
|
||||
#elif HW_AES == HW_AES_NEON
|
||||
#define HW_NAME_SUFFIX " (NEON accelerated)"
|
||||
#else
|
||||
#define HW_NAME_SUFFIX " (!NONEXISTENT ACCELERATED VERSION!)"
|
||||
#endif
|
||||
@@ -55,35 +89,35 @@
|
||||
* instance of.
|
||||
*/
|
||||
|
||||
static ssh2_cipher *aes_select(const ssh2_cipheralg *alg);
|
||||
static ssh2_cipher *aes_sw_new(const ssh2_cipheralg *alg);
|
||||
static void aes_sw_free(ssh2_cipher *);
|
||||
static void aes_sw_setiv_cbc(ssh2_cipher *, const void *iv);
|
||||
static void aes_sw_setiv_sdctr(ssh2_cipher *, const void *iv);
|
||||
static void aes_sw_setkey(ssh2_cipher *, const void *key);
|
||||
/*WINSCP static*/ ssh2_cipher *aes_hw_new(const ssh2_cipheralg *alg);
|
||||
/*WINSCP static*/ void aes_hw_free(ssh2_cipher *);
|
||||
/*WINSCP static*/ void aes_hw_setiv_cbc(ssh2_cipher *, const void *iv);
|
||||
/*WINSCP static*/ void aes_hw_setiv_sdctr(ssh2_cipher *, const void *iv);
|
||||
/*WINSCP static*/ void aes_hw_setkey(ssh2_cipher *, const void *key);
|
||||
static ssh_cipher *aes_select(const ssh_cipheralg *alg);
|
||||
static ssh_cipher *aes_sw_new(const ssh_cipheralg *alg);
|
||||
static void aes_sw_free(ssh_cipher *);
|
||||
static void aes_sw_setiv_cbc(ssh_cipher *, const void *iv);
|
||||
static void aes_sw_setiv_sdctr(ssh_cipher *, const void *iv);
|
||||
static void aes_sw_setkey(ssh_cipher *, const void *key);
|
||||
/*WINSCP static*/ ssh_cipher *aes_hw_new(const ssh_cipheralg *alg);
|
||||
/*WINSCP static*/ void aes_hw_free(ssh_cipher *);
|
||||
/*WINSCP static*/ void aes_hw_setiv_cbc(ssh_cipher *, const void *iv);
|
||||
/*WINSCP static*/ void aes_hw_setiv_sdctr(ssh_cipher *, const void *iv);
|
||||
/*WINSCP static*/ void aes_hw_setkey(ssh_cipher *, const void *key);
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
struct aes_extra {
|
||||
const ssh2_cipheralg *sw, *hw;
|
||||
const ssh_cipheralg *sw, *hw;
|
||||
};
|
||||
|
||||
#define VTABLES(cid, pid, bits, name, encsuffix, decsuffix, setiv) \
|
||||
/*WINSCP static */void cid##_sw##encsuffix(ssh2_cipher *, void *blk, int len); \
|
||||
/*WINSCP static */void cid##_sw##decsuffix(ssh2_cipher *, void *blk, int len); \
|
||||
const ssh2_cipheralg ssh_##cid##_sw = { \
|
||||
/*WINSCP static */void cid##_sw##encsuffix(ssh_cipher *, void *blk, int len); \
|
||||
/*WINSCP static */void cid##_sw##decsuffix(ssh_cipher *, void *blk, int len); \
|
||||
const ssh_cipheralg ssh_##cid##_sw = { \
|
||||
aes_sw_new, aes_sw_free, aes_sw_##setiv, aes_sw_setkey, \
|
||||
cid##_sw##encsuffix, cid##_sw##decsuffix, NULL, NULL, \
|
||||
pid, 16, bits, bits/8, 0, name " (unaccelerated)", \
|
||||
NULL, NULL }; \
|
||||
\
|
||||
/*WINSCP static*/ void cid##_hw##encsuffix(ssh2_cipher *, void *blk, int len); \
|
||||
/*WINSCP static*/ void cid##_hw##decsuffix(ssh2_cipher *, void *blk, int len); \
|
||||
const ssh2_cipheralg ssh_##cid##_hw = { \
|
||||
/*WINSCP static*/ void cid##_hw##encsuffix(ssh_cipher *, void *blk, int len); \
|
||||
/*WINSCP static*/ void cid##_hw##decsuffix(ssh_cipher *, void *blk, int len); \
|
||||
const ssh_cipheralg ssh_##cid##_hw = { \
|
||||
aes_hw_new, aes_hw_free, aes_hw_##setiv, aes_hw_setkey, \
|
||||
cid##_hw##encsuffix, cid##_hw##decsuffix, NULL, NULL, \
|
||||
pid, 16, bits, bits/8, 0, name HW_NAME_SUFFIX, \
|
||||
@@ -92,7 +126,7 @@ struct aes_extra {
|
||||
const struct aes_extra extra_##cid = { \
|
||||
&ssh_##cid##_sw, &ssh_##cid##_hw }; \
|
||||
\
|
||||
const ssh2_cipheralg ssh_##cid = { \
|
||||
const ssh_cipheralg ssh_##cid = { \
|
||||
aes_select, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
|
||||
pid, 16, bits, bits/8, 0, name " (dummy selector vtable)", \
|
||||
NULL, &extra_##cid }; \
|
||||
@@ -104,14 +138,14 @@ VTABLES(aes128_sdctr, "aes128-ctr", 128, "AES-128 SDCTR",,, setiv_sdctr)
|
||||
VTABLES(aes192_sdctr, "aes192-ctr", 192, "AES-192 SDCTR",,, setiv_sdctr)
|
||||
VTABLES(aes256_sdctr, "aes256-ctr", 256, "AES-256 SDCTR",,, setiv_sdctr)
|
||||
|
||||
static const ssh2_cipheralg ssh_rijndael_lysator = {
|
||||
static const ssh_cipheralg ssh_rijndael_lysator = {
|
||||
/* Same as aes256_cbc, but with a different protocol ID */
|
||||
aes_select, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
"rijndael-cbc@lysator.liu.se", 16, 256, 256/8, 0,
|
||||
"AES-256 CBC (dummy selector vtable)", NULL, &extra_aes256_cbc
|
||||
};
|
||||
|
||||
static const ssh2_cipheralg *const aes_list[] = {
|
||||
static const ssh_cipheralg *const aes_list[] = {
|
||||
&ssh_aes256_sdctr,
|
||||
&ssh_aes256_cbc,
|
||||
&ssh_rijndael_lysator,
|
||||
@@ -138,19 +172,21 @@ static bool aes_hw_available_cached(void)
|
||||
{
|
||||
static bool initialised = false;
|
||||
static bool hw_available;
|
||||
if (!initialised)
|
||||
if (!initialised) {
|
||||
hw_available = aes_hw_available();
|
||||
initialised = true;
|
||||
}
|
||||
return hw_available;
|
||||
}
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
static ssh2_cipher *aes_select(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *aes_select(const ssh_cipheralg *alg)
|
||||
{
|
||||
const struct aes_extra *extra = (const struct aes_extra *)alg->extra;
|
||||
const ssh2_cipheralg *real_alg =
|
||||
const ssh_cipheralg *real_alg =
|
||||
aes_hw_available_cached() ? extra->hw : extra->sw;
|
||||
|
||||
return ssh2_cipher_new(real_alg);
|
||||
return ssh_cipher_new(real_alg);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -968,38 +1004,38 @@ struct aes_sw_context {
|
||||
uint8_t *keystream_pos;
|
||||
} sdctr;
|
||||
} iv;
|
||||
ssh2_cipher ciph;
|
||||
ssh_cipher ciph;
|
||||
};
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
|
||||
static ssh2_cipher *aes_sw_new(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *aes_sw_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
aes_sw_context *ctx = snew(aes_sw_context);
|
||||
ctx->ciph.vt = alg;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static void aes_sw_free(ssh2_cipher *ciph)
|
||||
static void aes_sw_free(ssh_cipher *ciph)
|
||||
{
|
||||
aes_sw_context *ctx = container_of(ciph, aes_sw_context, ciph);
|
||||
smemclr(ctx, sizeof(*ctx));
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void aes_sw_setkey(ssh2_cipher *ciph, const void *vkey)
|
||||
static void aes_sw_setkey(ssh_cipher *ciph, const void *vkey)
|
||||
{
|
||||
aes_sw_context *ctx = container_of(ciph, aes_sw_context, ciph);
|
||||
aes_sliced_key_setup(&ctx->sk, vkey, ctx->ciph.vt->real_keybits);
|
||||
}
|
||||
|
||||
static void aes_sw_setiv_cbc(ssh2_cipher *ciph, const void *iv)
|
||||
static void aes_sw_setiv_cbc(ssh_cipher *ciph, const void *iv)
|
||||
{
|
||||
aes_sw_context *ctx = container_of(ciph, aes_sw_context, ciph);
|
||||
memcpy(ctx->iv.cbc.prevblk, iv, 16);
|
||||
}
|
||||
|
||||
static void aes_sw_setiv_sdctr(ssh2_cipher *ciph, const void *viv)
|
||||
static void aes_sw_setiv_sdctr(ssh_cipher *ciph, const void *viv)
|
||||
{
|
||||
aes_sw_context *ctx = container_of(ciph, aes_sw_context, ciph);
|
||||
const uint8_t *iv = (const uint8_t *)viv;
|
||||
@@ -1038,7 +1074,7 @@ static inline void memxor16(void *vout, const void *vlhs, const void *vrhs)
|
||||
}
|
||||
|
||||
static inline void aes_cbc_sw_encrypt(
|
||||
ssh2_cipher *ciph, void *vblk, int blklen)
|
||||
ssh_cipher *ciph, void *vblk, int blklen)
|
||||
{
|
||||
aes_sw_context *ctx = container_of(ciph, aes_sw_context, ciph);
|
||||
|
||||
@@ -1069,7 +1105,7 @@ static inline void aes_cbc_sw_encrypt(
|
||||
}
|
||||
|
||||
static inline void aes_cbc_sw_decrypt(
|
||||
ssh2_cipher *ciph, void *vblk, int blklen)
|
||||
ssh_cipher *ciph, void *vblk, int blklen)
|
||||
{
|
||||
aes_sw_context *ctx = container_of(ciph, aes_sw_context, ciph);
|
||||
uint8_t *blk = (uint8_t *)vblk;
|
||||
@@ -1120,7 +1156,7 @@ static inline void aes_cbc_sw_decrypt(
|
||||
}
|
||||
|
||||
static inline void aes_sdctr_sw(
|
||||
ssh2_cipher *ciph, void *vblk, int blklen)
|
||||
ssh_cipher *ciph, void *vblk, int blklen)
|
||||
{
|
||||
aes_sw_context *ctx = container_of(ciph, aes_sw_context, ciph);
|
||||
|
||||
@@ -1170,13 +1206,13 @@ static inline void aes_sdctr_sw(
|
||||
|
||||
#define SW_ENC_DEC(len) \
|
||||
/*WINSCP static*/ void aes##len##_cbc_sw_encrypt( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_cbc_sw_encrypt(ciph, vblk, blklen); } \
|
||||
/*WINSCP static*/ void aes##len##_cbc_sw_decrypt( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_cbc_sw_decrypt(ciph, vblk, blklen); } \
|
||||
/*WINSCP static*/ void aes##len##_sdctr_sw( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_sdctr_sw(ciph, vblk, blklen); }
|
||||
|
||||
SW_ENC_DEC(128)
|
||||
@@ -1372,10 +1408,10 @@ struct aes_ni_context {
|
||||
__m128i keysched_e[MAXROUNDKEYS], keysched_d[MAXROUNDKEYS], iv;
|
||||
|
||||
void *pointer_to_free;
|
||||
ssh2_cipher ciph;
|
||||
ssh_cipher ciph;
|
||||
};
|
||||
|
||||
/*static WINSCP*/ ssh2_cipher *aes_hw_new(const ssh2_cipheralg *alg)
|
||||
/*static WINSCP*/ ssh_cipher *aes_hw_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
if (!aes_hw_available_cached())
|
||||
return NULL;
|
||||
@@ -1398,7 +1434,7 @@ struct aes_ni_context {
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
/*static WINSCP*/ void aes_hw_free(ssh2_cipher *ciph)
|
||||
/*static WINSCP*/ void aes_hw_free(ssh_cipher *ciph)
|
||||
{
|
||||
aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph);
|
||||
void *allocation = ctx->pointer_to_free;
|
||||
@@ -1406,7 +1442,7 @@ struct aes_ni_context {
|
||||
sfree(allocation);
|
||||
}
|
||||
|
||||
/*static WINSCP*/ void aes_hw_setkey(ssh2_cipher *ciph, const void *vkey)
|
||||
/*static WINSCP*/ void aes_hw_setkey(ssh_cipher *ciph, const void *vkey)
|
||||
{
|
||||
aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph);
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
@@ -1415,13 +1451,13 @@ struct aes_ni_context {
|
||||
ctx->keysched_e, ctx->keysched_d);
|
||||
}
|
||||
|
||||
/*static WINSCP*/ FUNC_ISA void aes_hw_setiv_cbc(ssh2_cipher *ciph, const void *iv)
|
||||
/*static WINSCP*/ FUNC_ISA void aes_hw_setiv_cbc(ssh_cipher *ciph, const void *iv)
|
||||
{
|
||||
aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph);
|
||||
ctx->iv = _mm_loadu_si128(iv);
|
||||
}
|
||||
|
||||
/*static WINSCP*/ FUNC_ISA void aes_hw_setiv_sdctr(ssh2_cipher *ciph, const void *iv)
|
||||
/*static WINSCP*/ FUNC_ISA void aes_hw_setiv_sdctr(ssh_cipher *ciph, const void *iv)
|
||||
{
|
||||
aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph);
|
||||
__m128i counter = _mm_loadu_si128(iv);
|
||||
@@ -1431,7 +1467,7 @@ struct aes_ni_context {
|
||||
typedef __m128i (*aes_ni_fn)(__m128i v, const __m128i *keysched);
|
||||
|
||||
static FUNC_ISA inline void aes_cbc_ni_encrypt(
|
||||
ssh2_cipher *ciph, void *vblk, int blklen, aes_ni_fn encrypt)
|
||||
ssh_cipher *ciph, void *vblk, int blklen, aes_ni_fn encrypt)
|
||||
{
|
||||
aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph);
|
||||
|
||||
@@ -1446,7 +1482,7 @@ static FUNC_ISA inline void aes_cbc_ni_encrypt(
|
||||
}
|
||||
|
||||
static FUNC_ISA inline void aes_cbc_ni_decrypt(
|
||||
ssh2_cipher *ciph, void *vblk, int blklen, aes_ni_fn decrypt)
|
||||
ssh_cipher *ciph, void *vblk, int blklen, aes_ni_fn decrypt)
|
||||
{
|
||||
aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph);
|
||||
|
||||
@@ -1461,7 +1497,7 @@ static FUNC_ISA inline void aes_cbc_ni_decrypt(
|
||||
}
|
||||
|
||||
static FUNC_ISA inline void aes_sdctr_ni(
|
||||
ssh2_cipher *ciph, void *vblk, int blklen, aes_ni_fn encrypt)
|
||||
ssh_cipher *ciph, void *vblk, int blklen, aes_ni_fn encrypt)
|
||||
{
|
||||
aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph);
|
||||
|
||||
@@ -1478,13 +1514,13 @@ static FUNC_ISA inline void aes_sdctr_ni(
|
||||
|
||||
#define NI_ENC_DEC(len) \
|
||||
/*static WINSCP*/ FUNC_ISA void aes##len##_cbc_hw_encrypt( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_cbc_ni_encrypt(ciph, vblk, blklen, aes_ni_##len##_e); } \
|
||||
/*static WINSCP*/ FUNC_ISA void aes##len##_cbc_hw_decrypt( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_cbc_ni_decrypt(ciph, vblk, blklen, aes_ni_##len##_d); } \
|
||||
/*static WINSCP*/ FUNC_ISA void aes##len##_sdctr_hw( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_sdctr_ni(ciph, vblk, blklen, aes_ni_##len##_e); } \
|
||||
|
||||
NI_ENC_DEC(128)
|
||||
@@ -1493,6 +1529,317 @@ NI_ENC_DEC(256)
|
||||
|
||||
#endif // WINSCP_VS
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Hardware-accelerated implementation of AES using Arm NEON.
|
||||
*/
|
||||
|
||||
#elif HW_AES == HW_AES_NEON
|
||||
|
||||
/*
|
||||
* Manually set the target architecture, if we decided above that we
|
||||
* need to.
|
||||
*/
|
||||
#ifdef USE_CLANG_ATTR_TARGET_AARCH64
|
||||
/*
|
||||
* A spot of cheating: redefine some ACLE feature macros before
|
||||
* including arm_neon.h. Otherwise we won't get the AES intrinsics
|
||||
* defined by that header, because it will be looking at the settings
|
||||
* for the whole translation unit rather than the ones we're going to
|
||||
* put on some particular functions using __attribute__((target)).
|
||||
*/
|
||||
#define __ARM_NEON 1
|
||||
#define __ARM_FEATURE_CRYPTO 1
|
||||
#define FUNC_ISA __attribute__ ((target("neon,crypto")))
|
||||
#endif /* USE_CLANG_ATTR_TARGET_AARCH64 */
|
||||
|
||||
#ifndef FUNC_ISA
|
||||
#define FUNC_ISA
|
||||
#endif
|
||||
|
||||
#ifdef USE_ARM64_NEON_H
|
||||
#include <arm64_neon.h>
|
||||
#else
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
static bool aes_hw_available(void)
|
||||
{
|
||||
/*
|
||||
* For Arm, we delegate to a per-platform AES detection function,
|
||||
* because it has to be implemented by asking the operating system
|
||||
* rather than directly querying the CPU.
|
||||
*
|
||||
* That's because Arm systems commonly have multiple cores that
|
||||
* are not all alike, so any method of querying whether NEON
|
||||
* crypto instructions work on the _current_ CPU - even one as
|
||||
* crude as just trying one and catching the SIGILL - wouldn't
|
||||
* give an answer that you could still rely on the first time the
|
||||
* OS migrated your process to another CPU.
|
||||
*/
|
||||
return platform_aes_hw_available();
|
||||
}
|
||||
|
||||
/*
|
||||
* Core NEON encrypt/decrypt functions, one per length and direction.
|
||||
*/
|
||||
|
||||
#define NEON_CIPHER(len, repmacro) \
|
||||
static FUNC_ISA inline uint8x16_t aes_neon_##len##_e( \
|
||||
uint8x16_t v, const uint8x16_t *keysched) \
|
||||
{ \
|
||||
repmacro(v = vaesmcq_u8(vaeseq_u8(v, *keysched++));); \
|
||||
v = vaeseq_u8(v, *keysched++); \
|
||||
return veorq_u8(v, *keysched); \
|
||||
} \
|
||||
static FUNC_ISA inline uint8x16_t aes_neon_##len##_d( \
|
||||
uint8x16_t v, const uint8x16_t *keysched) \
|
||||
{ \
|
||||
repmacro(v = vaesimcq_u8(vaesdq_u8(v, *keysched++));); \
|
||||
v = vaesdq_u8(v, *keysched++); \
|
||||
return veorq_u8(v, *keysched); \
|
||||
}
|
||||
|
||||
NEON_CIPHER(128, REP9)
|
||||
NEON_CIPHER(192, REP11)
|
||||
NEON_CIPHER(256, REP13)
|
||||
|
||||
/*
|
||||
* The main key expansion.
|
||||
*/
|
||||
static FUNC_ISA void aes_neon_key_expand(
|
||||
const unsigned char *key, size_t key_words,
|
||||
uint8x16_t *keysched_e, uint8x16_t *keysched_d)
|
||||
{
|
||||
size_t rounds = key_words + 6;
|
||||
size_t sched_words = (rounds + 1) * 4;
|
||||
|
||||
/*
|
||||
* Store the key schedule as 32-bit integers during expansion, so
|
||||
* that it's easy to refer back to individual previous words. We
|
||||
* collect them into the final uint8x16_t form at the end.
|
||||
*/
|
||||
uint32_t sched[MAXROUNDKEYS * 4];
|
||||
|
||||
unsigned rconpos = 0;
|
||||
|
||||
for (size_t i = 0; i < sched_words; i++) {
|
||||
if (i < key_words) {
|
||||
sched[i] = GET_32BIT_LSB_FIRST(key + 4 * i);
|
||||
} else {
|
||||
uint32_t temp = sched[i - 1];
|
||||
|
||||
bool rotate_and_round_constant = (i % key_words == 0);
|
||||
bool sub = rotate_and_round_constant ||
|
||||
(key_words == 8 && i % 8 == 4);
|
||||
|
||||
if (rotate_and_round_constant)
|
||||
temp = (temp << 24) | (temp >> 8);
|
||||
|
||||
if (sub) {
|
||||
uint32x4_t v32 = vdupq_n_u32(temp);
|
||||
uint8x16_t v8 = vreinterpretq_u8_u32(v32);
|
||||
v8 = vaeseq_u8(v8, vdupq_n_u8(0));
|
||||
v32 = vreinterpretq_u32_u8(v8);
|
||||
temp = vget_lane_u32(vget_low_u32(v32), 0);
|
||||
}
|
||||
|
||||
if (rotate_and_round_constant) {
|
||||
assert(rconpos < lenof(key_setup_round_constants));
|
||||
temp ^= key_setup_round_constants[rconpos++];
|
||||
}
|
||||
|
||||
sched[i] = sched[i - key_words] ^ temp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Combine the key schedule words into uint8x16_t vectors and
|
||||
* store them in the output context.
|
||||
*/
|
||||
for (size_t round = 0; round <= rounds; round++)
|
||||
keysched_e[round] = vreinterpretq_u8_u32(vld1q_u32(sched + 4*round));
|
||||
|
||||
smemclr(sched, sizeof(sched));
|
||||
|
||||
/*
|
||||
* Now prepare the modified keys for the inverse cipher.
|
||||
*/
|
||||
for (size_t eround = 0; eround <= rounds; eround++) {
|
||||
size_t dround = rounds - eround;
|
||||
uint8x16_t rkey = keysched_e[eround];
|
||||
if (eround && dround) /* neither first nor last */
|
||||
rkey = vaesimcq_u8(rkey);
|
||||
keysched_d[dround] = rkey;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Auxiliary routine to reverse the byte order of a vector, so that
|
||||
* the SDCTR IV can be made big-endian for feeding to the cipher.
|
||||
*
|
||||
* In fact we don't need to reverse the vector _all_ the way; we leave
|
||||
* the two lanes in MSW,LSW order, because that makes no difference to
|
||||
* the efficiency of the increment. That way we only have to reverse
|
||||
* bytes within each lane in this function.
|
||||
*/
|
||||
static FUNC_ISA inline uint8x16_t aes_neon_sdctr_reverse(uint8x16_t v)
|
||||
{
|
||||
return vrev64q_u8(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Auxiliary routine to increment the 128-bit counter used in SDCTR
|
||||
* mode. There's no instruction to treat a 128-bit vector as a single
|
||||
* long integer, so instead we have to increment the bottom half
|
||||
* unconditionally, and the top half if the bottom half started off as
|
||||
* all 1s (in which case there was about to be a carry).
|
||||
*/
|
||||
static FUNC_ISA inline uint8x16_t aes_neon_sdctr_increment(uint8x16_t in)
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
/* There will be a carry if the low 64 bits are all 1s. */
|
||||
uint64x1_t all1 = vcreate_u64(0xFFFFFFFFFFFFFFFF);
|
||||
uint64x1_t carry = vceq_u64(vget_high_u64(vreinterpretq_u64_u8(in)), all1);
|
||||
|
||||
/* Make a word whose bottom half is unconditionally all 1s, and
|
||||
* the top half is 'carry', i.e. all 0s most of the time but all
|
||||
* 1s if we need to increment the top half. Then that word is what
|
||||
* we need to _subtract_ from the input counter. */
|
||||
uint64x2_t subtrahend = vcombine_u64(carry, all1);
|
||||
#else
|
||||
/* AArch32 doesn't have comparisons that operate on a 64-bit lane,
|
||||
* so we start by comparing each 32-bit half of the low 64 bits
|
||||
* _separately_ to all-1s. */
|
||||
uint32x2_t all1 = vdup_n_u32(0xFFFFFFFF);
|
||||
uint32x2_t carry = vceq_u32(
|
||||
vget_high_u32(vreinterpretq_u32_u8(in)), all1);
|
||||
|
||||
/* Swap the 32-bit words of the compare output, and AND with the
|
||||
* unswapped version. Now carry is all 1s iff the bottom half of
|
||||
* the input counter was all 1s, and all 0s otherwise. */
|
||||
carry = vand_u32(carry, vrev64_u32(carry));
|
||||
|
||||
/* Now make the vector to subtract in the same way as above. */
|
||||
uint64x2_t subtrahend = vreinterpretq_u64_u32(vcombine_u32(carry, all1));
|
||||
#endif
|
||||
|
||||
return vreinterpretq_u8_u64(
|
||||
vsubq_u64(vreinterpretq_u64_u8(in), subtrahend));
|
||||
}
|
||||
|
||||
/*
|
||||
* The SSH interface and the cipher modes.
|
||||
*/
|
||||
|
||||
typedef struct aes_neon_context aes_neon_context;
|
||||
struct aes_neon_context {
|
||||
uint8x16_t keysched_e[MAXROUNDKEYS], keysched_d[MAXROUNDKEYS], iv;
|
||||
|
||||
ssh_cipher ciph;
|
||||
};
|
||||
|
||||
static ssh_cipher *aes_hw_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
if (!aes_hw_available_cached())
|
||||
return NULL;
|
||||
|
||||
aes_neon_context *ctx = snew(aes_neon_context);
|
||||
ctx->ciph.vt = alg;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static void aes_hw_free(ssh_cipher *ciph)
|
||||
{
|
||||
aes_neon_context *ctx = container_of(ciph, aes_neon_context, ciph);
|
||||
smemclr(ctx, sizeof(*ctx));
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void aes_hw_setkey(ssh_cipher *ciph, const void *vkey)
|
||||
{
|
||||
aes_neon_context *ctx = container_of(ciph, aes_neon_context, ciph);
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
|
||||
aes_neon_key_expand(key, ctx->ciph.vt->real_keybits / 32,
|
||||
ctx->keysched_e, ctx->keysched_d);
|
||||
}
|
||||
|
||||
static FUNC_ISA void aes_hw_setiv_cbc(ssh_cipher *ciph, const void *iv)
|
||||
{
|
||||
aes_neon_context *ctx = container_of(ciph, aes_neon_context, ciph);
|
||||
ctx->iv = vld1q_u8(iv);
|
||||
}
|
||||
|
||||
static FUNC_ISA void aes_hw_setiv_sdctr(ssh_cipher *ciph, const void *iv)
|
||||
{
|
||||
aes_neon_context *ctx = container_of(ciph, aes_neon_context, ciph);
|
||||
uint8x16_t counter = vld1q_u8(iv);
|
||||
ctx->iv = aes_neon_sdctr_reverse(counter);
|
||||
}
|
||||
|
||||
typedef uint8x16_t (*aes_neon_fn)(uint8x16_t v, const uint8x16_t *keysched);
|
||||
|
||||
static FUNC_ISA inline void aes_cbc_neon_encrypt(
|
||||
ssh_cipher *ciph, void *vblk, int blklen, aes_neon_fn encrypt)
|
||||
{
|
||||
aes_neon_context *ctx = container_of(ciph, aes_neon_context, ciph);
|
||||
|
||||
for (uint8_t *blk = (uint8_t *)vblk, *finish = blk + blklen;
|
||||
blk < finish; blk += 16) {
|
||||
uint8x16_t plaintext = vld1q_u8(blk);
|
||||
uint8x16_t cipher_input = veorq_u8(plaintext, ctx->iv);
|
||||
uint8x16_t ciphertext = encrypt(cipher_input, ctx->keysched_e);
|
||||
vst1q_u8(blk, ciphertext);
|
||||
ctx->iv = ciphertext;
|
||||
}
|
||||
}
|
||||
|
||||
static FUNC_ISA inline void aes_cbc_neon_decrypt(
|
||||
ssh_cipher *ciph, void *vblk, int blklen, aes_neon_fn decrypt)
|
||||
{
|
||||
aes_neon_context *ctx = container_of(ciph, aes_neon_context, ciph);
|
||||
|
||||
for (uint8_t *blk = (uint8_t *)vblk, *finish = blk + blklen;
|
||||
blk < finish; blk += 16) {
|
||||
uint8x16_t ciphertext = vld1q_u8(blk);
|
||||
uint8x16_t decrypted = decrypt(ciphertext, ctx->keysched_d);
|
||||
uint8x16_t plaintext = veorq_u8(decrypted, ctx->iv);
|
||||
vst1q_u8(blk, plaintext);
|
||||
ctx->iv = ciphertext;
|
||||
}
|
||||
}
|
||||
|
||||
static FUNC_ISA inline void aes_sdctr_neon(
|
||||
ssh_cipher *ciph, void *vblk, int blklen, aes_neon_fn encrypt)
|
||||
{
|
||||
aes_neon_context *ctx = container_of(ciph, aes_neon_context, ciph);
|
||||
|
||||
for (uint8_t *blk = (uint8_t *)vblk, *finish = blk + blklen;
|
||||
blk < finish; blk += 16) {
|
||||
uint8x16_t counter = aes_neon_sdctr_reverse(ctx->iv);
|
||||
uint8x16_t keystream = encrypt(counter, ctx->keysched_e);
|
||||
uint8x16_t input = vld1q_u8(blk);
|
||||
uint8x16_t output = veorq_u8(input, keystream);
|
||||
vst1q_u8(blk, output);
|
||||
ctx->iv = aes_neon_sdctr_increment(ctx->iv);
|
||||
}
|
||||
}
|
||||
|
||||
#define NEON_ENC_DEC(len) \
|
||||
static FUNC_ISA void aes##len##_cbc_hw_encrypt( \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_cbc_neon_encrypt(ciph, vblk, blklen, aes_neon_##len##_e); } \
|
||||
static FUNC_ISA void aes##len##_cbc_hw_decrypt( \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_cbc_neon_decrypt(ciph, vblk, blklen, aes_neon_##len##_d); } \
|
||||
static FUNC_ISA void aes##len##_sdctr_hw( \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) \
|
||||
{ aes_sdctr_neon(ciph, vblk, blklen, aes_neon_##len##_e); } \
|
||||
|
||||
NEON_ENC_DEC(128)
|
||||
NEON_ENC_DEC(192)
|
||||
NEON_ENC_DEC(256)
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Stub functions if we have no hardware-accelerated AES. In this
|
||||
* case, aes_hw_new returns NULL (though it should also never be
|
||||
@@ -1508,24 +1855,24 @@ bool aes_hw_available(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
static ssh2_cipher *aes_hw_new(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *aes_hw_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define STUB_BODY { unreachable("Should never be called"); }
|
||||
|
||||
static void aes_hw_free(ssh2_cipher *ciph) STUB_BODY
|
||||
static void aes_hw_setkey(ssh2_cipher *ciph, const void *key) STUB_BODY
|
||||
static void aes_hw_setiv_cbc(ssh2_cipher *ciph, const void *iv) STUB_BODY
|
||||
static void aes_hw_setiv_sdctr(ssh2_cipher *ciph, const void *iv) STUB_BODY
|
||||
#define STUB_ENC_DEC(len) \
|
||||
static void aes##len##_cbc_hw_encrypt( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) STUB_BODY \
|
||||
static void aes##len##_cbc_hw_decrypt( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) STUB_BODY \
|
||||
static void aes##len##_sdctr_hw( \
|
||||
ssh2_cipher *ciph, void *vblk, int blklen) STUB_BODY
|
||||
static void aes_hw_free(ssh_cipher *ciph) STUB_BODY
|
||||
static void aes_hw_setkey(ssh_cipher *ciph, const void *key) STUB_BODY
|
||||
static void aes_hw_setiv_cbc(ssh_cipher *ciph, const void *iv) STUB_BODY
|
||||
static void aes_hw_setiv_sdctr(ssh_cipher *ciph, const void *iv) STUB_BODY
|
||||
#define STUB_ENC_DEC(len) \
|
||||
static void aes##len##_cbc_hw_encrypt( \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) STUB_BODY \
|
||||
static void aes##len##_cbc_hw_decrypt( \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) STUB_BODY \
|
||||
static void aes##len##_sdctr_hw( \
|
||||
ssh_cipher *ciph, void *vblk, int blklen) STUB_BODY
|
||||
|
||||
STUB_ENC_DEC(128)
|
||||
STUB_ENC_DEC(192)
|
||||
@@ -1533,40 +1880,8 @@ STUB_ENC_DEC(256)
|
||||
|
||||
#endif /* HW_AES */
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Auxiliary routines for use of AES in other contexts than the main
|
||||
* SSH packet protocol.
|
||||
*/
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
|
||||
void aes256_encrypt_pubkey(const void *key, void *blk, int len)
|
||||
{
|
||||
char iv[16];
|
||||
memset(iv, 0, 16);
|
||||
{ // WINSCP
|
||||
ssh2_cipher *cipher = ssh2_cipher_new(&ssh_aes256_cbc);
|
||||
ssh2_cipher_setkey(cipher, key);
|
||||
ssh2_cipher_setiv(cipher, iv);
|
||||
ssh2_cipher_encrypt(cipher, blk, len);
|
||||
ssh2_cipher_free(cipher);
|
||||
} // WINSCP
|
||||
}
|
||||
|
||||
void aes256_decrypt_pubkey(const void *key, void *blk, int len)
|
||||
{
|
||||
char iv[16];
|
||||
memset(iv, 0, 16);
|
||||
{ // WINSCP
|
||||
ssh2_cipher *cipher = ssh2_cipher_new(&ssh_aes256_cbc);
|
||||
ssh2_cipher_setkey(cipher, key);
|
||||
ssh2_cipher_setiv(cipher, iv);
|
||||
ssh2_cipher_decrypt(cipher, blk, len);
|
||||
ssh2_cipher_free(cipher);
|
||||
} // WINSCP
|
||||
}
|
||||
|
||||
|
||||
#ifdef MPEXT
|
||||
|
||||
#include "puttyexp.h"
|
||||
|
||||
18
source/putty/ssharcf.c
vendored
18
source/putty/ssharcf.c
vendored
@@ -9,7 +9,7 @@
|
||||
|
||||
typedef struct {
|
||||
unsigned char i, j, s[256];
|
||||
ssh2_cipher ciph;
|
||||
ssh_cipher ciph;
|
||||
} ArcfourContext;
|
||||
|
||||
static void arcfour_block(void *handle, void *vblk, int len)
|
||||
@@ -62,14 +62,14 @@ static void arcfour_setkey(ArcfourContext *ctx, unsigned char const *key,
|
||||
* to leak data about the key.
|
||||
*/
|
||||
|
||||
static ssh2_cipher *arcfour_new(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *arcfour_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
ArcfourContext *ctx = snew(ArcfourContext);
|
||||
ctx->ciph.vt = alg;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static void arcfour_free(ssh2_cipher *cipher)
|
||||
static void arcfour_free(ssh_cipher *cipher)
|
||||
{
|
||||
ArcfourContext *ctx = container_of(cipher, ArcfourContext, ciph);
|
||||
smemclr(ctx, sizeof(*ctx));
|
||||
@@ -85,25 +85,25 @@ static void arcfour_stir(ArcfourContext *ctx)
|
||||
sfree(junk);
|
||||
}
|
||||
|
||||
static void arcfour_ssh2_setiv(ssh2_cipher *cipher, const void *key)
|
||||
static void arcfour_ssh2_setiv(ssh_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)
|
||||
static void arcfour_ssh2_setkey(ssh_cipher *cipher, const void *key)
|
||||
{
|
||||
ArcfourContext *ctx = container_of(cipher, ArcfourContext, ciph);
|
||||
arcfour_setkey(ctx, key, ctx->ciph.vt->padded_keybytes);
|
||||
arcfour_stir(ctx);
|
||||
}
|
||||
|
||||
static void arcfour_ssh2_block(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void arcfour_ssh2_block(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
ArcfourContext *ctx = container_of(cipher, ArcfourContext, ciph);
|
||||
arcfour_block(ctx, blk, len);
|
||||
}
|
||||
|
||||
const ssh2_cipheralg ssh_arcfour128_ssh2 = {
|
||||
const ssh_cipheralg ssh_arcfour128_ssh2 = {
|
||||
arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey,
|
||||
arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL,
|
||||
"arcfour128",
|
||||
@@ -111,7 +111,7 @@ const ssh2_cipheralg ssh_arcfour128_ssh2 = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const ssh2_cipheralg ssh_arcfour256_ssh2 = {
|
||||
const ssh_cipheralg ssh_arcfour256_ssh2 = {
|
||||
arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey,
|
||||
arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL,
|
||||
"arcfour256",
|
||||
@@ -119,7 +119,7 @@ const ssh2_cipheralg ssh_arcfour256_ssh2 = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const ssh2_cipheralg *const arcfour_list[] = {
|
||||
static const ssh_cipheralg *const arcfour_list[] = {
|
||||
&ssh_arcfour256_ssh2,
|
||||
&ssh_arcfour128_ssh2,
|
||||
};
|
||||
|
||||
152
source/putty/sshauxcrypt.c
vendored
Normal file
152
source/putty/sshauxcrypt.c
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* sshauxcrypt.c: wrapper functions on ciphers for use in other
|
||||
* contexts than the main SSH packet protocol, such as encrypting
|
||||
* private key files and performing XDM-AUTHORIZATION-1.
|
||||
*
|
||||
* These all work through the standard cipher APIs, so they don't need
|
||||
* to live in the same actual source files as the ciphers they wrap,
|
||||
* and I think it keeps things tidier to have them out of the way here
|
||||
* instead.
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
static ssh_cipher *aes256_pubkey_cipher(const void *key)
|
||||
{
|
||||
/*
|
||||
* PuTTY's own .PPK format for SSH-2 private key files is
|
||||
* encrypted with 256-bit AES in CBC mode.
|
||||
*/
|
||||
char iv[16];
|
||||
memset(iv, 0, 16);
|
||||
ssh_cipher *cipher = ssh_cipher_new(&ssh_aes256_cbc);
|
||||
ssh_cipher_setkey(cipher, key);
|
||||
ssh_cipher_setiv(cipher, iv);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
void aes256_encrypt_pubkey(const void *key, void *blk, int len)
|
||||
{
|
||||
ssh_cipher *c = aes256_pubkey_cipher(key);
|
||||
ssh_cipher_encrypt(c, blk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
void aes256_decrypt_pubkey(const void *key, void *blk, int len)
|
||||
{
|
||||
ssh_cipher *c = aes256_pubkey_cipher(key);
|
||||
ssh_cipher_decrypt(c, blk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
static ssh_cipher *des3_pubkey_cipher(const void *vkey)
|
||||
{
|
||||
/*
|
||||
* SSH-1 private key files are encrypted with triple-DES in SSH-1
|
||||
* style (three separate CBC layers), but the same key is used for
|
||||
* the first and third layers.
|
||||
*/
|
||||
ssh_cipher *c = ssh_cipher_new(&ssh_3des_ssh1);
|
||||
uint8_t keys3[24], iv[8];
|
||||
|
||||
memcpy(keys3, vkey, 16);
|
||||
memcpy(keys3 + 16, vkey, 8);
|
||||
ssh_cipher_setkey(c, keys3);
|
||||
smemclr(keys3, sizeof(keys3));
|
||||
|
||||
memset(iv, 0, 8);
|
||||
ssh_cipher_setiv(c, iv);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void des3_decrypt_pubkey(const void *vkey, void *vblk, int len)
|
||||
{
|
||||
ssh_cipher *c = des3_pubkey_cipher(vkey);
|
||||
ssh_cipher_decrypt(c, vblk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
void des3_encrypt_pubkey(const void *vkey, void *vblk, int len)
|
||||
{
|
||||
ssh_cipher *c = des3_pubkey_cipher(vkey);
|
||||
ssh_cipher_encrypt(c, vblk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
static ssh_cipher *des3_pubkey_ossh_cipher(const void *vkey, const void *viv)
|
||||
{
|
||||
/*
|
||||
* OpenSSH PEM private key files are encrypted with triple-DES in
|
||||
* SSH-2 style (one CBC layer), with three distinct keys, and an
|
||||
* IV also generated from the passphrase.
|
||||
*/
|
||||
ssh_cipher *c = ssh_cipher_new(&ssh_3des_ssh2);
|
||||
ssh_cipher_setkey(c, vkey);
|
||||
ssh_cipher_setiv(c, viv);
|
||||
return c;
|
||||
}
|
||||
|
||||
void des3_decrypt_pubkey_ossh(const void *vkey, const void *viv,
|
||||
void *vblk, int len)
|
||||
{
|
||||
ssh_cipher *c = des3_pubkey_ossh_cipher(vkey, viv);
|
||||
ssh_cipher_decrypt(c, vblk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
void des3_encrypt_pubkey_ossh(const void *vkey, const void *viv,
|
||||
void *vblk, int len)
|
||||
{
|
||||
ssh_cipher *c = des3_pubkey_ossh_cipher(vkey, viv);
|
||||
ssh_cipher_encrypt(c, vblk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
static ssh_cipher *des_xdmauth_cipher(const void *vkeydata)
|
||||
{
|
||||
/*
|
||||
* XDM-AUTHORIZATION-1 uses single-DES, but packs the key into 7
|
||||
* bytes, so here we have to repack it manually into the canonical
|
||||
* form where it occupies 8 bytes each with the low bit unused.
|
||||
*/
|
||||
const unsigned char *keydata = (const unsigned char *)vkeydata;
|
||||
unsigned char key[8];
|
||||
int i, nbits, j;
|
||||
unsigned int bits;
|
||||
|
||||
bits = 0;
|
||||
nbits = 0;
|
||||
j = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (nbits < 7) {
|
||||
bits = (bits << 8) | keydata[j];
|
||||
nbits += 8;
|
||||
j++;
|
||||
}
|
||||
key[i] = (bits >> (nbits - 7)) << 1;
|
||||
bits &= ~(0x7F << (nbits - 7));
|
||||
nbits -= 7;
|
||||
}
|
||||
|
||||
ssh_cipher *c = ssh_cipher_new(&ssh_des);
|
||||
ssh_cipher_setkey(c, key);
|
||||
smemclr(key, sizeof(key));
|
||||
ssh_cipher_setiv(c, key);
|
||||
return c;
|
||||
}
|
||||
|
||||
void des_encrypt_xdmauth(const void *keydata, void *blk, int len)
|
||||
{
|
||||
ssh_cipher *c = des_xdmauth_cipher(keydata);
|
||||
ssh_cipher_encrypt(c, blk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
void des_decrypt_xdmauth(const void *keydata, void *blk, int len)
|
||||
{
|
||||
ssh_cipher *c = des_xdmauth_cipher(keydata);
|
||||
ssh_cipher_decrypt(c, blk, len);
|
||||
ssh_cipher_free(c);
|
||||
}
|
||||
|
||||
135
source/putty/sshblowf.c
vendored
135
source/putty/sshblowf.c
vendored
@@ -566,138 +566,115 @@ void blowfish_free_context(BlowfishContext *ctx)
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void blowfish_iv(BlowfishContext *ctx, const void *viv)
|
||||
static void blowfish_iv_be(BlowfishContext *ctx, const void *viv)
|
||||
{
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
ctx->iv0 = GET_32BIT_MSB_FIRST(iv);
|
||||
ctx->iv1 = GET_32BIT_MSB_FIRST(iv + 4);
|
||||
}
|
||||
|
||||
struct blowfish_ssh1_ctx {
|
||||
/* In SSH-1, need one key for each direction */
|
||||
BlowfishContext contexts[2];
|
||||
ssh1_cipher ciph;
|
||||
};
|
||||
|
||||
static ssh1_cipher *blowfish_ssh1_new(void)
|
||||
static void blowfish_iv_le(BlowfishContext *ctx, const void *viv)
|
||||
{
|
||||
struct blowfish_ssh1_ctx *ctx = snew(struct blowfish_ssh1_ctx);
|
||||
ctx->ciph.vt = &ssh1_blowfish;
|
||||
return &ctx->ciph;
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
ctx->iv0 = GET_32BIT_LSB_FIRST(iv);
|
||||
ctx->iv1 = GET_32BIT_LSB_FIRST(iv + 4);
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_free(ssh1_cipher *cipher)
|
||||
{
|
||||
struct blowfish_ssh1_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh1_ctx, ciph);
|
||||
smemclr(ctx, sizeof(*ctx));
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_sesskey(ssh1_cipher *cipher, const void *key)
|
||||
{
|
||||
struct blowfish_ssh1_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh1_ctx, ciph);
|
||||
blowfish_setkey(&ctx->contexts[0], key, SSH1_SESSION_KEY_LENGTH);
|
||||
ctx->contexts[0].iv0 = ctx->contexts[0].iv1 = 0;
|
||||
ctx->contexts[1] = ctx->contexts[0]; /* structure copy */
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct blowfish_ssh1_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh1_ctx, ciph);
|
||||
blowfish_lsb_encrypt_cbc(blk, len, ctx->contexts);
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct blowfish_ssh1_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh1_ctx, ciph);
|
||||
blowfish_lsb_decrypt_cbc(blk, len, ctx->contexts+1);
|
||||
}
|
||||
|
||||
struct blowfish_ssh2_ctx {
|
||||
struct blowfish_ctx {
|
||||
BlowfishContext context;
|
||||
ssh2_cipher ciph;
|
||||
ssh_cipher ciph;
|
||||
};
|
||||
|
||||
static ssh2_cipher *blowfish_ssh2_new(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *blowfish_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
struct blowfish_ssh2_ctx *ctx = snew(struct blowfish_ssh2_ctx);
|
||||
struct blowfish_ctx *ctx = snew(struct blowfish_ctx);
|
||||
ctx->ciph.vt = alg;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_free(ssh2_cipher *cipher)
|
||||
static void blowfish_free(ssh_cipher *cipher)
|
||||
{
|
||||
struct blowfish_ssh2_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh2_ctx, ciph);
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
smemclr(ctx, sizeof(*ctx));
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_setiv(ssh2_cipher *cipher, const void *iv)
|
||||
static void blowfish_ssh_setkey(ssh_cipher *cipher, const void *key)
|
||||
{
|
||||
struct blowfish_ssh2_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh2_ctx, ciph);
|
||||
blowfish_iv(&ctx->context, iv);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_setkey(ssh2_cipher *cipher, const void *key)
|
||||
{
|
||||
struct blowfish_ssh2_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh2_ctx, ciph);
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_setkey(&ctx->context, key, ctx->ciph.vt->padded_keybytes);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void blowfish_ssh1_setiv(ssh_cipher *cipher, const void *iv)
|
||||
{
|
||||
struct blowfish_ssh2_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh2_ctx, ciph);
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_iv_le(&ctx->context, iv);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_setiv(ssh_cipher *cipher, const void *iv)
|
||||
{
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_iv_be(&ctx->context, iv);
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_encrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_lsb_encrypt_cbc(blk, len, &ctx->context);
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_decrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_lsb_decrypt_cbc(blk, len, &ctx->context);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_encrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_msb_encrypt_cbc(blk, len, &ctx->context);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void blowfish_ssh2_decrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct blowfish_ssh2_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh2_ctx, ciph);
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_msb_decrypt_cbc(blk, len, &ctx->context);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_sdctr(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void blowfish_ssh2_sdctr(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct blowfish_ssh2_ctx *ctx =
|
||||
container_of(cipher, struct blowfish_ssh2_ctx, ciph);
|
||||
struct blowfish_ctx *ctx = container_of(cipher, struct blowfish_ctx, ciph);
|
||||
blowfish_msb_sdctr(blk, len, &ctx->context);
|
||||
}
|
||||
|
||||
const ssh1_cipheralg ssh1_blowfish = {
|
||||
blowfish_ssh1_new, blowfish_ssh1_free,
|
||||
blowfish_ssh1_sesskey,
|
||||
const ssh_cipheralg ssh_blowfish_ssh1 = {
|
||||
blowfish_new, blowfish_free,
|
||||
blowfish_ssh1_setiv, blowfish_ssh_setkey,
|
||||
blowfish_ssh1_encrypt_blk, blowfish_ssh1_decrypt_blk,
|
||||
8, "Blowfish-128 CBC"
|
||||
NULL, NULL, NULL,
|
||||
8, 128, SSH1_SESSION_KEY_LENGTH, SSH_CIPHER_IS_CBC, "Blowfish-256 CBC",
|
||||
NULL
|
||||
};
|
||||
|
||||
const ssh2_cipheralg ssh_blowfish_ssh2 = {
|
||||
blowfish_ssh2_new, blowfish_ssh2_free,
|
||||
blowfish_ssh2_setiv, blowfish_ssh2_setkey,
|
||||
const ssh_cipheralg ssh_blowfish_ssh2 = {
|
||||
blowfish_new, blowfish_free,
|
||||
blowfish_ssh2_setiv, blowfish_ssh_setkey,
|
||||
blowfish_ssh2_encrypt_blk, blowfish_ssh2_decrypt_blk, NULL, NULL,
|
||||
"blowfish-cbc",
|
||||
8, 128, 16, SSH_CIPHER_IS_CBC, "Blowfish-128 CBC",
|
||||
NULL
|
||||
};
|
||||
|
||||
const ssh2_cipheralg ssh_blowfish_ssh2_ctr = {
|
||||
blowfish_ssh2_new, blowfish_ssh2_free,
|
||||
blowfish_ssh2_setiv, blowfish_ssh2_setkey,
|
||||
const ssh_cipheralg ssh_blowfish_ssh2_ctr = {
|
||||
blowfish_new, blowfish_free,
|
||||
blowfish_ssh2_setiv, blowfish_ssh_setkey,
|
||||
blowfish_ssh2_sdctr, blowfish_ssh2_sdctr, NULL, NULL,
|
||||
"blowfish-ctr",
|
||||
8, 256, 32, 0, "Blowfish-256 SDCTR",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const ssh2_cipheralg *const blowfish_list[] = {
|
||||
static const ssh_cipheralg *const blowfish_list[] = {
|
||||
&ssh_blowfish_ssh2_ctr,
|
||||
&ssh_blowfish_ssh2
|
||||
};
|
||||
|
||||
6
source/putty/sshbpp.h
vendored
6
source/putty/sshbpp.h
vendored
@@ -54,7 +54,7 @@ void ssh_bpp_free(BinaryPacketProtocol *bpp);
|
||||
|
||||
BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx);
|
||||
void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
|
||||
const ssh1_cipheralg *cipher,
|
||||
const ssh_cipheralg *cipher,
|
||||
const void *session_key);
|
||||
/* This is only called from outside the BPP in server mode; in client
|
||||
* mode the BPP detects compression start time automatically by
|
||||
@@ -104,12 +104,12 @@ BinaryPacketProtocol *ssh2_bpp_new(
|
||||
LogContext *logctx, struct DataTransferStats *stats, bool is_server);
|
||||
void ssh2_bpp_new_outgoing_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
|
||||
const ssh_compression_alg *compression, bool delayed_compression);
|
||||
void ssh2_bpp_new_incoming_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
|
||||
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
|
||||
const ssh_compression_alg *compression, bool delayed_compression);
|
||||
|
||||
|
||||
26
source/putty/sshccp.c
vendored
26
source/putty/sshccp.c
vendored
@@ -20,7 +20,7 @@
|
||||
* This has an intricate link between the cipher and the MAC. The
|
||||
* keying of both is done in by the cipher and setting of the IV is
|
||||
* done by the MAC. One cannot operate without the other. The
|
||||
* configuration of the ssh2_cipheralg structure ensures that the MAC is
|
||||
* configuration of the ssh_cipheralg structure ensures that the MAC is
|
||||
* set (and others ignored) if this cipher is chosen.
|
||||
*
|
||||
* This cipher also encrypts the length using a different
|
||||
@@ -867,12 +867,12 @@ struct ccp_context {
|
||||
struct poly1305 mac;
|
||||
|
||||
BinarySink_IMPLEMENTATION;
|
||||
ssh2_cipher ciph;
|
||||
ssh_cipher ciph;
|
||||
ssh2_mac mac_if;
|
||||
};
|
||||
|
||||
static ssh2_mac *poly_ssh2_new(
|
||||
const ssh2_macalg *alg, ssh2_cipher *cipher)
|
||||
const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||
{
|
||||
struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
|
||||
ctx->mac_if.vt = alg;
|
||||
@@ -946,7 +946,7 @@ const ssh2_macalg ssh2_poly1305 = {
|
||||
16, 0, "Poly1305"
|
||||
};
|
||||
|
||||
static ssh2_cipher *ccp_new(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *ccp_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
struct ccp_context *ctx = snew(struct ccp_context);
|
||||
BinarySink_INIT(ctx, poly_BinarySink_write);
|
||||
@@ -955,7 +955,7 @@ static ssh2_cipher *ccp_new(const ssh2_cipheralg *alg)
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static void ccp_free(ssh2_cipher *cipher)
|
||||
static void ccp_free(ssh_cipher *cipher)
|
||||
{
|
||||
struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
|
||||
smemclr(&ctx->a_cipher, sizeof(ctx->a_cipher));
|
||||
@@ -964,14 +964,14 @@ static void ccp_free(ssh2_cipher *cipher)
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void ccp_iv(ssh2_cipher *cipher, const void *iv)
|
||||
static void ccp_iv(ssh_cipher *cipher, const void *iv)
|
||||
{
|
||||
/* struct ccp_context *ctx =
|
||||
container_of(cipher, struct ccp_context, ciph); */
|
||||
/* IV is set based on the sequence number */
|
||||
}
|
||||
|
||||
static void ccp_key(ssh2_cipher *cipher, const void *vkey)
|
||||
static void ccp_key(ssh_cipher *cipher, const void *vkey)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
|
||||
@@ -981,13 +981,13 @@ static void ccp_key(ssh2_cipher *cipher, const void *vkey)
|
||||
chacha20_key(&ctx->b_cipher, key);
|
||||
}
|
||||
|
||||
static void ccp_encrypt(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void ccp_encrypt(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
|
||||
chacha20_encrypt(&ctx->b_cipher, blk, len);
|
||||
}
|
||||
|
||||
static void ccp_decrypt(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void ccp_decrypt(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
|
||||
chacha20_decrypt(&ctx->b_cipher, blk, len);
|
||||
@@ -1010,7 +1010,7 @@ static void ccp_length_op(struct ccp_context *ctx, void *blk, int len,
|
||||
smemclr(iv, sizeof(iv));
|
||||
}
|
||||
|
||||
static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len,
|
||||
static void ccp_encrypt_length(ssh_cipher *cipher, void *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
|
||||
@@ -1018,7 +1018,7 @@ static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len,
|
||||
chacha20_encrypt(&ctx->a_cipher, blk, len);
|
||||
}
|
||||
|
||||
static void ccp_decrypt_length(ssh2_cipher *cipher, void *blk, int len,
|
||||
static void ccp_decrypt_length(ssh_cipher *cipher, void *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
|
||||
@@ -1026,7 +1026,7 @@ static void ccp_decrypt_length(ssh2_cipher *cipher, void *blk, int len,
|
||||
chacha20_decrypt(&ctx->a_cipher, blk, len);
|
||||
}
|
||||
|
||||
const ssh2_cipheralg ssh2_chacha20_poly1305 = {
|
||||
const ssh_cipheralg ssh2_chacha20_poly1305 = {
|
||||
|
||||
ccp_new,
|
||||
ccp_free,
|
||||
@@ -1043,7 +1043,7 @@ const ssh2_cipheralg ssh2_chacha20_poly1305 = {
|
||||
&ssh2_poly1305
|
||||
};
|
||||
|
||||
static const ssh2_cipheralg *const ccp_list[] = {
|
||||
static const ssh_cipheralg *const ccp_list[] = {
|
||||
&ssh2_chacha20_poly1305
|
||||
};
|
||||
|
||||
|
||||
283
source/putty/sshcrc.c
vendored
283
source/putty/sshcrc.c
vendored
@@ -1,229 +1,108 @@
|
||||
/*
|
||||
* CRC32 implementation.
|
||||
* CRC32 implementation, as used in SSH-1.
|
||||
*
|
||||
* The basic concept of a CRC is that you treat your bit-string
|
||||
* abcdefg... as a ludicrously long polynomial M=a+bx+cx^2+dx^3+...
|
||||
* over Z[2]. You then take a modulus polynomial P, and compute the
|
||||
* remainder of M on division by P. Thus, an erroneous message N
|
||||
* will only have the same CRC if the difference E = M-N is an
|
||||
* exact multiple of P. (Note that as we are working over Z[2], M-N
|
||||
* = N-M = M+N; but that's not very important.)
|
||||
* This particular form of the CRC uses the polynomial
|
||||
* P(x) = x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+1
|
||||
* and represents polynomials in bit-reversed form, so that the x^0
|
||||
* coefficient (constant term) appears in the bit with place value
|
||||
* 2^31, and the x^31 coefficient in the bit with place value 2^0. In
|
||||
* this representation, (x^32 mod P) = 0xEDB88320, so multiplying the
|
||||
* current state by x is done by shifting right by one bit, and XORing
|
||||
* that constant into the result if the bit shifted out was 1.
|
||||
*
|
||||
* What makes the CRC good is choosing P to have good properties:
|
||||
* There's a bewildering array of subtly different variants of CRC out
|
||||
* there, using different polynomials, both bit orders, and varying
|
||||
* the start and end conditions. There are catalogue websites such as
|
||||
* http://reveng.sourceforge.net/crc-catalogue/ , which generally seem
|
||||
* to have the convention of indexing CRCs by their 'check value',
|
||||
* defined as whatever you get if you hash the 9-byte test string
|
||||
* "123456789".
|
||||
*
|
||||
* - If its first and last terms are both nonzero then it cannot
|
||||
* be a factor of any single term x^i. Therefore if M and N
|
||||
* differ by exactly one bit their CRCs will guaranteeably
|
||||
* be distinct.
|
||||
* The crc32_rfc1662() function below, which starts off the CRC state
|
||||
* at 0xFFFFFFFF and complements it after feeding all the data, gives
|
||||
* the check value 0xCBF43926, and matches the hash function that the
|
||||
* above catalogue refers to as "CRC-32/ISO-HDLC"; among other things,
|
||||
* it's also the "FCS-32" checksum described in RFC 1662 section C.3
|
||||
* (hence the name I've given it here).
|
||||
*
|
||||
* - If it has a prime (irreducible) factor with three terms then
|
||||
* it cannot divide a polynomial of the form x^i(1+x^j).
|
||||
* Therefore if M and N differ by exactly _two_ bits they will
|
||||
* have different CRCs.
|
||||
*
|
||||
* - If it has a factor (x+1) then it cannot divide a polynomial
|
||||
* with an odd number of terms. Therefore if M and N differ by
|
||||
* _any odd_ number of bits they will have different CRCs.
|
||||
*
|
||||
* - If the error term E is of the form x^i*B(x) where B(x) has
|
||||
* order less than P (i.e. a short _burst_ of errors) then P
|
||||
* cannot divide E (since no polynomial can divide a shorter
|
||||
* one), so any such error burst will be spotted.
|
||||
*
|
||||
* The CRC32 standard polynomial is
|
||||
* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
|
||||
*
|
||||
* In fact, we don't compute M mod P; we compute M*x^32 mod P.
|
||||
*
|
||||
* The concrete implementation of the CRC is this: we maintain at
|
||||
* all times a 32-bit word which is the current remainder of the
|
||||
* polynomial mod P. Whenever we receive an extra bit, we multiply
|
||||
* the existing remainder by x, add (XOR) the x^32 term thus
|
||||
* generated to the new x^32 term caused by the incoming bit, and
|
||||
* remove the resulting combined x^32 term if present by replacing
|
||||
* it with (P-x^32).
|
||||
*
|
||||
* Bit 0 of the word is the x^31 term and bit 31 is the x^0 term.
|
||||
* Thus, multiplying by x means shifting right. So the actual
|
||||
* algorithm goes like this:
|
||||
*
|
||||
* x32term = (crcword & 1) ^ newbit;
|
||||
* crcword = (crcword >> 1) ^ (x32term * 0xEDB88320);
|
||||
*
|
||||
* In practice, we pre-compute what will happen to crcword on any
|
||||
* given sequence of eight incoming bits, and store that in a table
|
||||
* which we then use at run-time to do the job:
|
||||
*
|
||||
* outgoingplusnew = (crcword & 0xFF) ^ newbyte;
|
||||
* crcword = (crcword >> 8) ^ table[outgoingplusnew];
|
||||
*
|
||||
* where table[outgoingplusnew] is computed by setting crcword=0
|
||||
* and then iterating the first code fragment eight times (taking
|
||||
* the incoming byte low bit first).
|
||||
*
|
||||
* Note that all shifts are rightward and thus no assumption is
|
||||
* made about exact word length! (Although word length must be at
|
||||
* _least_ 32 bits, but ANSI C guarantees this for `unsigned long'
|
||||
* anyway.)
|
||||
* The crc32_ssh1() function implements the variant form used by
|
||||
* SSH-1, which uses the same update function, but starts the state at
|
||||
* zero and doesn't complement it at the end of the computation. The
|
||||
* check value for that version is 0x2DFD2D88, which that CRC
|
||||
* catalogue doesn't list at all.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Multi-function module. Can be compiled three ways.
|
||||
/*
|
||||
* Multiply a CRC value by x^4. This implementation strategy avoids
|
||||
* using a lookup table (which would be a side-channel hazard, since
|
||||
* SSH-1 applies this CRC to decrypted session data).
|
||||
*
|
||||
* - Compile with no special #defines. Will generate a table
|
||||
* that's already initialised at compile time, and one function
|
||||
* crc32_compute(buf,len) that uses it. Normal usage.
|
||||
* The basic idea is that you'd like to "multiply" the shifted-out 4
|
||||
* bits by the CRC polynomial value 0xEDB88320, or rather by that
|
||||
* value shifted right 3 bits (since you want the _last_ bit shifted
|
||||
* out, i.e. the one originally at the 2^3 position, to generate
|
||||
* 0xEDB88320 itself). But the scare-quoted "multiply" would have to
|
||||
* be a multiplication of polynomials over GF(2), which differs from
|
||||
* integer multiplication in that you don't have any carries. In other
|
||||
* words, you make a copy of one input shifted left by the index of
|
||||
* each set bit in the other, so that adding them all together would
|
||||
* give you the ordinary integer product, and then you XOR them
|
||||
* together instead.
|
||||
*
|
||||
* - Compile with INITFUNC defined. Will generate an uninitialised
|
||||
* array as the table, and as well as crc32_compute(buf,len) it
|
||||
* will also generate void crc32_init(void) which sets up the
|
||||
* table at run time. Useful if binary size is important.
|
||||
*
|
||||
* - Compile with GENPROGRAM defined. Will create a standalone
|
||||
* program that does the initialisation and outputs the table as
|
||||
* C code.
|
||||
* With a 4-bit multiplier, the two kinds of multiplication coincide
|
||||
* provided the multiplicand has no two set bits at positions
|
||||
* differing by less than 4, because then no two copies of the
|
||||
* multiplier can overlap to generate a carry. So I break up the
|
||||
* intended multiplicand K = 0xEDB88320 >> 3 into three sub-constants
|
||||
* a,b,c with that property, such that a^b^c = K. Then I can multiply
|
||||
* m by each of them separately, and XOR together the results.
|
||||
*/
|
||||
|
||||
#define POLY (0xEDB88320L)
|
||||
|
||||
#ifdef GENPROGRAM
|
||||
#define INITFUNC /* the gen program needs the init func :-) */
|
||||
#endif
|
||||
|
||||
#ifdef INITFUNC
|
||||
static inline uint32_t crc32_shift_4(uint32_t v)
|
||||
{
|
||||
const uint32_t a = 0x11111044, b = 0x08840020, c = 0x04220000;
|
||||
uint32_t m = v & 0xF;
|
||||
return (v >> 4) ^ (a*m) ^ (b*m) ^ (c*m);
|
||||
}
|
||||
|
||||
/*
|
||||
* This variant of the code generates the table at run-time from an
|
||||
* init function.
|
||||
* The 8-bit shift you need every time you absorb an input byte,
|
||||
* implemented simply by iterating the 4-bit shift twice.
|
||||
*/
|
||||
static unsigned long crc32_table[256];
|
||||
|
||||
void crc32_init(void)
|
||||
static inline uint32_t crc32_shift_8(uint32_t v)
|
||||
{
|
||||
unsigned long crcword;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
unsigned long newbyte, x32term;
|
||||
int j;
|
||||
crcword = 0;
|
||||
newbyte = i;
|
||||
for (j = 0; j < 8; j++) {
|
||||
x32term = (crcword ^ newbyte) & 1;
|
||||
crcword = (crcword >> 1) ^ (x32term * POLY);
|
||||
newbyte >>= 1;
|
||||
}
|
||||
crc32_table[i] = crcword;
|
||||
}
|
||||
return crc32_shift_4(crc32_shift_4(v));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* This variant of the code has the data already prepared.
|
||||
* Update an existing hash value with extra bytes of data.
|
||||
*/
|
||||
static const unsigned long crc32_table[256] = {
|
||||
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
|
||||
0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
|
||||
0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
|
||||
0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
|
||||
0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
|
||||
0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
|
||||
0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
|
||||
0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
|
||||
0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
|
||||
0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
|
||||
0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
|
||||
0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
|
||||
0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
|
||||
0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
|
||||
0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
|
||||
0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
|
||||
0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
|
||||
0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
|
||||
0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
|
||||
0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
|
||||
0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
|
||||
0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
|
||||
0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
|
||||
0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
|
||||
0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
|
||||
0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
|
||||
0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
|
||||
0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
|
||||
0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
|
||||
0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
|
||||
0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
|
||||
0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
|
||||
0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
|
||||
0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
|
||||
0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
|
||||
0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
|
||||
0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
|
||||
0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
|
||||
0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
|
||||
0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
|
||||
0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
|
||||
0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
|
||||
0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
|
||||
0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
|
||||
0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
|
||||
0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
|
||||
0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
|
||||
0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
|
||||
0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
|
||||
0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
|
||||
0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
|
||||
0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
|
||||
0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
|
||||
0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
|
||||
0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
|
||||
0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
|
||||
0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
|
||||
0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
|
||||
0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
|
||||
0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
|
||||
0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
|
||||
0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
|
||||
0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
|
||||
0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef GENPROGRAM
|
||||
int main(void)
|
||||
uint32_t crc32_update(uint32_t crc, ptrlen data)
|
||||
{
|
||||
int i;
|
||||
|
||||
crc32_init();
|
||||
for (i = 0; i < 256; i++) {
|
||||
printf("%s0x%08lXL%s",
|
||||
(i % 4 == 0 ? " " : " "),
|
||||
crc32_table[i],
|
||||
(i % 4 == 3 ? (i == 255 ? "\n" : ",\n") : ","));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long crc32_update(unsigned long crcword, const void *buf, size_t len)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *) buf;
|
||||
while (len--) {
|
||||
unsigned long newbyte = *p++;
|
||||
newbyte ^= crcword & 0xFFL;
|
||||
crcword = (crcword >> 8) ^ crc32_table[newbyte];
|
||||
}
|
||||
return crcword;
|
||||
const uint8_t *p = (const uint8_t *)data.ptr;
|
||||
for (size_t len = data.len; len-- > 0 ;)
|
||||
crc = crc32_shift_8(crc ^ *p++);
|
||||
return crc;
|
||||
}
|
||||
|
||||
unsigned long crc32_compute(const void *buf, size_t len)
|
||||
/*
|
||||
* The SSH-1 variant of CRC-32.
|
||||
*/
|
||||
uint32_t crc32_ssh1(ptrlen data)
|
||||
{
|
||||
return crc32_update(0L, buf, len);
|
||||
return crc32_update(0, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* The official version of CRC-32. Nothing in PuTTY proper uses this,
|
||||
* but it's useful to expose it to testcrypt so that we can implement
|
||||
* standard test vectors.
|
||||
*/
|
||||
uint32_t crc32_rfc1662(ptrlen data)
|
||||
{
|
||||
return crc32_update(0xFFFFFFFF, data) ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
18
source/putty/sshcrcda.c
vendored
18
source/putty/sshcrcda.c
vendored
@@ -75,16 +75,17 @@ void crcda_free_context(struct crcda_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static void crc_update(uint32_t *a, void *b)
|
||||
static void crc_update(uint32_t *a, const void *b)
|
||||
{
|
||||
*a = crc32_update(*a, b, 4);
|
||||
*a = crc32_update(*a, make_ptrlen(b, 4));
|
||||
}
|
||||
|
||||
/* detect if a block is used in a particular pattern */
|
||||
static bool check_crc(uint8_t *S, uint8_t *buf, uint32_t len, uint8_t *IV)
|
||||
static bool check_crc(const uint8_t *S, const uint8_t *buf,
|
||||
uint32_t len, const uint8_t *IV)
|
||||
{
|
||||
uint32_t crc;
|
||||
uint8_t *c;
|
||||
const uint8_t *c;
|
||||
|
||||
crc = 0;
|
||||
if (IV && !CMP(S, IV)) {
|
||||
@@ -104,13 +105,14 @@ static bool check_crc(uint8_t *S, uint8_t *buf, uint32_t len, uint8_t *IV)
|
||||
}
|
||||
|
||||
/* Detect a crc32 compensation attack on a packet */
|
||||
bool detect_attack(
|
||||
struct crcda_ctx *ctx, uint8_t *buf, uint32_t len, uint8_t *IV)
|
||||
bool detect_attack(struct crcda_ctx *ctx,
|
||||
const unsigned char *buf, uint32_t len,
|
||||
const unsigned char *IV)
|
||||
{
|
||||
register uint32_t i, j;
|
||||
uint32_t l;
|
||||
register uint8_t *c;
|
||||
uint8_t *d;
|
||||
register const uint8_t *c;
|
||||
const uint8_t *d;
|
||||
|
||||
assert(!(len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0));
|
||||
|
||||
267
source/putty/sshdes.c
vendored
267
source/putty/sshdes.c
vendored
@@ -774,32 +774,18 @@ static void des_key(DESContext *context, const void *vkey)
|
||||
}
|
||||
|
||||
struct des3_ssh1_ctx {
|
||||
/* 3 cipher context for each direction */
|
||||
DESContext contexts[6];
|
||||
ssh1_cipher ciph;
|
||||
DESContext contexts[3];
|
||||
ssh_cipher ciph;
|
||||
};
|
||||
|
||||
struct des_ssh1_ctx {
|
||||
/* 1 cipher context for each direction */
|
||||
DESContext contexts[2];
|
||||
ssh1_cipher ciph;
|
||||
};
|
||||
|
||||
static ssh1_cipher *des3_ssh1_new(void)
|
||||
static ssh_cipher *des3_ssh1_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
struct des3_ssh1_ctx *ctx = snew(struct des3_ssh1_ctx);
|
||||
ctx->ciph.vt = &ssh1_3des;
|
||||
ctx->ciph.vt = alg;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static ssh1_cipher *des_ssh1_new(void)
|
||||
{
|
||||
struct des_ssh1_ctx *ctx = snew(struct des_ssh1_ctx);
|
||||
ctx->ciph.vt = &ssh1_des;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static void des3_ssh1_free(ssh1_cipher *cipher)
|
||||
static void des3_ssh1_free(ssh_cipher *cipher)
|
||||
{
|
||||
struct des3_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh1_ctx, ciph);
|
||||
@@ -807,83 +793,65 @@ static void des3_ssh1_free(ssh1_cipher *cipher)
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void des_ssh1_free(ssh1_cipher *cipher)
|
||||
{
|
||||
struct des_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh1_ctx, ciph);
|
||||
smemclr(ctx, sizeof(*ctx));
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void des3_ssh1_sesskey(ssh1_cipher *cipher, const void *key)
|
||||
static void des3_ssh1_setkey(ssh_cipher *cipher, const void *key)
|
||||
{
|
||||
struct des3_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh1_ctx, ciph);
|
||||
des3_key(ctx->contexts, key);
|
||||
des3_key(ctx->contexts+3, key);
|
||||
}
|
||||
|
||||
static void des3_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len)
|
||||
static void des3_ssh1_setiv(ssh_cipher *cipher, const void *iv)
|
||||
{
|
||||
struct des3_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh1_ctx, ciph);
|
||||
/* SSH-1's idea of triple-DES CBC is three actual instances of the
|
||||
* whole of DES-CBC, i.e. three separate CBC layers each with
|
||||
* their own IV. So in principle we ought to be able to accept 24
|
||||
* bytes of IV here. However, SSH-1 initialises all IVs to zero
|
||||
* anyway, so we fudge it by just setting them all the same. */
|
||||
for (int i = 0; i < 3; i++)
|
||||
des_iv(&ctx->contexts[i], iv);
|
||||
}
|
||||
|
||||
static void des3_ssh1_encrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des3_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh1_ctx, ciph);
|
||||
des_3cbc_encrypt(blk, len, ctx->contexts);
|
||||
}
|
||||
|
||||
static void des3_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len)
|
||||
static void des3_ssh1_decrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des3_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh1_ctx, ciph);
|
||||
des_3cbc_decrypt(blk, len, ctx->contexts+3);
|
||||
}
|
||||
|
||||
static void des_ssh1_sesskey(ssh1_cipher *cipher, const void *key)
|
||||
{
|
||||
struct des_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh1_ctx, ciph);
|
||||
des_key(ctx->contexts, key);
|
||||
des_key(ctx->contexts+1, key);
|
||||
}
|
||||
|
||||
static void des_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh1_ctx, ciph);
|
||||
des_cbc_encrypt(blk, len, ctx->contexts);
|
||||
}
|
||||
|
||||
static void des_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des_ssh1_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh1_ctx, ciph);
|
||||
des_cbc_decrypt(blk, len, ctx->contexts+1);
|
||||
des_3cbc_decrypt(blk, len, ctx->contexts);
|
||||
}
|
||||
|
||||
struct des3_ssh2_ctx {
|
||||
DESContext contexts[3];
|
||||
ssh2_cipher ciph;
|
||||
ssh_cipher ciph;
|
||||
};
|
||||
|
||||
struct des_ssh2_ctx {
|
||||
struct des_ctx {
|
||||
DESContext context;
|
||||
ssh2_cipher ciph;
|
||||
ssh_cipher ciph;
|
||||
};
|
||||
|
||||
static ssh2_cipher *des3_ssh2_new(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *des3_ssh2_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
struct des3_ssh2_ctx *ctx = snew(struct des3_ssh2_ctx);
|
||||
ctx->ciph.vt = alg;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static ssh2_cipher *des_ssh2_new(const ssh2_cipheralg *alg)
|
||||
static ssh_cipher *des_new(const ssh_cipheralg *alg)
|
||||
{
|
||||
struct des_ssh2_ctx *ctx = snew(struct des_ssh2_ctx);
|
||||
struct des_ctx *ctx = snew(struct des_ctx);
|
||||
ctx->ciph.vt = alg;
|
||||
return &ctx->ciph;
|
||||
}
|
||||
|
||||
static void des3_ssh2_free(ssh2_cipher *cipher)
|
||||
static void des3_ssh2_free(ssh_cipher *cipher)
|
||||
{
|
||||
struct des3_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh2_ctx, ciph);
|
||||
@@ -891,15 +859,14 @@ static void des3_ssh2_free(ssh2_cipher *cipher)
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void des_ssh2_free(ssh2_cipher *cipher)
|
||||
static void des_free(ssh_cipher *cipher)
|
||||
{
|
||||
struct des_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh2_ctx, ciph);
|
||||
struct des_ctx *ctx = container_of(cipher, struct des_ctx, ciph);
|
||||
smemclr(ctx, sizeof(*ctx));
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void des3_ssh2_setiv(ssh2_cipher *cipher, const void *iv)
|
||||
static void des3_ssh2_setiv(ssh_cipher *cipher, const void *iv)
|
||||
{
|
||||
struct des3_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh2_ctx, ciph);
|
||||
@@ -908,169 +875,59 @@ static void des3_ssh2_setiv(ssh2_cipher *cipher, const void *iv)
|
||||
* CBC, so there's only one IV required, not three */
|
||||
}
|
||||
|
||||
static void des3_ssh2_setkey(ssh2_cipher *cipher, const void *key)
|
||||
static void des3_ssh2_setkey(ssh_cipher *cipher, const void *key)
|
||||
{
|
||||
struct des3_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh2_ctx, ciph);
|
||||
des3_key(ctx->contexts, key);
|
||||
}
|
||||
|
||||
static void des_ssh2_setiv(ssh2_cipher *cipher, const void *iv)
|
||||
static void des_setiv(ssh_cipher *cipher, const void *iv)
|
||||
{
|
||||
struct des_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh2_ctx, ciph);
|
||||
struct des_ctx *ctx = container_of(cipher, struct des_ctx, ciph);
|
||||
des_iv(&ctx->context, iv);
|
||||
}
|
||||
|
||||
static void des_ssh2_setkey(ssh2_cipher *cipher, const void *key)
|
||||
static void des_setkey(ssh_cipher *cipher, const void *key)
|
||||
{
|
||||
struct des_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh2_ctx, ciph);
|
||||
struct des_ctx *ctx = container_of(cipher, struct des_ctx, ciph);
|
||||
des_key(&ctx->context, key);
|
||||
}
|
||||
|
||||
static void des3_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void des3_ssh2_encrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des3_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh2_ctx, ciph);
|
||||
des_cbc3_encrypt(blk, len, ctx->contexts);
|
||||
}
|
||||
|
||||
static void des3_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void des3_ssh2_decrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des3_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh2_ctx, ciph);
|
||||
des_cbc3_decrypt(blk, len, ctx->contexts);
|
||||
}
|
||||
|
||||
static void des3_ssh2_sdctr(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void des3_ssh2_sdctr(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des3_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des3_ssh2_ctx, ciph);
|
||||
des_sdctr3(blk, len, ctx->contexts);
|
||||
}
|
||||
|
||||
static void des_ssh2_encrypt_blk(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void des_encrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh2_ctx, ciph);
|
||||
struct des_ctx *ctx = container_of(cipher, struct des_ctx, ciph);
|
||||
des_cbc_encrypt(blk, len, &ctx->context);
|
||||
}
|
||||
|
||||
static void des_ssh2_decrypt_blk(ssh2_cipher *cipher, void *blk, int len)
|
||||
static void des_decrypt_blk(ssh_cipher *cipher, void *blk, int len)
|
||||
{
|
||||
struct des_ssh2_ctx *ctx = container_of(
|
||||
cipher, struct des_ssh2_ctx, ciph);
|
||||
struct des_ctx *ctx = container_of(cipher, struct des_ctx, ciph);
|
||||
des_cbc_decrypt(blk, len, &ctx->context);
|
||||
}
|
||||
|
||||
void des3_decrypt_pubkey(const void *vkey, void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key + 8),
|
||||
GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[2]);
|
||||
des_3cbc_decrypt(blk, len, ourkeys);
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
void des3_encrypt_pubkey(const void *vkey, void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key + 8),
|
||||
GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[2]);
|
||||
des_3cbc_encrypt(blk, len, ourkeys);
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
void des3_decrypt_pubkey_ossh(const void *vkey, const void *viv,
|
||||
void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key + 8),
|
||||
GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key + 16),
|
||||
GET_32BIT_MSB_FIRST(key + 20), &ourkeys[2]);
|
||||
ourkeys[0].iv0 = GET_32BIT_MSB_FIRST(iv);
|
||||
ourkeys[0].iv1 = GET_32BIT_MSB_FIRST(iv+4);
|
||||
des_cbc3_decrypt(blk, len, ourkeys);
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
void des3_encrypt_pubkey_ossh(const void *vkey, const void *viv,
|
||||
void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key + 8),
|
||||
GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]);
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key + 16),
|
||||
GET_32BIT_MSB_FIRST(key + 20), &ourkeys[2]);
|
||||
ourkeys[0].iv0 = GET_32BIT_MSB_FIRST(iv);
|
||||
ourkeys[0].iv1 = GET_32BIT_MSB_FIRST(iv+4);
|
||||
des_cbc3_encrypt(blk, len, ourkeys);
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
static void des_keysetup_xdmauth(const void *vkeydata, DESContext *dc)
|
||||
{
|
||||
const unsigned char *keydata = (const unsigned char *)vkeydata;
|
||||
unsigned char key[8];
|
||||
int i, nbits, j;
|
||||
unsigned int bits;
|
||||
|
||||
bits = 0;
|
||||
nbits = 0;
|
||||
j = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (nbits < 7) {
|
||||
bits = (bits << 8) | keydata[j];
|
||||
nbits += 8;
|
||||
j++;
|
||||
}
|
||||
key[i] = (bits >> (nbits - 7)) << 1;
|
||||
bits &= ~(0x7F << (nbits - 7));
|
||||
nbits -= 7;
|
||||
}
|
||||
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), dc);
|
||||
}
|
||||
|
||||
void des_encrypt_xdmauth(const void *keydata, void *blk, int len)
|
||||
{
|
||||
DESContext dc;
|
||||
des_keysetup_xdmauth(keydata, &dc);
|
||||
des_cbc_encrypt(blk, len, &dc);
|
||||
}
|
||||
|
||||
void des_decrypt_xdmauth(const void *keydata, void *blk, int len)
|
||||
{
|
||||
DESContext dc;
|
||||
des_keysetup_xdmauth(keydata, &dc);
|
||||
des_cbc_decrypt(blk, len, &dc);
|
||||
}
|
||||
|
||||
const ssh2_cipheralg ssh_3des_ssh2 = {
|
||||
const ssh_cipheralg ssh_3des_ssh2 = {
|
||||
des3_ssh2_new, des3_ssh2_free, des3_ssh2_setiv, des3_ssh2_setkey,
|
||||
des3_ssh2_encrypt_blk, des3_ssh2_decrypt_blk, NULL, NULL,
|
||||
"3des-cbc",
|
||||
@@ -1078,7 +935,7 @@ const ssh2_cipheralg ssh_3des_ssh2 = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const ssh2_cipheralg ssh_3des_ssh2_ctr = {
|
||||
const ssh_cipheralg ssh_3des_ssh2_ctr = {
|
||||
des3_ssh2_new, des3_ssh2_free, des3_ssh2_setiv, des3_ssh2_setkey,
|
||||
des3_ssh2_sdctr, des3_ssh2_sdctr, NULL, NULL,
|
||||
"3des-ctr",
|
||||
@@ -1094,44 +951,38 @@ const ssh2_cipheralg ssh_3des_ssh2_ctr = {
|
||||
* apparently aren't the only people to do so, so we sigh
|
||||
* and implement it anyway.
|
||||
*/
|
||||
const ssh2_cipheralg ssh_des_ssh2 = {
|
||||
des_ssh2_new, des_ssh2_free, des_ssh2_setiv, des_ssh2_setkey,
|
||||
des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, NULL, NULL,
|
||||
const ssh_cipheralg ssh_des = {
|
||||
des_new, des_free, des_setiv, des_setkey,
|
||||
des_encrypt_blk, des_decrypt_blk, NULL, NULL,
|
||||
"des-cbc",
|
||||
8, 56, 8, SSH_CIPHER_IS_CBC, "single-DES CBC",
|
||||
NULL
|
||||
};
|
||||
|
||||
const ssh2_cipheralg ssh_des_sshcom_ssh2 = {
|
||||
des_ssh2_new, des_ssh2_free, des_ssh2_setiv, des_ssh2_setkey,
|
||||
des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, NULL, NULL,
|
||||
const ssh_cipheralg ssh_des_sshcom_ssh2 = {
|
||||
des_new, des_free, des_setiv, des_setkey,
|
||||
des_encrypt_blk, des_decrypt_blk, NULL, NULL,
|
||||
"des-cbc@ssh.com",
|
||||
8, 56, 8, SSH_CIPHER_IS_CBC, "single-DES CBC",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const ssh2_cipheralg *const des3_list[] = {
|
||||
static const ssh_cipheralg *const des3_list[] = {
|
||||
&ssh_3des_ssh2_ctr,
|
||||
&ssh_3des_ssh2
|
||||
};
|
||||
|
||||
const ssh2_ciphers ssh2_3des = { lenof(des3_list), des3_list };
|
||||
|
||||
static const ssh2_cipheralg *const des_list[] = {
|
||||
&ssh_des_ssh2,
|
||||
static const ssh_cipheralg *const des_list[] = {
|
||||
&ssh_des,
|
||||
&ssh_des_sshcom_ssh2
|
||||
};
|
||||
|
||||
const ssh2_ciphers ssh2_des = { lenof(des_list), des_list };
|
||||
|
||||
const ssh1_cipheralg ssh1_3des = {
|
||||
des3_ssh1_new, des3_ssh1_free, des3_ssh1_sesskey,
|
||||
des3_ssh1_encrypt_blk, des3_ssh1_decrypt_blk,
|
||||
8, "triple-DES inner-CBC"
|
||||
};
|
||||
|
||||
const ssh1_cipheralg ssh1_des = {
|
||||
des_ssh1_new, des_ssh1_free, des_ssh1_sesskey,
|
||||
des_ssh1_encrypt_blk, des_ssh1_decrypt_blk,
|
||||
8, "single-DES CBC"
|
||||
const ssh_cipheralg ssh_3des_ssh1 = {
|
||||
des3_ssh1_new, des3_ssh1_free, des3_ssh1_setiv, des3_ssh1_setkey,
|
||||
des3_ssh1_encrypt_blk, des3_ssh1_decrypt_blk, NULL, NULL, NULL,
|
||||
8, 168, 24, SSH_CIPHER_IS_CBC, "triple-DES inner-CBC", NULL
|
||||
};
|
||||
|
||||
3
source/putty/sshmd5.c
vendored
3
source/putty/sshmd5.c
vendored
@@ -285,8 +285,7 @@ struct hmacmd5_context *hmacmd5_make_context(void)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static ssh2_mac *hmacmd5_ssh2_new(const ssh2_macalg *alg,
|
||||
ssh2_cipher *cipher)
|
||||
static ssh2_mac *hmacmd5_ssh2_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||
{
|
||||
struct hmacmd5_context *ctx = hmacmd5_make_context();
|
||||
ctx->mac.vt = alg;
|
||||
|
||||
3
source/putty/sshsh256.c
vendored
3
source/putty/sshsh256.c
vendored
@@ -264,8 +264,7 @@ struct hmacsha256 {
|
||||
ssh2_mac mac;
|
||||
};
|
||||
|
||||
static ssh2_mac *hmacsha256_new(
|
||||
const ssh2_macalg *alg, ssh2_cipher *cipher)
|
||||
static ssh2_mac *hmacsha256_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||
{
|
||||
struct hmacsha256 *ctx = snew(struct hmacsha256);
|
||||
ctx->mac.vt = alg;
|
||||
|
||||
3
source/putty/sshsha.c
vendored
3
source/putty/sshsha.c
vendored
@@ -288,8 +288,7 @@ struct hmacsha1 {
|
||||
ssh2_mac mac;
|
||||
};
|
||||
|
||||
static ssh2_mac *hmacsha1_new(
|
||||
const ssh2_macalg *alg, ssh2_cipher *cipher)
|
||||
static ssh2_mac *hmacsha1_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||
{
|
||||
struct hmacsha1 *ctx = snew(struct hmacsha1);
|
||||
ctx->mac.vt = alg;
|
||||
|
||||
@@ -275,3 +275,12 @@ uintmax_t strtoumax(const char *nptr, char **endptr, int base)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined _M_ARM || defined _M_ARM64
|
||||
|
||||
bool platform_aes_hw_available(void)
|
||||
{
|
||||
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user