2.6加密与解密
密钥:对称式密钥,非对称式迷药
对称式密钥:明文(尚未加密原文)------加密------》密文
这个过程需要一个密钥X去加密
密文-------解密-------》明文
解密过程需要一个密钥X,和加密的是同一个密钥
非对称式密钥:通过某算法产生一对钥匙,选一个作为公钥,另一个为私钥
这个算法一般是质因数分解和素数的一些性质来实现。
数学上保证无法通过暴力破解的方式,通过一把钥匙计算出和它配对的另一把钥匙。
明文《------公钥------》密文《-------私钥------》明文
公钥:大众都知道;私钥:密钥对的产生者才知道。
非对称密钥加密可以用于数字签名
签名以后就无法抵赖了
A加密文件发给B,B用A的公钥解密,那么文件一定是用A的私钥加密的!因为A的私钥只有A自己持有,所以A无法抵赖发过这份文件。
一般把签名和加密合并起来使用。
明文----甲的私钥---》密文1----乙的公钥----》密文2-------乙的公钥解密------》密文1--------甲的私钥解密------》明文
这一过程中如果有第三方窃取文件,无法解密,因为拿不到乙方的私钥,乙方的私钥只有乙方自己才有。
另一种可能,如果第三方想冒充甲方给乙方发送文件,也不可行,第三方没有甲方的私钥,没有办法签名,这样在解密过程中的反签名解密环节就会失败。
非对称算法RSA,Java示例太复杂,不进行
对称密钥算法DES,AES
简单的加密算法,用的最多的就是异或运算
简单的加密与解密应用
简单异或运算
/*简单的加密与解密应用
简单异或运算*/
package secret;
public class SimpleSceret {
public static void main(String[] args) {
int x=10;
x = x^25;
System.out.println(x);
x = x^25;
System.out.println(x);
System.out.println(3^1);
/*
* 异或是一个数学运算符。它应用于逻辑运算。
在【布尔值运算】中:
真异或假的结果是真,假异或真的结果也是真,
真异或真的结果是假,假异或假的结果是假。
就是说两个值不相同,则异或结果为真。反之,为假。
在【二进制值运算】中:不同为1,相同为0,如1001异或1010等于0011。
异或也叫半加运算,其运算法则相当于不带进位的二进制加法:
二进制下用1表示真,0表示假,则异或的运算法则为:
0异或0=0,1异或0=1,0异或1=1,1异或1=0(同为0,异为1),
这些法则与加法是相同的,只是不带进位。
1.与1异或,可以使特定位翻转,
2.与0异或,保留其值
3.交换两值,不使用临时变量。a=a^b;b=b^a;a=a^b;
*/
}
}
19
10
2
可以将明文与密码异或得到密文,
解密时,密文再与密码异或得到明文。
对密文进行异或操作
/*简单的加密与解密应用
对密文进行异或操作*/
package secret;
public class SimpleSceret {
public static void main(String[] args) throws Exception {
String s = "我们abc";
String key = "xyz";
byte[] buf = s.getBytes("utf-8");
byte[] key_buf = key.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"));//显示
}
}
我们abc
较完整的代码
package secret;
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);
}
}
9EF1EB9CC2D6191B
我们ab
AES加密算法
package secret;
import javax.crypto.*;
import javax.crypto.spec.*;
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);
}
}
ra/whIE7ZE3Mc3higdmgmQ==
1中国人abc
一般的加密解密过程都比较喜欢byte而不是串本身,因为串里面的字符的Unicode码是有规则的,随意的运算很可能产生非法的Unicode,转成byte数组以后就没有这个风险了,任意处理不会产生非法数据。
但byte不易于人类阅读
上一个例子是转换为16进制的数
这个是转换为BASE64Encoder的串
解码是用BASE64Decoder转换为byte数组
AES加密算法,加密解密过程
设计程序
一种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
/*
设计程序
一种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
*/
package secret;
public class DesignProgram {
public static void main(String[] args) {
String s = "youandme";//密钥单词
String text = "welcometohangzhou";//待加密字符串
System.out.println("密钥单词:"+s);
char [][]a = creatMatrix(s);
System.out.println("密钥方阵为:");
showMatrix(a);//显示生成的方阵
System.out.println("加密后字符串为:"+getCharToEncrypt(text,a));
System.out.println("解密:"+getCharToEncrypt(getCharToEncrypt(text,a).toString(),a));//再调用一次
}
//加密过程
public static StringBuffer encrypt(char c,char d,char [][]a){
StringBuffer strb0 = new StringBuffer();
int x1 = 0;//取出两个点的横纵坐标
int y1 = 0;
int x2 = 0;
int y2 = 0;
int count = 0;//判断是否有一个字母不在矩阵中
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
if(a[i][j] == c){
x1 = i;//得到第一个字符的横纵坐标
y1 = j;
count++;
}
if(a[i][j] == d){
x2 = i;
y2 = j;
count++;
}
}
}
if(count!=2){//如果一对字母中有一个字母不在正方形中,则不变换,直接放入加密串中
strb0.append(c);
strb0.append(d);
}else{
if(x1==x2||y1==y2){//同一行或同一列,对调这两个字母
strb0.append(a[x2][y2]);
strb0.append(a[x1][y1]);
}else{
strb0.append(a[x1][y2]);//变换位置后的密文坐标
strb0.append(a[x2][y1]);
}
}
return strb0;
}
//3.待加密字符串取字母并加密
public static StringBuffer getCharToEncrypt(String text,char [][]a){
StringBuffer strb = new StringBuffer();//新建一个StringBuffer,存放加密后的字符串
char c = 0;
char d = 0;
for(int i=0;i<text.length();i+=2){
if(i==text.length()-1){//考虑最后一个
c = text.charAt(i);
strb.append(c);//如果最后只剩下一个字母,则不变换,直接放入加密串中
}else{
c = text.charAt(i);
d = text.charAt(i+1);
if(c==d){//如果一对字母中的两个字母相同,则不变换,直接放入加密串中
strb.append(c);
strb.append(d);
}else{
strb.append(encrypt(c, d, a));
}
}
}
return strb;//返回加密后的字符串StringBuffer
}
//2.显示方阵
public static void showMatrix(char [][]a){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
System.out.print(a[i][j]+" ");
}
System.out.println();
}
}
//1.生成方阵
public static char [][] creatMatrix(String s){
int start = 'a';
char [][]a = new char[5][5];
for(int i=0;i<5;i++){//行循环
for(int j=0;j<5;j++){//列循环
if(i*5+j < s.length()){
a[i][j] = s.charAt(i*5+j);//将密钥单词填入
}else{
while(true){
if(s.contains(String.valueOf((char)(start)))){//检查是否包含字母
start++;//跳到下一个字母
}else{
break;//如果不包含,跳出循环
}
}
a[i][j] = (char) start;//把字母填入矩阵
start++;//下一个字母
}
}
}
return a;
}
}
密钥单词: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
加密后字符串为:vbrmmomvugnagzguu
解密:welcometohangzhou