TA的每日心情 | 开心 2021-3-12 23:18 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
|
1.凯撒加密(Caesar cipher)简介
凯撒加密(Caesar cipher)是一种简单的消息编码方式:它根据字母表将消息中的每个字母移动常量位k。举个例子
如果k等于3,则在编码后的消息中,每个字母都会向前移动3位:a会被替换为d;b会被替换成f;依此类推。字母表末尾将回卷到字母表开头。于是,w会被替换为z, x会被替换为a。 在解码消息的时候,每个字母会反方向移动同样的位数。因此,如果k等于3,下面这条编码后的消息:
vlpsolflwb iroorzv frpsohalwb
会被解码成:
simplicity follows complexity
朱丽叶斯.凯撒在他的一些机密政府通信中真正用到了这种加密。遗憾的是,凯撒加密相当容易被破解。字母的移动只有26种可能;要破解密码,只需尝试各种密钥值, 直到有一种可行即可。 使用重复密钥(repeating key)可以对这种编码技术做出改进,这时不再将每个字母移动常位数,而是利用一列密钥值将各个字母移动不同的位数。如果消息长于这列密钥
值,可以从头再次使用这列密钥。例如,假设密钥值为:
3 1 7 4 2 5
则第1个字母会移动3位,第2个字母会移动1位,依此类推,将第6个字母移动5位之后,我们会从头再次使用这列密钥。于是第7个字母会移动3位,第8个字母会移动1位。反之解码的过程类似。
2.代码实现
我们都知道队列的特点是FIFO(先进先出),将密钥存储在队列 中,使用了一个密钥后,将这个密钥添加到队尾,这样较长的信息可以重复使用该密钥。
队列的java代码实现如下:
/**
* 链表队列的实现
*/
public class LinkedQueue {
private LinearNode front;
private LinearNode rear;
private int size;
/**
* 入队操作
* @param node
*/
public void enqueue(LinearNode node) {
if(0 == size) {
front = rear = node;
} else {
rear.setNext(node);
rear = node;
}
size++;
}
/**
* 出队操作
* @return
*/
public LinearNode dequeue() {
if(!isEmpty()) {
LinearNode l = front;
//when the size is 1
if(front == rear)
front = rear = null;
else
front = l.getNext();
size--;
return l;
} else {
front = rear = null;
return null;
}
}
/**
* 获得队列大小
* @return
*/
public int size() {
return size;
}
/**
* 判断队列是否为空
* @return
*/
public boolean isEmpty() {
if(0 < size)
return false;
else
return true;
}
/**
* 显示队列数据
*
*/
public void listNodes() {
while(!isEmpty()) {
System.out.println(dequeue().getElement());
}
}
public LinearNode getFront() {
return front;
}
public void setFront(LinearNode front) {
this.front = front;
}
public LinearNode getRear() {
return rear;
}
public void setRear(LinearNode rear) {
this.rear = rear;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
front指针指向队列的第一个元素,也就是即将出队的元素;rear指针指向队尾元素,也就是刚入队的元素。如果队列为空则入队时front和rear都指向刚入队的
元素;如果最后一个元素出队,队列为空,front和rear都为null。
凯撒加密代码如下:
/**
* 凯撒加密
*/
public class KasarEncryption {
private LinkedQueue encKeyQueue = new LinkedQueue();
private LinkedQueue decKeyQueue = new LinkedQueue();
public KasarEncryption(int key[]) {
genKey(key);
}
/**
* 处理密钥
* @param key
*/
private void genKey(int[] key) {
for(int i = 0 ; i < key.length ; i++) {
encKeyQueue.enqueue(new LinearNode<Integer>(new Integer(key)));
decKeyQueue.enqueue(new LinearNode<Integer>(new Integer(key)));
}
}
/**
* 加密
* @param plainText
* @return
*/
public String encrypt(String plainText) {
char chars[] = plainText.toCharArray();
for(int i = 0 ; i < chars.length ; i++) {
LinearNode<Integer> l = encKeyQueue.dequeue();
int movement = l.getElement().intValue();
chars += movement;
encKeyQueue.enqueue(l);
}
return new String(chars);
}
/**
* 解密
* @param encryptedText
* @return
*/
public String decrypt(String encryptedText) {
char chars[] = encryptedText.toCharArray();
for(int i = 0 ; i < chars.length ; i++) {
LinearNode<Integer> l = decKeyQueue.dequeue();
int movement = l.getElement().intValue();
chars -= movement;
decKeyQueue.enqueue(l);
}
return new String(chars);
}
public static void main(String args[]) throws InterruptedException {
String plainText = "my name is bilei";
int key[] = {3,5,4,1};
KasarEncryption ke = new KasarEncryption(key);
if(args.length > 0) {
plainText = "";
for(int i = 0 ; i < args.length ; i++) {
if(i == args.length-1)
plainText += args;
else
plainText += args+" ";
}
}
System.out.println("明文 "+plainText);
System.out.println("加密........");
String encryptedText = ke.encrypt(plainText);
System.out.println("密文 "+encryptedText);
Thread.sleep(3000);
System.out.println("解密........");
System.out.println("明文 "+ke.decrypt(encryptedText));
}
}
我们要用到两个队列,一个为加密队列,另一个为解密队列,这两个队列存放相同的密钥,消息格式存储为String类型,在加密解密操作时,将其转换为char数组
分别对数组中每一元素进行加密。
代码测试:
明文 darkdiable is jason;jason is darkdiable
加密........
密文 gfvlgnecoj$jv%nbvtr<mfwpq%mt#iesnimbeqi
解密........
明文 darkdiable is jason;jason is darkdiable
因为JAVA虚拟机中的编码方式采用unicode,char类型为2字节,所以对于中文编码也能很好支持,测试如下:
明文 凯撒加密测试
加密........
密文 ���寇济诚
解密........
明文 凯撒加密测试
源码下载:http://file.javaxxz.com/2014/11/3/000105937.zip |
|