How to generate ECDSA private and public key for D

2019-05-23 09:02发布

I am trying to create private and public keys for DNSSEC algorithm 13:

#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;
     const EC_POINT *pub_key = NULL;
     const EC_GROUP *group = NULL;
     const BIGNUM *res;
     BN_CTX *ctx;

     ctx = BN_CTX_new();

     eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
     EC_KEY_generate_key(eckey);

     res = EC_KEY_get0_private_key(eckey);
     printf("Private: %s\n", BN_bn2hex(res));

     group = EC_KEY_get0_group(eckey);
     pub_key  = EC_KEY_get0_public_key(eckey);
     printf("Public: %s\n", EC_POINT_point2hex(group, pub_key, 4, ctx));

     return 0;
}

Testing:

$ gcc -lcrypto test.c
$ ./a.out | perl -MMIME::Base64 -pe 's/(?<=:\s)(.+)/encode_base64(pack "H*", $1)/e'
Private: PgO6atAv+YEuyvRvvuTyDf8kz7vp/hQKNdKJyvVVBoQ=

Public: BAPe3AhjpcMCQPpZzZeFRwVuR4su/cmd3Vl2zn+i2izEWxOdbww/3fw4yAi0yQUUhlvXZqTnaeol
OK03LOdsKkk=

(Perl line just converts hex notation to binary and then to base64.)

But if I set this private key to DNS server (which accepts only private key and generates public on the fly) it returns public key which doesn't match this one returned by OpenSSL

Key inside DNS server (PowerDNS):
Private-key-format: v1.2
Algorithm: 13 (ECDSAP256SHA256)
PrivateKey: PgO6atAv+YEuyvRvvuTyDf8kz7vp/hQKNdKJyvVVBoQ=

$ dig @127.0.0.1 +short example.com DNSKEY
257 3 13 A97cCGOlwwJA+lnNl4VHBW5Hiy79yZ3dWXbOf6LaLMRbE51vDD/d/DjI CLTJBRSGW9dmpOdp6iU4rTcs52wqSQ==

So, I got A97cCGOlwwJA+lnNl4VHBW5Hiy79yZ3dWXbOf6LaLMRbE51vDD/d/DjI CLTJBRSGW9dmpOdp6iU4rTcs52wqSQ== which doesn't match BAPe3AhjpcMCQPpZzZeFRwVuR4su/cmd3Vl2zn+i2izEWxOdbww/3fw4yAi0yQUUhlvXZqTnaeol OK03LOdsKkk=.

Why this happened?

1条回答
你好瞎i
2楼-- · 2019-05-23 09:40

The two values are actually the same, except that OpenSSL adds a 0x04 prefix byte. This is a standard format, the 0x04 indicates that the point is in uncompressed form, it is followed by 32 bytes of the X coordinate of the point and then 32 bytes for the Y coordinate, for 65 bytes total.

The DNS entry just has the X and Y coordinates, without the prefix byte, for 64 bytes total.

Since this extra byte is the first byte, it changes the alignment of the base 64 encoding and the two encoded values look quite different.

Comparing the values, first your value from OpenSSL:

$ echo BAPe3AhjpcMCQPpZzZeFRwVuR4su/cmd3Vl2zn+i2izEWxOdbww/3fw4yAi0yQUUhlvXZqTnaeolOK03LOdsKkk= | base64 -D | xxd
00000000: 0403 dedc 0863 a5c3 0240 fa59 cd97 8547  .....c...@.Y...G
00000010: 056e 478b 2efd c99d dd59 76ce 7fa2 da2c  .nG......Yv....,
00000020: c45b 139d 6f0c 3fdd fc38 c808 b4c9 0514  .[..o.?..8......
00000030: 865b d766 a4e7 69ea 2538 ad37 2ce7 6c2a  .[.f..i.%8.7,.l*
00000040: 49

Next the value from DNS:

echo A97cCGOlwwJA+lnNl4VHBW5Hiy79yZ3dWXbOf6LaLMRbE51vDD/d/DjICLTJBRSGW9dmpOdp6iU4rTcs52wqSQ== | base64 -D | xxd
00000000: 03de dc08 63a5 c302 40fa 59cd 9785 4705  ....c...@.Y...G.
00000010: 6e47 8b2e fdc9 9ffffd 5976 ce7f a2da 2cc4  nG......Yv....,.
00000020: 5b13 9d6f 0c3f ddfc 38c8 08b4 c905 1486  [..o.?..8.......
00000030: 5bd7 66a4 e769 ea25 38ad 372c e76c 2a49  [.f..i.%8.7,.l*I

You can see that except for the extra 0x04 the two values are the same.

查看更多
登录 后发表回答