加密技术
最近由于工作需要,转而去研究加密与解密的东西,这个密码学的东西还是比较复杂的,还需要补一下数学知识。我会持续分享这方面的内容,由于初步涉及有可能总结的东西会有错误或逻辑漏洞,如果发生请及时告知和一起讨论。需要说明的是,这些都是学习笔记与感悟,和业务方案没有任何关系,并不会涉及泄露,故才会拿出分享。
在之前的加密解密的初涉文章中,我们讲到了加密算法的分类:对称加密,非对称加密,Hash算法。那么什么是传统加密技术呢?我们需要记住:对称加密也称传统加密或单钥加密,所以传统加密技术就是对称加密技术。下面开始介绍对称加密技术:
一些概念术语
明文:原始可理解的消息或数据,是算法的输入。
加密算法:加密算法对明文进行各种代替和变换。
密钥:密钥也是加密算法的输入。密钥独立于明文和算法。算法根据所用的特定密钥而产生不同的输出。算法所用的确切代替和变换也依靠密钥。
密文:作为算法的输出,看起来完全随机而杂乱的消息,依赖于明文和密钥。对于给定的消息,不同的密钥产生不同的密文,密文看上去是随机的数据流,并且其意义是不可理解的。
解密算法:本质上是加密算法的逆运算。输入密文和密钥,输出原始明文。
加密:从明文到密文的变换过程称为加密。
解密:从密文到明文的变换过程称为解密。
密码编码学:研究各种加密方案的领域称为密码编码学。这样的加密方案称为密码体制或密码。
密码分析学:不知道任何加密细节的条件下解密消息的技术属于密码分析学的范畴。密码分析学即外行所说的“破译”。
密码学:密码编码学和密码分析学统称为密码学。
传统密码的安全使用要满足两个要求:(1)加密算法必须足够强的(2)发送者和接收者必须在某种安全的形式下获得密钥并且必须保证密钥安全。
密码编码学系统具有以下3个独立的特征:
1.转换明文为密文的运算类型:所有的加密算法都基于两个原理:代替和置换。代替是将明文中的每个元素映射成另一个元素,置换是将明文中的元素重新排列。上述运算的基本要求是不允许有信息丢失(即所有的运算是可逆的)。大多数密码体制,也称为乘积密码系统,都使用了多层代替和置换。
2.所用的密钥数:如果发送方和接收方使用相同的密钥,这种密码称为对称密码,单密钥密码,秘密钥密码或传统密码。如果发收双方使用不同的密钥,这种密码就称为非对称密码,双钥或公钥密码。
3.处理明文的方法:分组密码每次处理输入的一组元素,相应地输出一组元素。流密码则是连续地处理输入元素,每次输出一个元素。
密码分析学和穷举攻击
攻击密码系统的典型目标是恢复使用的密钥而不是仅仅恢复出单个密文对应的明文。攻击传统的密码体制有两种通用的方法:
密码分析学:密码分析学攻击依赖算法的性质、明文的一般特征或某些明密文对。这种形式的攻击企图利用算法的特征来推导出特定的明文或使用的密钥。
穷举攻击:攻击者对一条密文尝试所有可能的密钥直到把它转化为可读的有意义的明文。平均而言,获得成功至少需要尝试所有可能密钥的一半。
基于密码分析者知道信息的多少,可以分为以下几种密码攻击类型:(1)唯密文攻击(2)已知明文攻击(3)选择明文攻击(4)选择密文攻击(5)选择文本攻击。
具体如下表:
古典加密方法
在介绍古典加密方法之前,我们先记住一句很重要的话:所有加密技术都要用到的两个基本模块:代替和置换。
代替技术是将明文字母替换成其他字母、数字或符号的方法。如果把明文看成是二进制序列的话,那么代替就是用密文位串来代替明文位串。
Caesar密码
Caesar翻译成中文为凯撒,这个密码非常简单,就是对字母表中的每个字母,用它之后的第3个字母来代替。比如如下示例:
明文:abcdefg
密文:DEFGHIJ
其代码实现的Java版本如下:
package com.general.encryanddecode;
import java.util.Random;
/**
* Caesar密码算法:简单的替代技术方案
* @author GeneralAndroid
*/
public class CaesarTest {
private int key;
private char[] p_table={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
'T','U','V','W','X','Y','Z'};
private char[] pContent;
private char[] cContent;
public CaesarTest(int key ,String pContent){
this.key=key;
this.pContent=pContent.toCharArray();
System.out.println("密钥:"+key+"\n明文:"+pContent);
}
public static void main(String[] args){
Random random=new Random();
CaesarTest caesarTest=new CaesarTest(random.nextInt(25),"GENERALANDROID");
caesarTest.encrypt();
caesarTest.decrypt();
}
public void encrypt(){
cContent=new char[pContent.length];
for(int i=0;i<pContent.length;i++){
cContent[i]=p_table[((int)pContent[i]+key)%26];
}
System.out.println("密文:"+new String(cContent));
}
public void decrypt(){
for(int i=0;i<cContent.length;i++){
pContent[i]=p_table[((int)cContent[i]-key)%26];
}
System.out.println("解密:"+new String(pContent));
}
}
/**
密钥:24
明文:GENERALANDROID
密文:RPYPCLWLYOCZTO
解密:GENERALANDROID
**/
单表代替密码
凡是采用简单重新排列明文字母表来作为密码表且每个相同的明文字母总是被同一个密文字母所替换的被称作单表替换密码。代码实现如下所示:
package com.general.encryanddecode;
import java.util.ArrayList;
/****
* 单表代替技术,依然比较容易攻破。
*/
public class SingleTableTest {
private char[] single_table={'G','F','E','D','C','B','A','H','I','J','K','N','M','L','P','Q','O','S','T','R','Z','X','U','Y','W','V'};
private char[] single_table_one={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
'T','U','V','W','X','Y','Z'};
private ArrayList<Character> a_single_table;
private ArrayList<Character> a_single_table_one;
private char[] pContent;
private char[] cContent;
public SingleTableTest(String content){
pContent=content.toCharArray();
System.out.println("原文:"+new String (pContent));
initTable();
}
private void initTable(){
a_single_table=new ArrayList<>(26);
a_single_table_one=new ArrayList<>(26);
a_single_table.add('G');
a_single_table.add('F');
a_single_table.add('E');
a_single_table.add('D');
a_single_table.add('C');
a_single_table.add('B');
a_single_table.add('A');
a_single_table.add('H');
a_single_table.add('I');
a_single_table.add('J');
a_single_table.add('K');
a_single_table.add('N');
a_single_table.add('M');
a_single_table.add('L');
a_single_table.add('P');
a_single_table.add('Q');
a_single_table.add('O');
a_single_table.add('S');
a_single_table.add('T');
a_single_table.add('R');
a_single_table.add('Z');
a_single_table.add('X');
a_single_table.add('U');
a_single_table.add('Y');
a_single_table.add('W');
a_single_table.add('V');
//--------------------------
a_single_table_one.add('A');
a_single_table_one.add('B');
a_single_table_one.add('C');
a_single_table_one.add('D');
a_single_table_one.add('E');
a_single_table_one.add('F');
a_single_table_one.add('G');
a_single_table_one.add('H');
a_single_table_one.add('I');
a_single_table_one.add('J');
a_single_table_one.add('K');
a_single_table_one.add('L');
a_single_table_one.add('M');
a_single_table_one.add('N');
a_single_table_one.add('O');
a_single_table_one.add('P');
a_single_table_one.add('Q');
a_single_table_one.add('R');
a_single_table_one.add('S');
a_single_table_one.add('T');
a_single_table_one.add('U');
a_single_table_one.add('V');
a_single_table_one.add('W');
a_single_table_one.add('X');
a_single_table_one.add('Y');
a_single_table_one.add('Z');
}
public void encrypt(){
cContent=new char[pContent.length];
for (int i=0;i<pContent.length;i++){
cContent[i]=single_table[a_single_table_one.indexOf(pContent[i])];
}
System.out.println("密文:"+new String (cContent));
}
public void decrypt(){
for(int i=0;i<cContent.length;i++){
pContent[i]=single_table_one[a_single_table.indexOf(cContent[i])];
}
System.out.println("明文:"+new String (pContent));
}
public static void main(String[] args){
SingleTableTest singleTableTest=new SingleTableTest("GENERALANDROIDGEAKAAZEN");
singleTableTest.encrypt();
singleTableTest.decrypt();
}
}
/***
*
原文:GENERALANDROIDGEAKAAZEN
密文:ACLCSGNGLDSPIDACGKGGVCL
明文:GENERALANDROIDGEAKAAZEN
*/
Playfair密码
最著名的多字母代替密码是Playfair密码,它把明文中的双字母音节作为一个单元并将其转换成密文的“双字母音节”。Playfair算法基于一个由密钥词构成的5*5字母矩阵。填充矩阵的方法是:首先将密钥词(去掉重复字母)从左到右,从上至下填在矩阵格子中,再将剩余的字母按字母表的顺序从左至右、从上至下填在矩阵剩下的格子里。字母I和J暂且当做一个字母。对明文按如下规则一次加密两个字母:
(1)如果该字母对的两个字母是相同的,那么在它们之间加一个填充字母,比如x。例如先把ballon变成ba lx lo on这样的4个字母对。
(2)落在矩阵同一行的明文字母对中的字母,由其右边的字母来代替,每行中最右边的一个字母就用该列中最左边的第一个字母来代替。
(3)落在矩阵同一列的明文字母对中的字母,由其下面的字母来代替,每行中最下面的一个字母就用该列中最上面的第一个字母来代替。
(4)其他的每组明文字母对中的字母按如下方式代替:该字母所在行为密文所在行,另一字母所在列为密文所在列。
举个例子如下:
密钥词
GEAKAAZENAAAAAAAAAAAAAAAAAAEEEEEEEEEEEEEEEEEENNNNNNNNNNNNNNNNNNNNNNNNNNNNNGGGGGGGGGGG
构建的字母矩阵:
G E A K Z
N B C D F
H I L M O
P Q R S T
U V W X Y
这里J不进行代替操作。具体代码实现如下:
package com.general.encryanddecode;
import java.util.ArrayList;
/***
* Playfair 多字母代替密码
*
*
* 最著名的多字母代替密码是Playfair密码,它把明文中的双字母音节作为一个单元并将其转换成密文的“双字母音节”。
* Playfair算法基于一个由密钥词构成的5*5字母矩阵。填充矩阵的方法是:首先将密钥词(去掉重复字母)从左到右,
* 从上至下填在矩阵格子中,再将剩余的字母按字母表的顺序从左至右、从上至下填在矩阵剩下的格子里。字母I和J暂且当做一个字母。
* 对明文按如下规则一次加密两个字母:
* (1)如果该字母对的两个字母是相同的,那么在它们之间加一个填充字母,比如x。例如先把ballon变成ba lx lo on这样的4个字母对。
* (2)落在矩阵同一行的明文字母对中的字母,由其右边的字母来代替,每行中最右边的一个字母就用该列中最左边的第一个字母来代替。
* (3)落在矩阵同一列的明文字母对中的字母,由其下面的字母来代替,每行中最下面的一个字母就用该列中最上面的第一个字母来代替。
* (4)其他的每组明文字母对中的字母按如下方式代替:该字母所在行为密文所在行,另一字母所在列为密文所在列。
*
*也就是说Playfair密码,首先需要构建矩阵,然后再按照规则进行加密
*
* @author generalandroid
*/
public class PlayfairTest {
/**密钥词**/
private String key;
private char[][] matrix=new char[5][5];
private int p_length;
private String pContent;
private char[] cContent;
private String table="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private ArrayList<String> p_array=new ArrayList<>();
private ArrayList<String> c_array=new ArrayList<>();
public PlayfairTest(String key,String content){
this.key=key;
pContent=content;
p_length=content.length();
System.out.println("密钥词:"+key+"\n原文:"+content);
initMatrix();
dealPContent();
}
public String getKey(){return key;}
/**构建矩阵**/
public void initMatrix(){
char[] c=initDealKey(key.toCharArray()).toCharArray();
for(char t_c:c){
if(table.indexOf(t_c)>=0){
table=table.replace(t_c,' ');
}
}
table=table.replaceAll(" ","");
// System.out.println("table remove key:"+table+"\n table lennth:"+table.length());
String s_matrix=(initDealKey(key.toCharArray())+table).replace("J","");//也就是说J不进行替换,这个不替换字母最好选用使用频率低的字母
// System.out.println("s_matrix length:"+s_matrix.length()+"\n s_matrix:"+s_matrix);
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
matrix[i][j]=s_matrix.charAt(i*5+j);
}
}
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
System.out.print(matrix[i][j]+"\t");
}
System.out.println();
}
}
/**去除重复密钥词**/
public String initDealKey(char[] key){
StringBuilder stringBuilder=new StringBuilder();
for(char c:key){
if(stringBuilder.indexOf(c+"")>=0) continue;
stringBuilder.append(c);
}
return stringBuilder.toString();
}
/**整理明文,不考虑字母分组中重复的情况**/
public ArrayList<String> dealPContent(){
int i=0;
boolean isRedeal=false;
for(;i<pContent.length()&&i+2<pContent.length();i=i+2){
String monogram=pContent.substring(i,i+2);
if(monogram.charAt(0)==monogram.charAt(1)) {
pContent=pContent.substring(0,i+1)+"Z"+pContent.substring(i+1,pContent.length());
isRedeal=true;
break;
}
p_array.add(monogram);
}
// System.out.println("p:"+p);
if (isRedeal){
p_array.clear();
dealPContent();
}
if(p_array.size()<pContent.length()/2){
p_array.add(pContent.substring(pContent.length()-2,pContent.length()));
}
// System.out.println("p length :"+p.length());
if(pContent.length()%2!=0) {
pContent = pContent + "Z";
p_array.clear();
dealPContent();
}
// System.out.println(p_array.toString());
return p_array;
}
/**加密字母对**/
public String encryptCovert(String p)
{
StringBuilder c=new StringBuilder();
char[] cp=p.toCharArray();
int x1=-1,y1=-1;
int x2=-1,y2=-1;
for(int i=0;i<5;i++){
for (int j=0;j<5;j++){
if(matrix[i][j]==cp[0]){
x1=i;
y1=j;
}
if (matrix[i][j]==cp[1]){
x2=i;
y2=j;
}
}
}
if(x1==x2){
if(y1==4){
c.append(matrix[x1][0]);
} else{
c.append(matrix[x1][y1+1]);
}
if(y2==4){
c.append(matrix[x2][0]);
}else{
c.append(matrix[x2][++y2]);
}
}else if(y1==y2){
if(x1==4){
c.append(matrix[0][y1]);
}else{
c.append(matrix[++x1][y1]);
}
if(x2==4){
c.append(matrix[0][y2]);
}else{
c.append(matrix[++x2][y2]) ;
}
} else{
c.append(matrix[x1][y2]);
c.append(matrix[x2][y1]);
}
return c.toString();
}
public void encrypt(){
if(p_array.size()<=0){
System.out.println("no p content");
return;
}
for (String c:p_array){
c_array.add(encryptCovert(c)) ;
}
StringBuilder s=new StringBuilder();
for(String c:c_array){
s.append(c);
}
System.out.println("密文:"+ s.toString());
}
public String decryptConvert(String c){
StringBuilder p=new StringBuilder();
char[] cp=c.toCharArray();
int x1=-1,y1=-1;
int x2=-1,y2=-1;
for(int i=0;i<5;i++){
for (int j=0;j<5;j++){
if(matrix[i][j]==cp[0]){
x1=i;
y1=j;
}
if (matrix[i][j]==cp[1]){
x2=i;
y2=j;
}
}
}
if(x1==x2){
if(y1==0){
p.append(matrix[x1][4]);
} else{
p.append(matrix[x1][y1-1]);
}
if(y2==0){
p.append(matrix[x2][4]);
}else{
p.append(matrix[x2][--y2]);
}
}else if(y1==y2){
if(x1==0){
p.append(matrix[4][y1]);
}else{
p.append(matrix[--x1][y1]);
}
if(x2==0){
p.append(matrix[4][y2]);
}else{
p.append(matrix[--x2][y2]) ;
}
} else{
p.append(matrix[x1][y2]);
p.append(matrix[x2][y1]);
}
return p.toString();
}
public void decrypt(){
if(c_array.size()<=0){
System.out.println("no c content");
return;
}
ArrayList<String> tmp=new ArrayList<>();
for(String c: c_array){
tmp.add(decryptConvert(c));
}
// System.out.println("tmp:"+tmp.toString());
for(int i=0;i<tmp.size();i++){
String c1=tmp.get(i);
String c2=null;
if((i+1)<tmp.size()){
c2=tmp.get(i+1);
}
if(c2!=null&&c1.charAt(0)==c2.charAt(0)&&c1.charAt(1)=='Z'){
c1=c1.replace('Z',' ');
tmp.set(i,c1);
}
}
StringBuilder stringBuilder=new StringBuilder();
for(String c:tmp){
stringBuilder.append(c);
}
String p=stringBuilder.toString();
p=p.replaceAll(" ","");
System.out.println("明文: "+p.substring(0,p_length));
}
public static void main(String[] args){
}
}
/**
*
密钥词:GEAKAAZENAAAAAAAAAAAAAAAAAAEEEEEEEEEEEEEEEEEENNNNNNNNNNNNNNNNNNNNNNNNNNNNNGGGGGGGGGGG
原文:GENERALANDROIDAABBBZENNCCADEFF
G E A K Z
N B C D F
H I L M O
P Q R S T
U V W X Y
密文:EABGWCRCBFTLMBKGECFEFEGBBDLCBKNN
明文: GENERALANDROIDAABBBZENNCCADEFF
*
*
*
*
* **/
要说的内容就这么多,如果文中有不对的地方,麻烦指出,如果喜欢我的文章,可以动动手指关注一下,赞一下,我会有更大的动力写出更多的文章,转载请注明出处:http://blog.csdn.net/android_jiangjun/article/details/78902150
参考资料:《密码编码学与网络安全》第六版
相关阅读
作为传统的To B软件企业,转型升级要从多方面入手。不仅要从商业模式上创新,还要把云、大数据等最新技术真正应用到产品中来,更要找到
社交金融是什么?社交金融是基于朋友圈关系的金融互助行为,兼具人际交往与资金融通的双重功能。社交金融具有去媒的特性,投融资都不需
想靠一个漂亮的外观来吸引参观者,是远远不够的。但国内的博物馆似乎多喜欢以夸张彪悍的造型来彰显卓尔不群,对于馆类内容的发掘和增
广告在变,传播生态也在变。广告不再是企业主的专利,广告会成为销售服务型企业的专利。未来,谁掌握了消费者,谁掌握了社群,谁就将成为商
今天的主题是传统企业怎么说人话,那传统企业家为什么不说人话呢?因为那一代人在成长的过程中,经历过物质匮乏的年代,整个年代的主题就