diff --git a/CMakeLists.txt b/CMakeLists.txt index 77c4fe23..d3be22b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,15 +23,8 @@ add_library(settings STATIC cmdline.c settings.c) add_library(crypto STATIC - sshaes.c sshauxcrypt.c sshdes.c sshdss.c sshecc.c sshhmac.c sshmd5.c sshrsa.c - sshsh256.c sshsh512.c sshsha.c sshsha3.c - ecc.c mpint.c - sshprng.c - sshcrc.c - sshdh.c sshmac.c - ssharcf.c sshblowf.c sshccp.c - sshblake2.c sshargon2.c sshbcrypt.c cproxy.c) +add_subdirectory(crypto) add_library(network STATIC be_misc.c nullplug.c errsock.c proxy.c logging.c x11disp.c) diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt new file mode 100644 index 00000000..74f86cd4 --- /dev/null +++ b/crypto/CMakeLists.txt @@ -0,0 +1,30 @@ +add_sources_from_current_dir(crypto + aes.c + arcfour.c + argon2.c + bcrypt.c + blake2.c + blowfish.c + chacha20-poly1305.c + crc32.c + des.c + diffie-hellman.c + dsa.c + ecc-arithmetic.c + ecc-ssh.c + hash_simple.c + hmac.c + mac.c + mac_simple.c + md5.c + mpint.c + prng.c + pubkey-pem.c + pubkey-ppk.c + pubkey-ssh1.c + rsa.c + sha256.c + sha512.c + sha3.c + sha1.c + xdmauth.c) diff --git a/sshaes.c b/crypto/aes.c similarity index 99% rename from sshaes.c rename to crypto/aes.c index 97ea9f31..a7ca1117 100644 --- a/sshaes.c +++ b/crypto/aes.c @@ -1,5 +1,5 @@ /* - * sshaes.c - implementation of AES + * Implementation of AES. */ #include diff --git a/ssharcf.c b/crypto/arcfour.c similarity index 100% rename from ssharcf.c rename to crypto/arcfour.c diff --git a/sshargon2.c b/crypto/argon2.c similarity index 100% rename from sshargon2.c rename to crypto/argon2.c diff --git a/sshbcrypt.c b/crypto/bcrypt.c similarity index 100% rename from sshbcrypt.c rename to crypto/bcrypt.c diff --git a/sshblake2.c b/crypto/blake2.c similarity index 100% rename from sshblake2.c rename to crypto/blake2.c diff --git a/sshblowf.c b/crypto/blowfish.c similarity index 100% rename from sshblowf.c rename to crypto/blowfish.c diff --git a/sshccp.c b/crypto/chacha20-poly1305.c similarity index 100% rename from sshccp.c rename to crypto/chacha20-poly1305.c diff --git a/sshcrc.c b/crypto/crc32.c similarity index 94% rename from sshcrc.c rename to crypto/crc32.c index b1dc8333..bd874433 100644 --- a/sshcrc.c +++ b/crypto/crc32.c @@ -1,6 +1,11 @@ /* * CRC32 implementation, as used in SSH-1. * + * (This is not, of course, a cryptographic function! It lives in the + * 'crypto' directory because SSH-1 uses it _as if_ it was crypto: it + * handles sensitive data, and we implement it with care for side + * channels.) + * * 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 diff --git a/sshdes.c b/crypto/des.c similarity index 99% rename from sshdes.c rename to crypto/des.c index d2ba9825..e8a26f0a 100644 --- a/sshdes.c +++ b/crypto/des.c @@ -1,5 +1,5 @@ /* - * sshdes.c: implementation of DES. + * Implementation of DES. */ /* diff --git a/sshdh.c b/crypto/diffie-hellman.c similarity index 100% rename from sshdh.c rename to crypto/diffie-hellman.c diff --git a/sshdss.c b/crypto/dsa.c similarity index 99% rename from sshdss.c rename to crypto/dsa.c index 3e0c7618..9976648e 100644 --- a/sshdss.c +++ b/crypto/dsa.c @@ -1,5 +1,5 @@ /* - * Digital Signature Standard implementation for PuTTY. + * Digital Signature Algorithm implementation for PuTTY. */ #include diff --git a/ecc.c b/crypto/ecc-arithmetic.c similarity index 99% rename from ecc.c rename to crypto/ecc-arithmetic.c index 72f9bfe5..6a896f92 100644 --- a/ecc.c +++ b/crypto/ecc-arithmetic.c @@ -1,3 +1,7 @@ +/* + * Basic arithmetic for elliptic curves, implementing ecc.h. + */ + #include #include "ssh.h" diff --git a/sshecc.c b/crypto/ecc-ssh.c similarity index 99% rename from sshecc.c rename to crypto/ecc-ssh.c index ba580dbf..c227f30f 100644 --- a/sshecc.c +++ b/crypto/ecc-ssh.c @@ -1,13 +1,5 @@ /* - * Elliptic-curve crypto module for PuTTY - * Implements the three required curves, no optional curves - * - * NOTE: Only curves on prime field are handled by the maths functions - * in Weierstrass form using Jacobian co-ordinates. - * - * Montgomery form curves are supported for DH. (Curve25519) - * - * Edwards form curves are supported for DSA. (Ed25519, Ed448) + * Elliptic-curve signing and key exchange for PuTTY's SSH layer. */ /* diff --git a/crypto/hash_simple.c b/crypto/hash_simple.c new file mode 100644 index 00000000..0115b920 --- /dev/null +++ b/crypto/hash_simple.c @@ -0,0 +1,13 @@ +/* + * Convenience function to hash a single piece of data, wrapping up + * the faff of making and freeing an ssh_hash. + */ + +#include "ssh.h" + +void hash_simple(const ssh_hashalg *alg, ptrlen data, void *output) +{ + ssh_hash *hash = ssh_hash_new(alg); + put_datapl(hash, data); + ssh_hash_final(hash, output); +} diff --git a/sshhmac.c b/crypto/hmac.c similarity index 100% rename from sshhmac.c rename to crypto/hmac.c diff --git a/sshmac.c b/crypto/mac.c similarity index 100% rename from sshmac.c rename to crypto/mac.c diff --git a/crypto/mac_simple.c b/crypto/mac_simple.c new file mode 100644 index 00000000..c705fd88 --- /dev/null +++ b/crypto/mac_simple.c @@ -0,0 +1,16 @@ +/* + * Convenience function to MAC a single piece of data, wrapping up + * the faff of making and freeing an ssh_mac. + */ + +#include "ssh.h" + +void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output) +{ + ssh2_mac *mac = ssh2_mac_new(alg, NULL); + ssh2_mac_setkey(mac, key); + ssh2_mac_start(mac); + put_datapl(mac, data); + ssh2_mac_genresult(mac, output); + ssh2_mac_free(mac); +} diff --git a/sshmd5.c b/crypto/md5.c similarity index 100% rename from sshmd5.c rename to crypto/md5.c diff --git a/mpint.c b/crypto/mpint.c similarity index 99% rename from mpint.c rename to crypto/mpint.c index d77726cc..fca7530f 100644 --- a/mpint.c +++ b/crypto/mpint.c @@ -1,3 +1,7 @@ +/* + * Multiprecision integer arithmetic, implementing mpint.h. + */ + #include #include #include diff --git a/sshprng.c b/crypto/prng.c similarity index 99% rename from sshprng.c rename to crypto/prng.c index 58df9945..247d1dcf 100644 --- a/sshprng.c +++ b/crypto/prng.c @@ -1,5 +1,5 @@ /* - * sshprng.c: PuTTY's cryptographic pseudorandom number generator. + * PuTTY's cryptographic pseudorandom number generator. * * This module just defines the PRNG object type and its methods. The * usual global instance of it is managed by sshrand.c. diff --git a/crypto/pubkey-pem.c b/crypto/pubkey-pem.c new file mode 100644 index 00000000..3eaa16aa --- /dev/null +++ b/crypto/pubkey-pem.c @@ -0,0 +1,32 @@ +/* + * Convenience functions to encrypt and decrypt OpenSSH PEM format for + * SSH-2 private key files. This uses triple-DES in SSH-2 style (one + * CBC layer), with three distinct keys, and an IV also generated from + * the passphrase. + */ + +#include "ssh.h" + +static ssh_cipher *des3_pubkey_ossh_cipher(const void *vkey, const void *viv) +{ + 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); +} diff --git a/crypto/pubkey-ppk.c b/crypto/pubkey-ppk.c new file mode 100644 index 00000000..7ffb570a --- /dev/null +++ b/crypto/pubkey-ppk.c @@ -0,0 +1,29 @@ +/* + * Convenience functions to encrypt and decrypt PuTTY's own .PPK + * format for SSH-2 private key files, which uses 256-bit AES in CBC + * mode. + */ + +#include "ssh.h" + +static ssh_cipher *aes256_pubkey_cipher(const void *key, const void *iv) +{ + 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, const void *iv, void *blk, int len) +{ + ssh_cipher *c = aes256_pubkey_cipher(key, iv); + ssh_cipher_encrypt(c, blk, len); + ssh_cipher_free(c); +} + +void aes256_decrypt_pubkey(const void *key, const void *iv, void *blk, int len) +{ + ssh_cipher *c = aes256_pubkey_cipher(key, iv); + ssh_cipher_decrypt(c, blk, len); + ssh_cipher_free(c); +} diff --git a/crypto/pubkey-ssh1.c b/crypto/pubkey-ssh1.c new file mode 100644 index 00000000..b3129e29 --- /dev/null +++ b/crypto/pubkey-ssh1.c @@ -0,0 +1,38 @@ +/* + * Convenience functions to encrypt and decrypt the standard format + * for SSH-1 private key files. This uses triple-DES in SSH-1 style + * (three separate CBC layers), but the same key is used for the first + * and third layers.CBC mode. + */ + +#include "ssh.h" + +static ssh_cipher *des3_pubkey_cipher(const void *vkey) +{ + 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); +} diff --git a/sshrsa.c b/crypto/rsa.c similarity index 100% rename from sshrsa.c rename to crypto/rsa.c diff --git a/sshsha.c b/crypto/sha1.c similarity index 100% rename from sshsha.c rename to crypto/sha1.c diff --git a/sshsh256.c b/crypto/sha256.c similarity index 100% rename from sshsh256.c rename to crypto/sha256.c diff --git a/sshsha3.c b/crypto/sha3.c similarity index 100% rename from sshsha3.c rename to crypto/sha3.c diff --git a/sshsh512.c b/crypto/sha512.c similarity index 100% rename from sshsh512.c rename to crypto/sha512.c diff --git a/crypto/xdmauth.c b/crypto/xdmauth.c new file mode 100644 index 00000000..86339b85 --- /dev/null +++ b/crypto/xdmauth.c @@ -0,0 +1,53 @@ +/* + * Convenience functions to encrypt and decrypt the cookies used in + * XDM-AUTHORIZATION-1. + */ + +#include "ssh.h" + +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); +} diff --git a/sshauxcrypt.c b/sshauxcrypt.c deleted file mode 100644 index 7f64b27a..00000000 --- a/sshauxcrypt.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * sshauxcrypt.c: wrapper functions on crypto primitives 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/hash/MAC 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, const void *iv) -{ - /* - * PuTTY's own .PPK format for SSH-2 private key files is - * encrypted with 256-bit AES in CBC mode. - */ - 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, const void *iv, void *blk, int len) -{ - ssh_cipher *c = aes256_pubkey_cipher(key, iv); - ssh_cipher_encrypt(c, blk, len); - ssh_cipher_free(c); -} - -void aes256_decrypt_pubkey(const void *key, const void *iv, void *blk, int len) -{ - ssh_cipher *c = aes256_pubkey_cipher(key, iv); - 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); -} - -void hash_simple(const ssh_hashalg *alg, ptrlen data, void *output) -{ - ssh_hash *hash = ssh_hash_new(alg); - put_datapl(hash, data); - ssh_hash_final(hash, output); -} - -void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output) -{ - ssh2_mac *mac = ssh2_mac_new(alg, NULL); - ssh2_mac_setkey(mac, key); - ssh2_mac_start(mac); - put_datapl(mac, data); - ssh2_mac_genresult(mac, output); - ssh2_mac_free(mac); -}