Java-列移位(Columnar Transposition Cipher)算法实现版本一
作者:互联网
这是几年前写的旧文,此前发布Wordpress小站上,现在又重新整理。算是温故知新,后续会继续整理。如有错误望及时指出,在此感谢。
场景描述
从数据安全角度而言,有些数据不希望在传输或序列化过程中明文化。在对安全要求不高的场合,可以考虑列移位算法来实现。
算法说明
http://www.practicalcryptography.com/ciphers/columnar-transposition-cipher/
算法的实现过程有很多种,我选了比较简单的一种。
加密算法描述
- 准备一个密钥,长度不限,密文字符可以重复;
- 根据密钥长度生成二维矩阵,根据密钥的长度算出二维矩阵的行数和列数;
- 根据密钥字符ASCII顺序按列读取字符得到加密字符串;
- 假设密钥为german,则二维矩阵的列数为6,列的ASCII码顺序为[2,1,5,3,0,4];
- 明文是密钥长度的整数倍,不足整数倍部分用特定字符填充(可选,本文中未这样实现);
加密算法举例
明文:
defend*the*east*wall*of*the*castle
密文:
d*altsetslhtfht*elee*o*en*wfcdea*a
密钥 | g | e | r | m | a | n |
---|---|---|---|---|---|---|
密钥顺序 | 0 | 1 | 2 | 3 | 4 | 5 |
字符顺序 | 2 | 1 | 5 | 3 | 0 | 4 |
d | e | f | e | n | d | |
***** | t | h | e | ***** | e | |
a | s | t | ***** | w | a | |
l | l | ***** | o | f | ***** | |
t | h | e | ***** | c | a | |
s | t | l | e |
在生成密文时,按照字符顺序按列读取
n*wfc
etslht
以此类推来生成密文
解密算法描述
- 根据密钥长度确定二维矩阵列数;
- 根据密钥字符顺序得到解密填充列数据时候的顺序;
- 假设密钥为german,则二维矩阵列数为6,矩阵列的读取顺序为[4, 1, 0, 3, 5, 2];
- 按照矩阵列读取顺序,将密文依大小按顺序写入二维矩阵中;
解密算法举例
密文:
d*altsetslhtfht*elee*o*en*wfcdea*a
明文:
defend*the*east*wall*of*the*castle
生成明文时,按照密钥顺序写入
n*wfc,写入密钥顺序第四列;
etslht,写入密钥顺序第一列;
以此类推来生成明文
源码实现
依赖MAVEN
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.*;
/**
*
* @Classname ColumnarTranspositionCipherTest1
* @Description 加密算法:列移位-Columnar Transposition Cipher
*/
public class ColumnarTranspositionCipherTest1 {
// public static final String keyStr = "mamihong";
public static final String keyStr = "german";
public static void main(String[] args) {
String inputString = "defend*the*east*wall*of*the*castle";
System.out.println("inputString:" + inputString);
System.out.println("---------加密----------");
String encipher = encipher(inputString);
System.out.println("encipher:" + encipher);
System.out.println("--------解密-----------");
System.out.println("decrypt:" + decrypt(encipher));
}
/**
* 加密
*
* @param inputString
* @return
*/
public static String encipher(String inputString) {
final char[] inputChars = inputString.toCharArray();
final int inputLength = inputChars.length;
//密文数组
final KeyLink[] keyLinkArray = getKeyLinkArrays(keyStr);
//矩阵的列宽
final int fieldSize = keyLinkArray.length;
//矩阵的行数
final int rowSize = (inputLength / fieldSize) + (inputLength % fieldSize == 0 ? 0 : 1);
//计算矩阵的长度
//矩阵的宽度
System.out.println("矩阵的行数:" + rowSize + ",矩阵的列数:" + fieldSize);
//创建二维矩阵
final char[][] charArrays = new char[rowSize][fieldSize];
//用原文填充二维矩阵
for (int i = 0; i < inputLength; i++) {
int c_i = i / fieldSize;
int c_j = i % fieldSize;
charArrays[c_i][c_j] = inputChars[i];
}
StringBuffer sBuilder = new StringBuffer();
for (int i = 0; i < keyLinkArray.length; i++) {
KeyLink keyLink = keyLinkArray[i];
//读出链表next的字符
char[] s;
if (Objects.nonNull(keyLink)) {
int keyOriginIndex = keyLink.originIndex;
s = readVerStr(charArrays, keyOriginIndex);
if (Objects.nonNull(s)) {
sBuilder.append(s);
}
//System.out.println("keyChar:" + keyLink + ",keyLink:" + keyLink + ",i:" + i + ",从二维矩阵的列:" + keyOriginIndex + ",读完了.此时:" + sBuilder);
}
}
return sBuilder.toString();
}
/**
* 解密
*
* @return
*/
public static String decrypt(String inputString) {
final int inputLength = inputString.length();
//生成密钥的链表结构
KeyLink[] keyLinkArrays = getKeyLinkArrays(keyStr);
//矩阵的列宽
final int rSize = keyLinkArrays.length;
//矩阵的行数
final int fSize = (inputLength / rSize) + (inputLength % rSize == 0 ? 0 : 1);
//计算矩阵的长度
//矩阵的宽度
System.out.println("矩阵的宽度:" + fSize + ",矩阵的深度:" + rSize);
//创建二维矩阵
final char[][] charArrays = new char[fSize][rSize];
//将密文按照链表结构中的定义写入二维矩阵中
int startIndex = 0;
for (int i = 0; i < keyLinkArrays.length; i++) {
KeyLink keyLink = keyLinkArrays[i];
if (keyLink != null) {
int keyOriginIndex = keyLink.originIndex;
//确定当前行i对应的数据宽度
int currSum = rSize * (fSize - 1) + (keyOriginIndex + 1);
//表示实际数据列的宽度
int realMatrixWidth = fSize;
if (currSum > inputLength) {
realMatrixWidth = fSize - 1;
}
int stopIndex = startIndex + realMatrixWidth;
String substring = inputString.substring(startIndex, stopIndex);
//System.out.println("keyLink:" + keyLink + ",currSum:" + currSum + ",realMatrixWidth:" + realMatrixWidth + ",substring:" + substring);
writeVerStr(charArrays, keyOriginIndex, substring.toCharArray());
startIndex += substring.length();
}
}
return ver2String(charArrays);
}
/**
* 打印二维矩阵中某一列的内容
*
* @param chars
* @return
*/
public static String ver2String(char[][] chars) {
if (chars.length > 0) {
int lengthRow = chars.length;
int lengthVertical = chars[0].length;
StringBuffer sBuilder = new StringBuffer();
for (int i = 0; i < lengthRow; i++) {
for (int j = 0; j < lengthVertical; j++) {
if (!Character.isISOControl(chars[i][j])) {
char c = chars[i][j];
sBuilder.append(c);
}
}
System.out.println("ver2String i:" + i + ",body:" + new String(chars[i]));
}
return sBuilder.toString();
} else {
return null;
}
}
/**
* 竖读
* 从二维矩阵中竖着读出第i列的所有内容
*
* @param chars
* @param verIndex
* @return
*/
public static char[] readVerStr(char[][] chars, int verIndex) {
if (chars.length > 0) {
int lengthRow = chars.length;
int lengthVertical = chars[0].length;
if (verIndex < lengthVertical) {
StringBuffer sBuilder = new StringBuffer();
for (int i = 0; i < lengthRow; i++) {
char c = chars[i][verIndex];
if (!Character.isISOControl(c)) {
sBuilder.append(c);
}
}
return sBuilder.toString().toCharArray();
} else {
return null;
}
} else {
return null;
}
}
/**
* 将char数组,写入二维char矩阵中,竖写
*
* @param chars
* @param verIndex
* @param cs
*/
public static void writeVerStr(char[][] chars, int verIndex, char[] cs) {
int lengthRow = chars.length;
int lengthVertical = chars[0].length;
for (int i = 0; i < lengthRow; i++) {
if (cs.length > i && !Character.isISOControl(cs[i])) {
char c = cs[i];
chars[i][verIndex] = c;
}
}
}
/**
* 根据密钥字符生成密钥对象数组
*
* @param token
* @return
*/
public static KeyLink[] getKeyLinkArrays(final String token) {
final char[] keyChars = token.toCharArray();
final int keyLength = keyChars.length;
char[] sortedKeyChars = Arrays.copyOf(keyChars, keyChars.length);
System.out.println("密钥排序前:" + Arrays.toString(sortedKeyChars));
Arrays.sort(sortedKeyChars);
System.out.println("密钥排序后:" + Arrays.toString(sortedKeyChars));
KeyLink[] keyLinkArray = new KeyLink[keyLength];
for (int i = 0; i < keyChars.length; i++) {
//将char按照
char keyChar = keyChars[i];
KeyLink keyLink = new KeyLink(keyChar, i, -1);
keyLinkArray[i] = keyLink;
}
for (int i = 0; i < sortedKeyChars.length; i++) {
//根据排序的密文arrys返回的下标,查找KeyLink
KeyLink[] foundKeyLink = getKeyLinkByCharName(keyLinkArray, sortedKeyChars[i]);
//System.out.println("从[i]:" + i + ",sortedKeyChars[i]:" + sortedKeyChars[i] + ",找到:" + Arrays.toString(foundKeyLink));
if (foundKeyLink != null) {
for (int j = 0; j < foundKeyLink.length; j++) {
if (foundKeyLink[j] != null) {
if (foundKeyLink[j].sortedIndex >= 0) {
//如果已使用,从下一个密文的索引开始再查
continue;
} else {
//未使用
foundKeyLink[j].sortedIndex = i;
break;
}
}
}
}
}
for (int i = 0; i < keyLinkArray.length; i++) {
System.out.println("getKeyLinkArrays i:" + i + ",keyLinkArray:" + keyLinkArray[i]);
}
return keyLinkArray;
}
/**
* 根据字符查询相关的密钥对象
*
* @param keyLinkArray
* @param charName
* @return
*/
public static KeyLink[] getKeyLinkByCharName(final KeyLink[] keyLinkArray, final char charName) {
int ct = 0;
for (int j = 0; j < keyLinkArray.length; j++) {
//判断数据组是不是包括了这个字符,且是不是配置了sortedIndex
if (keyLinkArray[j] != null && keyLinkArray[j].charName == charName) {
ct++;
}
}
int start = 0;
KeyLink[] tmp = new KeyLink[ct];
for (int j = 0; j < keyLinkArray.length || start < ct; j++) {
//判断数据组是不是包括了这个字符,且是不是配置了sortedIndex
if (keyLinkArray[j] != null && keyLinkArray[j].charName == charName) {
tmp[start] = keyLinkArray[j];
start++;
}
}
if (ct == 0) {
return null;
} else {
return tmp;
}
}
}
@AllArgsConstructor
@Data
class KeyLink {
char charName;
int originIndex;
int sortedIndex;
//KeyLink next;
@Override
public String toString() {
return "KeyLink{" +
"charName=" + charName +
", originIndex=" + originIndex +
", sortedIndex=" + sortedIndex +
'}';
}
}
总结
这个代码没有考虑矩阵数据对齐问题,需要在加解密时,需要额外进行数据对齐操作,可读性有待提升。
这种加密方式并不适合安全要求很高的场合。
标签:Java,int,Transposition,矩阵,char,length,Cipher,keyLinkArray,chars 来源: https://www.cnblogs.com/panshan-lurenjia/p/16306494.html