Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /trunk/ttssh2/ttxssh/keyfiles-putty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9256 - (hide annotations) (download) (as text)
Wed May 19 14:44:16 2021 UTC (2 years, 10 months ago) by nmaya
Original Path: branches/4-stable/ttssh2/ttxssh/keyfiles-putty.c
File MIME type: text/x-csrc
File size: 9913 byte(s)
PuTTY private key format version 3 (PPK3) に対応した。

Argon2 の復号に The reference C implementation of Argon2 (https://github.com/P-H-C/phc-winner-argon2) を使用する。
1 nmaya 9256 /* Imported from PuTTY 0.74, 0.75, TeraTerm Project */
2    
3     /*
4     * (C) 2021- TeraTerm Project
5     * All rights reserved.
6     *
7     * Redistribution and use in source and binary forms, with or without
8     * modification, are permitted provided that the following conditions
9     * are met:
10     *
11     * 1. Redistributions of source code must retain the above copyright
12     * notice, this list of conditions and the following disclaimer.
13     * 2. Redistributions in binary form must reproduce the above copyright
14     * notice, this list of conditions and the following disclaimer in the
15     * documentation and/or other materials provided with the distribution.
16     * 3. The name of the author may not be used to endorse or promote products
17     * derived from this software without specific prior written permission.
18     *
19     * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
20     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22     * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29     */
30    
31     #include "ttxssh.h"
32     #include "keyfiles-putty.h"
33    
34     // from sshpubk.c (ver 0.75)
35     BOOL str_to_uint32_t(const char *s, uint32_t *out)
36     {
37     char *endptr;
38     unsigned long converted = strtoul(s, &endptr, 10);
39     if (*s && !*endptr && converted <= ~(uint32_t)0) {
40     *out = converted;
41     return TRUE;
42     } else {
43     return FALSE;
44     }
45     }
46    
47     // from sshpubk.c (ver 0.74)
48     BOOL ppk_read_header(FILE * fp, char *header)
49     {
50     int len = 39;
51     int c;
52    
53     while (1) {
54     c = fgetc(fp);
55     if (c == '\n' || c == '\r' || c == EOF)
56     return FALSE;
57     if (c == ':') {
58     c = fgetc(fp);
59     if (c != ' ')
60     return FALSE;
61     *header = '\0';
62     return TRUE;
63     }
64     if (len == 0)
65     return FALSE;
66     *header++ = c;
67     len--;
68     }
69     return FALSE;
70     }
71    
72     // from sshpubk.c (ver 0.74)
73     char *ppk_read_body(FILE * fp)
74     {
75     buffer_t *buf = buffer_init();
76    
77     while (1) {
78     int c = fgetc(fp);
79     if (c == '\r' || c == '\n' || c == EOF) {
80     if (c != EOF) {
81     c = fgetc(fp);
82     if (c != '\r' && c != '\n')
83     ungetc(c, fp);
84     }
85     return buffer_ptr(buf);
86     }
87     buffer_put_char(buf, c);
88     }
89     }
90    
91     // from sshpubk.c (ver 0.74), and modified
92     // - use buffer_t insted of strbuf
93     // - use OpenSSL function
94     BOOL ppk_read_blob(FILE* fp, int nlines, buffer_t *blob)
95     {
96     BIO *bmem, *b64, *chain;
97     int i, len;
98     char line[200], buf[100];
99    
100     b64 = BIO_new(BIO_f_base64());
101     bmem = BIO_new(BIO_s_mem());
102     for (i=0; i<nlines && fgets(line, sizeof(line), fp)!=NULL; i++) {
103     BIO_write(bmem, line, strlen(line));
104     }
105     BIO_flush(bmem);
106     chain = BIO_push(b64, bmem);
107     BIO_set_mem_eof_return(chain, 0);
108     while ((len = BIO_read(chain, buf, sizeof(buf))) > 0) {
109     buffer_append(blob, buf, len);
110     }
111     BIO_free_all(chain);
112    
113     return TRUE;
114     }
115    
116     // from sshsha.c (ver 0.70), and modifled
117     // - use OpenSSL function
118     void hmac_sha1_simple(unsigned char *key, int keylen, void *data, int datalen,
119     unsigned char *output)
120     {
121     EVP_MD_CTX *ctx[2] = {0, 0};
122     unsigned char intermediate[20];
123     unsigned char foo[64];
124     const EVP_MD *md = EVP_sha1();
125     int i;
126     unsigned int len;
127    
128     ctx[0] = EVP_MD_CTX_new();
129     if (ctx[0] == NULL) {
130     return;
131     }
132     ctx[1] = EVP_MD_CTX_new();
133     if (ctx[1] == NULL) {
134     EVP_MD_CTX_free(ctx[0]);
135     return;
136     }
137    
138     memset(foo, 0x36, sizeof(foo));
139     for (i = 0; i < keylen && i < sizeof(foo); i++) {
140     foo[i] ^= key[i];
141     }
142     EVP_DigestInit(ctx[0], md);
143     EVP_DigestUpdate(ctx[0], foo, sizeof(foo));
144    
145     memset(foo, 0x5C, sizeof(foo));
146     for (i = 0; i < keylen && i < sizeof(foo); i++) {
147     foo[i] ^= key[i];
148     }
149     EVP_DigestInit(ctx[1], md);
150     EVP_DigestUpdate(ctx[1], foo, sizeof(foo));
151    
152     memset(foo, 0, sizeof(foo));
153    
154     EVP_DigestUpdate(ctx[0], data, datalen);
155     EVP_DigestFinal(ctx[0], intermediate, &len);
156    
157     EVP_DigestUpdate(ctx[1], intermediate, sizeof(intermediate));
158     EVP_DigestFinal(ctx[1], output, &len);
159    
160     EVP_MD_CTX_free(ctx[0]);
161     EVP_MD_CTX_free(ctx[1]);
162     }
163    
164     void hmac_sha256_simple(unsigned char *key, int keylen, void *data, int datalen,
165     unsigned char *output)
166     {
167     EVP_MD_CTX *ctx[2] = {0, 0};
168     unsigned char intermediate[32];
169     unsigned char foo[64];
170     const EVP_MD *md = EVP_sha256();
171     int i;
172     unsigned int len;
173    
174     ctx[0] = EVP_MD_CTX_new();
175     if (ctx[0] == NULL) {
176     return;
177     }
178     ctx[1] = EVP_MD_CTX_new();
179     if (ctx[1] == NULL) {
180     EVP_MD_CTX_free(ctx[0]);
181     return;
182     }
183    
184     memset(foo, 0x36, sizeof(foo));
185     for (i = 0; i < keylen && i < sizeof(foo); i++) {
186     foo[i] ^= key[i];
187     }
188     EVP_DigestInit(ctx[0], md);
189     EVP_DigestUpdate(ctx[0], foo, sizeof(foo));
190    
191     memset(foo, 0x5C, sizeof(foo));
192     for (i = 0; i < keylen && i < sizeof(foo); i++) {
193     foo[i] ^= key[i];
194     }
195     EVP_DigestInit(ctx[1], md);
196     EVP_DigestUpdate(ctx[1], foo, sizeof(foo));
197    
198     memset(foo, 0, sizeof(foo));
199    
200     EVP_DigestUpdate(ctx[0], data, datalen);
201     EVP_DigestFinal(ctx[0], intermediate, &len);
202    
203     EVP_DigestUpdate(ctx[1], intermediate, sizeof(intermediate));
204     EVP_DigestFinal(ctx[1], output, &len);
205    
206     EVP_MD_CTX_free(ctx[0]);
207     EVP_MD_CTX_free(ctx[1]);
208     }
209    
210     // from sshsha.c (ver 0.70) hmac_sha1_simple
211     // sshauxcrypt.c (ver 0.75) mac_simple, and modifled
212     // - use OpenSSL function
213     // - use EVP_MD instead of ssh2_macalg
214     void mac_simple(const EVP_MD *md,
215     unsigned char *key, int keylen, void *data, int datalen,
216     unsigned char *output)
217     {
218     EVP_MD_CTX *ctx[2] = {0, 0};
219     unsigned char intermediate[32]; // sha1: 160bit / sha256: 256bit
220     unsigned char foo[64]; // block size ... sha1: 512bit / sha256: 512bit
221     int i;
222     unsigned int len;
223    
224     ctx[0] = EVP_MD_CTX_new();
225     if (ctx[0] == NULL) {
226     return;
227     }
228     ctx[1] = EVP_MD_CTX_new();
229     if (ctx[1] == NULL) {
230     EVP_MD_CTX_free(ctx[0]);
231     return;
232     }
233    
234     memset(foo, 0x36, sizeof(foo));
235     for (i = 0; i < keylen && i < sizeof(foo); i++) {
236     foo[i] ^= key[i];
237     }
238     EVP_DigestInit(ctx[0], md);
239     EVP_DigestUpdate(ctx[0], foo, sizeof(foo));
240    
241     memset(foo, 0x5C, sizeof(foo));
242     for (i = 0; i < keylen && i < sizeof(foo); i++) {
243     foo[i] ^= key[i];
244     }
245     EVP_DigestInit(ctx[1], md);
246     EVP_DigestUpdate(ctx[1], foo, sizeof(foo));
247    
248     memset(foo, 0, sizeof(foo));
249    
250     EVP_DigestUpdate(ctx[0], data, datalen);
251     EVP_DigestFinal(ctx[0], intermediate, &len);
252    
253     EVP_DigestUpdate(ctx[1], intermediate, EVP_MD_size(md));
254     EVP_DigestFinal(ctx[1], output, &len);
255    
256     EVP_MD_CTX_free(ctx[0]);
257     EVP_MD_CTX_free(ctx[1]);
258     }
259    
260     // from sshpubk.c (ver 0.75), and modifled
261     // - delete unnecessary paramters
262     // - use char ** and int * instead of ptrlen
263     // - use buffer_t instead of strbuf
264     // - use OpenSSL function
265     // - use argon2 function
266     void ssh2_ppk_derive_keys(
267     unsigned fmt_version, const struct ssh2cipher* ciphertype,
268     unsigned char *passphrase, buffer_t *storage,
269     unsigned char **cipherkey, unsigned int *cipherkey_len,
270     unsigned char **cipheriv, unsigned int *cipheriv_len,
271     unsigned char **mackey, unsigned int *mackey_len,
272     ppk_argon2_parameters *params)
273     {
274     size_t mac_keylen = 0;
275     u_int ivlen;
276     unsigned int cipherkey_offset = 0;
277    
278     ivlen = (ciphertype->iv_len == 0) ? ciphertype->block_size : ciphertype->iv_len;
279    
280     switch (fmt_version) {
281     case 3: {
282     uint32_t taglen;
283     unsigned char *tag;
284    
285     if (ciphertype->key_len == 0) {
286     mac_keylen = 0;
287     break;
288     }
289     mac_keylen = 32;
290     taglen = ciphertype->key_len + ivlen + mac_keylen;
291     tag = (char *)malloc(taglen);
292    
293     argon2_hash(params->argon2_passes, params->argon2_mem,
294     params->argon2_parallelism,
295     passphrase, strlen(passphrase),
296     params->salt, params->saltlen,
297     tag, taglen,
298     NULL, 0,
299     params->type, 0x13);
300     buffer_append(storage, tag, taglen);
301    
302     free(tag);
303    
304     break;
305     }
306     case 2: {
307     unsigned ctr;
308     const EVP_MD *md = EVP_sha1();
309     EVP_MD_CTX *ctx = NULL;
310     unsigned char u[4], buf[20]; // SHA1: 20byte
311     unsigned int i, len, cipherkey_write_byte = 0;
312    
313     ctx = EVP_MD_CTX_new();
314    
315     /* Counter-mode iteration to generate cipher key data. */
316     for (ctr = 0; ctr * 20 < ciphertype->key_len; ctr++) {
317     EVP_DigestInit(ctx, md);
318     set_uint32_MSBfirst(u, ctr);
319     EVP_DigestUpdate(ctx, u, 4);
320     EVP_DigestUpdate(ctx, passphrase, strlen(passphrase));
321     EVP_DigestFinal(ctx, buf, &len);
322     buffer_append(storage, buf, 20);
323     cipherkey_write_byte += 20;
324     }
325     // TTSSH �� buffer_t ���� shrink �������������������A
326     // shrink ������ 40byte ������ 32byte �������g��
327     cipherkey_offset = cipherkey_write_byte - ciphertype->key_len;
328    
329     /* In this version of the format, the CBC IV was always all 0. */
330     for (i = 0; i < ivlen; i++) {
331     buffer_put_char(storage, 0);
332     }
333    
334     /* Completely separate hash for the MAC key. */
335     EVP_DigestInit(ctx, md);
336     mac_keylen = EVP_MD_size(md); // SHA1: 20byte
337     EVP_DigestUpdate(ctx, "putty-private-key-file-mac-key", 30);
338     EVP_DigestUpdate(ctx, passphrase, strlen(passphrase));
339     EVP_DigestFinal(ctx, buf, &len);
340     buffer_append(storage, buf, mac_keylen);
341    
342     EVP_MD_CTX_free(ctx);
343    
344     break;
345     }
346     }
347    
348     *cipherkey = storage->buf;
349     *cipherkey_len = ciphertype->key_len;
350     *cipheriv = storage->buf + ciphertype->key_len + cipherkey_offset;
351     *cipheriv_len = ivlen;
352     *mackey = storage->buf + ciphertype->key_len + cipherkey_offset + ivlen;
353     *mackey_len = mac_keylen;
354     }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26