Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/381.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何生成可用于C和Java的公钥和私钥?_Java_Openssl_Public Key_Public Key Encryption - Fatal编程技术网

如何生成可用于C和Java的公钥和私钥?

如何生成可用于C和Java的公钥和私钥?,java,openssl,public-key,public-key-encryption,Java,Openssl,Public Key,Public Key Encryption,我正在尝试在Windows7 64位上使用OpenSSL生成PKCS12公钥和私钥,该公钥和私钥可由C中的Microsoft CryptoAPI以及Java程序使用 以下是我遵循的步骤: 下载安装的微软Visual C++ 2008可重分发包(X64)DE: 下载并安装了“Win64 OpenSSL v1.0.2a Light”de: 要使用非对称(公钥)加密技术加密/解密任意大小的文件,您需要使用S/MIME编码: 1) 生成密钥对。这将生成2048位公共加密密钥/证书rsakpubcer

我正在尝试在Windows7 64位上使用OpenSSL生成PKCS12公钥和私钥,该公钥和私钥可由C中的Microsoft CryptoAPI以及Java程序使用

以下是我遵循的步骤:

下载安装的微软Visual C++ 2008可重分发包(X64)DE:

下载并安装了“Win64 OpenSSL v1.0.2a Light”de:

要使用非对称(公钥)加密技术加密/解密任意大小的文件,您需要使用S/MIME编码:

1) 生成密钥对。这将生成2048位公共加密密钥/证书rsakpubcert.key和匹配的私有解密密钥rsakpriv.key。-天10000意味着保持它的有效期很长一段时间(27年左右)。您将被要求(两次)使用PEM密码来加密私钥。如果不希望对其进行加密,请传递-nodes选项。公钥可以分发给任何想要向您发送数据的人

md C:\OpenSSL-Win64\bin    
cd C:\OpenSSL-Win64\bin    
set OPENSSL_CONF=C:\OpenSSL-Win64\bin\openssl.cfg    
openssl req -x509 -days 10000 -newkey rsa:2048 -keyout c:\opensslkeys\rsakpriv.key -out c:\opensslkeys\rsakpubcert.key

// pass phrase used: mypassword
2) 创建自签名证书的请求

openssl req -new -key c:\opensslkeys\rsakpriv.key -out c:\opensslkeys\server.csr
3) 从私钥中删除密码

openssl rsa -in c:\opensslkeys\rsakpriv.key -out c:\opensslkeys\rsakprivnopassword.key
4) 自行签署证书请求(-days为到期天数)
重要提示:使用“以管理员身份运行”启动命令提示符。否则会得到相同的结果:无法写入“随机状态”错误

cd C:\OpenSSL-Win64\bin    
set OPENSSL_CONF=C:\OpenSSL-Win64\bin\openssl.cfg    
openssl x509 -req -days 365 -in c:\opensslkeys\server.csr -signkey c:\opensslkeys\rsakprivnopassword.key -out c:\opensslkeys\server.crt
5) 将输出转换为我们可以在代码中使用的PKCS#12格式(-keysig参数允许我们使用密钥对进行签名)

此时,我可以使用以下命令使用openssl加密和解密文件:

要加密:

openssl smime -encrypt -binary -aes-256-cbc -in c:\opensslkeys\todo.txt -out c:\opensslkeys\done.txt -outform DER c:\opensslkeys\server.crt
要解密:

openssl smime -decrypt -binary -in c:\opensslkeys\done.txt -inform DER -out c:\opensslkeys\redone.txt -inkey c:\opensslkeys\rsakprivnopassword.key
然而,当我试图在Java中使用密钥时,程序阻塞了,说密钥格式是错误的

非常感谢您的帮助!我保证会把这篇文章发出去,为其他人提供完整的工作答案


完整的Java代码:

/*
PrivatePublicKey.java   
*/
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import javax.crypto.Cipher;
/* for IBM JDK need to replace: */
//import java.util.Base64;
/* with: */
import org.apache.commons.codec.binary.Base64;

public class PrivatePublicKey 
{
    public static void main(String[] args) throws Exception 
    {
        try 
        {
            PublicKeyReader myPublic = new PublicKeyReader();
            PublicKey publicKey = myPublic.get("./rsakpubcert.key");

            PrivateKeyReader myPrivate = new PrivateKeyReader();
            PrivateKey privateKey = myPrivate.get("./rsakprivnopassword.key");

            // Let's encrypt with private and decrypt with public
            // Encrypt with private key
            String firstString = "Ishana";

            Cipher privateEncryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            privateEncryptCipher.init(Cipher.ENCRYPT_MODE, privateKey);

            byte[] encryptedFirstString = privateEncryptCipher.doFinal(firstString.getBytes());
            String encodedEncryptedFirstString = Base64.encodeBase64String(encryptedFirstString);

            System.out.println("Encoded encrypted String for Ishana: " + encodedEncryptedFirstString);

            // Decrypt with public key
            // First decode the string
            byte[] decodedEncryptedFirstString = Base64.decodeBase64(encodedEncryptedFirstString);

            Cipher publicDecryptCipher = Cipher
                .getInstance("RSA/ECB/PKCS1Padding");
            publicDecryptCipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] decryptedFirstStringByte =     publicDecryptCipher.doFinal(decodedEncryptedFirstString);
            System.out.println("Decrypted String for Ishana: " + new String(decryptedFirstStringByte));
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
}
编辑,添加辅助代码:

import java.io.*;
import java.security.*;
import java.security.spec.*;


public class PublicKeyReader {

