1. 程式人生 > >DES演算法的JAVA實現(ECB模式)

DES演算法的JAVA實現(ECB模式)

文章目錄

一、演算法原理概述

參考自老師的PPT

加密過程

1541244158363

1541244631502

初始置換IP

1541244740744

迭代T

1541245001052

Feistel輪函式

1541245200505

子祕鑰生成

1541245413226

逆置換IP-1

1541245475171

解密過程

1541244245356

二、總體結構

class DES{
    //建構函式
	public DES(StringBuffer text, StringBuffer key, int mode) throws Exception {}
	//PKCS5填充處理明文
	public StringBuffer dealText(final StringBuffer origin)
{} //初始置換IP public void start() { //把明文或者密文轉換成二進位制字串 //分組加密或解密 IP(...); } //IP置換 public void IP(final String plaintextBinary) { //通過IP置換明文 //把置換後的明文分為左右兩塊 iterationT(...); } //迭代T public void iterationT(StringBuffer L, StringBuffer R) { //得到子祕鑰 getSbuKey(...); //16次迭代
feistel(...); //左右交換 //逆置換 //生成字串明文或密文 //END! } //Feistel輪函式 public StringBuffer feistel(final StringBuffer R, final StringBuffer subKey ) { //E擴充套件 //異或運算 //S-Box //P置換 } //子祕鑰生成 public StringBuffer[] getSubKey() { //把key轉換為二進位制 //PC1置換 // LS迴圈16輪生成子金鑰 // 把左右兩塊合併 // PC2置換 // 根據PC2壓縮C0D0,得到子金鑰 } //主函式 public static void main(String[] args){start();} }

三、模組分解

PKCS5填充處理明文

public StringBuffer dealText(final StringBuffer origin) {
		StringBuffer textBinary = new StringBuffer();
		//使用PKCS#5/PKCS7填充
		int max = group*8;
		int padding = max - origin.length();
        for (int i = 0; i < max; ++i) {
        	StringBuffer charBinary;
        	if(i >= origin.length()) {
        		charBinary = new StringBuffer(Integer.toBinaryString(padding));
        	}else
        		charBinary = new StringBuffer(Integer.toBinaryString(origin.charAt(i)));
            while (charBinary.length() < 8) {
            	charBinary.insert(0, 0);
            }
            textBinary.append(charBinary);
        }
        return textBinary;
	}

字串轉二進位制

	public StringBuffer string2Binary(final StringBuffer origin) {
		StringBuffer textBinary = new StringBuffer();
        for (int i = 0; i < origin.length(); ++i) {
        	StringBuffer charBinary = new StringBuffer(Integer.toBinaryString(origin.charAt(i)));
            while (charBinary.length() < 8) {
            	charBinary.insert(0, 0);
            }
            textBinary.append(charBinary);
        }
        return textBinary;
	}

IP置換

	public void IP(final String plaintextBinary) {
		//通過IP置換明文
        StringBuffer substitutePlaintext = new StringBuffer(); // 儲存置換後的明文
        for (int i = 0; i < 64; ++i) {
            substitutePlaintext.append(plaintextBinary.charAt(IP[i] - 1));
        }
        //把置換後的明文分為左右兩塊
        StringBuffer L = new StringBuffer(substitutePlaintext.substring(0, 32));
        StringBuffer R = new StringBuffer(substitutePlaintext.substring(32));
        iterationT(L, R);
	}

Feistel輪函式

