在 Java 中使用 RSA 私钥加密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1391692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:35:28  来源:igfitidea点击:

Encrypting with RSA private key in Java

javaencryptioncryptographyrsaprivate-key

提问by wadesworld

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

but converting it to use private keys rather than public. Following that example, I think what I need to do is:

我正在关注这个例子:http: //www.junkheap.net/content/public_key_encryption_java

但将其转换为使用私钥而不是公共密钥。按照那个例子,我认为我需要做的是:

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

So, the steps:

所以,步骤:

The key was generated from openssl with:

密钥是从 openssl 生成的:

openssl genrsa -aes256 -out private.pem 2048

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

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?
  • Any thoughts on the invalid key spec error?
  • 一般方法是对的吗?
  • PCKS8EncodedKeySpec 是要使用的正确密钥规范吗?
  • 关于无效密钥规范错误的任何想法?

采纳答案by erickson

First of all, I'm confused why you are planning to use a Cipherto encrypt with a private key, rather than signing with a Signature. I'm not sure that all RSA Cipherproviders will use the correct block type for setup, but it's worth a try.

首先,我很困惑为什么您打算使用 aCipher用私钥加密,而不是用Signature. 我不确定所有 RSACipher提供商都会使用正确的块类型进行设置,但值得一试。

Setting that aside, though, I think that you are trying to load a non-standard OpenSSL-format key. Converting it to DER with rsais essentially just a base-64 decode; the structure of the key is not PKCS #8.

尽管如此,我认为您正在尝试加载非标准 OpenSSL 格式的密钥。将其转换为 DERrsa本质上只是一个 base-64 解码;密钥的结构不是 PKCS #8。

Instead, after genrsa, use the openssl pkcs8command 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.

回答by ZZ Coder

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

回答by Kapil

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. 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. My choice will depend on whether the local hash computation gives me better performance viz a viz delegated hash computation with network latency.

允许使用私钥加密并非偶然。如果您想将签名分解为单独的散列和加密,那么使用私钥加密是必不可少的。假设我有一个需要签名的文档,我的密钥位于网络 HSM 上。现在,我可以将整个文档流式传输到 HSM 进行签名,也可以创建本地哈希并将其流式传输到 HSM 以单独进行加密。我的选择将取决于本地哈希计算是否为我提供更好的性能,即具有网络延迟的委托哈希计算。

回答by dmitry

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. 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.

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.

我最近偶然发现了同样的问题,提交了 PMR 22265,49R,IBM 支持在与“开发”(无论是谁)协商后裁定私钥不能用于加密。无论我如何试图与他们争论私钥不应该用于数据保护,这只是加密背后的一个目的,并且使用私钥进行加密以实现不可否认性是完全可以的,他们是不可动摇的在他们的信仰中。你必须爱那些坚持 2x2=5 的人。

以下是我解决这个问题的方法:本质上,我使用私钥的加密材料创建了一个公钥对象。如果您想避免“公钥不能用于解密”异常,您将需要做相反的事情,使用公钥的加密材料创建一个私钥对象,用公钥解密。

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

回答by Jimmy Chan

try this:

尝试这个:

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