1 /*
2  * sshauxcrypt.c: wrapper functions on crypto primitives for use in
3  * other contexts than the main SSH packet protocol, such as
4  * encrypting private key files and performing XDM-AUTHORIZATION-1.
5  *
6  * These all work through the standard cipher/hash/MAC APIs, so they
7  * don't need to live in the same actual source files as the ciphers
8  * they wrap, and I think it keeps things tidier to have them out of
9  * the way here instead.
10  */
11 
12 #include "ssh.h"
13 
aes256_pubkey_cipher(const void * key,const void * iv)14 static ssh_cipher *aes256_pubkey_cipher(const void *key, const void *iv)
15 {
16     /*
17      * PuTTY's own .PPK format for SSH-2 private key files is
18      * encrypted with 256-bit AES in CBC mode.
19      */
20     ssh_cipher *cipher = ssh_cipher_new(&ssh_aes256_cbc);
21     ssh_cipher_setkey(cipher, key);
22     ssh_cipher_setiv(cipher, iv);
23     return cipher;
24 }
25 
aes256_encrypt_pubkey(const void * key,const void * iv,void * blk,int len)26 void aes256_encrypt_pubkey(const void *key, const void *iv, void *blk, int len)
27 {
28     ssh_cipher *c = aes256_pubkey_cipher(key, iv);
29     ssh_cipher_encrypt(c, blk, len);
30     ssh_cipher_free(c);
31 }
32 
aes256_decrypt_pubkey(const void * key,const void * iv,void * blk,int len)33 void aes256_decrypt_pubkey(const void *key, const void *iv, void *blk, int len)
34 {
35     ssh_cipher *c = aes256_pubkey_cipher(key, iv);
36     ssh_cipher_decrypt(c, blk, len);
37     ssh_cipher_free(c);
38 }
39 
des3_pubkey_cipher(const void * vkey)40 static ssh_cipher *des3_pubkey_cipher(const void *vkey)
41 {
42     /*
43      * SSH-1 private key files are encrypted with triple-DES in SSH-1
44      * style (three separate CBC layers), but the same key is used for
45      * the first and third layers.
46      */
47     ssh_cipher *c = ssh_cipher_new(&ssh_3des_ssh1);
48     uint8_t keys3[24], iv[8];
49 
50     memcpy(keys3, vkey, 16);
51     memcpy(keys3 + 16, vkey, 8);
52     ssh_cipher_setkey(c, keys3);
53     smemclr(keys3, sizeof(keys3));
54 
55     memset(iv, 0, 8);
56     ssh_cipher_setiv(c, iv);
57 
58     return c;
59 }
60 
des3_decrypt_pubkey(const void * vkey,void * vblk,int len)61 void des3_decrypt_pubkey(const void *vkey, void *vblk, int len)
62 {
63     ssh_cipher *c = des3_pubkey_cipher(vkey);
64     ssh_cipher_decrypt(c, vblk, len);
65     ssh_cipher_free(c);
66 }
67 
des3_encrypt_pubkey(const void * vkey,void * vblk,int len)68 void des3_encrypt_pubkey(const void *vkey, void *vblk, int len)
69 {
70     ssh_cipher *c = des3_pubkey_cipher(vkey);
71     ssh_cipher_encrypt(c, vblk, len);
72     ssh_cipher_free(c);
73 }
74 
des3_pubkey_ossh_cipher(const void * vkey,const void * viv)75 static ssh_cipher *des3_pubkey_ossh_cipher(const void *vkey, const void *viv)
76 {
77     /*
78      * OpenSSH PEM private key files are encrypted with triple-DES in
79      * SSH-2 style (one CBC layer), with three distinct keys, and an
80      * IV also generated from the passphrase.
81      */
82     ssh_cipher *c = ssh_cipher_new(&ssh_3des_ssh2);
83     ssh_cipher_setkey(c, vkey);
84     ssh_cipher_setiv(c, viv);
85     return c;
86 }
87 
des3_decrypt_pubkey_ossh(const void * vkey,const void * viv,void * vblk,int len)88 void des3_decrypt_pubkey_ossh(const void *vkey, const void *viv,
89                               void *vblk, int len)
90 {
91     ssh_cipher *c = des3_pubkey_ossh_cipher(vkey, viv);
92     ssh_cipher_decrypt(c, vblk, len);
93     ssh_cipher_free(c);
94 }
95 
des3_encrypt_pubkey_ossh(const void * vkey,const void * viv,void * vblk,int len)96 void des3_encrypt_pubkey_ossh(const void *vkey, const void *viv,
97                               void *vblk, int len)
98 {
99     ssh_cipher *c = des3_pubkey_ossh_cipher(vkey, viv);
100     ssh_cipher_encrypt(c, vblk, len);
101     ssh_cipher_free(c);
102 }
103 
des_xdmauth_cipher(const void * vkeydata)104 static ssh_cipher *des_xdmauth_cipher(const void *vkeydata)
105 {
106     /*
107      * XDM-AUTHORIZATION-1 uses single-DES, but packs the key into 7
108      * bytes, so here we have to repack it manually into the canonical
109      * form where it occupies 8 bytes each with the low bit unused.
110      */
111     const unsigned char *keydata = (const unsigned char *)vkeydata;
112     unsigned char key[8];
113     int i, nbits, j;
114     unsigned int bits;
115 
116     bits = 0;
117     nbits = 0;
118     j = 0;
119     for (i = 0; i < 8; i++) {
120         if (nbits < 7) {
121             bits = (bits << 8) | keydata[j];
122             nbits += 8;
123             j++;
124         }
125         key[i] = (bits >> (nbits - 7)) << 1;
126         bits &= ~(0x7F << (nbits - 7));
127         nbits -= 7;
128     }
129 
130     ssh_cipher *c = ssh_cipher_new(&ssh_des);
131     ssh_cipher_setkey(c, key);
132     smemclr(key, sizeof(key));
133     ssh_cipher_setiv(c, key);
134     return c;
135 }
136 
des_encrypt_xdmauth(const void * keydata,void * blk,int len)137 void des_encrypt_xdmauth(const void *keydata, void *blk, int len)
138 {
139     ssh_cipher *c = des_xdmauth_cipher(keydata);
140     ssh_cipher_encrypt(c, blk, len);
141     ssh_cipher_free(c);
142 }
143 
des_decrypt_xdmauth(const void * keydata,void * blk,int len)144 void des_decrypt_xdmauth(const void *keydata, void *blk, int len)
145 {
146     ssh_cipher *c = des_xdmauth_cipher(keydata);
147     ssh_cipher_decrypt(c, blk, len);
148     ssh_cipher_free(c);
149 }
150 
hash_simple(const ssh_hashalg * alg,ptrlen data,void * output)151 void hash_simple(const ssh_hashalg *alg, ptrlen data, void *output)
152 {
153     ssh_hash *hash = ssh_hash_new(alg);
154     put_datapl(hash, data);
155     ssh_hash_final(hash, output);
156 }
157 
mac_simple(const ssh2_macalg * alg,ptrlen key,ptrlen data,void * output)158 void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output)
159 {
160     ssh2_mac *mac = ssh2_mac_new(alg, NULL);
161     ssh2_mac_setkey(mac, key);
162     ssh2_mac_start(mac);
163     put_datapl(mac, data);
164     ssh2_mac_genresult(mac, output);
165     ssh2_mac_free(mac);
166 }
167