首页 文章

使用OpenSSL密钥的Java加密

提问于
浏览
2

我有一种情况,我使用OpenSSL生成一个公钥/私钥对,用于gdcmanon按照他们网站上列出的说明 . 具体来说,我使用以下命令为gdcmanon生成我的密钥

$ openssl genrsa -out CA_key.pem
$ openssl req -new -key CA_key.pem -x509 -days 365 -out CA_cert.cer

然后我就可以按照他们的指示使用加密文件

gdcmanon -c CA_cert.cer -e original.dcm original_anonymized.dcm

并使用.dc翻译文件

gdcmanon -k CA_key.pem -d original_anonymized.dcm orginal_deanonymized.dcm

然后,我想使用该密钥解码Java中相应DICOM文件中的某些信息 . 在努力获得Java中的密钥之后,我找到了this页面,并且能够创建一个不会导致我的Java程序崩溃的密钥,以下调用

openssl pkcs8 -topk8 -inform PEM -outform DER -in CA_key.pem -out CA_key.pkcs8.pem -nocrypt

在完成所有这些以及大量阅读之后,我制作了以下Java代码

public static String decode(byte[] encryptedData) {
    Key key = readPEMKey(new File("CA_key.pkcs8.pem"));
    //Key key = readPEMKey(new File("CA_key.pem"));
    try {
        Cipher c = Cipher.getInstance("RSA");
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decValue = c.doFinal(encryptedData);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

private static Key readPEMKey(File key) {
    DataInputStream dis = null;
    BufferedReader reader = null;
    try {
        /*
        reader = new BufferedReader(new FileReader(key));
        String privKeyPEM = "";
        String line;
        while ((line = reader.readLine()) != null) {
            if (!line.equals("-----BEGIN RSA PRIVATE KEY-----") && !line.equals("-----END RSA PRIVATE KEY-----"))
            privKeyPEM += line + "\n";
        }
        byte[] encoded = new BASE64Decoder().decodeBuffer(privKeyPEM);
        */

        dis = new DataInputStream(new BufferedInputStream(new FileInputStream(key)));
        byte[] encoded = new byte[(int) key.length()];
        dis.readFully(encoded);

        // PKCS8 decode the encoded RSA private key
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PrivateKey privKey = kf.generatePrivate(keySpec);
        return privKey;
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        if (reader != null) {try {reader.close();} catch (Exception e) {e.printStackTrace();}}
        if (dis != null) {try {dis.close();} catch (Exception e) {e.printStackTrace();}}
    }
    return null;
}

我已经尝试了多种方法来以各种方式读取和处理私钥以进行解码(正如您可以从注释掉的部分中看出来的那样),但是,我还没有找到一个可以通过encryptedData解密的解决方案 . 如果我使用带有RSA算法的密码,我会得到以下堆栈跟踪

javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
at com.sun.crypto.provider.RSACipher.a(DashoA13*..)
at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at my.app.decode(Application.java:124)

这在行byte [] decValue = c.doFinal(encryptedData)中失败;

如果我使用AES算法的密码,我得到以下堆栈跟踪

java.security.InvalidKeyException: No installed provider supports this key: sun.security.rsa.RSAPrivateCrtKeyImpl
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at my.app.Application.decode(Application.java:123)

这在c.init行(Cipher.DECRYPT_MODE,key)失败;

我已经安装了JCE for Java 6(我正在使用它) . 我不知道我做错了什么 . 有人可以指出我正确的方向 .

谢谢

UPDATE

我一直在研究这个问题,并且尝试了Bouncy Castle,但还没有结果 . 这是我使用Bouncy Castle时的第一次尝试 .

BufferedReader reader = new BufferedReader(new FileReader(new File("CA_key.pem")));
PEMParser parser = new PEMParser(reader);
PEMKeyPair keyPair = (PEMKeyPair)parser.readObject();
AsymmetricKeyParameter privKeyParams = PrivateKeyFactory.createKey(keyPair.getPrivateKeyInfo());
AsymmetricKeyParameter publicKeyParams = PublicKeyFactory.createKey(keyPair.getPublicKeyInfo());
parser.close();

RSAEngine e = new RSAEngine();
e.init(false, publicKeyParams);
byte[] decValue = e.processBlock(encryptedData, 0, encryptedData.length);

我再次使用processBlock方法获得异常org.bouncycastle.crypto.DataLengthException:输入对于RSA密码来说太大了 . 我认为这是我之前遇到的问题 . 我真的很茫然,因为gdcmanon工具可以用CA_key.pem文件清楚地解密这个字符串,因为这是唯一的输入(除了要解密的文件) . 我在gdcmanon源代码中一直在寻找它,它看起来像是以某种方式使用AES 256密钥,但我只是看不出我是如何从我生成的RSA密钥中得到的 . 有人可以指出我正确的方向吗?

编辑

我已经更多地浏览了gdcmanon源代码,看起来他们使用的是加密消息语法(CMS) . 这对我来说是全新的,但似乎BC有一堆与CMS相关的类 . 具体来说,gdcmanon正在使用名为PKCS7_dataDecode的OpenSSL方法来解密数据 . 我没有找到关于如何在Java中执行此操作的好例子 . 有任何想法吗?

谢谢

1 回答

  • 0

    经过一段时间的奋斗,我终于得到了以下代码似乎可行 . 如果有人可以在没有BC的情况下告诉我一种方法,那将是非常棒的,但是现在我很高兴它有效 .

    public static String decode(byte[] encryptedData, String keyFile) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(new File(keyFile)));
            PEMParser parser = new PEMParser(reader);
            PEMKeyPair keyPair = (PEMKeyPair)parser.readObject();
            AsymmetricKeyParameter privKeyParams = PrivateKeyFactory.createKey(keyPair.getPrivateKeyInfo());
            parser.close();
    
            CMSEnvelopedData data = new CMSEnvelopedData(encryptedData);
            RecipientInformationStore recipients = data.getRecipientInfos();
    
            Iterator it = recipients.getRecipients().iterator();
    
            if (it.hasNext()) {
                RecipientInformation recipient = (RecipientInformation)it.next();
                byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(privKeyParams));
                String decryptedValue = new String(recData);
                return decryptedValue;
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            if (reader != null) {try {reader.close();} catch (Exception e) {e.printStackTrace();}}
        }
        return null;
    }
    

相关问题