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
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:
- https://stackoverflow.com/a/8713518/1016580
- https://stackoverflow.com/a/14052651/1016580
- https://stackoverflow.com/a/14068057/1016580
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.
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 }
où 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.
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;
}
Le BouncyCastle cadre a un PKCS1 Codeur pour résoudre ce problème: http://www.bouncycastle.org/docs/docs1.6/index.html
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
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