Java(Android)中的RSA密钥签名和验证

时间:2019-01-27 16:33:23

标签: android rsa public-key

我在理解RSA签名和验证的概念时遇到了一个小问题。 问题是我可以创建完美的密钥对(公钥和私钥)。

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        random = SecureRandom.getInstance("SHA1PRNG");
        keyGen.initialize(2048, random);
        KeyPair pair = keyGen.generateKeyPair();
        myPrivateKey = pair.getPrivate();
        myPublicKey = pair.getPublic();

签名和验证如下:

        //Singing with private key
        Signature s = Signature.getInstance("SHA1withRSA");
        s.initSign(javaPrivateKey);

        //Verifying with public key
        Signature s = Signature.getInstance("SHA1withRSA");
        s.initVerify(javaPublicKey);

当我打印myPrivateKey和myPublicKey时,我看到公钥和私钥的模数(n)和公有指数(e)相同。

我已经将公钥和私钥转换为base64和hex,并且得到了完全不同的不同值。但是,我无法使用base64或hex签署消息。我只能用从中得到的签名:

         myPrivateKey = pair.getPrivate();  

我知道需要使用每个人都可以看到的公钥进行验证。接收者验证消息后,接收者是否仅使用模数和指数?发送者需要共享公共密钥的哪一部分?键的模数和指数还是Base64或十六进制值?

1 个答案:

答案 0 :(得分:1)

是的,接收方仅使用模数和指数;从数学上讲,没有其他组件可以用来验证RSA的签名。

使用大数(在软件中实施RSA时通常使用BigInteger值)执行数学运算。为了执行任何类型的计算,实现必须重新生成这些数字。这些数字的传输方式与算法无关。

使用基于PKCS#1的某种东西对通用RSA公钥进行编码,后者使用ASN.1(定义结构)和BER / DER(定义该结构的编码)指定公钥格式。当然,不同的协议可以使用公共密钥的不同编码。例如,PGP使用完全不同的“包格式”对密钥进行编码。


但是,Java返回X.509(证书和CRL)规范中定义的SubjectPublicKeyInfo结构;除了模数和指数外,还包含一个算法标识符,以表明它是RSA公钥。因此,此结构还可用于分配其他类型的键值。可以通过在getEncoded()实例上调用RSAPublicKey来检索它-假定该实例与提供的Oracle实例兼容-通常情况下。 Android的实现当然应该与此结构兼容。请注意,SubjectPublicKeyInfo结构在其内部包含PKCS#1公钥结构

要进行反向操作,您需要一个KeyFactory.getInstance("RSA")并使用X509EncodedKeySpec派生密钥,并使用给定的字节数组进行初始化。


如果,您需要文本字符串而不是二进制字符串,则可以将getEncoded()返回的字节转换为64位和十六进制。当然,在这种情况下,您需要先对结果进行编码(即解码),然后才能对字节本身进行解码。

也可以自己编码模数和公共指数。您可以使用RSAPublicKey.getModulus()RSAPublicKey.getPublicExponent()来检索它们。要将它们反转回RSAPublicKey,可以使用KeyFactory.getInstance("RSA")RSAPublicKeySpec。这样,您可以例如只创建一个字符串"(<modulus>, <exp>)"并使用它来分发密钥。通常,您通常希望遵守预定义的标准。


此答案未涵盖的事实是,要使用公共密钥进行验证,您首先需要在公共密钥中建立 trust 。如果您不能信任公共密钥,那么您将不知道是谁创建了公共密钥。在这种情况下,您也不能相信验证操作的结果;签名可能是用对手的密钥对创建的。不过,对于这个答案来说,深入研究公钥基础结构(PKI / PKIX)有点太多。

同样:SHA-1不再被认为是安全的,尤其是用于签名生成/验证。您可能希望至少使用SHA256withRSA,或者使用稍微更高级,更安全的使用PSS的RSA方案。 2048位太小,无法舒适使用;如果方案允许,建议使用4096位密钥。