⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sshpubk.c

📁 大名鼎鼎的远程登录软件putty的Symbian版源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Generic SSH public-key handling operations. In particular, * reading of SSH public-key files, and also the generic `sign' * operation for ssh2 (which checks the type of the key and * dispatches to the appropriate key-type specific function). */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include "putty.h"#include "ssh.h"#include "misc.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) | \    ((unsigned long)(unsigned char)(cp)[2] << 8) | \    ((unsigned long)(unsigned char)(cp)[3]))#define rsa_signature "SSH PRIVATE KEY FILE FORMAT 1.1\n"#define BASE64_TOINT(x) ( (x)-'A'<26 ? (x)-'A'+0 :\                          (x)-'a'<26 ? (x)-'a'+26 :\                          (x)-'0'<10 ? (x)-'0'+52 :\                          (x)=='+' ? 62 : \                          (x)=='/' ? 63 : 0 )static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,			   char **commentptr, char *passphrase,			   const char **error){#define BUFSIZE 16384    unsigned char *buf = snewn(BUFSIZE, unsigned char);    unsigned char keybuf[16];    int len;    int i, j, ciphertype;    int ret = 0;    struct MD5Context md5c;    char *comment;    *error = NULL;    /* Slurp the whole file (minus the header) into a buffer. */    len = fread(buf, 1, BUFSIZE, fp);    fclose(fp);    if (len < 0 || len == sizeof(buf)) {	*error = "error reading file";	goto end;		       /* file too big or not read */    }    i = 0;    *error = "file format error";    /*     * A zero byte. (The signature includes a terminating NUL.)     */    if (len - i < 1 || buf[i] != 0)	goto end;    i++;    /* One byte giving encryption type, and one reserved uint32. */    if (len - i < 1)	goto end;    ciphertype = buf[i];    if (ciphertype != 0 && ciphertype != SSH_CIPHER_3DES)	goto end;    i++;    if (len - i < 4)	goto end;		       /* reserved field not present */    if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0	|| buf[i + 3] != 0) goto end;  /* reserved field nonzero, panic! */    i += 4;    /* Now the serious stuff. An ordinary SSH 1 public key. */    i += makekey(buf + i, len, key, NULL, 1);    if (i < 0)	goto end;		       /* overran */    if (pub_only) {	ret = 1;	goto end;    }    /* Next, the comment field. */    j = GET_32BIT(buf + i);    i += 4;    if (len - i < j)	goto end;    comment = snewn(j + 1, char);    if (comment) {	memcpy(comment, buf + i, j);	comment[j] = '\0';    }    i += j;    if (commentptr)	*commentptr = comment;    if (key)	key->comment = comment;    if (!key) {	ret = ciphertype != 0;	*error = NULL;	goto end;    }    /*     * Decrypt remainder of buffer.     */    if (ciphertype) {	MD5Init(&md5c);	MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));	MD5Final(keybuf, &md5c);	des3_decrypt_pubkey(keybuf, buf + i, (len - i + 7) & ~7);	memset(keybuf, 0, sizeof(keybuf));	/* burn the evidence */    }    /*     * We are now in the secret part of the key. The first four     * bytes should be of the form a, b, a, b.     */    if (len - i < 4)	goto end;    if (buf[i] != buf[i + 2] || buf[i + 1] != buf[i + 3]) {	*error = "wrong passphrase";	ret = -1;	goto end;    }    i += 4;    /*     * After that, we have one further bignum which is our     * decryption exponent, and then the three auxiliary values     * (iqmp, q, p).     */    j = makeprivate(buf + i, len - i, key);    if (j < 0) goto end;    i += j;    j = ssh1_read_bignum(buf + i, len - i, &key->iqmp);    if (j < 0) goto end;    i += j;    j = ssh1_read_bignum(buf + i, len - i, &key->q);    if (j < 0) goto end;    i += j;    j = ssh1_read_bignum(buf + i, len - i, &key->p);    if (j < 0) goto end;    i += j;    if (!rsa_verify(key)) {	*error = "rsa_verify failed";	freersakey(key);	ret = 0;    } else	ret = 1;  end:    memset(buf, 0, sizeof(buf));       /* burn the evidence */    sfree(buf);    return ret;#undef BUFSIZE}int loadrsakey(const Filename *filename, struct RSAKey *key, char *passphrase,	       const char **errorstr){    FILE *fp;    char buf[64];    int ret = 0;    const char *error = NULL;    fp = f_open(*filename, "rb");    if (!fp) {	error = "can't open file";	goto end;    }    /*     * Read the first line of the file and see if it's a v1 private     * key file.     */    if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {	/*	 * This routine will take care of calling fclose() for us.	 */	ret = loadrsakey_main(fp, key, FALSE, NULL, passphrase, &error);	fp = NULL;	goto end;    }    /*     * Otherwise, we have nothing. Return empty-handed.     */    error = "not an SSH-1 RSA file";  end:    if (fp)	fclose(fp);    if ((ret != 1) && errorstr)	*errorstr = error;    return ret;}/* * See whether an RSA key is encrypted. Return its comment field as * well. */int rsakey_encrypted(const Filename *filename, char **comment){    FILE *fp;    char buf[64];    fp = f_open(*filename, "rb");    if (!fp)	return 0;		       /* doesn't even exist */    /*     * Read the first line of the file and see if it's a v1 private     * key file.     */    if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {	const char *dummy;	/*	 * This routine will take care of calling fclose() for us.	 */	return loadrsakey_main(fp, NULL, FALSE, comment, NULL, &dummy);    }    fclose(fp);    return 0;			       /* wasn't the right kind of file */}/* * Return a malloc'ed chunk of memory containing the public blob of * an RSA key, as given in the agent protocol (modulus bits, * exponent, modulus). */int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,		   const char **errorstr){    FILE *fp;    char buf[64];    struct RSAKey key;    int ret;    const char *error = NULL;    /* Default return if we fail. */    *blob = NULL;    *bloblen = 0;    ret = 0;    fp = f_open(*filename, "rb");    if (!fp) {	error = "can't open file";	goto end;    }    /*     * Read the first line of the file and see if it's a v1 private     * key file.     */    if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {	memset(&key, 0, sizeof(key));	if (loadrsakey_main(fp, &key, TRUE, NULL, NULL, &error)) {	    *blob = rsa_public_blob(&key, bloblen);	    freersakey(&key);	    ret = 1;	    fp = NULL;	}    } else {	error = "not an SSH-1 RSA file";    }  end:    if (fp)	fclose(fp);    if ((ret != 1) && errorstr)	*errorstr = error;    return ret;}/* * Save an RSA key file. Return nonzero on success. */int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase){#define BUFSIZE 16384    unsigned char *buf = snewn(BUFSIZE, unsigned char);    unsigned char keybuf[16];    struct MD5Context md5c;    unsigned 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, 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, key->iqmp);    p += ssh1_write_bignum(p, key->q);    p += ssh1_write_bignum(p, key->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, (unsigned char *)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 = f_open(*filename, "wb");    if (fp) {	int ret = (fwrite(buf, 1, p - buf, fp) == (size_t) (p - buf));	ret = ret && (fclose(fp) == 0);        sfree(buf);	return ret;    } else {        sfree(buf);	return 0;    }#undef BUFSIZE}/* ---------------------------------------------------------------------- * SSH2 private key load/store functions. *//* * PuTTY's own format for SSH2 keys is as follows: * * The file is text. Lines are terminated by CRLF, although CR-only * and LF-only are tolerated on input. * * The first line says "PuTTY-User-Key-File-2: " plus the name of the * algorithm ("ssh-dss", "ssh-rsa" etc). * * The next line says "Encryption: " plus an encryption type. * Currently the only supported encryption types are "aes256-cbc" * and "none". * * The next line says "Comment: " plus the comment string. * * Next there is a line saying "Public-Lines: " plus a number N. * The following N lines contain a base64 encoding of the public * part of the key. This is encoded as the standard SSH2 public key * blob (with no initial length): so for RSA, for example, it will * read * *    string "ssh-rsa" *    mpint  exponent *    mpint  modulus * * Next, there is a line saying "Private-Lines: " plus a number N, * and then N lines containing the (potentially encrypted) private * part of the key. For the key type "ssh-rsa", this will be * composed of * *    mpint  private_exponent *    mpint  p                  (the larger of the two primes) *    mpint  q                  (the smaller prime) *    mpint  iqmp               (the inverse of q modulo p) *    data   padding            (to reach a multiple of the cipher block size) * * And for "ssh-dss", it will be composed of * *    mpint  x                  (the private key parameter) *  [ string hash   20-byte hash of mpints p || q || g   only in old format ] *  * Finally, there is a line saying "Private-MAC: " plus a hex * representation of a HMAC-SHA-1 of: * *    string  name of algorithm ("ssh-dss", "ssh-rsa") *    string  encryption type *    string  comment *    string  public-blob *    string  private-plaintext (the plaintext version of the *                               private part, including the final *                               padding) *  * The key to the MAC is itself a SHA-1 hash of: *  *    data    "putty-private-key-file-mac-key" *    data    passphrase * * (An empty passphrase is used for unencrypted keys.) * * If the key is encrypted, the encryption key is derived from the * passphrase by means of a succession of SHA-1 hashes. Each hash * is the hash of: * *    uint32  sequence-number *    data    passphrase * * where the sequence-number increases from zero. As many of these * hashes are used as necessary. * * For backwards compatibility with snapshots between 0.51 and * 0.52, we also support the older key file format, which begins * with "PuTTY-User-Key-File-1" (version number differs). In this * format the Private-MAC: field only covers the private-plaintext * field and nothing else (and without the 4-byte string length on * the front too). Moreover, for RSA keys the Private-MAC: field * can be replaced with a Private-Hash: field which is a plain * SHA-1 hash instead of an HMAC. This is not allowable in DSA * keys. (Yes, the old format was a mess. Guess why it changed :-) */static int read_header(FILE * fp, char *header){    int len = 39;    int c;    while (len > 0) {	c = fgetc(fp);	if (c == '\n' || c == '\r' || c == EOF)	    return 0;		       /* failure */	if (c == ':') {	    c = fgetc(fp);	    if (c != ' ')		return 0;	    *header = '\0';	    return 1;		       /* success! */	}	if (len == 0)	    return 0;		       /* failure */	*header++ = c;	len--;    }    return 0;			       /* failure */}static char *read_body(FILE * fp){    char *text;    int len;    int size;    int c;    size = 128;    text = snewn(size, char);    len = 0;    text[len] = '\0';    while (1) {	c = fgetc(fp);	if (c == '\r' || c == '\n') {	    c = fgetc(fp);	    if (c != '\r' && c != '\n' && c != EOF)		ungetc(c, fp);	    return text;	}	if (c == EOF) {	    sfree(text);	    return NULL;	}	if (len + 1 > size) {	    size += 128;	    text = sresize(text, size, char);	}	text[len++] = c;	text[len] = '\0';    }}int base64_decode_atom(char *atom, unsigned char *out){    int vals[4];    int i, v, len;    unsigned word;    char c;    for (i = 0; i < 4; i++) {	c = atom[i];	if (c >= 'A' && c <= 'Z')	    v = c - 'A';	else if (c >= 'a' && c <= 'z')	    v = c - 'a' + 26;	else if (c >= '0' && c <= '9')	    v = c - '0' + 52;	else if (c == '+')	    v = 62;	else if (c == '/')	    v = 63;	else if (c == '=')	    v = -1;	else	    return 0;		       /* invalid atom */	vals[i] = v;    }    if (vals[0] == -1 || vals[1] == -1)	return 0;    if (vals[2] == -1 && vals[3] != -1)	return 0;    if (vals[3] != -1)	len = 3;    else if (vals[2] != -1)	len = 2;    else	len = 1;    word = ((vals[0] << 18) |	    (vals[1] << 12) | ((vals[2] & 0x3F) << 6) | (vals[3] & 0x3F));    out[0] = (word >> 16) & 0xFF;    if (len > 1)	out[1] = (word >> 8) & 0xFF;    if (len > 2)	out[2] = word & 0xFF;    return len;}static unsigned char *read_blob(FILE * fp, int nlines, int *bloblen){    unsigned char *blob;    char *line;    int linelen, len;    int i, j, k;    /* We expect at most 64 base64 characters, ie 48 real bytes, per line. */    blob = snewn(48 * nlines, unsigned char);    len = 0;    for (i = 0; i < nlines; i++) {	line = read_body(fp);	if (!line) {	    sfree(blob);	    return NULL;	}	linelen = strlen(line);	if (linelen % 4 != 0 || linelen > 64) {	    sfree(blob);	    sfree(line);	    return NULL;	}	for (j = 0; j < linelen; j += 4) {	    k = base64_decode_atom(line + j, blob + len);	    if (!k) {		sfree(line);		sfree(blob);		return NULL;	    }	    len += k;	}	sfree(line);    }    *bloblen = len;    return blob;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -