if (errorstr) *errorstr = error;
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,				       char *passphrase){    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;    ret = NULL;			       /* return NULL for most errors */    encryption = comment = mac = NULL;    public_blob = private_blob = NULL;    fp = f_open(*filename, "rb");    if (!fp)	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	goto error;    if ((b = read_body(fp)) == NULL)	goto error;    /* Select key algorithm structure. */    if (!strcmp(b, "ssh-rsa"))	alg = &ssh_rsa;    else if (!strcmp(b, "ssh-dss"))	alg = &ssh_dss;    else {	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 (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. */	    ret = cipher ? SSH2_WRONG_PASSPHRASE : 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;    }    sfree(public_blob);    sfree(private_blob);    sfree(encryption);    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);    return ret;}