La valeur que vous avez fournie dans un commentaire 4bb5f0c58cc71806ec4d228b730dd252947e679cce05f71d434787fe228f14c799cf8965780bb308aa722ac179bfa5fd57592a72cbdcfe89ab61ad5d77251186d
est de la mauvaise longueur. Il s'agit de 129 chiffres hexadécimaux, alias nibbles, mais un point codé pour prime256v1 (alias secp256r1 ou P-256) doit être soit de 65 octets commençant par 04 (non compressé), soit de 33 octets commençant par 02 ou 03 (compressé). Lorsqu'une chaîne hexagonale (ou décimale ou octale d'ailleurs) représente une valeur de entier vous pouvez supprimer ou ajouter des zéros non significatifs sans modifier le nombre, mais un point CE est le suivant no un nombre entier.
Vous dites que votre code fournit 65 octets, ce qui est correct pour la version non compressée. Utilisez cela.
Contrairement à la plupart des autres algorithmes PK, OpenSSL ne dispose pas d'un format DER (et donc PEM) spécifique à l'algorithme pour ECC, donc tout ce qui est décrit avec précision comme nécessitant une clé publique PEM (et no un certificat, qui est la manière conventionnelle de transmettre une clé publique) doit utiliser le format X.509/PKIX SubjectPublicKeyInfo, qu'OpenSSL appelle PUBKEY
(comme indiqué dans la réponse de Shane) et des cartes en provenance ou à destination d'une EVP_PKEY
structure dans le programme. Pour construire cette structure à partir du point public brut, vous devez d'abord le combiner avec l'identification de la courbe pour former une véritable clé publique EC, puis l'identifier en tant que EC pour former une Générique publickey, et l'écrire. OpenSSL peut effectuer des E/S (y compris PEM) vers et depuis la mémoire en utilisant un BIO de type 'mem', sans fichier(s). (Et faire de ceci fermement une question de programmation et non une question de ligne de commande, qui serait vraiment hors sujet et appartiendrait à une autre pile, bien que beaucoup soient demandés ici de toute façon).
/* SO #56218946 */
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#ifdef _WIN32
#include <openssl/applink.c>
#endif
void err (const char *label){ // for test; improve for real code
fprintf (stderr, "Error in %s:\n", label);
ERR_print_errors_fp (stderr);
exit (1);
}
int main (void) //(int argc, char**argv)
{
ERR_load_crypto_strings(); /* or SSL_load_error_strings */
//OPENSSL_add_all_algorithms_noconf(); /* for PKCS#8 */
// test data -- replace for real use
char hex [] = "04bb5f0c58cc71806ec4d228b730dd252947e679cce05f71d434787fe228f14c799cf8965780bb308aa722ac179bfa5fd57592a72cbdcfe89ab61ad5d77251186d";
unsigned char raw [65]; for( int i = 0; i < 65; i++ ){ sscanf(hex+2*i, "%2hhx", raw+i); }
EC_KEY *eck = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); /* or OBJ_txt2nid("prime256v1") */
if( !eck ) err("ECCnewbyname");
EC_KEY_set_asn1_flag(eck, OPENSSL_EC_NAMED_CURVE); /* needed below 1.1.0 */
const unsigned char *ptr = raw;
if( !o2i_ECPublicKey (&eck, &ptr, sizeof(raw)) ) err("o2iECPublic=point");
EVP_PKEY * pkey = EVP_PKEY_new();
if( !EVP_PKEY_assign_EC_KEY(pkey, eck) ) err("PKEYassign");
BIO *bio = BIO_new(BIO_s_mem());
if( !PEM_write_bio_PUBKEY (bio, pkey) ) err("PEMwrite");
char *pem = NULL; long len = BIO_get_mem_data (bio, &pem);
fwrite (pem, 1, len, stdout); // for test; for real use as needed
return 0;
}
(AJOUTÉ) Alternativement, puisque l'encodage de points X9.62 est de taille fixe pour une courbe donnée, la structure SPKI encodée en DER pour une courbe donnée consiste en fait en un en-tête fixe suivi de la valeur du point, donc vous pourriez concaténer avec cet en-tête fixe et faire une conversion PEM générique : sortie tirets-BEGIN ligne, sortie base64 avec sauts de ligne, sortie tirets-END ligne. Bien qu'il ne soit pas difficile de calculer l'en-tête si l'on connaît le fonctionnement de l'ASN.1, un raccourci consiste à générer l'encodage SPKI pour une clé fictive avec par exemple openssl ecparam -genkey -name prime256v1 -outform der
et supprime les 65 derniers octets (ou 33 s'ils sont compressés à l'aide de l'option -conv_form
). Comparez avec les variantes de Java à Chargement d'une clé publique ECDSA brute de 64 octets en Java .