2 votes

Convertir une clé publique simple en PEM

J'ai généré une paire de clés EC en utilisant Prime-256v1 à partir d'une application de confiance et j'ai exporté la clé publique vers Normal OS. La taille de la clé est de 65 octets. La clé publique est en format simple (seulement l'hexagone de la clé).

La clé publique exportée doit être remise à une bibliothèque (tierce partie). La bibliothèque attend la clé publique au format PEM.

Après avoir cherché pendant un certain temps, j'ai compris qu'il fallait d'abord convertir la clé en clair au format DER, puis convertir le résultat en PEM. Mais je n'ai pas pu trouver d'API pour la conversion de la clé ordinaire en DER ou PEM.

J'ai trouvé cette API qui PEM_ASN1_write((i2d_of_void*)i2d_PUBKEY,PEM_STRING_PUBLIC,outfile,ctx->cert->key->public_key,NULL,NULL,0,NULL,NULL) ; qui convertit depuis un pointeur de fichier. Mais je ne suis pas en mesure d'effectuer des opérations sur les fichiers car le stockage des fichiers n'est pas possible. Je récupère la clé publique dans un tampon.

Je fais cela dans un programme C, s'il y a un exemple de code ou d'API pour convertir une clé hexagonale simple en PEM.

Merci d'avance

1voto

Shane Powell Points 6235

En utilisant l'utilitaire openssl, la commande que vous pouvez utiliser est :

openssl ec -in . \prime256pubkey.cer -pubin -inform der -pubout -outform pem -out . \prime256pubkey.pem

Pour reproduire cela avec du code, vous devez utiliser les principaux api d'openssl suivants

Un exemple d'openssl, transformé en code C++ autour de l'API openssl C, serait :

template<typename T, typename D>
std::unique_ptr<T, D> make_handle(T* handle, D deleter)
{
    return std::unique_ptr<T, D>{handle, deleter};
}

bool convert_der_ec_pubkey_to_pem()
{
    // read in DER ec public key
    auto infile = make_handle(BIO_new_file("prime256pubkey.cer", "rb"), BIO_free);
    if(!infile) return false;

    auto const eckey = make_handle(d2i_EC_PUBKEY_bio(infile.get(), nullptr), EC_KEY_free);
    if(!eckey) return false;

    infile.reset();

    // write out PEM ec public key
    auto outfile = make_handle(BIO_new_file("prime256pubkey.pem", "w"), BIO_free);
    if(!outfile) return false;

    return PEM_write_bio_EC_PUBKEY(outfile.get(), eckey.get()) != 0;
}

1voto

dave_thompson_085 Points 11995

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 .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X