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?
The two values are actually the same, except that OpenSSL adds a
0x04
prefix byte. This is a standard format, the0x04
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:
Next the value from DNS:
You can see that except for the extra
0x04
the two values are the same.