Экспорт EC_POINT с использованием point2hex в ASN1.DER и воссоздание с Java в качестве X.509 - PullRequest
0 голосов
/ 01 марта 2019

Я генерирую пару ключей ECDSA Prime256, используя OpenSSL с C ++, и пытаюсь импортировать шестнадцатеричную версию открытого ключа, используя Java.Я передаю байтовый массив, полученный из C ++, следующей функции в java, которая ожидает, что байтовый массив будет в кодированном формате X.509.

public static PublicKey getPublicKey(byte[] pk) throws NoSuchAlgorithmException, InvalidKeySpecException {
    EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pk);
    KeyFactory kf = KeyFactory.getInstance(Constant.KEY_FACTORY_TYPE);
    PublicKey pub = kf.generatePublic(publicKeySpec);
    return pub;
}

Я создаю пару ключей эллиптической кривой, используя следующую функциюкоторый повторяет EC_KEY*

EC_KEY* generate_keypair() {
    EC_KEY *eckey = EC_KEY_new();
    EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
    EC_KEY_set_group(eckey, ecgroup);
    EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
    int kpGenerationStatus = EC_KEY_generate_key(eckey);
    if (kpGenerationStatus) {
        return eckey;
    }
    return nullptr;
}

Учитывая пару ключей, возвращенную вышеописанной функцией, я хочу экспортировать открытый ключ в формат ASN1.DER, который можно импортировать с помощью метода java, описанного выше.

Я преобразую открытый ключ типа EC_POINT* в его шестнадцатеричную форму, используя EC_POINT_point2hex(), выполнив следующее:

EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY *keypair = generate_keypair();
char *result = NULL;
BN_CTX *ctx;
ctx = BN_CTX_new();
const EC_POINT *pub = EC_KEY_get0_public_key(keypair);
result = EC_POINT_point2hex(ecgroup, pub, POINT_CONVERSION_UNCOMPRESSED, ctx);
printf("%s\n", result);

, который возвращает следующее: 04F588CD1D7103A993D47E53D58C3F40BE8F570604CF2EA01A7657C1423EB19C51BC379F0BEE1FAA60BB9A07DE73EA9BEF7709C1C6429D4051B44F73A458FFB80D

Когда я проверяю это с помощью ASN.1 декодера , я вижу сообщение, которое говорит Length over 48 bits not supported at position 1 и пытается импортировать его, используя метод java, я получаю сообщение об ошибке:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): Should use short form for length

Есть ли что-то, чего мне не хватает при экспорте открытого ключа из EC_POINT * в закодированную шестнадцатеричную строку X.509, которую я могу импортировать для проверки любых подписей?

1 Ответ

0 голосов
/ 08 марта 2019

Вы идете в неправильном направлении, так как вы хотите значение ASN1 base64.

EC_POINT_point2hex преобразует значение внутреннего открытого ключа в шестнадцатеричное.Он не в формате ASN1.

Вы можете создать то, что вы хотите, из командной строки следующим образом:

  1. Создать закрытый ключ EC: openssl ecparam -name prime256v1 -genkey -noout -outkey.pem
  2. Дополнительный открытый ключ в формате DER (ASN1): openssl ec -in key.pem -pubout -outform der -out public.cer
  3. Преобразовать в base64 openssl base64 -in.\ public.cer

Если вы возьмете этот вывод и вставите его в ссылку декодера ASN.1, он будет работать нормально.

Теперь, чтобы превратить это в код, у вас есть генерация ключа EC, но вам нужны следующие шаги:

  1. Создать открытый ключ в формате ASN1
  2. Преобразовать его в base64

Чтобы создать открытый ключ в формате ASN1вы хотите использовать набор методов i2d_EC_PUBKEY и затем преобразовать в base64 с использованием фильтра BIO_f_base64 .

Так вот примерная проблема, которая возникает, когда я копирую вывод в ASN.1 ссылка на декодер работает нормально.

#include <openssl/bio.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/x509.h>

EC_KEY* generate_keypair() {
    EC_KEY *eckey = EC_KEY_new();
    EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
    EC_KEY_set_group(eckey, ecgroup);
    EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
    int kpGenerationStatus = EC_KEY_generate_key(eckey);
    if (kpGenerationStatus) {
        return eckey;
    }
    return nullptr;
}

int main()
{
    EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
    EC_KEY *keypair = generate_keypair();
    BIO* out = BIO_new(BIO_s_mem());
    BIO* b64 = BIO_new(BIO_f_base64());
    BIO_push(b64, out);

    i2d_EC_PUBKEY_bio(b64, keypair);

    BIO_flush(b64);


    // do what you want this the output in out memory BIO

    char* p;
    long length = BIO_get_mem_data(out, &p);

    // ensure null terminated but copying the buffer into a string to output...
    puts(std::string(p, length).c_str());

    BIO_free_all(out);
}

Не могу завершитьJava, но если он работает со строкой base64, сгенерированной вручную openssl, он будет работать с примером приложения.

...