📄 sshpubk.c
字号:
}/* * Magic error return value for when the passphrase is wrong. */const struct ssh2_userkey ssh2_wrong_passphrase = { NULL, NULL, NULL};const struct ssh_signkey *find_pubkey_alg(const char *name){ if (!strcmp(name, "ssh-rsa")) return &ssh_rsa; else if (!strcmp(name, "ssh-dss")) return &ssh_dss; else return NULL;}struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, char *passphrase, const char **errorstr){ FILE *fp; char header[40], *b, *encryption, *comment, *mac; const struct ssh_signkey *alg; struct ssh2_userkey *ret; int cipher, cipherblk; unsigned char *public_blob, *private_blob; int public_blob_len, private_blob_len; int i, is_mac, old_fmt; int passlen = passphrase ? strlen(passphrase) : 0; const char *error = NULL; ret = NULL; /* return NULL for most errors */ encryption = comment = mac = NULL; public_blob = private_blob = NULL; fp = f_open(*filename, "rb"); if (!fp) { error = "can't open file"; goto error; } /* Read the first header line which contains the key type. */ if (!read_header(fp, header)) goto error; if (0 == strcmp(header, "PuTTY-User-Key-File-2")) { old_fmt = 0; } else if (0 == strcmp(header, "PuTTY-User-Key-File-1")) { /* this is an old key file; warn and then continue */ old_keyfile_warning(); old_fmt = 1; } else { error = "not a PuTTY SSH-2 private key"; goto error; } error = "file format error"; if ((b = read_body(fp)) == NULL) goto error; /* Select key algorithm structure. */ alg = find_pubkey_alg(b); if (!alg) { sfree(b); goto error; } sfree(b); /* Read the Encryption header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Encryption")) goto error; if ((encryption = read_body(fp)) == NULL) goto error; if (!strcmp(encryption, "aes256-cbc")) { cipher = 1; cipherblk = 16; } else if (!strcmp(encryption, "none")) { cipher = 0; cipherblk = 1; } else { sfree(encryption); goto error; } /* Read the Comment header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) goto error; if ((comment = read_body(fp)) == NULL) goto error; /* Read the Public-Lines header line and the public blob. */ if (!read_header(fp, header) || 0 != strcmp(header, "Public-Lines")) goto error; if ((b = read_body(fp)) == NULL) goto error; i = atoi(b); sfree(b); if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL) goto error; /* Read the Private-Lines header line and the Private blob. */ if (!read_header(fp, header) || 0 != strcmp(header, "Private-Lines")) goto error; if ((b = read_body(fp)) == NULL) goto error; i = atoi(b); sfree(b); if ((private_blob = read_blob(fp, i, &private_blob_len)) == NULL) goto error; /* Read the Private-MAC or Private-Hash header line. */ if (!read_header(fp, header)) goto error; if (0 == strcmp(header, "Private-MAC")) { if ((mac = read_body(fp)) == NULL) goto error; is_mac = 1; } else if (0 == strcmp(header, "Private-Hash") && alg == &ssh_rsa && old_fmt) { if ((mac = read_body(fp)) == NULL) goto error; is_mac = 0; } else goto error; fclose(fp); fp = NULL; /* * Decrypt the private blob. */ if (cipher) { unsigned char key[40]; SHA_State s; if (!passphrase) goto error; if (private_blob_len % cipherblk) goto error; SHA_Init(&s); SHA_Bytes(&s, "\0\0\0\0", 4); SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, key + 0); SHA_Init(&s); SHA_Bytes(&s, "\0\0\0\1", 4); SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, key + 20); aes256_decrypt_pubkey(key, private_blob, private_blob_len); } /* * Verify the MAC. */ { char realmac[41]; unsigned char binary[20]; unsigned char *macdata; int maclen; int free_macdata; if (old_fmt) { /* MAC (or hash) only covers the private blob. */ macdata = private_blob; maclen = private_blob_len; free_macdata = 0; } else { unsigned char *p; int namelen = strlen(alg->name); int enclen = strlen(encryption); int commlen = strlen(comment); maclen = (4 + namelen + 4 + enclen + 4 + commlen + 4 + public_blob_len + 4 + private_blob_len); macdata = snewn(maclen, unsigned char); p = macdata;#define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len) DO_STR(alg->name, namelen); DO_STR(encryption, enclen); DO_STR(comment, commlen); DO_STR(public_blob, public_blob_len); DO_STR(private_blob, private_blob_len); free_macdata = 1; } if (is_mac) { SHA_State s; unsigned char mackey[20]; char header[] = "putty-private-key-file-mac-key"; SHA_Init(&s); SHA_Bytes(&s, header, sizeof(header)-1); if (cipher && passphrase) SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, mackey); hmac_sha1_simple(mackey, 20, macdata, maclen, binary); memset(mackey, 0, sizeof(mackey)); memset(&s, 0, sizeof(s)); } else { SHA_Simple(macdata, maclen, binary); } if (free_macdata) { memset(macdata, 0, maclen); sfree(macdata); } for (i = 0; i < 20; i++) sprintf(realmac + 2 * i, "%02x", binary[i]); if (strcmp(mac, realmac)) { /* An incorrect MAC is an unconditional Error if the key is * unencrypted. Otherwise, it means Wrong Passphrase. */ if (cipher) { error = "wrong passphrase"; ret = SSH2_WRONG_PASSPHRASE; } else { error = "MAC failed"; ret = NULL; } goto error; } } sfree(mac); /* * Create and return the key. */ ret = snew(struct ssh2_userkey); ret->alg = alg; ret->comment = comment; ret->data = alg->createkey(public_blob, public_blob_len, private_blob, private_blob_len); if (!ret->data) { sfree(ret->comment); sfree(ret); ret = NULL; error = "createkey failed"; goto error; } sfree(public_blob); sfree(private_blob); sfree(encryption); if (errorstr) *errorstr = NULL; return ret; /* * Error processing. */ error: if (fp) fclose(fp); if (comment) sfree(comment); if (encryption) sfree(encryption); if (mac) sfree(mac); if (public_blob) sfree(public_blob); if (private_blob) sfree(private_blob); if (errorstr) *errorstr = error; return ret;}char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm, int *pub_blob_len, const char **errorstr){ FILE *fp; char header[40], *b; const struct ssh_signkey *alg; unsigned char *public_blob; int public_blob_len; int i; const char *error = NULL; public_blob = NULL; fp = f_open(*filename, "rb"); if (!fp) { error = "can't open file"; goto error; } /* Read the first header line which contains the key type. */ if (!read_header(fp, header) || (0 != strcmp(header, "PuTTY-User-Key-File-2") && 0 != strcmp(header, "PuTTY-User-Key-File-1"))) { error = "not a PuTTY SSH-2 private key"; goto error; } error = "file format error"; if ((b = read_body(fp)) == NULL) goto error; /* Select key algorithm structure. Currently only ssh-rsa. */ alg = find_pubkey_alg(b); if (!alg) { sfree(b); goto error; } sfree(b); /* Read the Encryption header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Encryption")) goto error; if ((b = read_body(fp)) == NULL) goto error; sfree(b); /* we don't care */ /* Read the Comment header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) goto error; if ((b = read_body(fp)) == NULL) goto error; sfree(b); /* we don't care */ /* Read the Public-Lines header line and the public blob. */ if (!read_header(fp, header) || 0 != strcmp(header, "Public-Lines")) goto error; if ((b = read_body(fp)) == NULL) goto error; i = atoi(b); sfree(b); if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL) goto error; fclose(fp); if (pub_blob_len) *pub_blob_len = public_blob_len; if (algorithm) *algorithm = alg->name; return (char *)public_blob; /* * Error processing. */ error: if (fp) fclose(fp); if (public_blob) sfree(public_blob); if (errorstr) *errorstr = error; return NULL;}int ssh2_userkey_encrypted(const Filename *filename, char **commentptr){ FILE *fp; char header[40], *b, *comment; int ret; if (commentptr) *commentptr = NULL; fp = f_open(*filename, "rb"); if (!fp) return 0; if (!read_header(fp, header) || (0 != strcmp(header, "PuTTY-User-Key-File-2") && 0 != strcmp(header, "PuTTY-User-Key-File-1"))) { fclose(fp); return 0; } if ((b = read_body(fp)) == NULL) { fclose(fp); return 0; } sfree(b); /* we don't care about key type here */ /* Read the Encryption header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Encryption")) { fclose(fp); return 0; } if ((b = read_body(fp)) == NULL) { fclose(fp); return 0; } /* Read the Comment header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) { fclose(fp); sfree(b); return 1; } if ((comment = read_body(fp)) == NULL) { fclose(fp); sfree(b); return 1; } if (commentptr) *commentptr = comment; fclose(fp); if (!strcmp(b, "aes256-cbc")) ret = 1; else ret = 0; sfree(b); return ret;}int base64_lines(int datalen){ /* When encoding, we use 64 chars/line, which equals 48 real chars. */ return (datalen + 47) / 48;}void base64_encode(FILE * fp, unsigned char *data, int datalen, int cpl){ int linelen = 0; char out[4]; int n, i; while (datalen > 0) { n = (datalen < 3 ? datalen : 3); base64_encode_atom(data, n, out); data += n; datalen -= n; for (i = 0; i < 4; i++) { if (linelen >= cpl) { linelen = 0; fputc('\n', fp); } fputc(out[i], fp); linelen++; } } fputc('\n', fp);}int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, char *passphrase){ FILE *fp; unsigned char *pub_blob, *priv_blob, *priv_blob_encrypted; int pub_blob_len, priv_blob_len, priv_encrypted_len; int passlen; int cipherblk; int i; char *cipherstr; unsigned char priv_mac[20]; /* * Fetch the key component blobs. */ pub_blob = key->alg->public_blob(key->data, &pub_blob_len); priv_blob = key->alg->private_blob(key->data, &priv_blob_len); if (!pub_blob || !priv_blob) { sfree(pub_blob); sfree(priv_blob); return 0; } /* * Determine encryption details, and encrypt the private blob. */ if (passphrase) { cipherstr = "aes256-cbc"; cipherblk = 16; } else { cipherstr = "none"; cipherblk = 1; } priv_encrypted_len = priv_blob_len + cipherblk - 1; priv_encrypted_len -= priv_encrypted_len % cipherblk; priv_blob_encrypted = snewn(priv_encrypted_len, unsigned char); memset(priv_blob_encrypted, 0, priv_encrypted_len); memcpy(priv_blob_encrypted, priv_blob, priv_blob_len); /* Create padding based on the SHA hash of the unpadded blob. This prevents * too easy a known-plaintext attack on the last block. */ SHA_Simple(priv_blob, priv_blob_len, priv_mac); assert(priv_encrypted_len - priv_blob_len < 20); memcpy(priv_blob_encrypted + priv_blob_len, priv_mac, priv_encrypted_len - priv_blob_len); /* Now create the MAC. */ { unsigned char *macdata; int maclen; unsigned char *p; int namelen = strlen(key->alg->name); int enclen = strlen(cipherstr); int commlen = strlen(key->comment); SHA_State s; unsigned char mackey[20]; char header[] = "putty-private-key-file-mac-key"; maclen = (4 + namelen + 4 + enclen + 4 + commlen + 4 + pub_blob_len + 4 + priv_encrypted_len); macdata = snewn(maclen, unsigned char); p = macdata;#define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len) DO_STR(key->alg->name, namelen); DO_STR(cipherstr, enclen); DO_STR(key->comment, commlen); DO_STR(pub_blob, pub_blob_len); DO_STR(priv_blob_encrypted, priv_encrypted_len); SHA_Init(&s); SHA_Bytes(&s, header, sizeof(header)-1); if (passphrase) SHA_Bytes(&s, passphrase, strlen(passphrase)); SHA_Final(&s, mackey); hmac_sha1_simple(mackey, 20, macdata, maclen, priv_mac); memset(macdata, 0, maclen); sfree(macdata); memset(mackey, 0, sizeof(mackey)); memset(&s, 0, sizeof(s)); } if (passphrase) { unsigned char key[40]; SHA_State s; passlen = strlen(passphrase); SHA_Init(&s); SHA_Bytes(&s, "\0\0\0\0", 4); SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, key + 0); SHA_Init(&s); SHA_Bytes(&s, "\0\0\0\1", 4); SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, key + 20); aes256_encrypt_pubkey(key, priv_blob_encrypted, priv_encrypted_len); memset(key, 0, sizeof(key)); memset(&s, 0, sizeof(s)); } fp = f_open(*filename, "w"); if (!fp) return 0; fprintf(fp, "PuTTY-User-Key-File-2: %s\n", key->alg->name); fprintf(fp, "Encryption: %s\n", cipherstr); fprintf(fp, "Comment: %s\n", key->comment); fprintf(fp, "Public-Lines: %d\n", base64_lines(pub_blob_len)); base64_encode(fp, pub_blob, pub_blob_len, 64); fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len)); base64_encode(fp, priv_blob_encrypted, priv_encrypted_len, 64); fprintf(fp, "Private-MAC: "); for (i = 0; i < 20; i++) fprintf(fp, "%02x", priv_mac[i]); fprintf(fp, "\n"); fclose(fp); sfree(pub_blob); memset(priv_blob, 0, priv_blob_len); sfree(priv_blob); sfree(priv_blob_encrypted); return 1;}/* ---------------------------------------------------------------------- * A function to determine the type of a private key file. Returns * 0 on failure, 1 or 2 on success. */int key_type(const Filename *filename){ FILE *fp; char buf[32]; const char putty2_sig[] = "PuTTY-User-Key-File-"; const char sshcom_sig[] = "---- BEGIN SSH2 ENCRYPTED PRIVAT"; const char openssh_sig[] = "-----BEGIN "; int i; fp = f_open(*filename, "r"); if (!fp) return SSH_KEYTYPE_UNOPENABLE; i = fread(buf, 1, sizeof(buf), fp); fclose(fp); if (i < 0) return SSH_KEYTYPE_UNOPENABLE; if (i < 32) return SSH_KEYTYPE_UNKNOWN; if (!memcmp(buf, rsa_signature, sizeof(rsa_signature)-1)) return SSH_KEYTYPE_SSH1; if (!memcmp(buf, putty2_sig, sizeof(putty2_sig)-1)) return SSH_KEYTYPE_SSH2; if (!memcmp(buf, openssh_sig, sizeof(openssh_sig)-1)) return SSH_KEYTYPE_OPENSSH; if (!memcmp(buf, sshcom_sig, sizeof(sshcom_sig)-1)) return SSH_KEYTYPE_SSHCOM; return SSH_KEYTYPE_UNKNOWN; /* unrecognised or EOF */}/* * Convert the type word to a string, for `wrong type' error * messages. */char *key_type_to_str(int type){ switch (type) { case SSH_KEYTYPE_UNOPENABLE: return "unable to open file"; break; case SSH_KEYTYPE_UNKNOWN: return "not a private key"; break; case SSH_KEYTYPE_SSH1: return "SSH1 private key"; break; case SSH_KEYTYPE_SSH2: return "PuTTY SSH2 private key"; break; case SSH_KEYTYPE_OPENSSH: return "OpenSSH SSH2 private key"; break; case SSH_KEYTYPE_SSHCOM: return "ssh.com SSH2 private key"; break; default: return "INTERNAL ERROR"; break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -