Génération de clés RSA au format PKCS#1 en Java

lorsque je génère une paire de clés RSA en utilisant L'API Java, la clé publique est encodée au format X. 509 et la clé privée est encodée au format PKCS#8. Je cherche à coder les deux comme PKCS#1. Est-ce possible? J'ai passé beaucoup de temps à parcourir les docs Java, mais je n'ai pas trouvé de solution. Le résultat est le même quand J'utilise Java et les fournisseurs de Château gonflable.

Voici un extrait du code:

KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA","BC");
keygen.initialize(1024);
KeyPair pair = keygen.generateKeyPair();
PrivateKey priv = pair.getPrivate();
PublicKey pub = pair.getPublic();
byte[] privBytes = priv.getEncoded();
byte[] pubBytes = pub.getEncoded();

Les deux octets résultant les tableaux sont formatés sous X. 509 (public) et PKCS#8 (privé).

Toute aide serait grandement appréciée. Il y a des billets similaires, mais aucun ne répond vraiment à ma question.

Merci

21
demandé sur Anthony 2011-09-30 17:51:32

6 réponses

Vous aurez besoin de BouncyCastle:

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

les bribes de code ci-dessous ont été vérifiés et trouvés travaillant avec Bouncy Castle 1.52.

clé Privée

convertissez la clé privée de PKCS8 en PKCS1:

PrivateKey priv = pair.getPrivate();
byte[] privBytes = priv.getEncoded();

PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes);
ASN1Encodable encodable = pkInfo.parsePrivateKey();
ASN1Primitive primitive = encodable.toASN1Primitive();
byte[] privateKeyPKCS1 = primitive.getEncoded();

convertissez la clé privée en PKCS1 en PEM:

PemObject pemObject = new PemObject("RSA PRIVATE KEY", privateKeyPKCS1);
StringWriter stringWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.writeObject(pemObject);
pemWriter.close();
String pemString = stringWriter.toString();

Vérifiez avec la ligne de commande OpenSSL que le format de la clé est comme prévu:

openssl rsa -in rsa_private_key.pem -noout -text

clé Publique

convertir la clé publique de X. 509 SubjectPublicKeyInfo to PKCS1:

PublicKey pub = pair.getPublic();
byte[] pubBytes = pub.getEncoded();

SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
ASN1Primitive primitive = spkInfo.parsePublicKey();
byte[] publicKeyPKCS1 = primitive.getEncoded();

Convertir la clé publique dans PKCS1 à PEM:

PemObject pemObject = new PemObject("RSA PUBLIC KEY", publicKeyPKCS1);
StringWriter stringWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.writeObject(pemObject);
pemWriter.close();
String pemString = stringWriter.toString();

Vérifiez avec la ligne de commande OpenSSL que le format de la clé est comme prévu:

openssl rsa -in rsa_public_key.pem -RSAPublicKey_in -noout -text

Merci

Merci beaucoup aux auteurs des articles suivants posts:

ces messages contenaient des informations utiles, mais parfois périmées (i.e. pour les versions plus anciennes de BouncyCastle), qui m'ont aidé à construire ce message.

19
répondu Alexei Khlebnikov 2017-05-23 12:02:37

RFC5208, le format non chiffré PKCS#8 se compose d'un PrivateKeyInfo structure:

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

privateKey est:

"...une chaîne d'octets dont le contenu est la valeur de la clé privée. L'interprétation du contenu est défini dans l'enregistrement de la clé privée de l'algorithme. Pour une clé privée RSA, par exemple, le contenu est un encodage BER d'une valeur de type RSAPrivateKey."

RSAPrivateKey la structure est juste le PKCS#1 le codage de la clé, que l'on peut extraire à l'aide de BouncyCastle:

// pkcs8Bytes contains PKCS#8 DER-encoded key as a byte[]
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8Bytes);
RSAPrivateKeyStructure pkcs1Key = RSAPrivateKeyStructure.getInstance(
        pki.getPrivateKey());
byte[] pkcs1Bytes = pkcs1Key.getEncoded(); // etc.
5
répondu SimonJ 2012-01-03 14:12:28

j'ai écrit un programme C pour convertir pkcs8 clé privée en pkcs1. Il fonctionne!

/*****************************************
    convert pkcs8 private key file to pkcs1

    2013-1-25   Larry Wu     created
 ****************************************/

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <openssl/rsa.h>
#include <openssl/bio.h> 
#include <openssl/err.h> 
#include <openssl/pem.h>
#include <openssl/engine.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <stdarg.h>

#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <vector>

using namespace std;


#define MY_TRACE_ERROR printf


