三轮DES差分攻击(免费完整代码)

  • 具体步骤
  1. 获得S盒的差分对应表

在具体程序实现时可以建一个8*64*16的三维集合数组,经过如下算法,就可以生成差分分布表Sd(代码中“this.”指实例化后的操作对象),例如Sd[2][32][12]存放了第二个S盒输入差为32,输出差为12的所有可能输入值(输入值可能不止一个,也可能为空,所以Sd[i][j][k]本身是一个集合)。

差分对应表的一部分如下图所示,下图中S8表示第8个S盒,dSin表示S盒的输入差,dSout表示输出差,冒号后的值表示可能的输入值,该输入值为用十六进制表示的6比特值。

  1. 计算S盒的输入差与输出差(第三轮不交换)

如下图所示,dSin,dSout分别表示S盒的输入差和输出差,dSin是对第三轮密文差的右32比特做一个E盒扩展,dSout是将第一轮明文差的左32比特与第三轮密文差的左32比特进行异或,再进行一次逆P盒变换的结果。

  1. 更新密钥集合

根据第2步计算的S盒输入输出差查S盒的差分分布表,以获得S盒可能的输入值,再将这些输入值与密文的右32比特进行异或,即可得到可能的密钥值,将这些可能的密钥值与上一次计算所得的密钥集合取交集,即可完成密钥集合的更新(如果是第一次计算密钥集合,则直接将本次所得的密钥可能值赋给密钥集合)。

  1. 多次计算得出唯一确定的密钥值
  • 运行结果

本次测试要计算的密钥K3值为0x39,0x08,0x19,0x36,0x09, 0x36,0x00,0x18,可以看到,经过3次对密钥集合进行更新,即可唯一确定最终的密钥K3。

不过需要注意的是,不一定每次唯一确定密钥都只需要更新3次密钥集合,经过100000次的测试,有如下试验结果:

更新次数

1

2

3

4

5

实验次数

0

1396

53903

36789

6747

更新次数

6

7

8

9

10

实验次数

971

166

20

6

2

从表中可以看到,有53903次测试都在3次更新密钥集合后唯一确定了密钥,6次以上的占比就非常少。在一次实验中,有大约90%的可能性在3次或4次更新密钥后唯一确定密钥K3。

完整代码的三个文件如下:

DES_3R:生成测试数据,计算3轮DES,第3轮不交换,第1轮输入数据由随机函数生成。

package De_3R;
/**
 * 计算3轮DES,第3轮不交换
 * @author 实无所得
 *
 */
public class DES_3R {
    private byte[] key=null;
    private byte[][] ikey=null;
    private byte[] L0=null,R0=null;
    private byte[] L3=null,R3=null;
    private static byte[][] S= {{14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13},
                                {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9},
                                {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12},
                                {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14},
                                {2,12,4,1,7,10,11,6,5,8,3,15,13,0,14,9,14,11,2,12,4,7,13,1,5,0,15,13,3,9,8,6,4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3},
                                {12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13},
                                {4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12},
                                {13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}};

