RSA我应该使用X.509还是PKCS#1 [英] RSA should I use X.509 or PKCS #1

查看:120
本文介绍了RSA我应该使用X.509还是PKCS#1的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用例:我有一个用例,其中客户端生成私钥和公钥,将基数为64的已编码公钥发送到服务器.

Use case: I have a use case wherein client generates private and public key , sends the base 64 encoded public key to the server.

在服务器端,我将使用此公钥对消息进行加密,然后将加密的消息发送给客户端,客户端使用其私钥对消息进行解密.达成共识的算法是"RSA".

On server side I will encrypt a message using this public key and send the encrypted message to client , which the client decrypts using its private key.The algorithm agreed upon is 'RSA'.

问题出在服务器端,我看到某些密钥正在使用 X509EncodedKeySpec 作为密钥规范

The problem is on server side I am seeing that certain keys are working using X509EncodedKeySpec as key spec

byte[] publicBytes = Base64.decodeBase64(base64EncodedPubKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);

虽然某些键会引发异常(由java.security.InvalidKeyException引起:IOException:解析错误,不是序列),但使用 X509EncodedKeySpec 却可以使用RSAPublicKeySpec :

While some keys throw exception (Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence) using X509EncodedKeySpec but work using 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);

因此,我了解到的是,客户端和服务器需要同意是否使用: PKCS#1 X.509 用于对密钥进行编码.我的问题是哪种情况最适合我的用例? 任何准则何时使用哪种格式?

So, what I came to understand is that client and server need to agree whether to use: PKCS #1 or X.509 for encoding the key . My question is which one is better for my use case? Any guidelines when to use which format?

推荐答案

差别很小. Java调用X.509的密钥格式,更确切地称为ASN.1结构.在X.509中定义的SubjectPublicKeyInfo (或SPKI),或者等效地且更方便地在 RFC5280中定义sec 4.1 是处理大量灵活算法的一种非常简单的方法:它由一个子结构 AlgorithmIdentifier 组成,该子结构标识算法及其参数(如果适用),然后是一个不透明的BIT STRING其中包含实际密钥信息(已编码),该密钥信息的格式取决于AlgorithmIdentifier(由Identifier标识的算法).

There's very little difference. The key format Java calls X.509, more exactly known as the ASN.1 structure SubjectPublicKeyInfo (or SPKI) defined in X.509 or equivalently and more conveniently in RFC5280 sec 4.1, is a quite simple way to handle a large and flexible set of algorithms: it consists of a substructure AlgorithmIdentifier which identifies the algorithm and its parameters if applicable, then an opaque BIT STRING which contains the actual key information (encoded) in a format depending on (the algorithm identified by) the AlgorithmIdentifier.

对于RSA,算法相关部分 是PKCS1中定义的ASN.1结构 RSAPublicKey 或更方便地

For RSA, the algorithm-dependent part is the ASN.1 structure RSAPublicKey defined in PKCS1 or more conveniently RFC8017 appendix A.1.1 and its earlier versions, and duplicated in RFC3279 sec 2.3.1. Thus for RSA the X.509 (SPKI) format contains the PKCS1 format, and since RSA doesn't have parameters (or at least key-related parameters), the only real difference is that the X.509 format explicitly specifies that the key is RSA -- which in your application you already know.

您已经发现,香草(Oracle-was-Sun-now-OpenJDK)Java加密技术(又名JCA Java加密体系结构)直接仅支持X.509(SPKI)格式,这是一个次要优势.但是,如果使用BouncyCastle,则与Q中的代码相比,来回转换要容易得多.您只需使用 org.bouncycastle.asn1.x509.SubjectPublicKeyInfo 类添加或放弃AlgorithmIdentifier:

You have already discovered that vanilla (Oracle-was-Sun-now-OpenJDK) Java crypto, aka JCA Java Cryptographic Architecture, directly supports only the X.509 (SPKI) format, which is a minor advantage. However if you use BouncyCastle it is much easier to convert back and forth than the code in your Q; you simply use the org.bouncycastle.asn1.x509.SubjectPublicKeyInfo class to add or discard the 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));

请参阅我对类似的> golang x509.MarshalPKIXPublicKey与x509.MarshalPKCS1PublicKey(),尤其是以下链接:
将SubjectPublicKeyInfo格式的公钥转换为RSAPublicKey格式java
在Java中以PKCS#1格式生成RSA密钥
发送RSA公钥,javaME,充气城堡的问题

See my answer to the similar golang x509.MarshalPKIXPublicKey vs x509.MarshalPKCS1PublicKey() and especially the links to:
Converting A public key in SubjectPublicKeyInfo format to RSAPublicKey format java
Generating RSA keys in PKCS#1 format in Java
Problem transmiting a RSA public key, javaME , bouncy castle

如果您没有BouncyCastle,它会更难一些;您需要编写部分ASN.1解析器或生成器.完整的ASN.1处理相当复杂,但是在这种情况下,您只需要一个不太坏的小子集即可.(是的,这是个微弱的赞美.)如果我有更多时间,可以稍后再添加.

If you don't have BouncyCastle, it's a little harder; you need to write a partial ASN.1 parser or generator. Full ASN.1 processing is rather complicated, but for this case you need only a small subset that isn't too bad. (Yeah, that's faint praise.) I may add this later if I have more time.

更大的潜在问题是您的密钥未通过身份验证.公钥分发的困难部分(比微小格式的细节要难得多)是确保仅 合法密钥已分发.如果攻击者可以用他们的公钥代替正确的公钥,那么受害者就可以以一种易于攻击者阅读的方式对所谓的秘密数据进行加密,并且您所有花哨的加密代码完全是一文不值.

A much bigger potential issue is that your key is not authenticated. The hard part of public key distribution, much harder than tiny format details, is making sure that only the legitimate key is distributed. If an attacker can substitute their publickey for the correct one, then the victim encrypts the supposedly secret data in a way the attacker can easily read, and all your fancy cryptography code is completely worthless.

这就是为什么大多数实际系统都不会分发裸机公钥,而是分发可以验证密钥为正确密钥的证书的原因.有几种证书方案,但是到目前为止,最广泛使用的是X.509及其Internet概要文件PKIX-实际上,我在上面引用的RFC 5280和3279是PKIX的一部分.SSL-now-TLS使用X.509.代码签名使用X.509.S/MIME电子邮件使用X.509.(PGP/GPG使用不同类型的证书,而不是X.509,但仍然使用证书.)并且(原始)Java直接支持X.509证书,其性能甚至比"X.509"(SPKI)公钥更好甚至更好.

This is why most actual systems don't distribute bare publickeys, but instead certificates that allow verifying the key is the correct key. There are a few certificate schemes, but the most widespread by far is X.509 and its Internet profile PKIX -- in fact the RFCs I referenced above, 5280 and 3279, are part of PKIX. SSL-now-TLS uses X.509. Code-signing uses X.509. S/MIME email uses X.509. (PGP/GPG uses a different kind of certificates, not X.509, but still certificates.) And (vanilla) Java directly supports X.509 certificates just as well or even better than it does "X.509" (SPKI) publickeys.

这篇关于RSA我应该使用X.509还是PKCS#1的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