【问题标题】:RSA result with negative symbol in JAVAJAVA中带有负号的RSA结果
【发布时间】:2013-08-19 18:32:18
【问题描述】:

我不是密码学专家,当我使用下面的加密方法时,我得到了一些有趣的结果。

服务器是 .NET C#,客户端运行 JAVA。基本上,我们对信用卡信息进行加密,对于我拥有的 12 张信用卡,其中 11 张与以下方法完美配合。

但是,encrypt() 返回并转换为十六进制的结果中的一张卡(真正的 VISA 信用卡)在字符串的开头有一个负号,如下所示:

-6d9830a52b2c3add7a78fd9897bca19d.....,当服务器尝试解密它时它失败了,我认为根据这个解释应该是肯定的而不是否定的RSA - Encryption with negative exponent

            private static byte[] encrypt(String text, PublicKey pubRSA) throws Exception
            {
             Cipher cipher = Cipher.getInstance(RSA);
             cipher.init(Cipher.ENCRYPT_MODE, pubRSA);
             return cipher.doFinal(text.getBytes());
            }

            //Using this encryption method one card could not be decrypted by vPAY due to negative (exponential) symbol.
            //It may have the same affect with other cards
            public final static byte[] encrypt(String text)
            {
             try {

                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(Base64.decode(pkBase64));
                PublicKey pk = keyFactory.generatePublic(x509Spec);

                return encrypt(text, pk);
             }
             catch(Exception e)
             {
              e.printStackTrace();
             }
             return null;
            }

有没有人遇到过类似的情况并找到了解决方法? 我已经尝试了其他三种算法,它们具有不同的KeySpec 和相同的 publicKey(源是 base64 格式的字符串),但是即使使用之前工作的卡,服务器也无法解密它们......

更新 1

这是将加密结果以字节为单位转换为 HEX 的方式:

            public static String byteToHex(byte[] string)
              {
                    try {
                        return String.format("%04x", new BigInteger(string));
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        return null;
                    }
              }

【问题讨论】:

  • 如何转换为十六进制?字节签名是Java。在将其转换为十六进制字符串之前,您可能需要在 int (stackoverflow.com/questions/4266756/…) 中获取无符号值。
  • @Kazaag 感谢您对此的关注....请参阅“更新 1”。

标签: java encryption rsa


【解决方案1】:

您应该直接从byte[] 打印出十六进制字符串。这可以使用以下代码完成:

StringBuilder sb = new StringBuilder(data.length * 2);
for (int i = 0; i < data.length; i++) {
    sb.append(String.format("%02X", data[i] & 0xFF));
}
return sb.toString();

没有必要使用BigInteger。事实上,使用 BigInteger 是危险的。原因之一是您已经遇到过的:BigIntegerbyte[] 的转换默认使用有符号大端编码。另一件事是 RSA 签名的输出(作为整数)可能小于 比以十六进制表示的模数大小。这就是为什么 EJP 的解决方案有时会失败的原因。

RSA 输出以字节为单位定义,作为无符号大端编码,其位数与密钥大小相同(在标准文档中使用整数到八位字节字符串编码)。

【讨论】:

    【解决方案2】:

    public static String byteToHex(byte[] string)

    byte[] 不是字符串。这是一个字节数组。不要将自己与不适当的变量名混淆。字符串不是二进制数据的容器。

    return String.format("%04x", new BigInteger(string));
    

    尝试return new BigInteger(1,string).toString(16), 并查看Javadoc,了解为什么它在new BigInteger(string) 不适用的情况下有效。

    【讨论】:

    • 这并不总是有效。 BigInteger 输出可能小于 RSA 加密的输出。所以你会错过从零开始的。也不需要与 BigInteger 相互转换。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    • 2021-05-14
    相关资源
    最近更新 更多