RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 987227
Accepted
Rootware
Rootware
Asked:2020-05-30 09:24:21 +0000 UTC2020-05-30 09:24:21 +0000 UTC 2020-05-30 09:24:21 +0000 UTC

Java 和 C# 应用程序之间的 RSA 加密

  • 772

为什么在 C# 和 Java 中生成 512 位 RSA 密钥时,公钥字节的长度不同?

C#代码示例:

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
XDocument xdocPub = XDocument.Parse(rsa.ToXmlString(false));
string publicKey = xdocPub.Element("RSAKeyValue").Element("Modulus").Value;

byte[] publicArray = Convert.FromBase64String(publicKey);
Console.WriteLine("Public Key Byte Array Length: " + publicArray.Length);
Console.WriteLine("Public Key Base64 Length: " + publicKey.Length);
Console.WriteLine("Public Key Text: " + publicKey);

结果:

Public Key Byte Array Length: 64
Public Key Base64 Length: 88
Public Key Text: uELcIjgR6GpiayZ1wHruHOtO8dpg+xmg85VAvunWUEL+aifoyk9+CA/dez4UmuIwLEgRlpVoIIOD0e5i9v8lrQ==

Java 代码示例:

final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(new RSAKeyGenParameterSpec(512, RSAKeyGenParameterSpec.F4));
KeyPair pair = keyGen.genKeyPair();

final byte[] arrayPublic = ((RSAPublicKey) pair.getPublic()).getModulus().toByteArray();

System.out.println("Public Key [origin] lenght: " + arrayPublic.length);

String publicBase64 = Base64.getEncoder().encodeToString(arrayPublic);

System.out.println("Public Key [base64] lenght : " + publicBase64.length());
System.out.println("Public Key [base64]: " + publicBase64);

结果:

Public Key [origin] lenght: 65
Public Key [base64] lenght : 88
Public Key [base64]: ANuun1/CnOmk2ghsydz4cKvPCd7q0YqqeyjzLqtKx7QHqv1tFjJYsXquYGcY8zkaPsPBrRlCAJov7+J88GaFDKc=

我注意到在Java生成的key的字节数组中,key数组的开头有一个空字节。

最有趣的是,如果我从 C# 应用程序发送一个长度为 64 字节的密钥,那么在 Java 应用程序中,我会在以下代码中收到错误“指数大于模数”:

try
{
    final KeyFactory kfac = KeyFactory.getInstance("RSA");
    final BigInteger modulus = new BigInteger("здесь вставляется byte[] массив публичного ключа от C#");
    final RSAPublicKeySpec kspec1 = new RSAPublicKeySpec(modulus, RSAKeyGenParameterSpec.F4);

    RSAPublicKey publicKey = (RSAPublicKey) kfac.generatePublic(kspec1);
}
catch (GeneralSecurityException e)
{
    e.printStackTrace();
}

同时,如果我在将密钥从 C# 应用程序发送到 Java 应用程序之前在密钥的开头添加一个零字节,那么从 Java 应用程序端来看,加密初始化和发送数据的加密没有问题。但在这种情况下,我无法使用相同的加密实例对 C# 应用程序中的传入数据进行解码。我收到“错误数据”错误。

告诉我我做错了什么以及为什么键的长度不同?

UPD 1:添加了 Java 测试

PublicKey 取自 C# 中生成的第一个示例。

public class Test
{
    public static void main(String[] args)
    {
        final String base64key = "uELcIjgR6GpiayZ1wHruHOtO8dpg+xmg85VAvunWUEL+aifoyk9+CA/dez4UmuIwLEgRlpVoIIOD0e5i9v8lrQ==";

        try
        {
            byte[] publicKeyArray = Base64.getDecoder().decode(base64key);
            final KeyFactory kfac = KeyFactory.getInstance("RSA");
            final BigInteger modulus = new BigInteger(1, publicKeyArray);
            final RSAPublicKeySpec kspec1 = new RSAPublicKeySpec(modulus, RSAKeyGenParameterSpec.F4);

            RSAPublicKey publicKey = (RSAPublicKey) kfac.generatePublic(kspec1);

            byte[] array = publicKey.getModulus().toByteArray();

            System.out.println("Public Key [Array] lenght : " + array.length);

            String publicBase64 = Base64.getEncoder().encodeToString(array);

            System.out.println("Public Key [base64] lenght : " + publicBase64.length());
            System.out.println("Public Key [base64]: " + publicBase64);
        }
        catch (GeneralSecurityException e)
        {
            e.printStackTrace();
        }
    }
}

由于 RSAPublicKey 被初始化为 Java Base64,因此密钥与输入不匹配。虽然长度是65字节。但这仅适用于signum = 1.

Public Key [Array] lenght : 65
Public Key [base64] lenght : 88
Public Key [base64]: ALhC3CI4EehqYmsmdcB67hzrTvHaYPsZoPOVQL7p1lBC/mon6MpPfggP3Xs+FJriMCxIEZaVaCCDg9HuYvb/Ja0=

UPD 2:C# 生成 RSA 密钥的问题由Bouncy Castle库解决。该库有源代码,所以我只使用了 RSA 部分并在我的项目中实现了它。

java
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    default locale
    2020-05-30T11:48:52Z2020-05-30T11:48:52Z

    额外字节

    BigInteger.toByteArray在结果中包含数字的符号位:

    ...该数组将包含表示此 BigInteger 所需的最小字节数,包括至少一个符号位,即 (ceil((this.bitLength() + 1)/8)) ...

    包括。是的,开头的零字节可以根据需要截掉。你可以这样做System.arraycopy:

    byte[] array = publicKey.getModulus().toByteArray();
    //убираем лишний нолик
    final byte[] keyBytes = new byte[64];
    System.arraycopy(array, 1, keyBytes, 0, 64);
    

    请参阅@Maarten Bodewes对英文相关问题的回答(How insert bits into block in java cryptography?),有一种现成的方法可以“标准化”带有前导零的字节数组,它还考虑了以下情况该数组短于 64(它似乎只发生在私钥上)。

    不良数据

    构造函数BigInteger​(byte[] val)还需要数字的带符号表示,并尝试从密钥中读取符号位。尝试使用单独使用符号位的构造函数BigInteger​(int signum, byte\[\] magnitude):

    new BigInteger(1, /*байты ключа*/)
    

    关于 en.SO 的相关问题:

    • 如何在java中构建模数为64字节的rsa密钥
    • java - 如何在java密码学中将位插入块中?
    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5