📄 import.c
字号:
errmsg = "Key blob does not contain a key type string";
goto error;
}
if (len > sizeof(prefix_rsa) - 1 &&
!memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
type = RSA;
} else if (len > sizeof(prefix_dsa) - 1 &&
!memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
type = DSA;
} else {
errmsg = "Key is of unknown type";
goto error;
}
pos += 4+len;
/*
* Determine the cipher type.
*/
if (key->keyblob_len < pos+4 ||
(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
errmsg = "Key blob does not contain a cipher type string";
goto error;
}
if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
encrypted = 0;
else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
encrypted = 1;
else {
errmsg = "Key encryption is of unknown type";
goto error;
}
pos += 4+len;
/*
* Get hold of the encrypted part of the key.
*/
if (key->keyblob_len < pos+4 ||
(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
errmsg = "Key blob does not contain actual key data";
goto error;
}
ciphertext = (char *)key->keyblob + pos + 4;
cipherlen = len;
if (cipherlen == 0) {
errmsg = "Length of key data is zero";
goto error;
}
/*
* Decrypt it if necessary.
*/
if (encrypted) {
/*
* Derive encryption key from passphrase and iv/salt:
*
* - let block A equal MD5(passphrase)
* - let block B equal MD5(passphrase || A)
* - block C would be MD5(passphrase || A || B) and so on
* - encryption key is the first N bytes of A || B
*/
struct MD5Context md5c;
unsigned char keybuf[32], iv[8];
if (cipherlen % 8 != 0) {
errmsg = "Encrypted part of key is not a multiple of cipher block"
" size";
goto error;
}
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
MD5Final(keybuf, &md5c);
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
MD5Update(&md5c, keybuf, 16);
MD5Final(keybuf+16, &md5c);
/*
* Now decrypt the key blob.
*/
memset(iv, 0, sizeof(iv));
des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
cipherlen);
memset(&md5c, 0, sizeof(md5c));
memset(keybuf, 0, sizeof(keybuf));
/*
* Hereafter we return WRONG_PASSPHRASE for any parsing
* error. (But only if we've just tried to decrypt it!
* Returning WRONG_PASSPHRASE for an unencrypted key is
* automatic doom.)
*/
if (encrypted)
ret = SSH2_WRONG_PASSPHRASE;
}
/*
* Strip away the containing string to get to the real meat.
*/
len = GET_32BIT(ciphertext);
if (len < 0 || len > cipherlen-4) {
errmsg = "containing string was ill-formed";
goto error;
}
ciphertext += 4;
cipherlen = len;
/*
* Now we break down into RSA versus DSA. In either case we'll
* construct public and private blobs in our own format, and
* end up feeding them to alg->createkey().
*/
blobsize = cipherlen + 256;
blob = snewn(blobsize, unsigned char);
privlen = 0;
if (type == RSA) {
struct mpint_pos n, e, d, u, p, q;
int pos = 0;
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
if (!q.start) {
errmsg = "key data did not contain six integers";
goto error;
}
alg = &ssh_rsa;
pos = 0;
pos += put_string(blob+pos, "ssh-rsa", 7);
pos += put_mp(blob+pos, e.start, e.bytes);
pos += put_mp(blob+pos, n.start, n.bytes);
publen = pos;
pos += put_string(blob+pos, d.start, d.bytes);
pos += put_mp(blob+pos, q.start, q.bytes);
pos += put_mp(blob+pos, p.start, p.bytes);
pos += put_mp(blob+pos, u.start, u.bytes);
privlen = pos - publen;
} else if (type == DSA) {
struct mpint_pos p, q, g, x, y;
int pos = 4;
if (GET_32BIT(ciphertext) != 0) {
errmsg = "predefined DSA parameters not supported";
goto error;
}
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
if (!x.start) {
errmsg = "key data did not contain five integers";
goto error;
}
alg = &ssh_dss;
pos = 0;
pos += put_string(blob+pos, "ssh-dss", 7);
pos += put_mp(blob+pos, p.start, p.bytes);
pos += put_mp(blob+pos, q.start, q.bytes);
pos += put_mp(blob+pos, g.start, g.bytes);
pos += put_mp(blob+pos, y.start, y.bytes);
publen = pos;
pos += put_mp(blob+pos, x.start, x.bytes);
privlen = pos - publen;
} else
return NULL;
assert(privlen > 0); /* should have bombed by now if not */
retkey = snew(struct ssh2_userkey);
retkey->alg = alg;
retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
if (!retkey->data) {
sfree(retkey);
errmsg = "unable to create key data structure";
goto error;
}
retkey->comment = dupstr(key->comment);
errmsg = NULL; /* no error */
ret = retkey;
error:
if (blob) {
memset(blob, 0, blobsize);
sfree(blob);
}
memset(key->keyblob, 0, key->keyblob_size);
sfree(key->keyblob);
memset(&key, 0, sizeof(key));
sfree(key);
return ret;
}
int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
char *passphrase)
{
unsigned char *pubblob, *privblob;
int publen, privlen;
unsigned char *outblob;
int outlen;
struct mpint_pos numbers[6];
int nnumbers, initial_zero, pos, lenpos, i;
char *type;
char *ciphertext;
int cipherlen;
int ret = 0;
FILE *fp;
/*
* Fetch the key blobs.
*/
pubblob = key->alg->public_blob(key->data, &publen);
privblob = key->alg->private_blob(key->data, &privlen);
outblob = NULL;
/*
* Find the sequence of integers to be encoded into the OpenSSH
* key blob, and also decide on the header line.
*/
if (key->alg == &ssh_rsa) {
int pos;
struct mpint_pos n, e, d, p, q, iqmp;
pos = 4 + GET_32BIT(pubblob);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
assert(e.start && iqmp.start); /* can't go wrong */
numbers[0] = e;
numbers[1] = d;
numbers[2] = n;
numbers[3] = iqmp;
numbers[4] = q;
numbers[5] = p;
nnumbers = 6;
initial_zero = 0;
type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
} else if (key->alg == &ssh_dss) {
int pos;
struct mpint_pos p, q, g, y, x;
pos = 4 + GET_32BIT(pubblob);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
assert(y.start && x.start); /* can't go wrong */
numbers[0] = p;
numbers[1] = g;
numbers[2] = q;
numbers[3] = y;
numbers[4] = x;
nnumbers = 5;
initial_zero = 1;
type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
} else {
assert(0); /* zoinks! */
}
/*
* Total size of key blob will be somewhere under 512 plus
* combined length of integers. We'll calculate the more
* precise size as we construct the blob.
*/
outlen = 512;
for (i = 0; i < nnumbers; i++)
outlen += 4 + numbers[i].bytes;
outblob = snewn(outlen, unsigned char);
/*
* Create the unencrypted key blob.
*/
pos = 0;
PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4;
pos += 4; /* length field, fill in later */
pos += put_string(outblob+pos, type, strlen(type));
{
char *ciphertype = passphrase ? "3des-cbc" : "none";
pos += put_string(outblob+pos, ciphertype, strlen(ciphertype));
}
lenpos = pos; /* remember this position */
pos += 4; /* encrypted-blob size */
pos += 4; /* encrypted-payload size */
if (initial_zero) {
PUT_32BIT(outblob+pos, 0);
pos += 4;
}
for (i = 0; i < nnumbers; i++)
pos += sshcom_put_mpint(outblob+pos,
numbers[i].start, numbers[i].bytes);
/* Now wrap up the encrypted payload. */
PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8));
/* Pad encrypted blob to a multiple of cipher block size. */
if (passphrase) {
int padding = -(pos - (lenpos+4)) & 7;
while (padding--)
outblob[pos++] = random_byte();
}
ciphertext = (char *)outblob+lenpos+4;
cipherlen = pos - (lenpos+4);
assert(!passphrase || cipherlen % 8 == 0);
/* Wrap up the encrypted blob string. */
PUT_32BIT(outblob+lenpos, cipherlen);
/* And finally fill in the total length field. */
PUT_32BIT(outblob+4, pos);
assert(pos < outlen);
/*
* Encrypt the key.
*/
if (passphrase) {
/*
* Derive encryption key from passphrase and iv/salt:
*
* - let block A equal MD5(passphrase)
* - let block B equal MD5(passphrase || A)
* - block C would be MD5(passphrase || A || B) and so on
* - encryption key is the first N bytes of A || B
*/
struct MD5Context md5c;
unsigned char keybuf[32], iv[8];
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
MD5Final(keybuf, &md5c);
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
MD5Update(&md5c, keybuf, 16);
MD5Final(keybuf+16, &md5c);
/*
* Now decrypt the key blob.
*/
memset(iv, 0, sizeof(iv));
des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
cipherlen);
memset(&md5c, 0, sizeof(md5c));
memset(keybuf, 0, sizeof(keybuf));
}
/*
* And save it. We'll use Unix line endings just in case it's
* subsequently transferred in binary mode.
*/
fp = f_open(*filename, "wb"); /* ensure Unix line endings */
if (!fp)
goto error;
fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
fprintf(fp, "Comment: \"");
/*
* Comment header is broken with backslash-newline if it goes
* over 70 chars. Although it's surrounded by quotes, it
* _doesn't_ escape backslashes or quotes within the string.
* Don't ask me, I didn't design it.
*/
{
int slen = 60; /* starts at 60 due to "Comment: " */
char *c = key->comment;
while ((int)strlen(c) > slen) {
fprintf(fp, "%.*s\\\n", slen, c);
c += slen;
slen = 70; /* allow 70 chars on subsequent lines */
}
fprintf(fp, "%s\"\n", c);
}
base64_encode(fp, outblob, pos, 70);
fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
fclose(fp);
ret = 1;
error:
if (outblob) {
memset(outblob, 0, outlen);
sfree(outblob);
}
if (privblob) {
memset(privblob, 0, privlen);
sfree(privblob);
}
if (pubblob) {
memset(pubblob, 0, publen);
sfree(pubblob);
}
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -