编程算法基础-2.6加密与解密

16 篇文章 0 订阅

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


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值