web-dev-qa-db-fra.com

Conversion de la clé privée ECC au format PKCS # 1

Existe-t-il un moyen de convertir une clé privée ECC au format RSA PKCS # 1? J'ai d'abord essayé de le convertir en PKCS # 8 en utilisant OpenSSL:

openssl pkcs8 -topk8 -nocrypt -in EC_key.pem -out pkcs8_key.pem

Il en résulte un fichier pem qui est (ce que je suppose) au bon format PKCS8

-----BEGIN PRIVATE KEY-----
[snip]
-----END PRIVATE KEY-----

Lorsque vous essayez de le convertir ensuite de PKCS # 8 en PKCS # 1 à l'aide de la commande suivante:

openssl pkcs8 -inform pem -nocrypt -in pkcs8_key.pem -out pkcs1_key.pem

J'obtiens le même fichier qu'à l'étape précédente.

Lorsque vous utilisez la commande suivante pour la conversion:

openssl rsa –in pkcs8_key.pem –out pkcs1_key.pem

J'obtiens l'erreur suivante:

47049676604576: erreur: 0607907F: routines d'enveloppe numérique: EVP_PKEY_get1_RSA: attente d'une clé rsa: p_lib.c: 279:

Les clés EC peuvent-elles être converties en clés RSA PKCS # 1? Et si oui, comment?

14
Sid Said

Il pourrait y avoir un peu de confusion ici entre "RSA Laboratories", l'organisation qui édite les normes PKCS, et RSA, l'algorithme cryptographique. PKCS # 1 est l'une des normes PKCS, ainsi éditée par RSA Laboratories; il parle de l'algorithme RSA, et seulement ​​de l'algorithme RSA.

En particulier, il n'existe pas de "format PKCS # 1" pour les clés à courbe elliptique (EC), car les clés EC ne sont pas des clés RSA - ce sont des clés EC, ce qui n'est pas du tout le même type d'objet.


Cependant, la confusion s'est propagée beaucoup plus loin, alors découvrons quelques couches.

PKCS # 1 parle de RSA et définit un codage basé sur ASN.1 pour les clés privées RSA. Cela ressemble à ceci:

  RSAPrivateKey ::= SEQUENCE {
      version           Version,
      modulus           INTEGER,  -- n
      publicExponent    INTEGER,  -- e
      privateExponent   INTEGER,  -- d
      prime1            INTEGER,  -- p
      prime2            INTEGER,  -- q
      exponent1         INTEGER,  -- d mod (p-1)
      exponent2         INTEGER,  -- d mod (q-1)
      coefficient       INTEGER,  -- (inverse of q) mod p
      otherPrimeInfos   OtherPrimeInfos OPTIONAL
  }

Nous reconnaissons ici les différents éléments mathématiques qui constituent une paire de clés publique/privée RSA. Étant basé sur ASN.1 , ce type d'objet code (via DER ) en quelques octets. OpenSSL peut produire et consommer une telle séquence d'octets; cependant, il est courant de réencoder ces octets au format PEM traditionnel (et mal spécifié): les octets sont encodés avec Base64 , et un en-tête et un pied de page sont ajoutés, qui spécifient le type d'objet encodé .

Il est important de noter que le format brut basé sur ASN.1 pour les clés privées RSA, défini dans PKCS # 1, entraîne des séquences d'octets qui n'incluent PAS une identification sans ambiguïté pour le type de clé. Toute application qui lit une clé privée RSA codée DER dans ce format doit déjà savoir, à l'avance, qu'elle doit s'attendre à une clé privée RSA. L'en-tête PEM, qui dit "RSA PRIVATE KEY", fournit ces informations.

Étant donné que les normes PKCS ne parlent pas de PEM, elles fournissent leur propre solution au problème de l'identification du type de clé; il s'appelle PKCS # 8 . Une clé au format PKCS # 8 est à nouveau basée sur ASN.1, avec une structure qui ressemble à ceci:

  PrivateKeyInfo ::= SEQUENCE {
     version Version,
     privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
     privateKey PrivateKey,
     attributes [0] Attributes OPTIONAL }

  Version ::= INTEGER {v1(0)} (v1,...)

  PrivateKey ::= OCTET STRING

Cela signifie qu'un objet PKCS # 8 est vraiment un wrapper autour d'un autre format. Dans le cas d'une clé privée RSA, l'encapsuleur indique (via le champ privateKeyAlgorithm) que la clé est réellement une clé RSA et le contenu du champ PrivateKey (un OCTET STRING, c'est-à-dire une séquence arbitraire d'octets) sont vraiment le codage DER d'une clé privée PKCS # 1.

OpenSSL, par défaut, ne laisse pas un fichier PKCS # 8 vivre sa vie comme une séquence d'octets encodée en DER; il le convertira à nouveau en PEM et, cette fois, ajoutera l'en-tête "BEGIN PRIVATE KEY". Notez que cet en-tête ne pas spécifie le type de clé, car l'objet encodé (transformé en caractères via Base64) contient déjà les informations.

(Comme complication supplémentaire, PKCS # 8 définit également un chiffrement facultatif, souvent basé sur un mot de passe, des clés privées; et ​​le format traditionnel de type PEM qu'OpenSSL implémente aussi inclut certains prise en charge générique du cryptage par mot de passe; vous pouvez donc avoir plusieurs combinaisons d'encapsuleurs qui spécifient une sorte de cryptage, ce qui ne peut être décrit que comme un gâchis absolu.)

Maintenant, qu'est-ce que cela nous apprend sur les clés EC ? Les clés EC ne sont pas décrites par PKCS # 1 (qui ne parle que de RSA). Cependant, s'il existe un standard quelque part qui indique comment une clé privée EC peut être transformée en une séquence d'octets, alors:

  • cette séquence d'octets pourrait être encodée en PEM par OpenSSL avec un en-tête de texte explicite;
  • la même séquence d'octets pourrait être encapsulée dans un objet PKCS # 8.

Et c'est exactement ce qui se passe. La norme qui définit le format de codage pour les clés EC est SEC 1 (nominalement, la norme pour la cryptographie EC est ANSI X9.62; cependant, alors que X9.62 a réutilisé une grande partie de SEC 1, la spécification pour le codage private Les clés EC ne sont que dans SEC 1, car X9.62 ne concerne que l'encodage des clés publiques). Dans SEC 1 (section C.4), ce qui suit est défini:

  ECPrivateKey ::= SEQUENCE {
         version       INTEGER { ecPrivkeyVer1(1) },
         privateKey    OCTET STRING,
         parameters    [0] EXPLICIT ECDomainParameters OPTIONAL,
         publicKey     [1] EXPLICIT BIT STRING OPTIONAL
  }

Ainsi, une clé privée codée contient la clé privée elle-même (un entier dans la plage 1 ..n - 1, où n est l'ordre de sous-groupe de la courbe), éventuellement une description ou référence à la courbe utilisée, et éventuellement une copie de la clé publique (qui pourrait sinon être recalculée).

Essayons. Nous générons avec OpenSSL une nouvelle paire de clés EC, dans la courbe NIST P-256 standard (qui est la courbe que tout le monde implémente et utilise):

$ openssl ecparam -out ec1.pem -genkey -name prime256v1

Nous obtenons ceci, dans le ec1.pem fichier:

$ cat ec1.pem
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBdVHnnzZmJm+Z1HAYYOZlvnB8Dj8kVx9XBH+6UCWlGUoAoGCCqGSM49
AwEHoUQDQgAEThPp/xgEov0mKg2s0GII76VkZAcCc//3quAqzg+PuFKXgruaF7Kn
3tuQVWHBlyZX56oOstUYQh3418Z3Gb1+yw==
-----END EC PRIVATE KEY-----

Le premier élément ("PARAMETRES EC") est redondant; il contient une référence à la courbe utilisée, mais cette information est également présente dans le deuxième élément. Utilisons donc un éditeur de texte pour supprimer les "PARAMETRES EC", et nous ne gardons que la partie "EC PRIVATE KEY". Maintenant mon ec1.pem le fichier ressemble à ceci:

$ cat ec1.pem
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBdVHnnzZmJm+Z1HAYYOZlvnB8Dj8kVx9XBH+6UCWlGUoAoGCCqGSM49
AwEHoUQDQgAEThPp/xgEov0mKg2s0GII76VkZAcCc//3quAqzg+PuFKXgruaF7Kn
3tuQVWHBlyZX56oOstUYQh3418Z3Gb1+yw==
-----END EC PRIVATE KEY-----

Nous pouvons utiliser OpenSSL pour décoder sa structure:

$ openssl asn1parse -i -in ec1.pem
    0:d=0  hl=2 l= 119 cons: SEQUENCE          
    2:d=1  hl=2 l=   1 prim:  INTEGER           :01
    5:d=1  hl=2 l=  32 prim:  OCTET STRING      [HEX DUMP]:17551E79F3666266F99D4701860E665BE707C0E3F24571F57047FBA5025A5194
   39:d=1  hl=2 l=  10 cons:  cont [ 0 ]        
   41:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
   51:d=1  hl=2 l=  68 cons:  cont [ 1 ]        
   53:d=2  hl=2 l=  66 prim:   BIT STRING

Nous reconnaissons la structure ASN.1 attendue, telle que définie par SEC 1: une SEQUENCE qui contient un ENTIER de valeur 1 (le champ version), une OCTET STRING (le privateKey lui-même, qui est un codage non signé big-endian de la clé privée mathématique), une référence (étiquetée avec [0]) à la courbe utilisée (dans l'objet ASN.1, il s'agit de OID 1.2.840.10045.3.1.7; OpenSSL le traduit par le nom "prime256v1")) et (étiqueté avec [1]) une copie de la clé publique.

