当前位置: 首页 > 知识库问答 >
问题:

将字节数组转换为BigIntger不正确

赏成益
2023-03-14

自从我尝试模拟我的客户端和服务器之间处理数据包的连接以来,我一直在与字节数组和BigIntger进行斗争。

当我的客户端连接到服务器时,服务器发送了一个包含RSA公钥的响应,然后是一个十六进制数据包,如下所示:

C70001A100408031313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131E5AA194C3DBA71F9A38AF85D43C130A462BDCBACF85ED702B5E2FECB47197DAA433E7B5ACF5EF09A07C5DDE79B7A2EED76B91090CB981E13DBE316997FCF5DC51BE40B2D02D912457D97924B94094227F8BC65DD61FE78060B55BEAAA31C64E3B36863B407F7183DABA9D98F0C9061DED36AD16407F70C4925951BAA8807EC95

C70001A1004080之后的64字节是RSA公共指数。RSA指数后的128字节是模数。

然后我尝试提取指数和模来重新生成RSA公钥。我的步骤:

if (socket == null) socket = new Socket(loginHost, loginPort);
if (is == null) is = socket.getInputStream();
if (os == null) os = socket.getOutputStream();

int packageLength = 199;

byte[] response = IOUtils.toByteArray(is, packageLength); 

byte[] rsaPubExponentBytes = Arrays.copyOfRange(response, 7, 71);
byte[] rsaModuloBytes = Arrays.copyOfRange(response, 71, packageLength);

BigInteger rsaPubExponentNumber = new BigInteger(1, rsaPubExponentBytes);
BigInteger rsaModuloNumber = new BigInteger(1, rsaModuloBytes);

PublicKey pub = null;

try {
    RSAPublicKeySpec spec = new RSAPublicKeySpec(rsaModuloNumber, rsaPubExponentNumber);
    KeyFactory factory = KeyFactory.getInstance("RSA");
            
    pub = factory.generatePublic(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
    e.printStackTrace();
}

最后我有了一个公钥:

Sun RSA public key, 1024 bits
  modulus: 161275860318613570660794349609651113455378591213521007305334206887210873414776462027746458127536797075994278751416175612148660222076731030937875746805281690156725876857482174279314968596913890067397869829419019179316569148699704292044128937649866682741942026327643537075317389490824101005022833230463069842581
  public exponent: 2576402308106616697565204803576809648025446765525597158856684355852417401857269811228595453373248109634555141377011045066015451991315223244608818828620081

与服务器上的RSA进行比较

Sun RSA public key, 1024 bits
  modulus: 105278801605955351183032861925660079240049371193037037019863031780531990060755731057393990664319512505978954889835933668032824049054190807125138251307247771506918060803959346902566451812689470408398611041302277800747341495594297701677567604614145074223483256879948522462707345079591319551080307454838134385381
  public exponent: 2576402308106616697565204803576809648025446765525597158856684355852417401857269811228595453373248109634555141377011045066015451991315223244608818828620081

然后模数是错误的。我通过将BigIntger转换为字节数组并用十六进制显示它来再次检查

System.out.println(bytesToHex(rsaPubExponentNumber.toByteArray()));
System.out.println(bytesToHex(rsaModuloNumber.toByteArray()));

private String bytesToHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
       sb.append(String.format("%02X ", b));
    }
    return sb.toString().replaceAll(" ", "");
}

结果是:

指数:31313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131

模数<代码>00E5AA194C3DBA71F9A38AF85D43C130A462BDCBACF85ED702B5E2FECB47197DAA433E7B5ACF5EF09A07C5DDE79B7A2EED76B91090CB981E13DBE316997FCF5DC51BE40B2D02D912457D97924B94094227F8BC65DD61FE78060B55BEAAA31C64E3B36863B407F7183DABA9D98F0C9061DED36AD16407F70C4925951BAA8807EC95

模数现在开始时为00,生成了公钥,但不正确。

我还尝试了:

BigInteger exponent = new BigInteger(exponentHexString, 16);
BigInteger modulus = new BigInteger(modulusHexString, 16);

然而,结果还是一样。我该如何解决这个问题?

共有1个答案

裴英锐
2023-03-14

让我们看看您的代码和数据包流结构。

以下二进制流编码为十六进制字符串:

C70001A100408031313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131E5AA194C3DBA71F9A38AF85D43C130A462BDCBACF85ED702B5E2FECB47197DAA433E7B5ACF5EF09A07C5DDE79B7A2EED76B91090CB981E13DBE316997FCF5DC51BE40B2D02D912457D97924B94094227F8BC65DD61FE78060B55BEAAA31C64E3B36863B407F7183DABA9D98F0C9061DED36AD16407F70C4925951BAA8807EC95

