我希望能够生成与“ssh-keygen -t ecdsa”相同的公钥字符串。我有一个EC_KEY。
我尝试使用:
PEM_write_bio_EC_PUBKEY(bio_out, ecdsa);
...但是我得到的字符串太大了。
我试过了:
ec_group = EC_KEY_get0_group(pubkey->ecdsa);
ec_point = EC_KEY_get0_public_key(pubkey->ecdsa);
encoded = EC_POINT_point2hex(
ec_group,
ec_point,
POINT_CONVERSION_UNCOMPRESSED,
NULL);
......但显然我想要一些base64编码的东西。
有人可以指点我吗?
答案 0 :(得分:1)
@noloader提醒我,我可以查看ssh-keygen.c。
这是我发现的。
所有密钥类型(rsa,dsa,ecdsa)都会调用它:
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
if (n > 0) {
fprintf(f, "%s %s", key_ssh_name(key), uu);
success = 1;
}
key_to_blob()最终导致to_blob():
to_blob(const Key *key, u_char **blobp, u_int *lenp, int force_plain)
{
Buffer b;
int len, type;
if (blobp != NULL)
*blobp = NULL;
if (lenp != NULL)
*lenp = 0;
if (key == NULL) {
error("key_to_blob: key == NULL");
return 0;
}
buffer_init(&b);
type = force_plain ? key_type_plain(key->type) : key->type;
switch (type) {
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_RSA_CERT:
case KEY_ED25519_CERT:
/* Use the existing blob */
buffer_append(&b, buffer_ptr(&key->cert->certblob),
buffer_len(&key->cert->certblob));
最终会导致这种情况:
buffer_clear(&k->cert->certblob);
buffer_put_cstring(&k->cert->certblob, key_ssh_name(k));
/* -v01 certs put nonce first */
arc4random_buf(&nonce, sizeof(nonce));
if (!key_cert_is_legacy(k))
buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
/* XXX this substantially duplicates to_blob(); refactor */
switch (k->type) {
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT:
buffer_put_bignum2(&k->cert->certblob, k->dsa->p);
buffer_put_bignum2(&k->cert->certblob, k->dsa->q);
buffer_put_bignum2(&k->cert->certblob, k->dsa->g);
buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key);
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_CERT:
buffer_put_cstring(&k->cert->certblob,
key_curve_nid_to_name(k->ecdsa_nid));
buffer_put_ecpoint(&k->cert->certblob,
EC_KEY_get0_group(k->ecdsa),
EC_KEY_get0_public_key(k->ecdsa));
break;
#endif
最终导致这个(2):
int
buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
const EC_POINT *point)
{
u_char *buf = NULL;
size_t len;
BN_CTX *bnctx;
int ret = -1;
/* Determine length */
if ((bnctx = BN_CTX_new()) == NULL)
fatal("%s: BN_CTX_new failed", __func__);
len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
NULL, 0, bnctx);
if (len > BUFFER_MAX_ECPOINT_LEN) {
error("%s: giant EC point: len = %lu (max %u)",
__func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
goto out;
}
/* Convert */
buf = xmalloc(len);
if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
buf, len, bnctx) != len) {
error("%s: EC_POINT_point2oct length mismatch", __func__);
goto out;
}
/* Append */
buffer_put_string(buffer, buf, len);
ret = 0;
out:
if (buf != NULL) {
bzero(buf, len);
free(buf);
}
BN_CTX_free(bnctx);
return ret;
}
这里构建了实际的字符串:
buf = xmalloc(len);
if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
buf, len, bnctx) != len) {
error("%s: EC_POINT_point2oct length mismatch", __func__);
goto out;
}
/* Append */
buffer_put_string(buffer, buf, len);
以下内容用于呈现"八位字符串" ( bnctx 应该被允许为NULL):
EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED, buf, len, bnctx);
答案 1 :(得分:1)
事实证明,公钥字符串是PKCS8。在命令行,您可以使用 OpenSSL从OpenSSL ECDSA转换为OpenSSH :
$ openssl ecparam -genkey -name prime256v1 -noout -out prime256v1.key.pem
$ openssl ec -in prime256v1.key.pem -pubout | ssh-keygen -f /dev/stdin -i -m PKCS8
read EC key
writing EC key
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC3FrhznL2pQ/titzgnWrbznR3ve2eNEgevog/aS7SszS9Vkq0uFefavBF4M2Txc34sIQ5TPiZxYdm9uO1siXSw=
只需找到您正在使用的语言的PKCS8库。对于Python,看起来PyCrypto和Paramiko都支持它,基于这个要点:https://gist.github.com/jtriley/7270594
首先,这个:
sha1digest = hashlib.sha1(k.exportKey('DER', pkcs=8)).hexdigest()
exportKey 包含以下内容:
if use_pycrypto:
key = RSA.importKey(key_fobj, passphrase=passphrase)
else:
key = paramiko.RSAKey.from_private_key(key_fobj,
password=passphrase)
答案 2 :(得分:0)
我希望能够生成与“ssh-keygen -t ecdsa”相同的公钥字符串。
您可以使用id_ecdsa
编写私钥(PEM_write_ECPrivateKey
)。快速搜索来源:
$ grep -R PrivateKey *
...
ssh-keygen.c: ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL,
ssh-keygen.c: ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL,
ssh-keygen.c: ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL,
但是,我不相信OpenSSL会以您期望的格式字符串写出“公钥字符串”(id_ecdsa.pub
):
$ cat id_ecdsa.pub
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz
dHAyNTYAAABBBEs/aVnJ16NcSOTGVNbk8ifPvPbZ0Edxd7uclo/5chC81MK7
iFb/++6parCUv0FBh47MBxV+k4rxGJ1OESe4Vxs= jwalton@debian-q500
这是因为OpenSSL缺少应用SSH格式的功能。 OpenSSL仅处理DER和PEM编码,而不处理SSH编码。
为了完整性,可以调用PEM_write_EC_PUBKEY
,但PEM格式不包括序言(如ecdsa-sha2-nistp256
)或结尾(如电子邮件地址)。