DES加解密过程详解:

 

代码实现细节如下,DES加解密是对合运算,直接使用一个方法完成

import java.util.InputMismatchException;
import java.util.Scanner;

public class DES {

    private static byte S1[] = {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};
    private static byte S2[] = {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};
    private static byte S3[] = {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};
    private static byte S4[] = {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};
    private static byte S5[] = {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 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};
    private static byte S6[] = {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};
    private static byte S7[] = {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};
    private static byte S8[] = {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 static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        System.out.println("请输入明文:");
        String message = sc.nextLine(); // 明文

        //填充明文,使其长度为8的整数倍
        message = paddingMess(message);

        System.out.println("请输入加密密钥(8个字符):");
        String inputKey = sc.nextLine(); // 密钥
        char inputKeyArr[] = inputKey.toCharArray();
        char inputKeyBin[][] = new char[8][8];

        // 加密密钥的二进制存放
        keyStrTokeyBin(inputKeyArr, inputKeyBin);

        String cypher = Encrypt(message, inputKeyBin, 1);

        String cypherHex = binToHex(cypher);

        System.out.println("DES加密结果:" + cypher);
        System.out.println("十六DES加密结果:" + cypherHex);

        //加解密分割线---------------

        System.out.println("请输入解密密钥(8个字符):");

        inputKey = sc.nextLine(); // 解密密钥
        inputKeyArr = inputKey.toCharArray();   //解密密钥字符串
        keyStrTokeyBin(inputKeyArr, inputKeyBin);   //解密密钥的二进制数组,8列

        // 解密密钥的二进制存放
        keyStrTokeyBin(inputKeyArr, inputKeyBin);

        String messDec = Encrypt(cypher, inputKeyBin, -1);
        String messDecHex = binToHex(messDec);
        message = hexMessToString(messDec);

        System.out.println("DES解密结果:" + messDec);
        System.out.println("十六DES解密结果:" + messDecHex);
        System.out.println("解密结果:" + message);

    }

    /**
     * @param message  该参数是传入的明文或者密文信息
     * @param inputKey 该参数是二进制二维密钥数组,密钥长度行,8列
     * @param flag     因为DES是对合运算,所以该函数同时可以进行加密和解密,flag位即加密解密标记位,1为加密,0为解密
     * @return 返回加密或者解密后的二进制数组
     */
    public static String Encrypt(String message, char inputKey[][], int flag) {

        char masterKeyLeft[] = new char[28];
        char masterKeyRight[] = new char[28];

        byte keyRevLft[] = {57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3,
                60, 52, 44, 36};
        byte keyRevRight[] = {63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13,
                5, 28, 20, 12, 4};

        // 对左28位和右28位赋值
        for (int i = 0; i < masterKeyLeft.length; i++) {
            masterKeyLeft[i] = inputKey[keyRevLft[i] / 8][keyRevLft[i] % 8 - 1];
        }
        for (int i = 0; i < masterKeyRight.length; i++) {
            masterKeyRight[i] = inputKey[keyRevRight[i] / 8][keyRevRight[i] % 8 - 1];
        }

        // 定义左移位数的数组
        byte moveArr[] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

        // 定义子密钥数组并且移为选择赋值
        char subKey[][] = new char[16][48];
        for (int i = 0; i < subKey.length; i++) {
            subKey[i] = getSubKey(masterKeyLeft, masterKeyRight, moveArr[i]);
        }

        // 得到子密钥,开始加密

        // 创建明文或者密文二进制数组及赋值
        char messageBin[][];
        if (flag == 1) {
            messageBin = new char[message.length() / 8][64];
            messageBin = messageToBin(message);
        }
        else {
            messageBin = new char[message.length() / 64][64];
            for (int i = 0; i < messageBin.length; i++) {
                messageBin[i] = message.substring(64 * i,64 * (i + 1)).toCharArray();
            }
        }
        // 开始循环对每个64位进行加密或者解密

        String cypher = "";
        cypher = interater(subKey,messageBin,flag);

        return cypher;
    }

