Java中使用RSA私钥加密

发布于 2024-08-04 07:17:52 字数 1983 浏览 5 评论 0原文

我正在尝试使用 RSA 私钥加密某些内容。

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

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

  • 读入 DER 格式的私钥
  • 生成 PCKS8EncodedKeySpec
  • 从 KeyFactory 调用generatePrivate() 来获取私钥对象
  • 使用该私钥对象与 Cipher 对象进行加密

所以,步骤:

密钥是从 openssl 生成的:

openssl genrsa -aes256 -out private.pem 2048

,然后转换为 DER 格式:

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

我使用以下方法生成 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;

然后使用以下方法生成私钥对象:

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;

但是,在调用时:

pk = kf.generatePrivate(privateKeySpec);

我得到:

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)

问题:

  • 一般方法正确吗?
  • PCKS8EncodedKeySpec 是正确使用的密钥规范吗?
  • 关于无效的关键规范错误有什么想法吗?

I'm trying to encrypt some content with an RSA private key.

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:

  • 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

So, the steps:

The key was generated from openssl with:

openssl genrsa -aes256 -out private.pem 2048

and then was converted to DER format with:

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

I generate the PKCS8EncodedKeySpec with:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

怎言笑 2024-08-11 07:17:52

您无法使用私钥加密。如果 JCE 允许您这样做,那只是偶然。

您需要使用签名。这是执行此操作的代码片段,

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

You can't encrypt with private key. If JCE allows you to do that, it's just by accident.

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();
深空失忆 2024-08-11 07:17:52

首先,我很困惑为什么您计划使用Cipher 来使用私钥进行加密,而不是使用Signature 进行签名。我不确定所有 RSA Cipher 提供程序都会使用正确的块类型进行设置,但值得一试。

不过,抛开这一点,我认为您正在尝试加载非标准 OpenSSL 格式的密钥。使用 rsa 将其转换为 DER 本质上只是一个 Base-64 解码;密钥的结构不是 PKCS #8。

相反,在 genrsa 之后,使用 openssl pkcs8 命令将生成的密钥转换为未加密的 PKCS #8、DER 格式:

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

这将生成一个未加密的私钥,可以使用一个PKCS8EncodedKeySpec

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. I'm not sure that all RSA Cipher providers will use the correct block type for setup, but it's worth a try.

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

Instead, after genrsa, use the openssl pkcs8 command to convert the generated key to unencrypted PKCS #8, DER format:

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.

往事随风而去 2024-08-11 07:17:52

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

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.

金橙橙 2024-08-11 07:17:52

这个问题很老了,但我最近偶然发现了这个问题(我正在实现一些需要使用私钥加密的协议的要求)。我将引用 论坛

我最近偶然发现了同样的问题,提交了 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);

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.

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);
苍白女子 2024-08-11 07:17:52

试试这个:

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

try this:

java.security.Security.addProvider(
                     new org.bouncycastle.jce.provider.BouncyCastleProvider()
            );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文