使用BigInteger进行大数运算

        BigInteger是Java程序员在密码学中进行大数运算基础工具,使用过程中经常出现的错误是正负数问题和16进制转换问题。具体来说就是:

        一)大数最高位为1的情况下,字节数组与BigInteger的转换问题

        以以下例子说明,比如:

        byte[] data new byte[1];

        data[0] = (byte)0xC7

        使用new BigInteger(byte[] data)方法把byte数组转换为BigInteger,并不处理符号,最高位是1时做负数处理:

        BigInteger bi = new BigInteger(data);

        //以下输出为-39

        System.out.println(bi.toString(16));  /

        //以下输出为xw==。也就是0xC7的base64编码        

        System.out.println(Base64.getEncoder().encodeToString(bi.toByteArray())); 

        为了解决以上问题,需要使用new BigInteger(int sign, byte[] data)进行转换,针对最高位为1的情况,会自动进行补0处理。

        BigInteger bi = new BigInteger(1,data);

        //以下输出为C7,也就是说转换成16进制串时,会自动去除表示正数的00

        System.out.println(bi.toString(16));  

        //以下输出为AMc=。也就是0x00C7的base64编码        

        System.out.println(Base64.getEncoder().encodeToString(bi.toByteArray())); 

         所以,从字节数组转换为BigInteger时,使用BigInteger第二个构造函数,并且sign=1。

        二)BigInteger与16进制数转换

        使用BigInteger(String data, 16),可以把16进制数转换为大数,并且自动处理最高位为1的情况。比如:

        String data = "C7";

        //以下输出为C7,自动在最高位补0,处理正负数。
        System.out.println(new BigInteger(data, 16).toString(16));

        //以下代码可以验证是否做了补0处理。输出仍为AMc=

        System.out.println(Base64.getEncoder().encodeToString(new BigInteger(data, 16).toByteArray()));
 

        BigInteger.toString(16),可以把大数转换为16进制串。使用该转换存在一个问题,就是并不做偶数位对齐,比如:

        String data = "07";

        //以下输出为7

       System.out.println(new BigInteger(data, 16).toString(16));

       一般国密算法中的二进制串都是偶数字节的,所以如果出现奇数字节的二进制数,使用BigInteger就会出现很多错误。为了保证输出的是偶数字节,就需要使用toByteArray方法,比如:

        //以下输出为Bw==,也就是07的base64编码

        System.out.println(Base64.getEncoder().encodeToString(new BigInteger(data, 16).toByteArray()));

        综合以上常见问题,在使用BigInteger进行大数运算时注意以下两点:

        1)从字节数组转换为大数时,要使用双参的构造函数,并且设置符号参数sign为1

        2)从大数转换成16进制数时,先转换为字节数组,然后再从中剔除高位的补0。

你可能感兴趣的:(java)