热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java列移位(ColumnarTranspositionCipher)算法实现版本一

这是几年前写的旧文,此前发布Wordpress小站上,现在又重新整理。算是温故知新,后续会继续整理。如有错误望及时指出,在此感谢。场景描述从数据安全角度而言,有些数据不希望在传输或

这是几年前写的旧文,此前发布Wordpress小站上,现在又重新整理。算是温故知新,后续会继续整理。如有错误望及时指出,在此感谢。



场景描述

从数据安全角度而言,有些数据不希望在传输或序列化过程中明文化。在对安全要求不高的场合,可以考虑列移位算法来实现。


算法说明

http://www.practicalcryptography.com/ciphers/columnar-transposition-cipher/

算法的实现过程有很多种,我选了比较简单的一种。


加密算法描述



  1. 准备一个密钥,长度不限,密文字符可以重复;

  2. 根据密钥长度生成二维矩阵,根据密钥的长度算出二维矩阵的行数和列数;

  3. 根据密钥字符ASCII顺序按列读取字符得到加密字符串;

  4. 假设密钥为german,则二维矩阵的列数为6,列的ASCII码顺序为[2,1,5,3,0,4];

  5. 明文是密钥长度的整数倍,不足整数倍部分用特定字符填充(可选,本文中未这样实现);


加密算法举例

明文:
defend*the*east*wall*of*the*castle
密文:
d*altsetslhtfht*elee*o*en*wfcdea*a























































































密钥german
密钥顺序012345
字符顺序215304
defend
*****the*****e
ast*****wa
ll*****of*****
the*****ca
stle

在生成密文时,按照字符顺序按列读取


n*wfc



etslht


以此类推来生成密文


解密算法描述



  1. 根据密钥长度确定二维矩阵列数;

  2. 根据密钥字符顺序得到解密填充列数据时候的顺序;

  3. 假设密钥为german,则二维矩阵列数为6,矩阵列的读取顺序为[4, 1, 0, 3, 5, 2];

  4. 按照矩阵列读取顺序,将密文依大小按顺序写入二维矩阵中;


解密算法举例

密文:
d*altsetslhtfht*elee*o*en*wfcdea*a
明文:
defend*the*east*wall*of*the*castle

生成明文时,按照密钥顺序写入


n*wfc,写入密钥顺序第四列;



etslht,写入密钥顺序第一列;


以此类推来生成明文


源码实现

依赖MAVEN


org.projectlombok
lombok
1.16.22

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 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 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 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 for (int j = 0; 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 StringBuffer sBuilder = new StringBuffer();
for (int i = 0; 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 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 //将char按照
char keyChar = keyChars[i];
KeyLink keyLink = new KeyLink(keyChar, i, -1);
keyLinkArray[i] = keyLink;
}
for (int i = 0; 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 if (foundKeyLink[j] != null) {
if (foundKeyLink[j].sortedIndex >= 0) {
//如果已使用,从下一个密文的索引开始再查
continue;
} else {
//未使用
foundKeyLink[j].sortedIndex = i;
break;
}
}
}
}
}
for (int i = 0; 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 //判断数据组是不是包括了这个字符,且是不是配置了sortedIndex
if (keyLinkArray[j] != null && keyLinkArray[j].charName == charName) {
ct++;
}
}
int start = 0;
KeyLink[] tmp = new KeyLink[ct];
for (int j = 0; 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学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
author-avatar
fmz4733974
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有