算法基础——2.6加密与解密

例一:简单加密

public class A
{
	public static void main(String[] args) throws Exception
	{
		String s = "我们abc";
		String key = "xyz";
		
		byte[] key_buf = key.getBytes("utf-8");
		
		//加密
		byte[] buf = s.getBytes("utf-8");
		for(int i=0; i<buf.length; i++){
			buf[i] ^= key_buf[i%key_buf.length]; 
		}
		
		// 解密
		for(int i=0; i<buf.length; i++){
			buf[i] ^= key_buf[i%key_buf.length]; 
		}
		
				
		System.out.println(new String(buf, "utf-8"));
	}
}

例二:完整简单加密

public class Simple
{
	// buf 中的byte每个都转为16进制的串的表述形式
	static String byteToAF(byte[] buf)
	{
		StringBuffer sb = new StringBuffer();
		for(int i=0; i<buf.length; i++){
			sb.append(String.format("%02X",buf[i]));
		}
		return sb.toString();
	}
	
	// 用16进制串形式表达的 byte,转换为byte数组
	static byte[] AFtoByte(String s)
	{
		byte[] out = new byte[s.length()/2];
		
		for(int i=0; i<s.length(); i+=2){
			out[i/2] = (byte)(Character.getNumericValue(s.charAt(i)) * 16
				+ Character.getNumericValue(s.charAt(i+1)));
		} 
		
		return out;
	}
	
	// 加密过程
	static String encrypt(String src, String key)
	{
		if(key.length()<1) return null;
		try{
			byte[] buf_txt = src.getBytes("utf-8");
			byte[] buf_key = key.getBytes("utf-8");
			
			for(int i=0; i<buf_txt.length; i++){
				buf_txt[i] ^= buf_key[i%buf_key.length];
			}
			
			return byteToAF(buf_txt);
			
		}
		catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	// 解密过程
	static String decrypt(String src, String key)
	{
		if(key.length()<1) return null;
		try{
			byte[] buf_txt = AFtoByte(src);
			byte[] buf_key = key.getBytes("utf-8");
			
			for(int i=0; i<buf_txt.length; i++){
				buf_txt[i] ^= buf_key[i%buf_key.length];
			}
			
			return new String(buf_txt,"utf-8");
			
		}
		catch(Exception e){
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static void main(String[] args)
	{
		String s = encrypt("我们ab","xyz");
		System.out.println(s);
			
		String s2 = decrypt(s,"xyz");
		System.out.println(s2);		
	}
}

例三:AES加密

import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


public class AES
{
	
	public static String encrypt(String src, String pwd) 
	{  
		try {
			// 处理密钥
	        byte[] bKey = pwd.getBytes("utf-8");
	        byte[] buf = new byte[16]; // 创建一个空的16位字节数组(默认值为0)
	
	        for (int i = 0; i < bKey.length && i < buf.length; i++) {
	            buf[i] = bKey[i];
	        }
			SecretKeySpec key = new SecretKeySpec(buf, "AES"); 
			
			// 加密
			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
			cipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] out = cipher.doFinal(src.getBytes("utf-8"));
			
			//转为串
			return new BASE64Encoder().encode(out);
		} 
		catch (Exception e) {
			e.printStackTrace();
		}  

		return "";
	}
	
	public static String decrypt(String src, String pwd) 
	{  
		try {
			// 处理密钥
	        byte[] bKey = pwd.getBytes("utf-8");
	        byte[] buf = new byte[16]; // 创建一个空的16位字节数组(默认值为0)
	
	        for (int i = 0; i < bKey.length && i < buf.length; i++) {
	            buf[i] = bKey[i];
	        }
			SecretKeySpec key = new SecretKeySpec(buf, "AES"); 
			
			// 密文还原为byte[]
			buf = new BASE64Decoder().decodeBuffer(src);
			
			// 解密
			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
			cipher.init(Cipher.DECRYPT_MODE, key);
			byte[] out = cipher.doFinal(buf);
			
			// 转为串
			return new String(out,"utf-8");
		} 
		catch (Exception e) {
			e.printStackTrace();
		}  

		return "";
	}
	
	public static void main(String[] args) throws Exception
	{
		String s = "1中国人abc";
		
		String s2 = encrypt(s,"xyz1");
		
		System.out.println(s2);
		
		String s3 = decrypt(s2,"xyz1");
		
		System.out.println(s3);
	}
}

例四:

/*设计程序
一种Playfair密码变种加密方法如下:首先选择一个密钥单词(称为pair)(字母不重复,且都为小写字母),然后与字母表中其他字母一起填入至一个5x5的方阵中,填入方法如下:
1.首先按行填入密钥串。
2.紧接其后,按字母序按行填入不在密钥串中的字母。
3.由于方阵中只有25个位置,最后剩下的那个字母则不需变换。
如果密钥为youandme,则该方阵如下:
y o u a n
d m e b c
f g h i j
k l p q r
s t v w x
在加密一对字母时,如am,在方阵中找到以这两个字母为顶点的矩形(红色字体):
y o u a n
d m e b c
f g h i j
k l p q r
s t v w x
这对字母的加密字母为该矩形的另一对顶点,如本例中为ob。
请设计程序,使用上述方法对输入串进行加密,并输出加密后的串。
另外有如下规定:
1、一对一对取字母,如果最后只剩下一个字母,则不变换,直接放入加密串中;
2、如果一对字母中的两个字母相同,则不变换,直接放入加密串中;
3、如果一对字母中有一个字母不在正方形中,则不变换,直接放入加密串中;
4、如果字母对出现在方阵中的同一行或同一列,如df或hi,则只需简单对调这两个字母,即变换为fd或ih;
5、如果在正方形中能够找到以字母对为顶点的矩形,假如字母对为am,则该矩形的另一对顶点字母中,与a同行的字母应在前面,在上例中应是ob;同样若待变换的字母对为ta,则变换后的字母对应为wo;
6、本程序中输入串均为小写字母,并不含标点、空格或其它字符。
解密方法与加密相同,即对加密后的字符串再加密,将得到原始串。
要求输入形式如下:
从控制台输入两行字符串,第一行为密钥单词(长度小于等于25),第二行为待加密字符串(长度小于等于50),两行字符串末尾都有一个回车换行符,并且两行字符串均为小写字母,不含其它字符。
在标准输出上输出加密后的字符串。
例如,若输入:
youandme
welcometohangzhou
则表示输入的密钥单词为youandme,形成的正方形如上所示;待加密字符串为welcometohangzhou。在正方形中可以找到以第一对字母we为顶点的矩形,对应另一对顶点字母为vb,因此加密后为vb,同理可找到与字母对lc,et,oh,ho对应的顶点字母对。而字母对om位于上述正方形中的同一列,所以直接以颠倒这两个字母来加密,即为mo,字母对an同理。字母对gz中的z不在上述正方形中,因此原样放到加密串中。最后剩一个字母u也原样输出。
因此输出的结果为:
vbrmmomvugnagzguu*/

public class C6 {
	static char [][] key = new char[5][5];//5x5的方阵
	static int [] alp = new int[26];//字母表,表示26个字母是否已经出现,-1表示没有出现过,i>-1表示已经出现,i/5为在方阵的横坐标,i%5为在方阵的纵坐标
	
	//将密匙转化为5x5的方阵
	public static void change(char []ckey) {
		for(int i = 0; i < 26; ++i)//字母表初始化
			alp[i] = -1;
		
		// 按行填入密钥串
		for (int ix = 0; ix < ckey.length; ++ix) {
			key[ix / 5][ix % 5] = ckey[ix];
			switch (ckey[ix]) {// 密钥中出现的字母,置为true
			case 'a':
				alp['a' - 'a'] = ix;
				break;
			case 'b':
				alp['b' - 'a'] = ix;
				break;
			case 'c':
				alp['c' - 'a'] = ix;
				break;
			case 'd':
				alp['d' - 'a'] = ix;
				break;
			case 'e':
				alp['e' - 'a'] = ix;
				break;
			case 'f':
				alp['f' - 'a'] = ix;
				break;
			case 'g':
				alp['g' - 'a'] = ix;
				break;
			case 'h':
				alp['h' - 'a'] = ix;
				break;
			case 'i':
				alp['i' - 'a'] = ix;
				break;
			case 'j':
				alp['j' - 'a'] = ix;
				break;
			case 'k':
				alp['k' - 'a'] = ix;
				break;
			case 'l':
				alp['l' - 'a'] = ix;
				break;
			case 'm':
				alp['m' - 'a'] = ix;
				break;
			case 'n':
				alp['n' - 'a'] = ix;
				break;
			case 'o':
				alp['o' - 'a'] = ix;
				break;
			case 'p':
				alp['p' - 'a'] = ix;
				break;
			case 'q':
				alp['q' - 'a'] = ix;
				break;
			case 'r':
				alp['r' - 'a'] = ix;
				break;
			case 's':
				alp['s' - 'a'] = ix;
				break;
			case 't':
				alp['t' - 'a'] = ix;
				break;
			case 'u':
				alp['u' - 'a'] = ix;
				break;
			case 'v':
				alp['v' - 'a'] = ix;
				break;
			case 'w':
				alp['w' - 'a'] = ix;
				break;
			case 'x':
				alp['x' - 'a'] = ix;
				break;
			case 'y':
				alp['y' - 'a'] = ix;
				break;
			case 'z':
				alp['z' - 'a'] = ix;
				break;
			default:
				break;
			}
		}
		// 紧接其后,按字母序按行填入不在密钥串中的字母
		for (int j = ckey.length, k = 0; j < 25 && k < 26; ++j, ++k) {
			// 不在密钥串中的字母
			if (alp[k] == -1) {
				key[j / 5][j % 5] = (char) (k + 'a');
				alp[k] = j;
			} else {
				j--;
			}
		}

		// 输出转化过 的5*5的矩阵
		for (int i = 0; i < 5; ++i) {
			for (int j = 0; j < 5; ++j) {
				System.out.print(key[i][j] + " ");
			}
			System.out.println();
		}
	}
	
	// 加密过程
	public static String encrypt (String pair, String s){
		// 处理密钥
		char []ckey = pair.toCharArray();//密匙
		change(ckey);//将密匙转化为5x5的方阵
		
		
		char [] c_s = s.toCharArray();
		//从待加密字符串取每对字母加密
		for(int i = 1; i < c_s.length; i += 2){//1
			//2如果一对字母中的两个字母相同,则不变换,直接放入加密串中;3或一对字母中有一个字母不在正方形中 时则不变换,直接放入加密串中
			if(c_s[i-1] == c_s[i] || (alp[c_s[i-1] - 'a'] == -1) || (alp[c_s[i] - 'a'] == -1))
				continue;
			//两个字母都在在正方形中且一对字母中的两个字母不同
			else {
				int row1 = alp[c_s[i-1] - 'a'] / 5;//一对字母中的第一个字母横坐标
				int clum1 = alp[c_s[i-1] - 'a'] % 5;//一对字母中的第一个字母纵坐标
				int row2 = alp[c_s[i] - 'a'] / 5;//一对字母中的第二个字母横坐标
				int clum2 = alp[c_s[i] - 'a'] % 5;//一对字母中的第二个字母纵坐标
				
				if(row1 == row2 || clum1 == clum2){//4如果字母对出现在方阵中的同一行或同一列,如df或hi,则只需简单对调这两个字母
					char temp = c_s[i-1];
					c_s[i-1] = c_s[i];
					c_s[i] = temp;
				}
				//5、如果在正方形中能够找到以字母对为顶点的矩形,假如字母对为am,则该矩形的另一对顶点字母中,与a同行的字母应在前面,
				//在上例中应是ob;同样若待变换的字母对为ta,则变换后的字母对应为wo;
				else{
					c_s[i-1] = key[row1][clum2];
					c_s[i] = key[row2][clum1];
				}
			}
/*			if(c_s.length % 2 == 1 && i == c_s.length ){
				break;
			}*/
		}
	
		String s2 = new String(c_s);//存储加密过的字符串
		return s2;
	}
	
	// 解密过程
	public static String decrypt (String pair, String s){
		// 处理密钥
		char []ckey = pair.toCharArray();//密匙
		change(ckey);//将密匙转化为5x5的方阵
		
		char [] c_s = s.toCharArray();
		//从待加密字符串取每对字母加密
		for(int i = 1; i < c_s.length; i += 2){//1
			//2如果一对字母中的两个字母相同,则不变换,直接放入加密串中;3或一对字母中有一个字母不在正方形中 时则不变换,直接放入加密串中
			if(c_s[i-1] == c_s[i] || (alp[c_s[i-1] - 'a'] == -1) || (alp[c_s[i] - 'a'] == -1))
				continue;
			//两个字母都在在正方形中且一对字母中的两个字母不同
			else {
				int row1 = alp[c_s[i-1] - 'a'] / 5;//一对字母中的第一个字母横坐标
				int clum1 = alp[c_s[i-1] - 'a'] % 5;//一对字母中的第一个字母纵坐标
				int row2 = alp[c_s[i] - 'a'] / 5;//一对字母中的第二个字母横坐标
				int clum2 = alp[c_s[i] - 'a'] % 5;//一对字母中的第二个字母纵坐标
				
				if(row1 == row2 || clum1 == clum2){//4如果字母对出现在方阵中的同一行或同一列,如df或hi,则只需简单对调这两个字母
					char temp = c_s[i-1];
					c_s[i-1] = c_s[i];
					c_s[i] = temp;
				}
				//5、如果在正方形中能够找到以字母对为顶点的矩形,假如字母对为am,则该矩形的另一对顶点字母中,与a同行的字母应在前面,
				//在上例中应是ob;同样若待变换的字母对为ta,则变换后的字母对应为wo;
				else{
					c_s[i-1] = key[row1][clum2];
					c_s[i] = key[row2][clum1];
				}
			}
/*			if(c_s.length % 2 == 1 && i == c_s.length ){
				break;
			}*/
		}
	
		String s2 = new String(c_s);//存储加密过的字符串
		return s2;

	}
	
	public static void main(String[] args) {
		String s;//待加密字符串
		String pair;//密匙
		Scanner scan = new Scanner(System.in);
		System.out.println("请输入两行字符串,第一行为密钥单词(长度小于等于25),第二行为待加密字符串(长度小于等于50):");
		pair = scan.nextLine();
		s = scan.nextLine();
		
		String s2 = encrypt(pair, s);
		String s3 = decrypt (pair, s2);
		System.out.println("加密过的字符串:");
		System.out.println(s2);
		System.out.println("解密过的字符串:");
		System.out.println(s3);
		
	}

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值