java实现PlayFair密码加解密算法

Playfair密码是最著名的多表代换密码,他把明文中的双字母音节作为一个单元并将其转换成密文的“双字母音节”。

Playfair算法基于一个由密钥词构成的5×5字母矩阵。填充矩阵的方法是:首先将密钥词从左至右、从上至下填在矩阵格子里,再将剩余的字母按字母表的顺序从左至右、从上至下填在矩阵剩下的格子里。英语有26个字母,可以去掉使用频率最少的一个字母,或者可以把i和j当成一个字母看待。

1、先将明文整理成两个一对,如果成对后有两个相同字母是一对,就在两个字母中间插入一个填充字母,然后重新排列。如果最后一个字母是单个的,则在其后面插入一个填充字符。填充字符首先要约定好。

2、然后对明文按下面的规则一次加密两个字母:

1.落在矩阵同一行的明文字母对中的字母由其右边的字母来代换,每行中最右边的字母用该行中最左边的字母来代换。

2.落在矩阵同一列的明文字母对中的字母由其下面的字母来代换,每列最下面的字母用该列最上面的字母代换。

3.如果明文字母对中的两个字母既不在同一行,也不在同一列,则由这两个字母确定的矩形的其他两个角的字母代换,(可以事先约定好横向代换或者纵向代换)。

 

解密时用相同的密钥生成与加密相同的矩阵。然后对密文按下面的规则一次解密两个字母。

1.落在矩阵同一行的密文字母对中的字母由其左边的字母来代换,每行中最左边的字母用该行中最右边的字母来代换。

2.落在矩阵同一列的密文字母对中的字母由其下面的字母来代换,每列最上面的字母用该列最下面的字母代换。

3.如果明文字母对中的两个字母既不在同一行,也不在同一列,则由这两个字母确定的矩形的其他两个角的字母代换,(事先约定好的横向代换或者纵向代换)。

下面给出一个例子,在本例中我们约定用横向代换,将i和j视为同一字符,并且填充字符为x。

明文:you are a goodlistener

密钥:hello world

1.我们将明文字母配对得到:youa re ag ox od li st en er(两个o之间填充了一个字符x)。

2.  生成加密矩阵

3.  然后根据上面的加密规则得到密文:OBXRDHDILYEBAQTNHPHD 

4.  同理,根据密文和密钥,依据上面的解密规则也可得出明文。

下面是用java实现的Playfair加解密算法:

import java.nio.CharBuffer;
/*
 * PlayFair解密与解密
 */
