欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java实现DES加解密 DES加解密详解

程序员文章站 2024-03-14 14:21:22
...

DES加解密过程详解:

https://blog.csdn.net/wowocpp/article/details/80136245

代码实现细节如下,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();

    }

}

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