2009-09-08 11 views
10

J'essaie de crypter du contenu avec une clé privée RSA.Cryptage avec une clé privée RSA en Java

que je suis cet exemple: http://www.junkheap.net/content/public_key_encryption_java

mais la conversion à utiliser les clés privées plutôt que publiques. À la suite de cet exemple, je pense que ce que je dois faire est:

  • Lire dans une clé privée DER format
  • Générer un PCKS8EncodedKeySpec
  • appel generatePrivate() de KeyFactory pour obtenir un objet clé privée
  • Utilisez cet objet clé privée avec l'objet Cipher pour faire le cryptage

Ainsi, les étapes:

la clé a été générée FRO m OpenSSL avec:

openssl genrsa -aes256 -out private.pem 2048

puis a été converti en format DER avec:

openssl rsa -in private.pem -outform DER -out private.der

je produis le PKCS8EncodedKeySpec avec:

byte[] encodedKey = new byte[(int)inputKeyFile.length()]; 

try { 
    new FileInputStream(inputKeyFile).read(encodedKey); 
} catch (FileNotFoundException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey); 
return privateKeySpec; 

Et puis générer la clé privée objet avec:

PrivateKey pk = null; 

try { 
    KeyFactory kf = KeyFactory.getInstance(RSA_METHOD); 
    pk = kf.generatePrivate(privateKeySpec); 
} catch (NoSuchAlgorithmException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} catch (InvalidKeySpecException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 
return pk; 

Cependant, l'appel à:

pk = kf.generatePrivate(privateKeySpec); 

Je reçois:

java.security.spec.InvalidKeySpecException: Unknown key spec. 
at com.sun.net.ssl.internal.ssl.JS_KeyFactory.engineGeneratePrivate(DashoA12275) 
at com.sun.net.ssl.internal.ssl.JSA_RSAKeyFactory.engineGeneratePrivate(DashoA12275) 
at java.security.KeyFactory.generatePrivate(KeyFactory.java:237) 

Questions:

  • Est-ce l'approche générale non?
  • La clé PCKS8EncodedKeySpec est-elle la bonne clé à utiliser?
  • Des réflexions sur l'erreur de spécification de clé non valide?
+0

Je suis passé par celui-ci et les ont générés avec Java: http://stackoverflow.com/questions/19640735/load-public-key-data-from -fichier – Hayro

Répondre

6

Tout d'abord, je suis confus pourquoi vous prévoyez d'utiliser un Cipher pour chiffrer avec une clé privée, plutôt que de signer avec un Signature. Je ne suis pas sûr que tous les fournisseurs RSAutilisent le type de bloc correct pour l'installation, mais cela vaut la peine d'essayer. Mais, mis à part cela, je pense que vous essayez de charger une clé au format OpenSSL non standard. Convertir en DER avec rsa est essentiellement juste un décodeur base-64; la structure de la clé n'est pas PKCS # 8.

Au lieu de cela, après genrsa, utilisez la commande openssl pkcs8 pour convertir la clé générée à PKCS non crypté # 8, format DER:

openssl pkcs8 -topk8 -nocrypt -in private.pem -outform der -out private.der 

Cela produira une clé privée non chiffrée qui peut être chargé avec un PKCS8EncodedKeySpec.

+0

Honnêtement, je n'étais pas au courant de la signature. Pour m'assurer que je comprends son utilisation, j'initialiserais l'objet de signature, appellerais la mise à jour avec les octets que je veux signer, et ensuite l'indicatif d'appel? Et puis je peux stocker les octets retournés à partir du signe comme ma signature numérique? – wadesworld

+0

Oui, c'est l'utilisation correcte. – erickson

+0

Bonjour. Quelqu'un a finalement résolu le problème? J'ai un privateKey que je ne peux pas charger dans Java pour continuer avec la phase de signature. Mon privateKey est RSA, PKCS # 8 DER et il a un mot de passe. Comment puis-je charger ça en Java? L'exception dans mon cas est 'java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: entrée DER, erreur de variable Integer' – BRabbit27

10

Vous ne pouvez pas crypter avec une clé privée. Si JCE vous permet de faire cela, c'est juste par accident.

Vous devez utiliser la signature. Voici l'extrait de code pour le faire,

signer = Signature.getInstance("SHA1withRSA"); 
signer.initSign(privateKey); // PKCS#8 is preferred 
signer.update(dataToSign); 
byte[] signature = signer.sign(); 
+1

's/public/private /' dans votre première ligne. – caf

+0

Parfait - merci beaucoup! – wadesworld

4

Ce n'est pas un hasard si le cryptage avec une clé privée est autorisé. Si vous souhaitez rompre une signature dans un hachage individuel et un cryptage, le cryptage avec une clé privée est essentiel. Disons que j'ai un document que je dois signer et ma clé réside sur un HSM réseau. Maintenant, soit je stream le document entier au HSM pour signer ou je peux créer un hachage local et le diffuser au HSM pour le cryptage seul. Mon choix dépendra de savoir si le calcul de hachage local me donne de meilleures performances à savoir un calcul de hachage délégué avec un temps de latence réseau.

2

Cette question est assez ancienne, mais j'ai récemment trébuché sur le problème (je suis en train de mettre en œuvre les exigences d'un protocole qui nécessite un cryptage avec une clé privée). Je vais citer le poste de forum:

