2015-11-20 78 views
1

我有一些使用PHP openssl_seal函数生成的加密数据。与带有密码保护密钥的PHP openssl_open相当的Java是什么?

我需要用Java解密(打开)该数据。

我发现了一篇解释它的文章(http://blog.local.ch/en/2007/10/29/openssl-php-to-java/),但是这并不包括解密数据所需的密钥反过来被密码保护的场景。

我应该如何修改文章中提到的解决方案中使用一个密码保护的密钥?

守则提到的文章中:根据文章

package ch.local.common.util.crypto; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileReader; 
import java.security.Key; 
import java.security.KeyPair; 
import java.security.KeyStore; 
import java.security.PrivateKey; 
import java.security.PublicKey; 
import java.security.Security; 
import java.security.cert.Certificate; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.spec.SecretKeySpec; 

import org.bouncycastle.jce.provider.BouncyCastleProvider; 
import org.bouncycastle.openssl.PEMReader; 
import org.bouncycastle.util.encoders.Base64; 

/** 
* For decrypting data encrypted with PHP's openssl_seal() 
* 
* Example - String envKey is the Base64 encoded, RSA encrypted envelop key 
* and String sealedData is the Base64 encoded, RC4 encrypted payload, which 
* you got from PHP's openssl_seal() then; 
* 
* <pre> 
* KeyPair keyPair = OpenSSLInterop.keyPairPEMFile(
*   "/path/to/openssl/privkey_rsa.pem" 
*  ); 
* 
* PrivateKey privateKey = keyPair.getPrivate(); 
* String plainText = OpenSSLInterop.decrypt(sealedData, envKey, privateKey); 
* </pre> 
* 
* @see http://www.php.net/openssl_seal 
* @author Harry Fuecks 
* @since Oct 25, 2007 
* @version $Id$ 
*/ 
public class OpenSSLInterop { 

    private static boolean bcInitialized = false; 

    /** 
    * @param cipherKey 
    * @param cipherText 
    * @param privateKey 
    * @return 
    * @throws Exception 
    */ 
    public static String decrypt(String cipherText, String cipherKey, PrivateKey privateKey) 
    throws Exception { 

     return decrypt(cipherText, cipherKey, privateKey, "UTF-8"); 

    } 

    /** 
    * @param cipherKey Base64 encoded, RSA encrypted key for RC4 decryption 
    * @param cipherText Base64 encoded, RC4 encrypted payload 
    * @param privateKey 
    * @param charsetName 
    * @return decrypted payload 
    * @throws Exception 
    */ 
    public static String decrypt(String cipherText, String cipherKey, PrivateKey privateKey, String charsetName) 
    throws Exception { 

     byte[] plainKey = decryptRSA(Base64.decode(cipherKey), privateKey); 
     byte[] plaintext = decryptRC4(plainKey, Base64.decode(cipherText)); 
     return new String(plaintext, charsetName); 

    } 

    /** 
    * Loads a KeyPair object from an OpenSSL private key file 
    * (Just wrapper around Bouncycastles PEMReader) 
    * @param filename 
    * @return 
    * @throws Exception 
    */ 
    public static KeyPair keyPairFromPEMFile(String filename) 
    throws Exception { 

     if (!bcInitialized) { 
      Security.addProvider(new BouncyCastleProvider()); 
      bcInitialized = true; 
     } 

     FileReader keyFile = new FileReader(filename); 
     PEMReader pemReader = new PEMReader(keyFile); 
     return (KeyPair)pemReader.readObject(); 

    } 

    /** 
    * Returns a KeyPair from a Java keystore file. 
    * 
    * Note that you can convert OpenSSL keys into Java Keystore using the 
    * "Not yet commons-ssl" KeyStoreBuilder 
    * See - http://juliusdavies.ca/commons-ssl/utilities/ 
    * e.g. 
    * 
    * $ java -cp not-yet-commons-ssl-0.3.8.jar org.apache.commons.ssl.KeyStoreBuilder \ 
    *  "privkey password" ./privkey.pem ./pubkey.pem 
    * 
    * @param filename 
    * @param alias 
    * @param keystorePassword 
    * @return 
    */ 
    public static KeyPair keyPairFromKeyStore(String filename, String alias, String keystorePassword) 
    throws Exception { 

     KeyStore keystore = KeyStore.getInstance("JKS"); 
     File keystoreFile = new File(filename); 

     FileInputStream in = new FileInputStream(keystoreFile); 
     keystore.load(in, keystorePassword.toCharArray()); 
     in.close(); 

     Key key = keystore.getKey(alias, keystorePassword.toCharArray()); 
     Certificate cert = keystore.getCertificate(alias); 
     PublicKey publicKey = cert.getPublicKey(); 

     return new KeyPair(publicKey, (PrivateKey)key); 

    } 

    /** 
    * @param cipherKey 
    * @param privateKey 
    * @return 
    * @throws Exception 
    */ 
    private static byte[] decryptRSA(byte[] cipherKey, PrivateKey privateKey) throws Exception { 

     Cipher cipher = Cipher.getInstance("RSA"); 
     cipher.init(Cipher.DECRYPT_MODE, privateKey); 
     return cipher.doFinal(cipherKey); 

    } 

    /** 
    * Defaults to UTF-8 as the output encoding 
    * @param plainKey Base64 encoded, RSA encrypted key for RC4 decryption 
    * @param cipherText Base64 encoded, RC4 encrypted payload 
    * @return decrypted payload 
    * @throws Exception 
    */ 
    private static byte[] decryptRC4(byte[] plainKey, byte[] cipherText) 
    throws Exception { 

     SecretKey skeySpec = new SecretKeySpec(plainKey, "RC4"); 
     Cipher cipher = Cipher.getInstance("RC4"); 
     cipher.init(Cipher.DECRYPT_MODE, skeySpec); 
     return cipher.doFinal(cipherText); 

    } 

} 

用法:

KeyPair keyPair = OpenSSLInterop. keyPairFromPEMFile("/path/to/openssl/privkey_rsa.pem"); 
PrivateKey privateKey = keyPair.getPrivate(); 
String plainText = OpenSSLInterop.decrypt(sealedData, envKey, privateKey); 

的感谢!

+0

感谢标题编辑,我忘了“Java”的一部分:P – jotadepicas

回答

0

您需要修改所提供的代码keyPairFromPEMFile方法是这样的:

public static KeyPair keyPairFromPEMFile(String filename, final String password) throws Exception { 

    if (!bcInitialized) { 
     Security.addProvider(new BouncyCastleProvider()); 
     bcInitialized = true; 
    } 

    FileReader keyFile = new FileReader(filename); 
    PEMReader pemReader = new PEMReader(keyFile, new PasswordFinder() { 

     public char[] getPassword() { 
      return password.toCharArray(); 
     }}); 

    return (KeyPair)pemReader.readObject(); 

} 

现在,您可以指定密码检索通过创建一个新PasswordFinder实例存储密钥的PEM文件以字符数组的形式返回给定的密码。

请注意,我使用BouncyCastle的版本1.46。如果你转向更新的版本,你将需要通过几种方式来调整你的代码,特别是密码查找器将被替换为new Password()实例。您可以参考有关这样的改编本的其他问题:Bouncy Castle : PEMReader => PEMParser