【问题标题】:Difference between results with RSA Encryption with Bouncy Castle in Java and C#使用 Java 和 C# 中的 Bouncy Castle 进行 RSA 加密的结果之间的差异
【发布时间】:2015-08-08 19:02:16
【问题描述】:

我有一个需要移植到 C# 的 Java 工作示例应用程序(它使用 Bouncy Castle)(我也在 C# 中使用 Bouncy Castle)。

代码几乎相同。然而,即使我为两者提供完全相同的模数和指数,结果数组也是完全不同的字符串。

重申:Java 摘录是有效的代码

我哪里错了?提前谢谢!

Java:

public static String encodeRSA(String keyModulus, String keyExponent,
        String data) {
    try {

        byte btMod[] = Base64.decode(keyModulus);
        byte btExp[] = Base64.decode(keyExponent);

        BigInteger modulus = new BigInteger(1, btMod);
        BigInteger pubExp = new BigInteger(1, btExp);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(modulus, pubExp);
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] cipherData = cipher.doFinal(data.getBytes());
        String tmp = new String(Base64.encode(cipherData));

        System.out.println(tmp);

        return tmp;
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
    return "";
}

C#:

    private static string EncodeRSA(string modulus, string exponent, string data)
    {
        //Base64, DotNetUtilities functions and BigInteger type are from Bouncy Castle
        byte[] btMod = Base64.Decode(modulus);
        byte[] btExp = Base64.Decode(exponent);

        BigInteger mod = new BigInteger(1, btMod);
        BigInteger exp = new BigInteger(1, btExp);

        RsaKeyParameters bcKeySpec = new RsaKeyParameters(false, mod, exp);
        RSAParameters keySpec = DotNetUtilities.ToRSAParameters(bcKeySpec);

        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(keySpec);


        byte[] plaintext = Encoding.UTF8.GetBytes(data);
        byte[] ciphertext = rsa.Encrypt(plaintext, false);
        string cipherresult = Encoding.UTF8.GetString(Base64.Encode(ciphertext));
        return cipherresult;
    }

模量:

gdBAMJVXCuEGhX0b1hPAggpD7Ayi33JhsARksGkEatQsdox3BG3bTR/vz8M4vZe74EZj0aZrk0rGJGmAEJZ9GlXq6JzIRYBW5zULsBoPDq4spgobECJLsXq8CnZzOrOM+meIXFhoK8Jyob4X9q62HkDwhMMyqsBG0epWMHPIgkU=

指数:

AQAB

输出:

Java output for the entry "1]teste]111111]MTExMTExMTExMTExMTExMQ==" 
using the given modulus/exponent

dUCVsGrZIwSyh0ZAxon3wMSPPoQqflpRNtQ5c+TILuOR/5IihABJpZRL6E1TjYs62WXvQUbeFqRYbdAvbjY3YZk+aSviBosdN54+T8+/5agjveeDBi6LXu6r1+KBriq2K1ULg9YC62SrSbRN8VMJ9gkgatF2ux06PyouJOPJPN8=

编辑 - 具有给定条目、模数和指数的 C# 输出

CHyg5J+OMuG9H9S7R24Lg2iXeLN/Rgh7XcyDQJqMNZobH0V1hqe2dxrcE3R+UrVl/aDWJg3aXNtP3+8YFA17fLr9yIbIYv5o2zeRMdHbyrW/z26JGaynsay096KEzJ0uBAACJQ3LZryd5ei7zzo77Bnka2Un7C9TJvldswhldxM=

【问题讨论】:

  • 你的 C# 输出在哪里?我已经看到了一些错误和不一致之处,但是如果没有 C# 输出,我无法完全回答。
  • Java 'byte' 是有符号字节,因此它转换为 C# 'sbtye',而不是 'byte'。将 'byte' 更改为 'sbyte' 并检查输出。
  • @DaveDoknjas 这不会解决它。请注意,输出是 base64。 Base64 一次编码 6 位,它不关心该位是符号位还是值位。
  • @MaartenBodewes:啊-感谢您的澄清!
  • 谢谢@MaartenBodewes!我添加了 C# 输出

标签: java c# encryption rsa bouncycastle


【解决方案1】:

RSA 加密或任何安全加密方法的输出会向攻击者输出无法区分的随机数据。这由对称密码的 IV 和 RSA 的 填充方法 执行。如果不是这种情况,那么攻击者将能够看到不同密文的相似之处;加密“是”两次,就会出现相同的密文。因此攻击者可以轻松区分E(pk, "yes") | E(pk, "yes")E(pk, "yes") | E (pk, "no")

所以 Java 和 C# 都输出一个密文,该密文正好是编码前模数的大小。然而,在用于 RSA 的模幂运算之前,明文首先用安全的随机数据填充。验证密文生成是否正确的方法是使用私钥解密密文。实际上,如果您多次运行 Java 或 C#,您会发现即使在相同的语言/运行时,密文也会不断变化。

【讨论】:

  • 感谢@MaartenBodewes 的澄清。关于单元测试:如果我需要为像这样的加密方法(用于加密)编写单元测试,我将大致依赖于以前已知的解密方法,反之亦然?有没有办法为加密方法编写可靠的单元测试?
  • 好吧,因为您将使用测试密钥(我希望),您应该始终能够加密解密。然而,我主要测试输入/输出处理的正确性。 RSA 本身应该由平台测试。您当然应该进行一两个测试来测试平台上没有灾难性故障,即测试 2 个加密具有不同的密文以及单个加密/解密是否正常工作。否则:边界检查、状态检查等应该让你忙个不停。
猜你喜欢
  • 1970-01-01
  • 2012-04-25
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 2011-05-02
  • 2020-01-17
  • 1970-01-01
  • 2017-02-19
相关资源
最近更新 更多