为什么 OpenSSL 生成的 ECDSA public 密钥与 DNS 服务器生成的 DNSKEY 不匹配?
Why ECDSA public key generated by OpenSSL doesn't match DNSKEY generated by DNS server?
我正在尝试从 DNSSEC 算法 13 (ECDSAP256SHA256) 的已知私钥中获取 public 密钥。我用了这个例子:
我的密钥修改如下:
// using figures on: https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
// gcc -Wall ecdsapubkey.c -o ecdsapubkey -lcrypto
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
int main()
{
EC_KEY *eckey = NULL;
EC_POINT *pub_key = NULL;
const EC_GROUP *group = NULL;
BIGNUM start;
BIGNUM *res;
BN_CTX *ctx;
BN_init(&start);
ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required
res = &start;
BN_hex2bn(&res,"589c51d2b528a99c1d19702f865284ec09e3e080606ddc3f56f0906268fd25e3");
eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
group = EC_KEY_get0_group(eckey);
pub_key = EC_POINT_new(group);
EC_KEY_set_private_key(eckey, res);
/* pub_key is a new uninitialized `EC_POINT*`. priv_key res is a `BIGNUM*`. */
if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
printf("Error at EC_POINT_mul.\n");
EC_KEY_set_public_key(eckey, pub_key);
char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);
printf("%s", cc);
BN_CTX_free(ctx);
free(cc);
return 0;
}
正在尝试:
$ gcc -lcrypto t.c
$ ./a.out | perl -e 'print pack "H*", <>' | base64
BDdZbz79hEKFi9bIlExzZEqPQVhNqcjJqaWSWnoBTYn21XEL7y4YQXnB8N4JWAy33inTD1CyEI20
TusbH6MSxyc=
这是我在 DNS 服务器 (PowerDNS) 中的内容:
Private-key-format: v1.2
Algorithm: 13 (ECDSAP256SHA256)
PrivateKey: WJxR0rUoqZwdGXAvhlKE7Anj4IBgbdw/VvCQYmj9JeM=
获取 DNSKEY 记录:
$ dig @127.0.0.1 +short example.com DNSKEY
257 3 13 JELaKnxPV49rnxShsHbS8MX9rfJZcpRKgqCHUn1WYyDLcXGDYYEQ8soL I9OLVJFN5Gn/4TjXF6g0T1IEBsuFew==
而且它与我通过 OpenSSL 获得的密钥完全不匹配。为什么?
我没有考虑到的主要事情是这个密钥有不同的长度:从 openssl 返回的二进制格式的密钥是 65 字节长,而来自 DNS 服务器的密钥是 64 字节长。如果我在十六进制编辑器中查看两个键的二进制表示,我可以看到它们只是第一个字节不同。可以在此处找到更详细的解释:
所以,这段C代码可以这样重写(还有一点是使用了不正确的曲线,应该是NID_X9_62_prime256v1):
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
int main()
{
EC_KEY *eckey = NULL;
EC_POINT *pub_key = NULL;
const EC_GROUP *group = NULL;
BIGNUM start;
BIGNUM *res;
BN_CTX *ctx;
BN_init(&start);
ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required
res = &start;
BN_hex2bn(&res,"589c51d2b528a99c1d19702f865284ec09e3e080606ddc3f56f0906268fd25e3");
eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
group = EC_KEY_get0_group(eckey);
pub_key = EC_POINT_new(group);
EC_KEY_set_private_key(eckey, res);
/* pub_key is a new uninitialized `EC_POINT*`. priv_key res is a `BIGNUM*`. */
if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
printf("Error at EC_POINT_mul.\n");
EC_KEY_set_public_key(eckey, pub_key);
char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);
printf("%s", cc+2);
BN_CTX_free(ctx);
free(cc);
return 0;
}
现在匹配:
$ ./a.out | perl -e 'print pack "H*", <>' | base64
JELaKnxPV49rnxShsHbS8MX9rfJZcpRKgqCHUn1WYyDLcXGDYYEQ8soLI9OLVJFN5Gn/4TjXF6g0
T1IEBsuFew==
我正在尝试从 DNSSEC 算法 13 (ECDSAP256SHA256) 的已知私钥中获取 public 密钥。我用了这个例子:
我的密钥修改如下:
// using figures on: https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
// gcc -Wall ecdsapubkey.c -o ecdsapubkey -lcrypto
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
int main()
{
EC_KEY *eckey = NULL;
EC_POINT *pub_key = NULL;
const EC_GROUP *group = NULL;
BIGNUM start;
BIGNUM *res;
BN_CTX *ctx;
BN_init(&start);
ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required
res = &start;
BN_hex2bn(&res,"589c51d2b528a99c1d19702f865284ec09e3e080606ddc3f56f0906268fd25e3");
eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
group = EC_KEY_get0_group(eckey);
pub_key = EC_POINT_new(group);
EC_KEY_set_private_key(eckey, res);
/* pub_key is a new uninitialized `EC_POINT*`. priv_key res is a `BIGNUM*`. */
if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
printf("Error at EC_POINT_mul.\n");
EC_KEY_set_public_key(eckey, pub_key);
char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);
printf("%s", cc);
BN_CTX_free(ctx);
free(cc);
return 0;
}
正在尝试:
$ gcc -lcrypto t.c
$ ./a.out | perl -e 'print pack "H*", <>' | base64
BDdZbz79hEKFi9bIlExzZEqPQVhNqcjJqaWSWnoBTYn21XEL7y4YQXnB8N4JWAy33inTD1CyEI20
TusbH6MSxyc=
这是我在 DNS 服务器 (PowerDNS) 中的内容:
Private-key-format: v1.2
Algorithm: 13 (ECDSAP256SHA256)
PrivateKey: WJxR0rUoqZwdGXAvhlKE7Anj4IBgbdw/VvCQYmj9JeM=
获取 DNSKEY 记录:
$ dig @127.0.0.1 +short example.com DNSKEY
257 3 13 JELaKnxPV49rnxShsHbS8MX9rfJZcpRKgqCHUn1WYyDLcXGDYYEQ8soL I9OLVJFN5Gn/4TjXF6g0T1IEBsuFew==
而且它与我通过 OpenSSL 获得的密钥完全不匹配。为什么?
我没有考虑到的主要事情是这个密钥有不同的长度:从 openssl 返回的二进制格式的密钥是 65 字节长,而来自 DNS 服务器的密钥是 64 字节长。如果我在十六进制编辑器中查看两个键的二进制表示,我可以看到它们只是第一个字节不同。可以在此处找到更详细的解释:
所以,这段C代码可以这样重写(还有一点是使用了不正确的曲线,应该是NID_X9_62_prime256v1):
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
int main()
{
EC_KEY *eckey = NULL;
EC_POINT *pub_key = NULL;
const EC_GROUP *group = NULL;
BIGNUM start;
BIGNUM *res;
BN_CTX *ctx;
BN_init(&start);
ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required
res = &start;
BN_hex2bn(&res,"589c51d2b528a99c1d19702f865284ec09e3e080606ddc3f56f0906268fd25e3");
eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
group = EC_KEY_get0_group(eckey);
pub_key = EC_POINT_new(group);
EC_KEY_set_private_key(eckey, res);
/* pub_key is a new uninitialized `EC_POINT*`. priv_key res is a `BIGNUM*`. */
if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
printf("Error at EC_POINT_mul.\n");
EC_KEY_set_public_key(eckey, pub_key);
char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);
printf("%s", cc+2);
BN_CTX_free(ctx);
free(cc);
return 0;
}
现在匹配:
$ ./a.out | perl -e 'print pack "H*", <>' | base64
JELaKnxPV49rnxShsHbS8MX9rfJZcpRKgqCHUn1WYyDLcXGDYYEQ8soLI9OLVJFN5Gn/4TjXF6g0
T1IEBsuFew==