    public DES_3R(String key) {
        setKey(key);
        setLR0();
    }
    public DES_3R(byte[] key) {
        setKey(key);
        setLR0();
    }
    public DES_3R() {
        setKey(new byte[0]);
        setLR0();
    }
    private byte[] PC1(byte[] in) {
        byte[] result=new byte[8];
        result[0]=(byte) (((in[7]>>1)&0x40)|((in[6]>>2)&0x20)|((in[5]>>3)&0x10)|((in[4]>>4)&0x08)|((in[3]>>5)&0x04)|((in[2]>>6)&0x02)|((in[1]>>7)&0x01));
        result[1]=(byte) (((in[0]>>1)&0x40)|((in[7]>>1)&0x20)|((in[6]>>2)&0x10)|((in[5]>>3)&0x08)|((in[4]>>4)&0x04)|((in[3]>>5)&0x02)|((in[2]>>6)&0x01));
        result[2]=(byte) (((in[1]   )&0x40)|((in[0]>>1)&0x20)|((in[7]>>1)&0x10)|((in[6]>>2)&0x08)|((in[5]>>3)&0x04)|((in[4]>>4)&0x02)|((in[3]>>5)&0x01));
        result[3]=(byte) (((in[2]<<1)&0x40)|((in[1]   )&0x20)|((in[0]>>1)&0x10)|((in[7]>>1)&0x08)|((in[6]>>2)&0x04)|((in[5]>>3)&0x02)|((in[4]>>4)&0x01));
        result[4]=(byte) (((in[7]<<5)&0x40)|((in[6]<<4)&0x20)|((in[5]<<3)&0x10)|((in[4]<<2)&0x08)|((in[3]<<1)&0x04)|((in[2]   )&0x02)|((in[1]>>1)&0x01));
        result[5]=(byte) (((in[0]<<5)&0x40)|((in[7]<<3)&0x20)|((in[6]<<2)&0x10)|((in[5]<<1)&0x08)|((in[4]   )&0x04)|((in[3]>>1)&0x02)|((in[2]>>2)&0x01));
        result[6]=(byte) (((in[1]<<4)&0x40)|((in[0]<<3)&0x20)|((in[7]<<1)&0x10)|((in[6]   )&0x08)|((in[5]>>1)&0x04)|((in[4]>>2)&0x02)|((in[3]>>3)&0x01));
        result[7]=(byte) (((in[2]<<3)&0x40)|((in[1]<<2)&0x20)|((in[0]<<1)&0x10)|((in[3]>>1)&0x08)|((in[2]>>2)&0x04)|((in[1]>>3)&0x02)|((in[0]>>4)&0x01));
        return result;
    }
    private byte[] PC2(byte[] in) {
        byte[] result=new byte[8];
        result[0]=(byte) (((in[1]<<5)&0x20)|((in[2]   )&0x10)|((in[1]   )&0x08)|((in[3]>>2)&0x04)|((in[0]>>5)&0x02)|((in[0]>>2)&0x01));
        result[1]=(byte) (((in[0]<<1)&0x20)|((in[3]<<4)&0x10)|((in[2]>>3)&0x08)|((in[0]<<1)&0x04)|((in[2]<<1)&0x02)|((in[1]>>4)&0x01));
        result[2]=(byte) (((in[3]   )&0x20)|((in[2]<<2)&0x10)|((in[1]<<1)&0x08)|((in[0]>>1)&0x04)|((in[3]>>1)&0x02)|((in[1]>>6)&0x01));
        result[3]=(byte) (((in[2]   )&0x20)|((in[0]<<4)&0x10)|((in[3]<<2)&0x08)|((in[2]<<1)&0x04)|((in[1]   )&0x02)|((in[0]>>5)&0x01));
        result[4]=(byte) (((in[5]<<4)&0x20)|((in[7]   )&0x10)|((in[4]>>1)&0x08)|((in[5]>>3)&0x04)|((in[6]>>1)&0x02)|((in[7]>>1)&0x01));
        result[5]=(byte) (((in[4]   )&0x20)|((in[5]<<2)&0x10)|((in[7]>>2)&0x08)|((in[6]>>2)&0x04)|((in[4]>>1)&0x02)|((in[6]>>1)&0x01));
        result[6]=(byte) (((in[6]>>0)&0x20)|((in[6]<<4)&0x10)|((in[5]   )&0x08)|((in[7]<<2)&0x04)|((in[4]   )&0x02)|((in[7]>>3)&0x01));
        result[7]=(byte) (((in[6]<<2)&0x20)|((in[5]<<4)&0x10)|((in[7]>>3)&0x08)|((in[5]>>4)&0x04)|((in[4]>>5)&0x02)|((in[4]>>3)&0x01));
        return result;
    }
    private byte[] shift(byte[] in,int n) {
        byte[] result=new byte[8];
        for(int i=0;i<8;i++) {
            if(i==3)result[3]=(byte) (((in[3]<<n)|(in[0]>>(7-n)))&0x7f);
            else if(i==7)result[7]=(byte) (((in[7]<<n)|(in[4]>>(7-n)))&0x7f);
            else result[i]=(byte) (((in[i]<<n)|(in[i+1]>>(7-n)))&0x7f);
        }
        return result;
    }
    private void geneKey() {
        this.ikey=new byte[3][8];
        byte[] PC1ShiftOut,PC2Out;
        int[] shiftCount= {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
        PC1ShiftOut=PC1(this.key);
        for(int i=0;i<3;i++) {
            PC1ShiftOut=shift(PC1ShiftOut, shiftCount[i]);
            PC2Out=PC2(PC1ShiftOut);
            System.arraycopy(PC2Out, 0, this.ikey[i], 0, 8);
        }
    }
    private byte[] E(byte[] in) {
        byte[] result=new byte[8];
        result[0]=(byte) (((in[3]<<5)&0x20)|((in[0]>>3)&0x10)|((in[0]>>3)&0x08)|((in[0]>>3)&0x04)|((in[0]>>3)&0x02)|((in[0]>>3)&0x01));
        result[1]=(byte) (((in[0]<<1)&0x20)|((in[0]<<1)&0x10)|((in[0]<<1)&0x08)|((in[0]<<1)&0x04)|((in[0]<<1)&0x02)|((in[1]>>7)&0x01));
        result[2]=(byte) (((in[0]<<5)&0x20)|((in[1]>>3)&0x10)|((in[1]>>3)&0x08)|((in[1]>>3)&0x04)|((in[1]>>3)&0x02)|((in[1]>>3)&0x01));
        result[3]=(byte) (((in[1]<<1)&0x20)|((in[1]<<1)&0x10)|((in[1]<<1)&0x08)|((in[1]<<1)&0x04)|((in[1]<<1)&0x02)|((in[2]>>7)&0x01));
        result[4]=(byte) (((in[1]<<5)&0x20)|((in[2]>>3)&0x10)|((in[2]>>3)&0x08)|((in[2]>>3)&0x04)|((in[2]>>3)&0x02)|((in[2]>>3)&0x01));
        result[5]=(byte) (((in[2]<<1)&0x20)|((in[2]<<1)&0x10)|((in[2]<<1)&0x08)|((in[2]<<1)&0x04)|((in[2]<<1)&0x02)|((in[3]>>7)&0x01));
        result[6]=(byte) (((in[2]<<5)&0x20)|((in[3]>>3)&0x10)|((in[3]>>3)&0x08)|((in[3]>>3)&0x04)|((in[3]>>3)&0x02)|((in[3]>>3)&0x01));
        result[7]=(byte) (((in[3]<<1)&0x20)|((in[3]<<1)&0x10)|((in[3]<<1)&0x08)|((in[3]<<1)&0x04)|((in[3]<<1)&0x02)|((in[0]>>7)&0x01));
        return result;
    }
    private byte[] S(byte[] in) {
        byte[] result=new byte[8];
        for(int i=0;i<8;i++) {
            int t=(in[i]&0x20)|((in[i]&0x01)<<4)|((in[i]>>1)&0xf);
            result[i]=S[i][t];
        }
        return result;
    }
    private byte[] P(byte[] in) {
        byte[] result=new byte[4];
        result[0]=(byte) (((in[3]<<7)&0x80)|((in[1]<<5)&0x40)|((in[4]<<5)&0x20)|((in[5]<<1)&0x10)|((in[7]   )&0x08)|((in[2]<<2)&0x04)|((in[6]<<1)&0x02)|((in[4]>>3)&0x01));
        result[1]=(byte) (((in[0]<<4)&0x80)|((in[3]<<5)&0x40)|((in[5]<<4)&0x20)|((in[6]<<2)&0x10)|((in[1]   )&0x08)|((in[4]   )&0x04)|((in[7]   )&0x02)|((in[2]>>2)&0x01));
        result[2]=(byte) (((in[0]<<5)&0x80)|((in[1]<<6)&0x40)|((in[5]<<5)&0x20)|((in[3]<<2)&0x10)|((in[7]<<3)&0x08)|((in[6]<<1)&0x04)|((in[0]   )&0x02)|((in[2]>>3)&0x01));
        result[3]=(byte) (((in[4]<<6)&0x80)|((in[3]<<3)&0x40)|((in[7]<<3)&0x20)|((in[1]<<2)&0x10)|((in[5]<<1)&0x08)|((in[2]<<1)&0x04)|((in[0]<<1)&0x02)|((in[6]>>3)&0x01));
        return result;
    }
    private byte[] XOR(byte[] in,byte[] ikey) {
        byte[] result=new byte[in.length];
        for(int i=0;i<in.length;i++)
            result[i]=(byte) (in[i]^ikey[i]);
        return result;
    }
    public void Excute() {
        byte[] Li=new byte[4];
        byte[] Ri=new byte[4];
        byte[] Xo;
        System.arraycopy(L0, 0, Li, 0, 4);
        System.arraycopy(R0, 0, Ri, 0, 4);
        for(int i=0;i<3;i++) {
            Xo=XOR(E(Ri), this.ikey[i]);
            Xo=XOR(P(S(Xo)),Li);
            Li=Ri;
            Ri=Xo;
        }
        L3=Ri;
        R3=Li;
    }
    
    public void Excute(byte[] L0,byte[] R0) {
        setLR0(L0,R0);
        Excute();
    }
    public void showInfo() {
        showKey();
        showIkey();
        showPlain();
        showCipher();
    }
    public void showIkeyN() {
        System.out.print("密钥K3: ");
        for(int i=0;i<8;i++)
            System.out.print(String.format("%02x ",this.ikey[2][i]));
        System.out.println();
    }
    public void showIkey() {
        int i,j;
        for(i=0;i<3;i++) {
            System.out.print(String.format("K%d: ", i));
            for(j=0;j<8;j++)
                System.out.print(String.format("%02x ",this.ikey[i][j]));
            System.out.println();
        }
    }
    public void showKey() {
        int i;
        System.out.print("Key:\n  Hex:");
        for(i=0;i<8;i++)
            System.out.print(String.format("%02x ",this.key[i]));
        System.out.print("\n  CH:");
        String strKey=new String(this.key);
        System.out.println(strKey);
    }
    public void showPlain() {
        System.out.print("Plain: ");
        for(int i=0;i<4;i++)
            System.out.print(String.format("0x%02x,",this.L0[i]));
        for(int i=0;i<4;i++)
            System.out.print(String.format("0x%02x,",this.R0[i]));
        System.out.println();
    }
    public void showCipher() {
        System.out.print("Cipher: ");
        for(int i=0;i<4;i++)
            System.out.print(String.format("0x%02x,",this.L3[i]));
        for(int i=0;i<4;i++)
            System.out.print(String.format("0x%02x,",this.R3[i]));
        System.out.println();
    }
    public void setKey(byte[] key) {
        this.key=new byte[8];
        int n=key.length>8?8:key.length;
        for(int i=0;i<n;i++)
            this.key[i] = key[i];
        geneKey();
    }
    public void setKey(String key) {
        setKey(key.getBytes());
    }
    public void UpdateL0() {
        this.L0=new byte[4];
        for(int i=0;i<4;i++)
            this.L0[i]=(byte) (Math.random()*256);
    }
    public void UpdateR0() {
        this.R0=new byte[4];
        for(int i=0;i<4;i++)
            this.R0[i]=(byte) (Math.random()*256);
    }
    public void setLR0() {
        this.L0=new byte[4];
        this.R0=new byte[4];
        for(int i=0;i<4;i++) {
            this.L0[i]=(byte) (Math.random()*256);
            this.R0[i]=(byte) (Math.random()*256);
        }
    }
    public void setLR0(byte[] L0,byte[] R0) {
        this.L0=new byte[4];
        this.R0=new byte[4];
        int nL=L0.length>4?4:L0.length;
        for(int i=0;i<nL;i++)
            this.L0[i] = L0[i];
        int nR=R0.length>4?4:R0.length;
        for(int i=0;i<nR;i++)
            this.R0[i] = R0[i];
    }
    public void setLR0(byte[] LR0) {
        this.L0=new byte[4];
        this.R0=new byte[4];
        int nL=LR0.length>4?4:LR0.length;
        for(int i=0;i<nL;i++)
            this.L0[i] = LR0[i];
        int nR=LR0.length>8?4:(nL-4);
        for(int i=0;i<nR;i++)
            this.R0[i] = LR0[i+4];
    }
    public byte[] getLR0() {
        if(L0==null||R0==null)return null;
        byte[] LR0=new byte[8];
        System.arraycopy(L0, 0, LR0, 0, 4);
        System.arraycopy(R0, 0, LR0, 4, 4);
        return LR0;
    }
    public byte[] getLR3() {
        if(L3==null||R3==null)return null;
        byte[] LR3=new byte[8];
        System.arraycopy(L3, 0, LR3, 0, 4);
        System.arraycopy(R3, 0, LR3, 4, 4);
        return LR3;
    }
}

De_3R:进行3轮差分攻击,输入的两组明文右32比特要相同(由DES_3R类生成)。
 

package De_3R;

import java.util.HashSet;
import java.util.Set;
/**
 * 3轮DES差分攻击
 * @author 实无所得
 *
 */
@SuppressWarnings("rawtypes")
public class De_3R {
    private byte[] dP=null;
    private byte[] dC=null;
    private byte[] Ex=null;
    private byte[][][] count=new byte[8][64][16];
    private Set[][][] Sd=new HashSet[8][64][16];
    private Set[] KeySet=new HashSet[8];
    private static int[][] S= {
            {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13},
            {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9},
            {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12},
            {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14},
            {2,12,4,1,7,10,11,6,5,8,3,15,13,0,14,9,14,11,2,12,4,7,13,1,5,0,15,13,3,9,8,6,4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3},
            {12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13},
            {4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12},
            {13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}};