Nous pouvons le convertir au format PKCS # 8 (non chiffré):

$ openssl pkcs8 -topk8 -nocrypt -in ec1.pem -out ec2.pem

ce qui donne ceci:

$ cat ec2.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgF1UeefNmYmb5nUcB
hg5mW+cHwOPyRXH1cEf7pQJaUZShRANCAAROE+n/GASi/SYqDazQYgjvpWRkBwJz
//eq4CrOD4+4UpeCu5oXsqfe25BVYcGXJlfnqg6y1RhCHfjXxncZvX7L
-----END PRIVATE KEY-----

que nous pouvons décoder avec OpenSSL:

$ openssl asn1parse -i -in ec2.pem
    0:d=0  hl=3 l= 135 cons: SEQUENCE          
    3:d=1  hl=2 l=   1 prim:  INTEGER           :00
    6:d=1  hl=2 l=  19 cons:  SEQUENCE          
    8:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey
   17:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
   27:d=1  hl=2 l= 109 prim:  OCTET STRING      [HEX DUMP]:306B0201010420(...)

(J'ai tronqué le vidage hexadécimal.) Cette structure est en effet un objet PKCS # 8:

  • Le champ identifiant de l'algorithme dit: "ceci contient une clé EC" (techniquement, il utilise un identifiant dont le nom est "id-ecPublicKey", mais puisque cela se produit dans un fichier PKCS # 8, tout le monde sait que cela signifie vraiment un EC privé clé).
  • Le fichier comprend comme paramètres clés une référence à la courbe utilisée.
  • La valeur de clé est codée dans le contenu d'un OCTET STRING. Si nous décodons davantage cette OCTET STRING, nous trouverons la clé privée EC codée comme spécifié par SEC 1 (de manière amusante, la référence à la courbe semble avoir été omise dans ce cas, car elle est déjà présente dans les paramètres clés).

La conversion peut être effectuée dans l'autre sens (du PKCS # 8 au format SEC 1 brut) avec:

$ openssl ec -in ec2.pem -out ec3.pem

Vous obtiendrez alors dans le fichier ec3.pem exactement ce que vous aviez dans le fichier ec1.pem: un objet codé PEM avec en-tête "BEGIN EC PRIVATE KEY".


Résumé: Il n'y a pas de "clé EC au format PKCS # 1": PKCS # 1 est uniquement pour les clés RSA, pas les clés EC. Cependant, il existe un autre format, analogue à PKCS # 1 mais conçu pour les clés EC, et défini dans SEC 1. OpenSSL peut convertir ce format en PKCS # 8 générique avec le "openssl pkcs8 "et revenir au format SEC 1 avec" openssl ec ".

27
Thomas Pornin

Les clés EC peuvent-elles être converties en clés RSA PKCS # 1? Et si oui, comment?

Non. RSA n'a rien à voir avec ECC.

Maintenant, pour certains crypto, il existe à la fois une version régulière et une version EC.
(Exemples: DH/ECDH, DSA/ECDSA.) Mais: Il n'y a tout simplement pas de "ECRSA". Il n'y a que RSA.

0
StackzOfZtuff