简体   繁体   English

使用Java中的RSA私钥加密

[英]Encrypting with RSA private key in Java

I'm trying to encrypt some content with an RSA private key. 我正在尝试使用RSA私钥加密某些内容。

I'm following this example: http://www.junkheap.net/content/public_key_encryption_java 我正在关注这个例子: http//www.junkheap.net/content/public_key_encryption_java

but converting it to use private keys rather than public. 但转换它使用私钥而不是公共。 Following that example, I think what I need to do is: 在这个例子之后,我认为我需要做的是:

  • Read in a DER-format private key 读入DER格式的私钥
  • Generate a PCKS8EncodedKeySpec 生成PCKS8EncodedKeySpec
  • call generatePrivate() from KeyFactory to get a private key object 从KeyFactory调用generatePrivate()来获取私钥对象
  • Use that private key object with the Cipher object to do the encryption 将该私钥对象与Cipher对象一起使用以进行加密

So, the steps: 那么,步骤:

The key was generated from openssl with: 密钥是从openssl生成的:

openssl genrsa -aes256 -out private.pem 2048

and then was converted to DER format with: 然后转换为DER格式:

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

I generate the PKCS8EncodedKeySpec with: 我生成PKCS8EncodedKeySpec:

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;

And then generate the private key object with: 然后生成私钥对象:

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;

However, on the call to: 但是,在致电:

pk = kf.generatePrivate(privateKeySpec);

I get: 我明白了:

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: 问题:

  • Is the general approach right? 一般方法是对的吗?
  • Is the PCKS8EncodedKeySpec the right keyspec to use? PCKS8EncodedKeySpec是否使用正确的keyspec?
  • Any thoughts on the invalid key spec error? 有关无效密钥规范错误的任何想法?

You can't encrypt with private key. 您无法使用私钥加密。 If JCE allows you to do that, it's just by accident. 如果JCE允许你这样做,那只是偶然的。

You need to use signature. 你需要使用签名。 Here are the code snippet to do that, 以下是执行此操作的代码段,

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

First of all, I'm confused why you are planning to use a Cipher to encrypt with a private key, rather than signing with a Signature . 首先,我很困惑为什么你打算使用Cipher来加密私钥,而不是使用签名进行Signature I'm not sure that all RSA Cipher providers will use the correct block type for setup, but it's worth a try. 我不确定所有RSA Cipher提供商都会使用正确的块类型进行设置,但值得一试。

Setting that aside, though, I think that you are trying to load a non-standard OpenSSL-format key. 但是,除此之外,我认为您正在尝试加载非标准的OpenSSL格式密钥。 Converting it to DER with rsa is essentially just a base-64 decode; rsa将它转换为DER本质上只是一个base-64解码; the structure of the key is not PKCS #8. 密钥的结构不是PKCS#8。

Instead, after genrsa , use the openssl pkcs8 command to convert the generated key to unencrypted PKCS #8, DER format: 相反,在genrsa之后,使用openssl pkcs8命令将生成的密钥转换为未加密的PKCS#8,DER格式:

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

This will produce an unencrypted private key that can be loaded with a PKCS8EncodedKeySpec . 这将生成一个未加密的私钥,可以加载PKCS8EncodedKeySpec

Its not an accident that encryption with private key is allowed. 允许使用私钥加密并非偶然。 If you want to break a signature into individual hashing and encryption, then encrypting with private key is essential. 如果要将签名分解为单独的散列和加密,则必须使用私钥进行加密。 Lets say I have a document which i need to sign and my key resides on a network HSM. 假设我有一个文档,我需要签名,我的密钥驻留在网络HSM上。 Now either I stream the entire document to the HSM to sign or I can create a local hash and stream it to the HSM for encryption alone. 现在要么将整个文档流式传输到HSM进行签名,要么我可以创建本地哈希并将其流式传输到HSM以进行加密。 My choice will depend on whether the local hash computation gives me better performance viz a viz delegated hash computation with network latency. 我的选择将取决于本地哈希计算是否给了我更好的性能,即带有网络延迟的委托哈希计算。

This question is pretty old, but I recently stumbled upon the problem (I'm implementing requirements of some protocol which requires encryption with private key). 这个问题很老了,但我最近偶然发现了这个问题(我正在实现一些需要使用私钥加密的协议的要求)。 I will just quote the post from forum : 我将引用论坛的帖子

I recently stumbled upon the same issue, submitted PMR 22265,49R, and IBM Support after consultation with "development" (whoever those are) ruled that private keys cannot be used for encryption. 我最近偶然发现了同样的问题,提交了PMR 22265,49R和IBM支持人员,在咨询“开发”(无论是谁)之后,他们认为私钥不能用于加密。 No matter how much I tried to argue with them that private keys should not be used for data protection, which is only one purpose behind encryption, and that it is perfectly fine to use private keys for encryption to achieve non-repudiation, they were unshakable in their belief. 无论我多么努力与他们争论私钥不应该用于数据保护,这只是加密背后的一个目的,并且使用私钥进行加密以实现不可否认性是完全正常的,它们是不可动摇的他们的信仰。 You have got to love people, who insist that 2x2=5. 你必须爱上那些坚持认为2x2 = 5的人。

Here is how I worked around this problem: Essentially, I created a public key object with private key's crypto material. 以下是我解决这个问题的方法:基本上,我使用私钥的加密材料创建了一个公钥对象。 You will need to do the reverse, create a private key object with public key's crypto material, to decrypt with public key if you want to avoid the "Public key cannot be used to decrypt" exception. 您需要执行相反的操作,使用公钥的加密材料创建私钥对象,如果要避免“公钥不能用于解密”异常,则使用公钥解密。

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);

try this: 试试这个:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM