Man*_*ena 1 java public-key-encryption public-key
用例:我有一个用例,其中客户端生成私钥和公钥,将 base 64 编码的公钥发送到服务器。
在服务器端,我将使用此公钥加密消息并将加密消息发送到客户端,客户端使用其私钥解密。商定的算法是“RSA”。
问题出在服务器端,我看到某些密钥正在X509EncodedKeySpec用作密钥规范
byte[] publicBytes = Base64.decodeBase64(base64EncodedPubKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Run Code Online (Sandbox Code Playgroud)
虽然有些键会使用以下方法抛出异常 ( Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence)X509EncodedKeySpec但可以使用RSAPublicKeySpec:
byte[] publicBytes = Base64.decodeBase64(base64EncodedPubKey);
org.bouncycastle.asn1.pkcs.RSAPublicKey.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.RSAPublicKey.getInstance(publicBytes);
BigInteger modulus = pkcs1PublicKey.getModulus();
BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Run Code Online (Sandbox Code Playgroud)
所以,我开始理解的是客户端和服务器需要同意是否使用:
PKCS #1或X.509对 key 进行编码。我的问题是哪个更适合我的用例? 何时使用哪种格式的任何指南?
差别很小。Java 调用 X.509 的密钥格式,更确切地说SubjectPublicKeyInfo是 X.509 中定义的 ASN.1 结构(或 SPKI),或者等效且更方便地在RFC5280 sec 4.1 中,是一种非常简单的方法来处理大量灵活的算法:它由一个子结构组成,该子结构AlgorithmIdentifier标识算法及其参数(如果适用),然后是一个不透明的 BIT STRING,其中包含实际关键信息(编码),格式取决于(由算法标识)AlgorithmIdentifier。
对于 RSA,算法相关部分是RSAPublicKey在 PKCS1 或更方便的RFC8017 附录 A.1.1及其早期版本中定义的 ASN.1 结构,并在RFC3279 sec 2.3.1 中复制。因此,对于 RSA,X.509 (SPKI) 格式包含PKCS1 格式,并且由于 RSA 没有参数(或至少与密钥相关的参数),唯一真正的区别是 X.509 格式明确指定了密钥是 RSA——在您的应用程序中您已经知道了。
您已经发现 vanilla (Oracle-was-Sun-now-OpenJDK) Java 加密,又名 JCA Java 加密架构,仅直接支持 X.509 (SPKI) 格式,这是一个次要优势。但是,如果您使用 BouncyCastle,与 Q 中的代码相比,来回转换要容易得多;您只需使用org.bouncycastle.asn1.x509.SubjectPublicKeyInfo该类添加或丢弃 AlgorithmIdentifier:
// test data source
KeyStore ks = KeyStore.getInstance("JKS"); ks.load (new FileInputStream (args[0]), args[1].toCharArray());
byte[] spkienc = ks.getCertificate(args[2]).getPublicKey().getEncoded();
System.out.println (DatatypeConverter.printHexBinary(spkienc));
// extract PKCS1 part of original SPKI
byte[] pkcs1enc = SubjectPublicKeyInfo.getInstance(spkienc).parsePublicKey().getEncoded();
System.out.println (DatatypeConverter.printHexBinary(pkcs1enc));
// rebuild SPKI from the PKCS1
AlgorithmIdentifier algid = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
byte[] spki2enc = new SubjectPublicKeyInfo (algid, pkcs1enc).getEncoded();
System.out.println (DatatypeConverter.printHexBinary(spki2enc));
Run Code Online (Sandbox Code Playgroud)
请参阅我对类似golang x509.MarshalPKIXPublicKey 与 x509.MarshalPKCS1PublicKey() 的回答,尤其是以下链接:
Converting A public key in SubjectPublicKeyInfo format to RSAPublicKey format java
Generating RSA keys in PKCS#1 format in Java Problem transfer
a RSA public key, javaME,充气城堡
如果你没有 BouncyCastle,那就有点难了;您需要编写部分 ASN.1 解析器或生成器。完整的 ASN.1 处理相当复杂,但对于这种情况,您只需要一个还不错的小子集。(是的,这是微不足道的赞美。)如果我有更多时间,我可能会在以后添加。
一个更大的潜在问题是您的密钥未经过身份验证。公钥分发的困难部分,比微小的格式细节更难,是确保只分发合法的密钥。如果攻击者可以将他们的公钥替换为正确的公钥,那么受害者就会以一种攻击者可以轻松读取的方式加密所谓的秘密数据,而您所有花哨的加密代码就完全一文不值。
这就是为什么大多数实际系统不分发裸公钥,而是分发允许验证密钥是正确密钥的证书。有一些证书方案,但迄今为止最广泛使用的是 X.509 及其 Internet 配置文件 PKIX —— 事实上,我上面引用的 RFC 5280 和 3279 是 PKIX 的一部分。SSL-now-TLS 使用 X.509。代码签名使用 X.509。S/MIME 电子邮件使用 X.509。(PGP/GPG 使用不同类型的证书,不是 X.509,但仍然是证书。)而且(vanilla)Java 直接支持 X.509 证书与“X.509”(SPKI)公钥一样好甚至更好.
| 归档时间: |
|
| 查看次数: |
3001 次 |
| 最近记录: |