    public static void innerInterater(char L0[], char R0[], char subKey[]) {

        char tempResult[] = new char[32];

        //选择扩展数组
        byte selectE[] = {32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17,
                18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1};

        //R0经过运算得到48位的中间变量
        char tempR0[] = new char[48];
        for (int i = 0; i < tempR0.length; i++) {
            tempR0[i] = R0[selectE[i] - 1];
        }
        //得到选择结果

        //中间变量与子密钥亦或,结果中间变量中覆盖原有数据
        for (int i = 0; i < tempR0.length; i++) {
            if (tempR0[i] == subKey[i])
                tempR0[i] = '0';
            else
                tempR0[i] = '1';
        }

        //48位选择出32位
        for (int i = 0; i < tempR0.length - 5; i += 6) {
            String temp = "";
            temp += tempR0[i];
            temp += tempR0[i + 5];
            int column = Integer.parseInt(temp, 2);
            temp = "";
            temp += tempR0[i + 1];
            temp += tempR0[i + 2];
            temp += tempR0[i + 3];
            temp += tempR0[i + 4];
            int row = Integer.parseInt(temp, 2);

            byte ret = 0;
            switch (i / 6) {
                case 0:
                    ret = S1[column * 16 + row];
                    break;
                case 1:
                    ret = S2[column * 16 + row];
                    break;
                case 2:
                    ret = S3[column * 16 + row];
                    break;
                case 3:
                    ret = S4[column * 16 + row];
                    break;
                case 4:
                    ret = S5[column * 16 + row];
                    break;
                case 5:
                    ret = S6[column * 16 + row];
                    break;
                case 6:
                    ret = S7[column * 16 + row];
                    break;
                case 7:
                    ret = S8[column * 16 + row];
                    break;
            }

            String retStr = Integer.toBinaryString(ret);
            while (retStr.length() != 4)
                retStr = '0' + retStr;
            char retArr[] = retStr.toCharArray();

            for (int j = (i / 6) * 4, t = 0; j < 4 * (i / 6 + 1); j++, t++) {
                tempResult[j] = retArr[t];
            }

        }

        //置换运算P,打乱顺序
        byte selectP[] = {16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19,
                13, 30, 6, 22, 11, 4, 25};

        //这里tempResult中存放的是经过S盒选择的32位数据
        //下面开始执行P置换,再与L0亦或运算得到R0,暂时继续存放到tempResult中

        //48位选择32位结束,得到经过F运算的结果,存放在tempResult中,f函数结果与L0亦或重新赋值
        char result[] = new char[tempResult.length];
        for (int j = 0; j < tempResult.length; j++) {
            if (tempResult[selectP[j] - 1] == L0[j])
                result[j] = '0';
            else
                result[j] = '1';
        }

        for (int i = 0; i < result.length; i++) {
            L0[i] = R0[i];
            R0[i] = result[i];
        }

    }

    public static String Decrypt(String cypher, char inputKey[][]) {
        String messageDec = "";

        return messageDec;
    }

    public static char[] getSubKey(char masterKeyLeft[], char masterKeyRight[], byte num) {
        char subKey[] = new char[48];
        char tempArrL[] = new char[num]; // 临时数组,存放移位溢出的数据
        char tempArrR[] = new char[num]; // 临时数组,存放移位溢出的数据

        // 移位
        for (int i = 0; i < num; i++) {
            tempArrL[i] = masterKeyLeft[i];
            tempArrR[i] = masterKeyRight[i];
        }

        for (int i = 0; i < masterKeyLeft.length - num; i++) {
            masterKeyLeft[i] = masterKeyLeft[i + num];
            masterKeyRight[i] = masterKeyRight[i + num];
        }

        for (int i = num; i > 0; i--) {
            masterKeyLeft[masterKeyLeft.length - i] = tempArrL[num - i];
            masterKeyRight[masterKeyRight.length - i] = tempArrR[num - i];
        }

        // 移位完成,对两个数组选择,结果赋值给subKey

        // 定义置换选择2的矩阵
        byte selectArr[] = {14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41,
                52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32};

        // 生成子密钥
        for (int i = 0; i < selectArr.length; i++) {
            if (selectArr[i] > 28) {
                subKey[i] = masterKeyRight[selectArr[i] - 29];
            } else {
                subKey[i] = masterKeyLeft[selectArr[i] - 1];
            }
        }

        return subKey;
    }

    /**
     * 该方法有两个参数
     *
     * @param inputKeyArr 该参数是密钥数组
     * @param inputKeyBin 该参数是密钥数组的二进制存放
     *                    两个参数都是修改后返回
     */
    public static void keyStrTokeyBin(char inputKeyArr[], char inputKeyBin[][]) {

        for (int i = 0; i < inputKeyBin.length; i++) {
            String inputKeyBlock = Integer.toBinaryString(inputKeyArr[i]);
            int t = 8 - inputKeyBlock.length();
            while (t != 0) {
                inputKeyBlock = "0" + inputKeyBlock;
                t = 8 - inputKeyBlock.length();
            }
            inputKeyBin[i] = inputKeyBlock.toCharArray();
        }

        return;
    }