  public static PublicKey get(String filename)
throws Exception {

    File f = new File(filename);
    FileInputStream fis = new FileInputStream(f);
    DataInputStream dis = new DataInputStream(fis);
    byte[] keyBytes = new byte[(int)f.length()];
    dis.readFully(keyBytes);
    dis.close();

    X509EncodedKeySpec spec =
      new X509EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePublic(spec);
  }
}

如何生成可用于C和Java的公钥和私钥

生成密钥对并在内存中表示它们不同于在Java或其他框架/库(如OpenSSL)中使用它们

表示内存中的键是特定于框架/库的

对密钥进行编码以使不同的框架/库能够使用它们是一个诀窍


然而,当我试图在Java中使用密钥时,程序阻塞了,说密钥格式是错误的

在Java中,对键调用
getBytes()
就足够了。钥匙将以自然的形式提供。例如,在RSA公钥上调用它将导致来自PKCS 1的ASN.1编码

互操作性考虑的其他格式是私钥和PKCS12的PKCS8。

也有PEM,但它是一种较旧的格式。PEM可以用于公钥,但您应该使用PKCS8或PKCS12用于私钥



使用OpenSSL生成的私有文件可能是加密的PEM格式(您应该说明您为它们使用的编码)。见和。如果是DER编码的话,那么请看

我终于能够做到这一点了

起点是:

遇到的问题

1) CryptoAPI使用的Microsoft公钥和私钥使用Java无法使用的专有二进制格式(通常称为PUBLICKEYBLOB和PRIVATEKEYBLOB)。需要转换钥匙

2) Crypto API以小端二进制格式加密,而Java以大端二进制格式读取字节。参考:和 需要进行二进制转换

3) Microsoft CryptoAPI在对消息进行加密时填充消息。这意味着要在Java中解密,需要RSA算法的精确实现,这需要考虑使用的填充方案

在Java解密方面,我使用了Cipher.getInstance(“RSA/NONE/pkcs1ppadding”)


希望这对其他人有所帮助。

PublicKeyReader/PrivateKeyReader不是标准的JRE类。它们属于哪个库?我看到这是从服务器故障迁移而来的。另请参见.javacrypto(JCE)可以直接使用PKCS#12;只需
java.security.Keystore.getInstance(“PKCS12”)
。从文件中加载它,然后使用其中的密钥和证书执行所需的操作。(PKCS#12通常可以有多个密钥和证书,Java支持这一点,OpenSSL库也支持这一点,但OpenSSL命令行不支持。)
OpenSSL req-newkey
在OP identified(1.0.2)版本中创建PKCS#8加密(和PEM),Java无法直接处理
openssl rsa
删除加密,但使用“原始”PKCS#1。改为执行
openssl pkey
将生成未加密的PKCS#8,添加
-outform der
将使RSA类型的Java KeyFactory可读。PKCS#8,尤其是PKCS#**12**是常见的文件格式;PKCS#**11**是硬件或伪硬件设备的通用接口,通常不使用任何格式的文件。谢谢Dave。我知道我应该验证PKCS11而不是依赖内存…您好。关于#1,您能否给出如何将BLOB转换为纯文本并返回BLOB格式的建议?
import java.io.*;
import java.security.*;
import java.security.spec.*;


public class PublicKeyReader {

  public static PublicKey get(String filename)
throws Exception {

    File f = new File(filename);
    FileInputStream fis = new FileInputStream(f);
    DataInputStream dis = new DataInputStream(fis);
    byte[] keyBytes = new byte[(int)f.length()];
    dis.readFully(keyBytes);
    dis.close();

    X509EncodedKeySpec spec =
      new X509EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePublic(spec);
  }
}
import java.io.*;
import java.security.*;
import java.security.spec.*;

public class PrivateKeyReader {

  public static PrivateKey get(String filename)
  throws Exception {

    File f = new File(filename);
    FileInputStream fis = new FileInputStream(f);
    DataInputStream dis = new DataInputStream(fis);
    byte[] keyBytes = new byte[(int)f.length()];
    dis.readFully(keyBytes);
    dis.close();

    PKCS8EncodedKeySpec spec =
      new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePrivate(spec);
  }
}