From 5b30e6f7a6ff2ec5841b79bdc49671f6c3544f25 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 18 Apr 2021 13:16:59 +0100 Subject: [PATCH] Move crypto into its own subdirectory. Similarly to 'utils', I've moved all the stuff in the crypto build-time library into a source directory of its own, and while I'm at it, split up the monolithic sshauxcrypt.c into its various unrelated parts. This is also an opportunity to remove the annoying 'ssh' prefix from the front of the file names, and give several of them less cryptic names. --- CMakeLists.txt | 9 +- crypto/CMakeLists.txt | 30 +++++ sshaes.c => crypto/aes.c | 2 +- ssharcf.c => crypto/arcfour.c | 0 sshargon2.c => crypto/argon2.c | 0 sshbcrypt.c => crypto/bcrypt.c | 0 sshblake2.c => crypto/blake2.c | 0 sshblowf.c => crypto/blowfish.c | 0 sshccp.c => crypto/chacha20-poly1305.c | 0 sshcrc.c => crypto/crc32.c | 5 + sshdes.c => crypto/des.c | 2 +- sshdh.c => crypto/diffie-hellman.c | 0 sshdss.c => crypto/dsa.c | 2 +- ecc.c => crypto/ecc-arithmetic.c | 4 + sshecc.c => crypto/ecc-ssh.c | 10 +- crypto/hash_simple.c | 13 ++ sshhmac.c => crypto/hmac.c | 0 sshmac.c => crypto/mac.c | 0 crypto/mac_simple.c | 16 +++ sshmd5.c => crypto/md5.c | 0 mpint.c => crypto/mpint.c | 4 + sshprng.c => crypto/prng.c | 2 +- crypto/pubkey-pem.c | 32 +++++ crypto/pubkey-ppk.c | 29 +++++ crypto/pubkey-ssh1.c | 38 ++++++ sshrsa.c => crypto/rsa.c | 0 sshsha.c => crypto/sha1.c | 0 sshsh256.c => crypto/sha256.c | 0 sshsha3.c => crypto/sha3.c | 0 sshsh512.c => crypto/sha512.c | 0 crypto/xdmauth.c | 53 ++++++++ sshauxcrypt.c | 166 ------------------------- 32 files changed, 230 insertions(+), 187 deletions(-) create mode 100644 crypto/CMakeLists.txt rename sshaes.c => crypto/aes.c (99%) rename ssharcf.c => crypto/arcfour.c (100%) rename sshargon2.c => crypto/argon2.c (100%) rename sshbcrypt.c => crypto/bcrypt.c (100%) rename sshblake2.c => crypto/blake2.c (100%) rename sshblowf.c => crypto/blowfish.c (100%) rename sshccp.c => crypto/chacha20-poly1305.c (100%) rename sshcrc.c => crypto/crc32.c (94%) rename sshdes.c => crypto/des.c (99%) rename sshdh.c => crypto/diffie-hellman.c (100%) rename sshdss.c => crypto/dsa.c (99%) rename ecc.c => crypto/ecc-arithmetic.c (99%) rename sshecc.c => crypto/ecc-ssh.c (99%) create mode 100644 crypto/hash_simple.c rename sshhmac.c => crypto/hmac.c (100%) rename sshmac.c => crypto/mac.c (100%) create mode 100644 crypto/mac_simple.c rename sshmd5.c => crypto/md5.c (100%) rename mpint.c => crypto/mpint.c (99%) rename sshprng.c => crypto/prng.c (99%) create mode 100644 crypto/pubkey-pem.c create mode 100644 crypto/pubkey-ppk.c create mode 100644 crypto/pubkey-ssh1.c rename sshrsa.c => crypto/rsa.c (100%) rename sshsha.c => crypto/sha1.c (100%) rename sshsh256.c => crypto/sha256.c (100%) rename sshsha3.c => crypto/sha3.c (100%) rename sshsh512.c => crypto/sha512.c (100%) create mode 100644 crypto/xdmauth.c delete mode 100644 sshauxcrypt.c 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); -}