Java等同于带有密码保护密钥的PHP的openssl_open?

Jotadepicas

我有一些使用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);

谢谢!

Jotadepicas

您需要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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Java等同于带有密码保护密钥的PHP的openssl_open?

来自分类Dev

PHP等同于VB.NET密码哈希函数

来自分类Dev

等同于VB.NET密码哈希函数的PHP

来自分类Dev

Join 是否等同于带有列子查询的查询?

来自分类Dev

Java等同于python的“ with”

来自分类Dev

Java等同于Python的webbrowser.open()

来自分类Dev

是否有TCl等同于PHP的标头标记

来自分类Dev

Python xlrd-带有密码保护的工作表的open_workbook方法

来自分类Dev

Python xlrd-带有密码保护的工作表的open_workbook方法

来自分类Dev

具有密码保护的SSH密钥的parallel-ssh

来自分类Dev

JavaScript等同于PHP $ array [$ i] []

来自分类Dev

PHP等同于.Net实体框架

来自分类Dev

PHP等同于MySQL的UNHEX()?

来自分类Dev

Lambda等同于PHP中的Python

来自分类Dev

等同于Python中的implode(php)

来自分类Dev

PHP:是空的($ var)等同于!$ var

来自分类Dev

Laravel Hash等同于核心php

来自分类Dev

PHP等同于JavaScript绑定

来自分类Dev

PHP等同于Python的locals()?

来自分类Dev

JavaScript等同于PHP mail()

来自分类Dev

Qt / C ++等同于php例程

来自分类Dev

Java等同于GC.SuppressFinalize

来自分类Dev

Java等同于Thread.MemoryBarrier

来自分类Dev

Java等同于C#的“内部”

来自分类Dev

带有文件列表的表单,用密码保护

来自分类Dev

如何使sbt`test`等同于带有某些选项的run命令?

来自分类Dev

F#等同于带有案例类/区分联合的Scala惰性val

来自分类Dev

功能等同于带有变量比较的if表达式

来自分类Dev

使用带有向量优化的C ++ 20的std :: popcount等同于popcnt intristic吗?