    public De_3R() {
        init();
    }
    
    private byte[] E(byte[] in) {
        byte[] result=new byte[8];
        result[0]=(byte) (((in[3]<<5)&0x20)|((in[0]>>3)&0x10)|((in[0]>>3)&0x08)|((in[0]>>3)&0x04)|((in[0]>>3)&0x02)|((in[0]>>3)&0x01));
        result[1]=(byte) (((in[0]<<1)&0x20)|((in[0]<<1)&0x10)|((in[0]<<1)&0x08)|((in[0]<<1)&0x04)|((in[0]<<1)&0x02)|((in[1]>>7)&0x01));
        result[2]=(byte) (((in[0]<<5)&0x20)|((in[1]>>3)&0x10)|((in[1]>>3)&0x08)|((in[1]>>3)&0x04)|((in[1]>>3)&0x02)|((in[1]>>3)&0x01));
        result[3]=(byte) (((in[1]<<1)&0x20)|((in[1]<<1)&0x10)|((in[1]<<1)&0x08)|((in[1]<<1)&0x04)|((in[1]<<1)&0x02)|((in[2]>>7)&0x01));
        result[4]=(byte) (((in[1]<<5)&0x20)|((in[2]>>3)&0x10)|((in[2]>>3)&0x08)|((in[2]>>3)&0x04)|((in[2]>>3)&0x02)|((in[2]>>3)&0x01));
        result[5]=(byte) (((in[2]<<1)&0x20)|((in[2]<<1)&0x10)|((in[2]<<1)&0x08)|((in[2]<<1)&0x04)|((in[2]<<1)&0x02)|((in[3]>>7)&0x01));
        result[6]=(byte) (((in[2]<<5)&0x20)|((in[3]>>3)&0x10)|((in[3]>>3)&0x08)|((in[3]>>3)&0x04)|((in[3]>>3)&0x02)|((in[3]>>3)&0x01));
        result[7]=(byte) (((in[3]<<1)&0x20)|((in[3]<<1)&0x10)|((in[3]<<1)&0x08)|((in[3]<<1)&0x04)|((in[3]<<1)&0x02)|((in[0]>>7)&0x01));
        return result;
    }
    
