http://scz.617.cn:8/misc/201909271517.txt
学习burpsuite的loader-kengen原理的时候,以下字符通过Java BigInteger表示输出和pyhon里的不一致
tdq99QBI3DtnQQ7rRJLR0uAdOXT69SUfAB/8O2zi0lsk4/bXkM58TP6cuhOzeYyrVUJrM11IsJhWrv8SiomzJ/rqledlx+P1G5B3MxFVfjML9xQz0ocZi3N+7dHMjf9/jPuFO7KmGfwjWdU4ItXSHFneqGBccCDHEy4bhXKuQrA=
pyhon下10进制和16进制
127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048
0xb5dabdf50048dc3b67410eeb4492d1d2e01d3974faf5251f001ffc3b6ce2d25b24e3f6d790ce7c4cfe9cba13b3798cab55426b335d48b09856aeff128a89b327faea95e765c7e3f51b90773311557e330bf71433d287198b737eedd1cc8dff7f8cfb853bb2a619fc2359d53822d5d21c59dea8605c7020c7132e1b8572ae42b0
Java下
String str = "tdq99QBI3DtnQQ7rRJLR0uAdOXT69SUfAB/8O2zi0lsk4/bXkM58TP6cuhOzeYyrVUJrM11IsJhWrv8SiomzJ/rqledlx+P1G5B3MxFVfjML9xQz0ocZi3N+7dHMjf9/jPuFO7KmGfwjWdU4ItXSHFneqGBccCDHEy4bhXKuQrA=";
byte[] data = Base64.getDecoder().decode(str);
BigInteger b1 = new BigInteger(data);
System.out.println(b1);
System.out.println(DatatypeConverter.printHexBinary(b1.toByteArray()));
输出
-52066768130934566439500559297314615291892304421089340360693479140969218997677889761506763277018310938245034902798204370365028707815815191416699717714739283001723086687716447871142873393142172449083131123026127168866247070895014001077827926244452182313294790657245179326250544550856741143926708290527631097168
B5DABDF50048DC3B67410EEB4492D1D2E01D3974FAF5251F001FFC3B6CE2D25B24E3F6D790CE7C4CFE9CBA13B3798CAB55426B335D48B09856AEFF128A89B327FAEA95E765C7E3F51B90773311557E330BF71433D287198B737EEDD1CC8DFF7F8CFB853BB2A619FC2359D53822D5D21C59DEA8605C7020C7132E1B8572AE42B0
发现16进制结果是一样的,只是10进制一个是负数,导致后面的结果也对应不起来。
对于BigInteger详细介绍可以看这里,对于计算机二进制数据编码方式也做了介绍。
https://www.cnblogs.com/noteless/p/9877957.html
这里只是引用其中一部分:
计算机中存储的数值都是补码的形式
正数的补码与原码相同
负数的补码是他的原码取反再加一
即补码的补码等于原码
原码,符号位+数值位,符号位为0 表示正数,符号位为1 表示负数,数值位就是真值的绝对值
根据上面规则再看原文给出的计算步骤:
补码计算步骤
第一步求原码: 先写出来她的原码--->符号位+数值位(绝对值) |
第二步求反码: 如果是正数 反码与原码一样 如果是负数 反码为原码取反(除符号位外,逐位翻转) |
第三步求补码: 如果是正数 补码与原码一样 如果是负数 补码为反码 + 1 |
第四步扩充: 如果不足数据类型的宽度,将需要填充到指定宽度 符号位扩充,也就是正数补0 负数补1 |
总结 不管什么形式,第一位始终都是符号位,0 表示正数, 1表示负数 正数原码/反码/补码 全都一样,知道一种就直接得到另外的形式 负数如果知道补码,想要得到他的原码,只需要对补码再一次的求补码即可 |
默认原始数据给出的是正数,然而Java没有无符号的类型,没有当做正数处理,我们这里转换一下
//创建一个数组,并添加符号位,正数符号为0,再把数据复制过去
byte[] test=new byte[data.length+1];
test[0] = 0;
System.arraycopy(data,0,test,1,data.length);
BigInteger b4=new BigInteger(test);
System.out.println(DatatypeConverter.printHexBinary(b4.toByteArray()));
System.out.println(b4);
然后我们看一下输出
127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048
00B5DABDF50048DC3B67410EEB4492D1D2E01D3974FAF5251F001FFC3B6CE2D25B24E3F6D790CE7C4CFE9CBA13B3798CAB55426B335D48B09856AEFF128A89B327FAEA95E765C7E3F51B90773311557E330BF71433D287198B737EEDD1CC8DFF7F8CFB853BB2A619FC2359D53822D5D21C59DEA8605C7020C7132E1B8572AE42B0
发现10进制数据一致了,也不是负数了,只不过16进制多补了一个符号位0,不影响数值大小。
这样做是不是太麻烦了,自己每次转换,其实有默认的构造方法的,这里可以传入1和-1代表正负数
BigInteger b2 = new BigInteger(1, data);
System.out.println(b2);
System.out.println(DatatypeConverter.printHexBinary(b2.toByteArray()));
输出是一致的
127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048
00B5DABDF50048DC3B67410EEB4492D1D2E01D3974FAF5251F001FFC3B6CE2D25B24E3F6D790CE7C4CFE9CBA13B3798CAB55426B335D48B09856AEFF128A89B327FAEA95E765C7E3F51B90773311557E330BF71433D287198B737EEDD1CC8DFF7F8CFB853BB2A619FC2359D53822D5D21C59DEA8605C7020C7132E1B8572AE42B0
下面验证一下补码计算,创建一个负数的,然后通过b2正数的来计算一下这个负数的,比较一下结果
BigInteger b3 = new BigInteger(-1, data);
System.out.println(b3);
System.out.println(DatatypeConverter.printHexBinary(b3.toByteArray()));
BigInteger b6 = b2.not().add(BigInteger.ONE);
System.out.println(b6);
System.out.println(DatatypeConverter.printHexBinary(b6.toByteArray()));
--------------b3--------------
-127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048
FF4A25420AFFB723C498BEF114BB6D2E2D1FE2C68B050ADAE0FFE003C4931D2DA4DB1C09286F3183B3016345EC4C867354AABD94CCA2B74F67A95100ED75764CD805156A189A381C0AE46F88CCEEAA81CCF408EBCC2D78E6748C81122E3372008073047AC44D59E603DCA62AC7DD2A2DE3A621579FA38FDF38ECD1E47A8D51BD50
--------------b6--------------
-127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048
FF4A25420AFFB723C498BEF114BB6D2E2D1FE2C68B050ADAE0FFE003C4931D2DA4DB1C09286F3183B3016345EC4C867354AABD94CCA2B74F67A95100ED75764CD805156A189A381C0AE46F88CCEEAA81CCF408EBCC2D78E6748C81122E3372008073047AC44D59E603DCA62AC7DD2A2DE3A621579FA38FDF38ECD1E47A8D51BD50
二者结果一致,所以说明Java BigInteger处理byte[]数组时直接把数据存储的,没有符号位的概念。我们要么构造的时候传入符号位的参数,要么自己添加数组符号位。
补充:
正数我们处理byte[]数组时添加一个符号位test[0]=0,如果这个是负数我们数组肯定不是0了,上面说过0是表示正数,1是表示负数,但是Java BigInteger有单独的符号标记,你传入的数据它不会区分符号位,也就是你传入1,它不会按符号位对待,也会参与到运算的,所以我们不能设置1,我们需要传入的是补码,下面计算一下应该传入多少
BigInteger b7=new BigInteger(new byte[]{1}).not().add(BigInteger.ONE);
System.out.println(b7);
System.out.println(DatatypeConverter.printHexBinary(b7.toByteArray()));
输出为
-1
FF
所以我们应该传入FF
byte[] test1 = new byte[data.length + 1];
test1[0] = (byte) 0xFF;
System.arraycopy(data, 0, test1, 1, data.length);
BigInteger b5 = new BigInteger(test1);
System.out.println(b5);
System.out.println(DatatypeConverter.printHexBinary(b5.toByteArray()));
输出
-52066768130934566439500559297314615291892304421089340360693479140969218997677889761506763277018310938245034902798204370365028707815815191416699717714739283001723086687716447871142873393142172449083131123026127168866247070895014001077827926244452182313294790657245179326250544550856741143926708290527631097168
B5DABDF50048DC3B67410EEB4492D1D2E01D3974FAF5251F001FFC3B6CE2D25B24E3F6D790CE7C4CFE9CBA13B3798CAB55426B335D48B09856AEFF128A89B327FAEA95E765C7E3F51B90773311557E330BF71433D287198B737EEDD1CC8DFF7F8CFB853BB2A619FC2359D53822D5D21C59DEA8605C7020C7132E1B8572AE42B0
发现这个b5的结果和b1一样,多加了一位符号位结果还一样,可能有点绕,但仔细一想,说明符合我们的推算的,也就是BigInteger就是没有区分符号位,直接把所有数据参与计算的,本身这个数据是正数,应该按正数处理,BigInteger全部参与了运算,还把结果当做了负数了,我们按负数换算后创建的BigInteger对象和没有转换的结果一样,还吃掉了一个符号位,本来多加上一位,最后结果没了。
看了还可能比较懵逼,下面再给一个例子慢慢体会把b3是传入-1构造的,b1是没有任何参数的,然后我们通过计算得到一下b3
BigInteger b8 = b1.not().add(BigInteger.ONE);
System.out.println(b8);
System.out.println(DatatypeConverter.printHexBinary(b8.toByteArray()));
输出两个比对
--------------b3--------------
-127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048
FF4A25420AFFB723C498BEF114BB6D2E2D1FE2C68B050ADAE0FFE003C4931D2DA4DB1C09286F3183B3016345EC4C867354AABD94CCA2B74F67A95100ED75764CD805156A189A381C0AE46F88CCEEAA81CCF408EBCC2D78E6748C81122E3372008073047AC44D59E603DCA62AC7DD2A2DE3A621579FA38FDF38ECD1E47A8D51BD50
--------------b8--------------
52066768130934566439500559297314615291892304421089340360693479140969218997677889761506763277018310938245034902798204370365028707815815191416699717714739283001723086687716447871142873393142172449083131123026127168866247070895014001077827926244452182313294790657245179326250544550856741143926708290527631097168
4A25420AFFB723C498BEF114BB6D2E2D1FE2C68B050ADAE0FFE003C4931D2DA4DB1C09286F3183B3016345EC4C867354AABD94CCA2B74F67A95100ED75764CD805156A189A381C0AE46F88CCEEAA81CCF408EBCC2D78E6748C81122E3372008073047AC44D59E603DCA62AC7DD2A2DE3A621579FA38FDF38ECD1E47A8D51BD50
10进制部分数值不一致,但是16进制部分b3只是比b8开头多了一个FF,后面部分完全一致。说明BigInteger没有符号位的,除非你指定符号位。不指定符号位不默认添加符号位,把所有数据参与计算。所以BigInteger在传入非字符时最好指定符号位,因为传入字符默认就是10进制,都有正负之分了。传入byte[]数组时不指定符号位时,填充符号位时,正数可以填充0,负数可以填充0xFF。
来源:oschina
链接:https://my.oschina.net/googlewell/blog/3156138