Je suis récemment tombé sur la même question, soumis PMR 22265,49R et IBM Support après consultation avec le « développement » (ce sont ceux qui) a décidé que les clés privées ne peuvent pas être utilisés pour le chiffrement. Peu importe combien j'ai essayé d'argumenter avec eux que les clés privées ne devraient pas être utilisées pour la protection des données, ce qui est seulement un but derrière le cryptage, et qu'il est parfaitement bien d'utiliser des clés privées pour le cryptage pour obtenir la non répudiation, ils étaient inébranlables dans leur croyance. Vous devez aimer les gens, qui insistent sur le fait que 2x2 = 5.

Voici comment j'ai travaillé autour de ce problème: Essentiellement, j'ai créé un objet de clé publique avec le matériel crypto de la clé privée. Vous devrez faire l'inverse, créer un objet clé privée avec le matériel crypto de la clé publique, pour décrypter avec la clé publique si vous voulez éviter l'exception "La clé publique ne peut pas être utilisée pour déchiffrer".

RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) ks.getKey(keyAlias, ksPassword.trim().toCharArray()); 
RSAPublicKeySpec spec = new RSAPublicKeySpec(
    privateKey.getModulus(), 
    privateKey.getPrivateExponent() 
); 
Key fakePublicKey = KeyFactory.getInstance("RSA").generatePublic(spec); 
encryptCipher.init(Cipher.ENCRYPT_MODE, fakePublicKey); 
+1

Cela est très risqué si vous traitez l'exposant de clé privée comme l'exposant public et le distribuez, car étant donné la clé privée (que vous appelez la "clé publique") il est facile de dériver la clé publique réelle (que vous êtes maintenant appeler la "clé privée"). Ne laissez pas cette "clé publique" par inadvertance en public, sinon votre système sera compromis. Il peut être aussi simple que de deviner que l'exposant de la «clé privée» est 65537. –

+0

Je cherchais cela si longtemps. Je suis tellement reconnaissant pour cette réponse. Le nom «clé privée et publique» est totalement faux dans ce cas d'utilisation, mais il y a des situations où cela est pertinent. –

+0

@JimFlood Si je comprends bien, et que ma situation est similaire, dmitry a créé un 'RSAPublicKeySpec' pour contenir les données de la clé privée. Évidemment, il ne distribuera pas la clé privée, seulement la clé publique originale qui peut maintenant être utilisée pour prouver (déchiffrer) que la clé privée était pour le chiffrement - c'est-à-dire la non-répudiation. – Guss

0

essayez ceci:

java.security.Security.addProvider(
        new org.bouncycastle.jce.provider.BouncyCastleProvider() 
      ); 
Questions connexes