📄 sshpubk.c
字号:
}
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 + -