[转载] 用Java语言实现对十六进制字符串异或运算

参考链接: 交换两个字符串,而无需在Java中使用第三个用户定义的变量

前言:好久没有写博客,最近一年感觉真是好忙,各种做不完的工作。相信很多上班族都会有这种感觉。最近对NFC进行写卡操作,需要计算一个校验位。一般情况下,校验位多数是由前几个字节进行异或运算所得。 

  

现在我就先说一下我使用的场景: 

把一个16字节的数据写到CPU卡(如交通卡)里面,最后一字节是校验码---前十五字节异或。 

我开始从网上找了一些别人写的算法发现计算后结果不对,或者就是写的太复杂了,于是自己就写了一个,感觉也比较简单,现在分享给大家,希望一起交流一下。 

第一节:什么是异或运算(主要摘自百度百科,熟悉的童靴可以跳过) 

定义: 

 

 

 异或,英文为exclusive OR,或缩写成xor

 

 

 异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:

 

 

 a⊕b = (¬a ∧ b) ∨ (a ∧¬b)

 

 

 如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

 

 

 异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位。

 

 

 异或略称为XOR、EOR、EX-OR

 

 

 程序中有三种演算子:XOR、xor、⊕。

 

 

 使用方法如下

 

 

 z = x ⊕ y

 

 

 z = x xor y

 

运算规则: 

 

 

 

 1. a ⊕ a = 0

 

 

 2. a ⊕ b = b ⊕ a

 

 

 3. a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c;

 

 

 4. d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c.

 

 

 5. a ⊕ b ⊕ a = b.

 

 

 6.若x是二进制数0101,y是二进制数1011

 

 

 则x⊕y=1110

 

 

 只有在两个比较的位不同时其结果是1,否则结果为0

 

 

 即“两个输入相同时为0,不同则为1”!

 

 

  

 

逻辑: 

 

 

 

 逻辑表达式:F=AB’⊕A’B((AB’⊕A’B)’=AB⊙A’B’,⊙为“同或”运算)

 

 

 异或逻辑的真值表如图1所

 

 

  示,其逻辑符号如图2所示。异或逻辑的关系是:当AB不同时,输出P=1;当AB相同时,输出P=0。“⊕”是异或运算符号,异或逻辑也是与或非逻辑的组合,其逻辑表达式为:

 

 

 P=A⊕B

 

 

 由图1可知,异或运算的规则是

 

 

 0⊕0=0,0⊕1=1

 

 

 1⊕0=1,1⊕1=0

 

 

 口诀:相同取0,相异取1

  

 

 

 事实上,XOR 在英文里面的定义为either one (is one), but not both, 也即只有一个为真(1)时,取真(1)。

 

作用: 

 

 

 

 在计算机中普遍运用,异或(xor)的逻辑符号一般用xor,也有用⊕的:

 

 

 真⊕假=真

 

 

 假⊕真=真

 

 

 假⊕假=假

 

 

 真⊕真=假

 

 

 或者为:

 

 

 True ⊕ False = True

 

 

 False ⊕ True = True

 

 

 False ⊕ False = False

 

 

 True ⊕ True = False

 

 

 部分计算机语言用1表示真,用0表示假,所以两个字节按位异或如下

 

   

    

     00000000

      

    

     xor

      

    

     00000000

      

    

     ----------------------------------

        

    

     00000000

      

 

 ============我是分界线1============

 

 

 下面是两个二进制数值进行异或计算:

 

   

    

     11111111

      

    

     xor

      

    

     00000000

      

    

     ----------------------------

        

    

     11111111

      

 

 ============我是分界线2============

 

 

 现实中用的都是十进制的数值,那么我们来看一看两个十进制数值是怎么进行异或计算:

 

 

 5 ⊕ 2 = ?

 

 

 1.进行异或计算前会把数值都转换为二进制的:

 

 

 5和2转为二进制分别为:0101 、0010

 

   

    

     0101

      

    

     xor

      

    

     0010

      

    

     ----------------------------

        

    

     0111

      

 

 2.再把结果 0111 转换为十进制的:7

 

 

 3.所以 5 ⊕ 2 = 7

 