public class PlayFair {
	public static char[] encode(char[] plain, char[] key, char replace){
		// 构造解密矩阵
		char[][] matrix = constructMatrix(key);
		// 为缓冲区分配空间
		CharBuffer xplain = CharBuffer.allocate(plain.length * 2);
		// 重新生成明文
		int len = 0;
		int i = 0;
		for(i = 0; i < plain.length - 1; i++){
			xplain.append(plain[i]);
			if(i != plain.length - 1){
				if(plain[i] == plain[i + 1]){
					xplain.append(replace);
				}else{
					xplain.append(plain[i + 1]);
					i++;
				}
			}else{
				xplain.append(replace);
			}
			len += 2;
		}
		// 剩余最后一个字符
		if(i == plain.length - 1){
			xplain.append(plain[i]);
			xplain.append(replace);
			len += 2;
		}
		char[] xxplain = new char[len];
		xplain.position(0);
		xplain.get(xxplain);
		System.out.println("整理后的明文: " + new String(xxplain));
		char[] cipher = getCipher(xxplain, matrix);
		return cipher;
	}
	/**
	 * 根据密文和密钥解密密文并返回生成的明文
	 * @param cipher
	 * @param key
	 * @return
	 */
	public static char[] decode(char[] cipher, char[] key){
		// 构造解密矩阵
		char[][] matrix = constructMatrix(key);
		char[] plain = getPlain(cipher, matrix);
		return plain;
	}
	/**
	 * 根据密文和解密矩阵返回明文
	 * @param cipher
	 * @param matrix
	 * @return
	 */
	private static char[] getPlain(char[] cipher, char[][] matrix){
		char[] plain = new char[cipher.length];
		int index = 0;
		for(int i = 0; i < cipher.length; i += 2){
			int row1, row2, col1, col2;
			String[] pos1, pos2;
			pos1 = getPosition(matrix, cipher[i]);
			pos2 = getPosition(matrix, cipher[i + 1]);
			if(pos1 == null || pos2 == null){
				throw new RuntimeException("m密文中包含无效字符!!!");
			}
			row1 = Integer.parseInt(pos1[0]);
			col1 = Integer.parseInt(pos1[1]);
			row2  =Integer.parseInt(pos2[0]);
			col2 = Integer.parseInt(pos2[1]);
			if(row1 == row2){
				// 同一行的情况
				if(col1 == 0){
					plain[index++] = matrix[row1][matrix[0].length - 1];
					plain[index++] = matrix[row1][col2 - 1];
				}else if(col2 == 0){
					plain[index++] = matrix[row1][col1 - 1];
					plain[index++] = matrix[row1][matrix[0].length - 1];
				}else{
					plain[index++] = matrix[row1][col1 - 1];
					plain[index++] = matrix[row1][col2 - 1];
				}
			
			}else if(col1 == col2){
				// 同一列的情况
				if(row1 == 0){
					plain[index++] = matrix[matrix.length - 1][col1];
					plain[index++] = matrix[row2 - 1][col1];
				}else if(row2 == 0){
					plain[index++] = matrix[row1 - 1][col1];
					plain[index++] = matrix[matrix.length - 1][col1];
				}else{
					plain[index++] = matrix[row1 - 1][col1];
					plain[index++] = matrix[row2 - 1][col2];
				}
			}else{
				plain[index++] = matrix[row1][col2];
				plain[index++] = matrix[row2][col1];
			}
		}
		return plain;
	}
	/**
	 * 根据明文和加密矩阵得到密文
	 * @param plain
	 * @param matrix
	 * @return
	 */
	private static char[] getCipher(char[] plain, char[][] matrix){
		char[] cipher = new char[plain.length];
		int index = 0;
		for(int i = 0; i < plain.length - 1; i += 2){
			int row1, row2, col1, col2;
			String[] pos1, pos2;
			pos1 = getPosition(matrix, plain[i]);
			pos2 = getPosition(matrix, plain[i + 1]);
			if(pos1 == null || pos2 == null){
				throw new RuntimeException("明文中包含无效字符!!!");
			}
			row1 = Integer.parseInt(pos1[0]);
			col1 = Integer.parseInt(pos1[1]);
			row2  =Integer.parseInt(pos2[0]);
			col2 = Integer.parseInt(pos2[1]);
			if(row1 == row2){
				// 同一行的情况
				if(col1 == matrix[0].length - 1){
					cipher[index++] = matrix[row1][0];
					cipher[index++] = matrix[row1][col2 + 1];
				}else if(col2 == matrix[0].length - 1){
					cipher[index++] = matrix[row1][col1 + 1];
					cipher[index++] = matrix[row1][0];
				}else{
					cipher[index++] = matrix[row1][col1 + 1];
					cipher[index++] = matrix[row1][col2 + 1];
				}
			}else if(col1 == col2){
				//同一列的情况
				if(row1 == matrix.length - 1){
					cipher[index++] = matrix[0][col1];
					cipher[index++] = matrix[row2 + 1][col1];
				}else if(col2 == matrix.length - 1){
					cipher[index++] = matrix[row1 + 1][col1];
					cipher[index++] = matrix[0][col1];
				}else{
					cipher[index++] = matrix[row1 + 1][col1];
					cipher[index++] = matrix[row2 + 1][col2];
				}
			}else{
				cipher[index++] = matrix[row1][col2];
				cipher[index++] = matrix[row2][col1];
			}
		}
		return cipher;
	}
	/**
	 * 返回字符在矩阵中的位置
	 * @param matrix
	 * @param ch
	 * @return
	 */
	private static String[] getPosition(char[][] matrix, char ch){
		String[] pos = new String[]{null, null};
		for(int i = 0; i < matrix.length; i++){
			for(int j = 0; j < matrix[0].length; j++){
				if((matrix[i][j] == ch) || (matrix[i][j] == 'j' && ch == 'i') || (matrix[i][j] == 'i' && ch == 'j')){
					pos[0] = i + "";
					pos[1] = j + "";
					return pos;
				}
			}
		}
		return null;
	}
	/**
	 *用密钥构造矩阵
	 * @param cyber
	 * @param key
	 * @return
	 */
	private static char[][] constructMatrix(char[] key){
		char[][] matrix = new char[5][5];
		CharBuffer buf = CharBuffer.allocate(25);
		buf.append(key[0]);
		// 移除密钥中重复的字符
		for(int i = 1; i < key.length; i++){
			if(!contains(buf.array(), key[i])){
				buf.append(key[i]);
			}
		}
		// 将字母表中剩余的字符加入
		for(int i = 0; i < 26; i++){
			char ch = (char) ('a' + i);
			if(!contains(buf.array(), ch)){
				buf.append(ch);
			}
		}
		int index = 0;
		buf.position(0);
		System.out.println("开始构造矩阵...");
		for(int i = 0; i < matrix.length; i++){
			for(int j = 0; j < matrix[0].length; j++){
				if(index != buf.length()){
					matrix[i][j] = buf.get(index++);
					System.out.print(matrix[i][j] + "\t");
				}
			}
			System.out.println();
		}
		buf.clear();
		return matrix;
	}
	/**
	 * 判断是否包含字符(这里将i和j视为同一个字符)
	 * @param buf
	 * @param c
	 * @return
	 */
	private static boolean contains(char[] buf, char c) {
		for(int i = 0; i < buf.length; i++){
			if(buf[i] == c || (c == 'j' && buf[i] == 'i') || (c == 'i' && buf[i] == 'j'))
				return true;
		}
		return false;
	}
}
public class Test {
	public static void main(String[] args) {
		String plain = "you are a good listener".replaceAll(" ", "");	// 明文,去掉空格
		String key = "hello world".replaceAll(" ", "");					// 密钥,去掉空格
		char replace = 'x';													// 填充字符
		System.out.println("明文: " + plain + " \n密钥: " + key + "\n填充字符: " + replace);
		char[] cipher = PlayFair.encode(plain.toLowerCase().toCharArray(), key.toLowerCase().toCharArray(), replace);
		System.out.println("==========================================");
		System.out.println("密文: " + new String(cipher).toUpperCase());
		char[] plain1 = PlayFair.decode(cipher, key.toLowerCase().toCharArray());	// 输入密文和密钥解密
		System.out.println("解密后的明文:" + new String(plain1));
	}
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值