	public StringBuffer feistel(final StringBuffer R, final StringBuffer subKey ) {
		//E擴充套件
		StringBuffer RExtent = new StringBuffer(); // 儲存擴充套件後的右邊
        for (int i = 0; i < 48; ++i) {
            RExtent.append(R.charAt(E[i] - 1));
        }
		//異或運算
        for (int i = 0; i < 48; ++i) {
            RExtent.replace(i, i + 1, (RExtent.charAt(i) == subKey.charAt(i)) ? "0" :"1");
        }
		//S-Box
        StringBuffer SBoxString = new StringBuffer();
        for(int i = 0; i < 8; ++i) {
        	String SBoxInput = RExtent.substring(i * 6, (i + 1) * 6);
        	int row = Integer.parseInt(Character.toString(SBoxInput.charAt(0)) + SBoxInput.charAt(5), 2);
            int column = Integer.parseInt(SBoxInput.substring(1, 5), 2);
            
            StringBuffer SBoxOutput = new StringBuffer(Integer.toBinaryString(SBox[i][row * 16 + column]));
            while (SBoxOutput.length() < 4) {
                SBoxOutput.insert(0, 0);
            }
            SBoxString.append(SBoxOutput);
        }
		//P置換
        StringBuffer substituteSBoxString= new StringBuffer(); // 儲存置換後的R
        for (int i = 0; i < 32; ++i) {
        	substituteSBoxString.append(SBoxString.charAt(P[i] - 1));
        }
        return substituteSBoxString;
	}
	

子金鑰生成

//子祕鑰生成
public StringBuffer[] getSubKey() {
	//把key轉換為二進位制
	StringBuffer keyBinary = string2Binary(key);
	
	StringBuffer[] subKey = new StringBuffer[16]; // 儲存子金鑰
	//PC1置換
	StringBuffer C0 = new StringBuffer(); // 儲存金鑰左塊
    StringBuffer D0 = new StringBuffer(); // 儲存金鑰右塊
    for (int i = 0; i < 28; ++i) {
        C0.append(keyBinary.charAt(PC1[i] - 1));
        D0.append(keyBinary.charAt(PC1[i + 28] - 1));
    }
    
    // LS迴圈16輪生成子金鑰
    for (int i = 0; i < 16; ++i) {
        // 迴圈左移
    	char mTemp;
        mTemp = C0.charAt(0);
        C0.deleteCharAt(0);
        C0.append(mTemp);
        mTemp = D0.charAt(0);
        D0.deleteCharAt(0);
        D0.append(mTemp);
        if(i != 0 && i != 1 && i != 8 && i != 15) {
        	mTemp = C0.charAt(0);
            C0.deleteCharAt(0);
            C0.append(mTemp);
            mTemp = D0.charAt(0);
            D0.deleteCharAt(0);
            D0.append(mTemp);
        }
        // 把左右兩塊合併
        StringBuffer C0D0 = new StringBuffer(C0.toString() + D0.toString());
        
        // PC2置換
        // 根據PC2壓縮C0D0,得到子金鑰
        StringBuffer C0D0Temp = new StringBuffer();
        for (int j = 0; j < 48; ++j) {
            C0D0Temp.append(C0D0.charAt(PC2[j] - 1));
        }
        subKey[i] = C0D0Temp;
    }
    return subKey;
}

十六次迭代

//迭代T
	public void iterationT(StringBuffer L, StringBuffer R) {
		//得到子祕鑰
		StringBuffer[] subKey = getSubKey();
		//這是解密的子祕鑰
		if(encrypt_decrypt != 0) {
			StringBuffer[] temp = getSubKey();
			for (int i = 0; i < 16; ++i) {
                subKey[i] = temp[15 - i];
            }
		}
		StringBuffer Lbackup = new StringBuffer();
		StringBuffer Rbackup = new StringBuffer();
		Lbackup.replace(0, L.length(), L.toString());
		Rbackup.replace(0, R.length(), R.toString());
		//16次迭代
		for(int i = 0; i < 16; i++) {
			//不能直接用等於號!!!!!
			StringBuffer tempL = new StringBuffer(L);
			StringBuffer tempR = new StringBuffer(R);
			//字串賦值
			L.replace(0, 32, R.toString());
			StringBuffer feistelString = feistel(tempR, subKey[i]);
			
			for(int j = 0; j < 32; j++) {
				R.replace(j, j + 1, (tempL.charAt(j) == feistelString.charAt(j)) ? "0" :"1");
			}
		}
		
		//左右交換
		StringBuffer RL = new StringBuffer(R.toString() + L.toString());
		//逆置換
		StringBuffer substituteRL = new StringBuffer(); // 儲存置換後的LR
        for (int i = 0; i < 64; ++i) {
            substituteRL.append(RL.charAt(IPReverse[i] - 1));
        }
        //生成字串明文或密文
        for (int i = 0; i < 8; ++i) {
            String temp = substituteRL.substring(i * 8, (i + 1) * 8);
            //加密
            if(encrypt_decrypt == 0) {
            	ciphertext.append((char) Integer.parseInt(temp, 2));
            	StringBuffer tempHex = new StringBuffer(Integer.toHexString(Integer.parseInt(temp, 2)));
            	while(tempHex.length() < 2) {
            		tempHex.insert(0, "0");
            	}
            	ciphertextHex.append(tempHex + " ");
            //解密
            }else {
            	plaintext.append((char) Integer.parseInt(temp, 2));
            }
            	
        }
        //END!
	}

四、資料結構

StringBuffer plaintext 明文字串

理論上明文字串長度可以任意,加密時八個字元(位元組)一組,也就是64bit,不夠8個位元組一組使用PKCS#5標準填充

假設待加密資料長度為x,那麼將會在後面padding的位元組數目為8-(x%8),每個padding的位元組值是8-(x%8)。

特別地,當待加密資料長度x恰好是8的整數倍,也是要在後面多增加8個位元組,每個位元組是0x08。

StringBuffer ciphertext 密文字串

密文字串只能是8位元組的整數倍,因為它是通過明文加密得到的,如果不是8的整數倍也就不存在明文了

StringBuffer key 金鑰

這裡的金鑰是用字串表示,不是十六進位制!!!

StringBuffer ciphertextHex 密文的十六進位制表示
int group 分組數(DES64bit為一個分組,所以需要根據每組來加密相應的明文)
int encrypt_decrypt 演算法模式:0表示加密,其餘表示解密

int[] IP IP置換表
int[] IPReverse IP逆置換表

int[] E E擴充套件表
int[] P P置換
int[] PC1 PC1置換
int[] PC2 PC2壓縮置換
int[][] SBox 8個S-Box

五、執行結果

執行說明:

主函式分為兩個部分:加密和解密

加密部分輸入明文,金鑰和演算法模式(0表示加密,其餘表示解密),輸出密文

解密部分輸入密文(這裡直接用上面生成的密文,好對比結果),金鑰(與上面同樣的金鑰),演算法模式,應該輸出同樣的明文

1540126222637

可以看到確實能夠實現加密再解密得到原資料!

六、原始碼

public class DES {
	private StringBuffer plaintext;
	private StringBuffer ciphertext;
	private StringBuffer key;
	private StringBuffer ciphertextHex;
	private int group;
	//0表示加密,其餘表示解密
	private int encrypt_decrypt;
	//IP置換
	private static final int[] 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
			}; 
	//IP逆置換
	private static final int[] IPReverse = { 
			40, 8, 48, 16, 56, 24, 
            
           

相關推薦

DES演算法JAVA實現ECB模式

文章目錄 一、演算法原理概述 加密過程 初始置換IP 迭代T Feistel輪函式 子祕鑰生成 逆置換IP-1 解

Dijkstra演算法 java實現含測試

D演算法的實現(求任意點到其他點的最短距離): package D; import java.util.ArrayList; import java.util.List; /** * @author sean22 * @date 2017/12/13/013.

連結串列排序演算法java實現連結串列的快速排序、插入排序、歸併排序

難易程度:★★ 重要性:★★★      連結串列的排序相對陣列的排序更為複雜些,也是考察求職者是否真正理解了排序演算法(而不是“死記硬背”) 連結串列的插入排序 public class LinkedInsertSort { static cla

簡單選擇排序演算法原理及java實現超詳細

選擇排序是一種非常簡單的排序演算法,就是在序列中依次選擇最大(或者最小)的數,並將其放到待排序的數列的起始位置。 簡單選擇排序的原理 簡單選擇排序的原理非常簡單,即在待排序的數列中尋找最大(或者最小)的一個數,與第 1 個元素進行交換,接著在剩餘的待排序的數列中繼續找最大(最小)的一個數,與第 2 個元素交

八大排序演算法JAVA實現時間複雜度O(n-logn)篇

本文講述時間複雜度為n*logn的排序演算法:歸併排序、快速排序、堆排序以及希爾排序的原理、Java實現以及變形應用。 一、歸併排序  原理:把兩個有序數列合併為一個有序數列。需遞迴實現。  Java實現: 1 public int[] mergeSort(in

八大排序演算法JAVA實現時間複雜度O(n-n)篇

本文主要描述3個時間複雜度為n2的排序演算法:氣泡排序、選擇排序、插入排序。 1.氣泡排序:由陣列頭部開始,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。每次交換完成後,當前陣列最大值就會被放在最後。 1 public int[] bubbleSort

基礎排序演算法 java 實現冒泡、選擇、插入、快排、歸併、堆排

package demo; import java.util.Arrays; public class SortUtil { private static void printArr(int[] arr) { System.out.println

常見加密演算法java實現MD5,SHA-256,SHA-512

import org.apache.commons.codec.digest.DigestUtils; public class PasswordEncode {     private static String pwdAlgorithm = "MD5";     /**      * 加密密碼演算法  

PBFT 演算法 java實現

PBFT 演算法的java實現(下) 在上一篇部落格中(如果沒有看上一篇部落格建議去看上一篇部落格),我們介紹了使用Java實現PBFT演算法中節點的加入,view的同步等操作。在這篇部落格中,我將介紹PBFT演算法中共識過程的實現。 專案地址:GitHub 共識過程 這個是hyperch

資料結構的Java實現十四—— 圖

1、圖的定義 圖通常有個固定的形狀,這是由物理或抽象的問題所決定的。比如圖中節點表示城市,而邊可能表示城市間的班機航線。如下圖是美國加利福利亞簡化的高速公路網:    ①、鄰接:如果兩個頂點被同一條邊連線,就稱這兩個頂點是鄰接的。如上圖 I 和 G 就是鄰接的,而

基於keepalived+nginx+lvs的負載均衡的實現DR模式

LVS結合keepalive LVS可以實現負載均衡,但是不能夠進行健康檢查,比如一個rs出現故障,LVS 仍然會把請求轉發給故障的rs伺服器,這樣就會導致請求的無效性。keepalive 軟體可以進行健康檢查,而且能同時實現 LVS 的高可用性,解決 LVS 單點故障的問

java實現從txt……寫入execl

本文使用jxl,如果使用maven 直接引入即可。 <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</a

淺談常見的七種加密演算法實現附程式碼

1. 前言 數字簽名、資訊加密 是前後端開發都經常需要使用到的技術,應用場景包括了使用者登入、交易、資訊通訊、oauth 等等,不同的應用場景也會需要使用到不同的簽名加密演算法,或者需要搭配不一樣的 簽名加密演算法來達到業務目標。這裡簡單的給大家介紹幾種常見的簽

十大排序演算法及其實現C++ & Python

經典的幾大排序演算法,網上各種版本程式碼質量層次不齊。在此想自己做個總結,一方面希望通過這次總結加深自己對幾種排序演算法的認識和記憶,另一方面也希望能寫下來與大家分享。 每個演算法力求給出普通解法和最優解法,當前部分排序演算法還沒有給出最優解,待後續的

劍指Offer——程式設計題的Java實現更新完畢……

二維陣列中的查詢 在一個二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。 /* * 思路 矩陣是有序的,從右上角來看,向左數字遞減,向下數字遞

【機器學習演算法-python實現】KNN-k近鄰演算法實現附原始碼

 下載地址 kNN演算法及例項原始碼實現#coding=utf-8 ''' Created on Sep 16, 2010 kNN: k Nearest Neighbors Input: inX: vector to compare to existing dataset (1xN)

常見的幾種內排序演算法以及實現C語言

所有未排序的陣列是經過檢查合法的 主要的內排序包括冒泡、插入、希爾、堆排序、歸併、快速、桶排序等 其C語言實現的原始檔下載地址:http://download.csdn.net/detail/mcu_tian/9530227 氣泡排序 氣泡排序應該是排序中最簡單的演算法了

TF-IDF演算法-Python實現附原始碼

一、背景         TF-IDF演算法全稱 termfrequency–inverse document frequency,是一種用於資訊檢索與資訊探勘的常用加權技術。它的演算法複雜度並不高,但能很好的滿足搜尋高相關度文件的需求。由於它的高效性,TF-IDF 模型在搜尋引擎等實際應用中被廣泛使用

詳解二叉查詢樹演算法實現c語言

 樹(Tree)是n(n≥0)個結點的有限集。在任意一棵非空樹中:(1)有且僅有一個特定的被稱為根(Root)的結點;(2)當n>1時,其餘結點可分為m(m>0)個互不相交的有限集T1,T2,…,Tm,其中每一個集合本身又是一棵樹,並且稱為根的子樹(SubTre