巧用: 

 

 

 

 与其它语言不同,C语言和C++语言的异或不用xor,而是用“^”,键入方式为Shift+6。(而其它语言的“^”一般表示乘方)

 

 

 若需要交换两个变量的值,除了通常使用的借用中间变量进行交换外,还可以利用异或,仅使用两个变量进行交换,如:

 

 

  

   

       

       1

       

       

       2

       

       

       3

        

       

        

        a=a^b;

        

        

        b=b^a;

        

        

        a=a^b;

        

        

  

 

 

 详解:

 

 

  

   

       

       1

       

       

       2

       

       

       3

        

       

        

        a1=a^b

        

        

        b=a1^b

        

        

        a=a1^b=a1^(a1^b)=a1^a1^b=b

        

        

  

 

 

 注意:

 

 

  

   

       

       1

        

       

        

        a=a^b^(b=a);//此类形式是不正确的UB行为,在不同编译器中会有不同的结果,切勿使用

        

        

  

 

 

 这样就完成了a与b的交换。

 

 

 综上:同一变量与另一变量和其异或值异或等于自身。

 

 

 用例:可使用于加密算法某一环节或更多环节,使算法更复杂,不易被破解,安全性更高。[1] 

 

第二节:用java语言实现: 

 

  

 

private static String xor(String strHex_X,String strHex_Y){ 

            //将x、y转成二进制形式 

            String anotherBinary=Integer.toBinaryString(Integer.valueOf(strHex_X,16)); 

            String thisBinary=Integer.toBinaryString(Integer.valueOf(strHex_Y,16)); 

            String result = ""; 

            //判断是否为8位二进制,否则左补零 

            if(anotherBinary.length() != 8){ 

            for (int i = anotherBinary.length(); i <8; i++) { 

                    anotherBinary = "0"+anotherBinary; 

                } 

            } 

            if(thisBinary.length() != 8){ 

            for (int i = thisBinary.length(); i <8; i++) { 

                    thisBinary = "0"+thisBinary; 

                } 

            } 

            //异或运算 

            for(int i=0;i<anotherBinary.length();i++){ 

            //如果相同位置数相同,则补0,否则补1 

                    if(thisBinary.charAt(i)==anotherBinary.charAt(i)) 

                        result+="0"; 

                    else{ 

                        result+="1"; 

                    } 

                }

            Log.e("code",result);

            return Integer.toHexString(Integer.parseInt(result, 2)); 

        } 

注意:以上方法是针对一个十六进制字符串一字节之间的异或运算,如对十五字节的十六进制字符串异或运算:1312f70f900168d900007df57b4884 

先进行拆分:13 12 f7 0f 90 01 68 d9 00 00 7d f5 7b 48 84 

13 xor 12-->1 

1 xor f7-->f6 

f6 xor 0f-->f9 

.... 

62 xor 84-->e6 

即,得到的一字节校验码为:e6 

补充,给一些朋友增加了一个简单的调用方法,仅供参考: 

 

public String checkcode_0007(String para){

         String[] dateArr = new String[15];

         try {

             dateArr[0] = para.substring(0, 2);

             dateArr[1] = para.substring(2, 4);

             dateArr[2] = para.substring(4, 6);

             dateArr[3] = para.substring(6, 8);

             dateArr[4] = para.substring(8, 10);

             dateArr[5] = para.substring(10, 12);

             dateArr[6] = para.substring(12, 14);

             dateArr[7] = para.substring(14, 16);

             dateArr[8] = para.substring(16, 18);

             dateArr[9] = para.substring(18, 20);

             dateArr[10] = para.substring(20, 22);

             dateArr[11] = para.substring(22, 24);

             dateArr[12] = para.substring(24, 26);

             dateArr[13] = para.substring(26, 28);

             dateArr[14] = para.substring(28, 30);

        } catch (Exception e) {

            // TODO: handle exception

        }

        String code = "";

        for (int i = 0; i < dateArr.length-1; i++) {

            if(i == 0){

                code = xorString(dateArr[i], dateArr[i+1]);

            }else{

                code = xorString(code, dateArr[i]);

            }

        }

        return code;

}然后再主函数或者其他方法里面调用: 

 

 

String code = checkcode_0007("1312f70f900168d900007df57b4884");code就是获取的校验码了。

上一篇:攻防世界 Reverse高手进阶区 2分题 reverse-for-the-holy-grail-350


下一篇:【BZOJ 2115】Xor