X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/8c3cd914db62fcba242eba74eba223c1c927aaa5..6e522441172d5b1c2a2fa4d0f6bbe905ce6b647a:/sshpubk.c diff --git a/sshpubk.c b/sshpubk.c index d58e30a5..fd40db77 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -10,6 +10,12 @@ #include "ssh.h" +#define PUT_32BIT(cp, value) do { \ + (cp)[3] = (value); \ + (cp)[2] = (value) >> 8; \ + (cp)[1] = (value) >> 16; \ + (cp)[0] = (value) >> 24; } while (0) + #define GET_32BIT(cp) \ (((unsigned long)(unsigned char)(cp)[0] << 24) | \ ((unsigned long)(unsigned char)(cp)[1] << 16) | \ @@ -24,7 +30,7 @@ (x)=='+' ? 62 : \ (x)=='/' ? 63 : 0 ) -static int loadrsakey_main(FILE *fp, struct RSAKey *key, +static int loadrsakey_main(FILE *fp, struct RSAKey *key, struct RSAAux *aux, char **commentptr, char *passphrase) { unsigned char buf[16384]; unsigned char keybuf[16]; @@ -106,10 +112,19 @@ static int loadrsakey_main(FILE *fp, struct RSAKey *key, /* * After that, we have one further bignum which is our - * decryption modulus, and then we're done. + * decryption exponent, and then the three auxiliary values + * (iqmp, q, p). */ i += makeprivate(buf+i, key); if (len-i < 0) goto end; + if (aux) { + i += ssh1_read_bignum(buf+i, &aux->iqmp); + if (len-i < 0) goto end; + i += ssh1_read_bignum(buf+i, &aux->q); + if (len-i < 0) goto end; + i += ssh1_read_bignum(buf+i, &aux->p); + if (len-i < 0) goto end; + } ret = 1; end: @@ -117,7 +132,8 @@ static int loadrsakey_main(FILE *fp, struct RSAKey *key, return ret; } -int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) { +int loadrsakey(char *filename, struct RSAKey *key, struct RSAAux *aux, + char *passphrase) { FILE *fp; unsigned char buf[64]; @@ -131,7 +147,7 @@ int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) { */ if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { - return loadrsakey_main(fp, key, NULL, passphrase); + return loadrsakey_main(fp, key, aux, NULL, passphrase); } /* @@ -159,7 +175,103 @@ int rsakey_encrypted(char *filename, char **comment) { */ if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { - return loadrsakey_main(fp, NULL, comment, NULL); + return loadrsakey_main(fp, NULL, NULL, comment, NULL); } return 0; /* wasn't the right kind of file */ } + +/* + * Save an RSA key file. Return nonzero on success. + */ +int saversakey(char *filename, struct RSAKey *key, struct RSAAux *aux, + char *passphrase) { + unsigned char buf[16384]; + unsigned char keybuf[16]; + struct MD5Context md5c; + char *p, *estart; + FILE *fp; + + /* + * Write the initial signature. + */ + p = buf; + memcpy(p, rsa_signature, sizeof(rsa_signature)); + p += sizeof(rsa_signature); + + /* + * One byte giving encryption type, and one reserved (zero) + * uint32. + */ + *p++ = (passphrase ? SSH_CIPHER_3DES : 0); + PUT_32BIT(p, 0); p += 4; + + /* + * An ordinary SSH 1 public key consists of: a uint32 + * containing the bit count, then two bignums containing the + * modulus and exponent respectively. + */ + PUT_32BIT(p, ssh1_bignum_bitcount(key->modulus)); p += 4; + p += ssh1_write_bignum(p, key->modulus); + p += ssh1_write_bignum(p, key->exponent); + + /* + * A string containing the comment field. + */ + if (key->comment) { + PUT_32BIT(p, strlen(key->comment)); p += 4; + memcpy(p, key->comment, strlen(key->comment)); + p += strlen(key->comment); + } else { + PUT_32BIT(p, 0); p += 4; + } + + /* + * The encrypted portion starts here. + */ + estart = p; + + /* + * Two bytes, then the same two bytes repeated. + */ + *p++ = random_byte(); + *p++ = random_byte(); + p[0] = p[-2]; p[1] = p[-1]; p += 2; + + /* + * Four more bignums: the decryption exponent, then iqmp, then + * q, then p. + */ + p += ssh1_write_bignum(p, key->private_exponent); + p += ssh1_write_bignum(p, aux->iqmp); + p += ssh1_write_bignum(p, aux->q); + p += ssh1_write_bignum(p, aux->p); + + /* + * Now write zeros until the encrypted portion is a multiple of + * 8 bytes. + */ + while ((p-estart) % 8) + *p++ = '\0'; + + /* + * Now encrypt the encrypted portion. + */ + if (passphrase) { + MD5Init(&md5c); + MD5Update(&md5c, passphrase, strlen(passphrase)); + MD5Final(keybuf, &md5c); + des3_encrypt_pubkey(keybuf, estart, p-estart); + memset(keybuf, 0, sizeof(keybuf)); /* burn the evidence */ + } + + /* + * Done. Write the result to the file. + */ + fp = fopen(filename, "wb"); + if (fp) { + int ret = (fwrite(buf, 1, p-buf, fp) == (size_t)(p-buf)); + ret = ret && (fclose(fp) == 0); + return ret; + } else + return 0; +}