/*
    gcc -Wall -o pkcs_8to1 pkcs_8to1.cpp -g -lstdc++ -lcrypto -lssl
*/
int main(int argc, char **argv)
{
    EVP_PKEY * pkey = NULL;
    string kin_fname;
    FILE *kin_file = NULL;
    string kout_fname;
    FILE *kout_file = NULL;

    // param
    if(argc != 3)
    {
        printf("Usage: %s <pkcs8_key_file> <pkcs1_key_file>\n", argv[0]);
        return 1;
    }

    kin_fname = argv[1];
    kout_fname = argv[2];


    // init
    OpenSSL_add_all_digests();
    ERR_load_crypto_strings();

    // read key
    if((kin_file = fopen(kin_fname.c_str(), "r")) == NULL)
    {
        MY_TRACE_ERROR("kin_fname open fail:%s\n", kin_fname.c_str());
        return 1;
    }

    if ((pkey = PEM_read_PrivateKey(kin_file, NULL, NULL, NULL)) == NULL) 
    {
        ERR_print_errors_fp(stderr);
        MY_TRACE_ERROR("PEM_read_PrivateKey fail\n");
        fclose(kin_file);
        return 2;
    }

    // write key
    if((kout_file = fopen(kout_fname.c_str(), "w")) == NULL)
    {
        MY_TRACE_ERROR("kout_fname open fail:%s\n", kout_fname.c_str());
        return 1;
    }

    if (!PEM_write_PrivateKey(kout_file, pkey, NULL, NULL, 0, NULL, NULL)) 
    {
        ERR_print_errors_fp(stderr);
        MY_TRACE_ERROR("PEM_read_PrivateKey fail\n");
        fclose(kout_file);
        return 2;
    }

    // clean
    fclose(kin_file);
    fclose(kout_file);
    EVP_PKEY_free(pkey);

    return 0;
}
1
répondu larry 2015-04-27 11:54:35

Le BouncyCastle cadre a un PKCS1 Codeur pour résoudre ce problème: http://www.bouncycastle.org/docs/docs1.6/index.html

0
répondu klaustopher 2011-09-30 14:15:00

j'ai essayé de générer OpenSSL-amicale des clés publiques RSA au format DER à l'aide de BountyCastle J2ME bibliothèque porté sur BlackBerry, mon code:

public void testMe() throws Exception {
  RSAKeyPairGenerator generator = new RSAKeyPairGenerator();
  generator.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x10001),
                 new SecureRandom(), 512, 80));
  AsymmetricCipherKeyPair keyPair = generator.generateKeyPair();

  RSAKeyParameters params =  (RSAKeyParameters) keyPair.getPublic();
  RSAPublicKeyStructure struct = new RSAPublicKeyStructure(params.getModulus(), 
                                                           params.getExponent());

  SubjectPublicKeyInfo info = 
    new SubjectPublicKeyInfo(new AlgorithmIdentifier("1.2.840.113549.1.1.1"), 
                             struct);

  byte[] bytes = info.getDEREncoded();

  FileOutputStream out = new FileOutputStream("/tmp/test.der");

  out.write(bytes);
  out.flush();
  out.close();
}

Clé était toujours incorrect:

$ openssl asn1parse -in test.der -inform DER -i
0:d=0  hl=2 l=  90 cons: SEQUENCE          
2:d=1  hl=2 l=  11 cons:  SEQUENCE          
4:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
15:d=1  hl=2 l=  75 prim:  BIT STRING     

j'ai changé d'org.bouncycastle.asn1.x509.AlgorithmIdentifier

public AlgorithmIdentifier(
    String     objectId)
{
    this.objectId = new DERObjectIdentifier(objectId);
    // This line has been added
    this.parametersDefined = true;
}

Et maintenant avoir de belles clé:

$ openssl asn1parse -in test.der -inform DER -i
0:d=0  hl=2 l=  92 cons: SEQUENCE          
2:d=1  hl=2 l=  13 cons:  SEQUENCE          
4:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
15:d=2  hl=2 l=   0 prim:   NULL              
17:d=1  hl=2 l=  75 prim:  BIT STRING 

Qui peut être utilisé pour chiffrer:

$ echo "123" | openssl rsautl -pubin  -inkey test.der -encrypt -keyform DER -out y
$ wc -c y
64 y
0
répondu Maciej Łopaciński 2012-01-03 11:39:52

je sais que c'est vieux post. mais j'ai passé deux jours à résoudre ce problème et finalement trouver BouncyCastle peut le faire

ASN1Encodable

http://www.bouncycastle.org/docs/docs1.5on/org/bouncycastle/asn1/ASN1Encodable.html

0
répondu aminhotob 2014-12-17 16:10:17