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

📄 sshpubk.c

📁 一个支持FTP,SFTP的客户端程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	}

	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 + -