根据您的代码:

  • 从索引7到71的字节是指数字节,

IIUC,你要从上面的字节串中提取指数和模。

您面临的问题源于这样一个事实,即在密码学中,数字通常是无符号整数,具有协议定义的字节顺序,而Java的BigIntger是大端有符号整数。

为了将任意整数(有符号/无符号、大端/小端)转换为BigIntger,必须执行一些阴谋。

在您的情况下,只需反转字节数组就足够了,正如评论中建议的那样:

int packageLength = 199;

byte[] response = IOUtils.toByteArray(is, packageLength); 

byte[] rsaPubExponentBytes = Arrays.copyOfRange(response, 7, 71);
byte[] rsaModuloBytes = Arrays.copyOfRange(response, 71, packageLength);

// missing step!
reverse(rsaPubExponentBytes);
reverse(rsaModuloBytes);

BigInteger rsaPubExponentNumber = new BigInteger(1, rsaPubExponentBytes);
BigInteger rsaModuloNumber = new BigInteger(1, rsaModuloBytes);
// ...
public static void reverse(byte[] arr) {
    for (int i = 0; i < arr.length / 2) {
        int tmp = arr[i]
        arr[i] = arr[arr.length - 1 - i];
        arr[arr.length - 1 - i] = tmp;
    }
}

我在做我的一个项目时遇到过类似的问题。您可能会发现我的库SRP-6变量非常有用:

byte[] stream = new Hex("C70001A100408031313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131E5AA194C3DBA71F9A38AF85D43C130A462BDCBACF85ED702B5E2FECB47197DAA433E7B5ACF5EF09A07C5DDE79B7A2EED76B91090CB981E13DBE316997FCF5DC51BE40B2D02D912457D97924B94094227F8BC65DD61FE78060B55BEAAA31C64E3B36863B407F7183DABA9D98F0C9061DED36AD16407F70C4925951BAA8807EC95").asArray();

BigInteger exponent = 
    new SRP6CustomIntegerVariable(
        Bytes.wrapped(Arrays.copyOfRange(stream, 7, 71)),
        ByteOrder.LITTLE_ENDIAN
    ).asNonNegativeBigInteger();
BigInteger modulus = 
    new SRP6CustomIntegerVariable(
        Bytes.wrapped(Arrays.copyOfRange(stream, 71, stream.length)),
        ByteOrder.LITTLE_ENDIAN
    ).asNonNegativeBigInteger();
 类似资料:
  • 问题内容: 我有一个接收a的函数,但是我所拥有的a是进行此转换的最佳方法是什么? 我想我可以走很长一段路,然后将其放入字符串并放入字节中,但这听起来很难看,而且我认为还有更好的方法可以做到。 问题答案: 我同意Brainstorm的方法:假设您要传递机器友好的二进制表示形式,请使用该库。OP建议可能会有一些开销。纵观源的实施,我看到它做了一些运行时的决策最大的灵活性。 对?Write()接受一个非

  • 问题内容: 将转换为的快速方法是什么? 例如 问题答案: 看看ByteBuffer类。 设置字节顺序保证了,,和。 或者,你可以手动执行以下操作: 该班是专为尽管这样的脏手任务。实际上,私有定义了以下辅助方法:

  • 问题内容: 我有一个要加密的字节数组,然后转换为字符串,以便可以传输。当我收到字符串时,我必须将字符串转换回字节数组,以便可以对其进行解密。我检查了接收到的字符串是否与发送的字符串(包括长度)匹配,但是当我使用诸如str.getBytes()之类的东西将其转换为字节数组时,它与我的原始字节数组不匹配。 示例输出: 任何想法如何将接收到的字符串转换为与发送的字节数组匹配的字节数组? 谢谢 问题答案:

  • 问题内容: 假设我有一个4字符串,并且我想将此字符串转换为字节数组,其中字符串中的每个字符都转换为等效的十六进制。例如 我正在尝试让我的输出成为 有没有简单的方法可以做到这一点? 问题答案: 编码功能可以为您提供帮助,编码返回字符串的编码版本 或者你可以使用数组模块

  • 问题内容: 我想从数据库中获取图像。为此,我为图像创建了一个字节数组,该数组由字符串传递,现在我想将该字符串转换为图像格式。我正在将该图像分配给Jlabel字段。代码如下: 问题答案:

  • 问题内容: 当我对字节的调用全部为0 后查看缓冲区时,从相机返回的位图是不可变的……但这无关紧要,因为它正在执行复制操作。 此代码可能有什么问题? 问题答案: 尝试这样: