2

PHP openssl_seal関数で生成された暗号化データがいくつかあります。

そのデータを 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);

ありがとう!

4

1 に答える 1

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指定されたパスワードを char の配列として返す新しいインスタンスを作成することで、キーを格納する PEM ファイルを取得するためのパスワードを指定できるようになりました。

bouncycastle バージョン 1.46 を使用していることに注意してください。新しいバージョンに移行する場合、いくつかの方法でコードを調整する必要があります。特に、passwordFinder はnew Password()インスタンスに置き換えられます。このような適応に関する他の質問を参照できます: Bouncy Castle : PEMReader => PEMParser

于 2015-11-20T01:16:11.360 に答える