    private byte[] InvP(byte[] in) {
        byte[] result=new byte[8];
        result[0]=(byte) (((in[1]>>4)&0x08)|((in[2]>>5)&0x04)|((in[2]   )&0x02)|((in[3]>>1)&0x01));
        result[1]=(byte) (((in[1]   )&0x08)|((in[3]>>2)&0x04)|((in[0]>>5)&0x02)|((in[2]>>6)&0x01));
        result[2]=(byte) (((in[2]<<3)&0x08)|((in[1]<<2)&0x04)|((in[3]>>1)&0x02)|((in[0]>>2)&0x01));
        result[3]=(byte) (((in[3]>>3)&0x08)|((in[2]>>2)&0x04)|((in[1]>>5)&0x02)|((in[0]>>7)&0x01));
        result[4]=(byte) (((in[0]<<3)&0x08)|((in[1]   )&0x04)|((in[3]>>6)&0x02)|((in[0]>>5)&0x01));
        result[5]=(byte) (((in[0]>>1)&0x08)|((in[3]>>1)&0x04)|((in[1]>>4)&0x02)|((in[2]>>5)&0x01));
        result[6]=(byte) (((in[3]<<3)&0x08)|((in[1]>>2)&0x04)|((in[2]>>1)&0x02)|((in[0]>>1)&0x01));
        result[7]=(byte) (((in[0]   )&0x08)|((in[3]>>3)&0x04)|((in[1]   )&0x02)|((in[2]>>3)&0x01));
        return result;
    }
    private byte[] XOR(byte[] in1,byte[] in2) {
        byte[] result=new byte[in1.length];
        for(int i=0;i<in1.length;i++)
            result[i]=(byte) (in1[i]^in2[i]);
        return result;
    }
    @SuppressWarnings("unchecked")
    public void excDecode() {
        if(this.dC==null)return;
        
        byte[] dPL=new byte[4];
        byte[] dCL=new byte[4];
        byte[] dCR=new byte[4];
        byte[] dPLXCL,dSout,dSin;
        System.arraycopy(dP, 0, dPL, 0, 4);
        System.arraycopy(dC, 0, dCL, 0, 4);
        System.arraycopy(dC, 4, dCR, 0, 4);
        dSin=E(dCR);
        dPLXCL=XOR(dPL,dCL);
        dSout=InvP(dPLXCL);
        
        Set[] CalKey=new HashSet[8];//查差分对应表并计算后得到的密钥值
        for(int i=0;i<8;i++) {
            CalKey[i]=new HashSet<Byte>();
            for (Object set : this.Sd[i][dSin[i]][dSout[i]]) {
                int n=(int) (((Integer) set).byteValue()^this.Ex[i]);
                CalKey[i].add(n);
            }
        }
        for(int i=0;i<8;i++)
            KeySet[i].retainAll(CalKey[i]);//取交集
    }
    @SuppressWarnings("unchecked")
    public void init() {
        for(int i=0;i<8;i++)
            KeySet[i]=new HashSet<Integer>();
        setKeySet();
        for(int i=0;i<8;i++)
            for(int j=0;j<64;j++)
                for(int k=0;k<16;k++)
                    this.Sd[i][j][k]=new HashSet<Integer>();
        for(int i=0;i<8;i++)
            for(int j=0;j<64;j++)
                for(int k=0;k<64;k++) {
                    int t1=(j&0x20)|((j&0x01)<<4)|((j>>1)&0xf);
                    int t2=(k&0x20)|((k&0x01)<<4)|((k>>1)&0xf);
                    this.count[i][j^k][S[i][t1]^S[i][t2]]++;
                    this.Sd[i][j^k][S[i][t1]^S[i][t2]].add(j);
                }
    }
    @SuppressWarnings("unchecked")
    public void setKeySet() {
        for(int i=0;i<8;i++)
            for(int j=0;j<64;j++)
                this.KeySet[i].add(j);
    }
    public void setP(byte[] P1,byte[] P2) {
        this.dP=new byte[8];
        for(int i=0;i<8;i++)
            this.dP[i]=(byte) (P1[i]^P2[i]);
    }
    public void showDP() {
        System.out.print("dP: ");
        for(int i=0;i<8;i++)
            System.out.print(String.format("%02x ",this.dP[i]));
        System.out.println();
    }
    public void setC(byte[] C1,byte[] C2) {
        this.dC=new byte[8];
        byte[] RC1=new byte[4];
        System.arraycopy(C1, 4, RC1, 0, 4);
        this.Ex=E(RC1);
        for(int i=0;i<8;i++)
            this.dC[i]=(byte) (C1[i]^C2[i]);
    }
    public void showDC() {
        System.out.print("dC: ");
        for(int i=0;i<8;i++)
            System.out.print(String.format("%02x ",this.dC[i]));
        System.out.println();
    }
    public void ShowSd() {
        for(int i=0;i<8;i++) {
            for(int j=0;j<64;j++)
                for(int k=0;k<16;k++) {
                    System.out.print("S"+(i+1)+" dSin="+j+" dSout="+k+": ");
                    for (Object b : this.Sd[i][j][k].toArray())
                        System.out.print(String.format("%02x ", ((Integer)b).byteValue()));
                    System.out.println();
                }
            System.out.println();
        }
    }
    public void ShowCount() {
        for(int i=0;i<8;i++) {
            for(int j=0;j<64;j++)
                for(int k=0;k<16;k++) {
                    System.out.print("S"+(i+1)+" dSin="+j+" dSout="+k+": ");
                    System.out.println(String.format("%d", this.count[i][j][k]));
                }
            System.out.println();
        }
    }
    public void ShowKeySet() {
        for(int i=0;i<8;i++) {
            System.out.print("KeySet"+(i+1)+": ");
            for (Object b : this.KeySet[i].toArray())
                System.out.print(String.format("%02x ", ((Integer)b).byteValue()));
            System.out.println();
        }
    }
    public boolean IsKeySetUnique() {
        boolean isUnique=true;
        for(int i=0;i<8;i++) {
            if(this.KeySet[i].size()!=1) {
                isUnique=false;
                break;
            }
        }
        return isUnique;
    }
}

testDe_3R:用于测试。
 

package De_3R;

import java.util.Scanner;
/**
 * 测试3轮DES差分攻击
 * @author 实无所得
 *
 */
public class testDe_3R {
    public static void main(String[] args) {
        String key="de3r_key";
        DES_3R dx=new DES_3R(key);
        De_3R de=new De_3R();
//        de.ShowSd();    //显示差分对应表
        test1(dx, de);
//        test2(dx, de,10000);
    }
    public static void test1(DES_3R dx,De_3R de) {
        int n=0;
        byte[] P1,P2,C1,C2;
        String str="";
        Scanner scanner=new Scanner(System.in);
        dx.showIkeyN();
        do{
            n++;
            System.out.println(String.format("第%d次更新密钥的结果:", n));
            //生成一对明文输入和一对密文输出
            dx.setLR0();
            P1=dx.getLR0();
            dx.Excute();
            C1=dx.getLR3();
            dx.UpdateL0();
            P2=dx.getLR0();
            dx.Excute();
            C2=dx.getLR3();
            //更新一次密钥集合
            de.setP(P1, P2);
            de.setC(C1, C2);
            de.excDecode();
            de.showDP();
            de.showDC();
            de.ShowKeySet();
            
            System.out.print("按n继续:");
            str=scanner.next();
        }while(str.equals("n"));
        scanner.close();
    }
    public static void test2(DES_3R dx,De_3R de,int N) {
        if(N<0||N>100000) {
            System.out.println("请输入合适的N值!");
            return;
        }
        byte[] P1,P2,C1,C2;
        int n=0;
        int[] count=new int[20];
        for(int i=0;i<N;i++) {
            do{
                n++;
                //生成一对明文输入和一对密文输出
                dx.setLR0();
                P1=dx.getLR0();
                dx.Excute();
                C1=dx.getLR3();
                dx.UpdateL0();
                P2=dx.getLR0();
                dx.Excute();
                C2=dx.getLR3();
                //更新一次密钥集合
                de.setP(P1, P2);
                de.setC(C1, C2);
                de.excDecode();
            }while(!de.IsKeySetUnique());
            de.setKeySet();
            count[n-1]++;
            n=0;
        }
        for(int i=0;i<20;i++)
            System.out.printf("%2d次:%5d : %f\n",i+1, count[i],(float)count[i]/N);
    }
}


版权声明:本文为weixin_43261410原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。