DES演算法的JAVA實現(ECB模式)
文章目錄
一、演算法原理概述
參考自老師的PPT
加密過程
初始置換IP
迭代T
Feistel輪函式
子祕鑰生成
逆置換IP-1
解密過程
二、總體結構
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
分組數(DES
以64bit
為一個分組,所以需要根據每組來加密相應的明文)
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表示加密,其餘表示解密),輸出密文
解密部分輸入密文(這裡直接用上面生成的密文,好對比結果),金鑰(與上面同樣的金鑰),演算法模式,應該輸出同樣的明文
可以看到確實能夠實現加密再解密得到原資料!
六、原始碼
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++實現(有註釋):統計數字某位數的個數,用隨機函式產生100個[0,99]範圍內的隨機整數, 統計數字的個位上的數字分別為0,1,2,3,4,5,6,7,8,9的數的個數,並打印出來。
#include<iostream>
#include<cstdlib>// #include <stdlib.h> void srand( unsigned seed );
//功能: 設定rand()隨機序列種子。對於給定的種子se
常見的幾種內排序演算法以及實現(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