    /**
     * @param message   传入的参数是二进制字符串    this parament is a binary String waited to be Hex String
     * @return           返回的参数是二进制字符串转化出的十六进制字符串 this method retun the Hex String of parament Binary String
     */
    public static String binToHex(String message) {

        char messageArr[] = message.toCharArray();
        String hexTemp = "";
        String retStr = "";

        for (int i = 0; i < message.length(); i += 8) {
            hexTemp = "";
            for (int j = 0; j < 8; j++) {
                hexTemp += messageArr[i + j];
            }
            hexTemp = Integer.toHexString(Integer.parseInt(hexTemp, 2));
            if (hexTemp.length() != 2)
                hexTemp = "0" + hexTemp;
            retStr += hexTemp;
        }

        return retStr;
    }

    /**
     * @param message 该参数是传入的明文信息
     * @return 返回值是使用=字符填充后的明文,其长度为8的整数倍
     */
    public static String paddingMess(String message) {

        StringBuilder strBud = new StringBuilder(message);

        if (message.length() % 8 != 0) { // 用等号=将明文填充够8的整数倍
            while (strBud.length() % 8 != 0) {
                strBud.append("=");
            }
        }

        return strBud.toString();
    }

    public static char[][] messageToBin(String message) {

        char messageBin[][] = new char[message.length() / 8][64];
        char messageCha[] = message.toCharArray();

        // 明文二进制数组赋值
        String bin = ""; // 明文的二进制字符串
        for (int i = 0; i < messageCha.length; i++) {
            int t = 8 - Integer.toBinaryString(messageCha[i]).length();
            while (t != 0) {
                bin += '0';
                t--;
            }
            bin += Integer.toBinaryString(messageCha[i]);
        }

        for (int i = 0; i < messageBin.length; i++) {
            if (i == messageBin.length - 1) {
                messageBin[i] = bin.substring(64 * i, bin.length()).toCharArray();
            } else {
                messageBin[i] = bin.substring(64 * i, 64 * (i + 1)).toCharArray();
            }
        }

        return messageBin;

    }

    public static String interater(char subKey[][],char messageBin[][],int flag) {

        char L0[] = new char[32];
        char R0[] = new char[32];

        byte ip[] = {58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64,
                56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37,
                29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7};

        String cypher = "";

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

            //对L0 R0 赋值
            for (int j = 0; j < messageBin[i].length; j++) {
                if (j >= 32)
                    R0[j - 32] = messageBin[i][ip[j] - 1];
                else
                    L0[j] = messageBin[i][ip[j] - 1];

            }

            //开始对当前分组进行16轮迭代
            for (int j = 0; j < 16; j++) {
                if (flag == 1) //加密
                    innerInterater(L0, R0, subKey[j]);
                else if(flag == -1)    //解密
                    innerInterater(L0, R0, subKey[15-j]);
                else
                    throw new InputMismatchException();
            }

            //最后一轮迭代不交换左右L0 和 R0,但是循环里交换了,循环外再次交换回来
            char tempR0;
            for (int j = 0; j < L0.length; j++) {
                tempR0 = L0[j];
                L0[j] = R0[j];
                R0[j] = tempR0;
            }

            //逆初始置换IPRev
            String tempCry = "";
            for (int j = 0; j < L0.length; j++) {
                tempCry += L0[j];
            }
            for (int j = 0; j < R0.length; j++) {
                tempCry += R0[j];
            }

            char tempCryArr[] = tempCry.toCharArray();

            byte ipRev[] = {40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62,
                    30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34,
                    2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25};

            char cryRevArr[] = new char[tempCryArr.length];

            for (int j = 0; j < cryRevArr.length; j++)
                cryRevArr[j] = tempCryArr[ipRev[j] - 1];

            cypher += new String(cryRevArr);

        }

        return cypher;

    }

    public static String hexMessToString(String message) {
        StringBuilder messageCha = new StringBuilder();

        char arr[] = new char[8];
        for (int i = 0; i < message.length() / 8; i++) {
            arr = message.substring(8 * i,8 * (i + 1)).toCharArray();
            messageCha.append((char)Integer.parseInt(new String(arr),2));
        }

        return messageCha.toString();

    }

}

代码细节有任何问题欢迎评论私聊提问