目录
一 古代密码学
1.替换法
2.移位法
3.古典密码学的破解方式
二 近代密码学
三 现代密码学
1.散列函数(哈希函数)
2.对称加密
3.非对称加密
四 如何设置密码才安全
1.密码不要太常见
2.各个应用软件里面的密码不要设置一样
3.在设置密码的时候,可以加一些特殊的标记
实例一 字符串对应的ASCII编码
五 凯撒加密
六 频率分析法
七 Byte和bit的关系
八 现代加密方式
九 使用DES加密和解密
十 base64
十一 toString()和new String()的原理
十二 AES加密和解密
十三 加密模式和填充模式
14. 消息摘要算法
15.非对称加密
16.公钥和私钥生成规则
17.私钥加密
古代就已经开始使用密码,目的:就是希望保护信息
就是使用固定的信息,将原文替换为密文。
例如:bee,将b替换成w,将e替换成p,最后替换为wpp。
替换法的加密方式:
①,单表替换。
单表替换指的是原文和密文使用同一张表,
②,多表替换。
多表替换指的是,有很多张表,原文和密文进行对比。
列如:表一:abcde-swtrp,表二:abcde-chfhk,表三:abcde-jftou
原文:bee
密钥:312
密文:fpk
移位法,是按照字母,在字母表上面的位置,进行移动。
凯撒加密:
例如:abcde往后面移动2位cdefg
频率分析法:在密码学中,频率分析是指研究字母或者字母组合在文本中出现的频率。
二战时出现了恩尼格玛密码机,是一种用于加密与解密文件的密码机。核心使用的是替换法和移位法。被人工智能之父图灵破解
常见的加密方式,MD5,SHA-1, SHA-256
对称加密方式和解密方式使用的是同一把密钥
对称加密分为:序列密码(流加密),分组密码(块加密)两种,流密码是对信息流中的每一个元素(一个字母或一个比特)作为基本处理单元进行加密,块加密是对信息流分块,再对每一块分别加密。
例如原文为1234567890,流加密即先对1进行加密,再对2进行加密,再对3进行加密。。。。最后拼接成密文。
块加密先分成不同的块,如1234块,5678块,90XX(XX为补位数字)成块,再分别对不同块进行加密,最后拼接成密文。前文提到的古典密码学加密方法,都属于流加密。
非对称加密有两把密钥,使用公钥加密,使用私钥解密。或者使用私钥加密,使用公钥解密。
例如:123456
如果设置一样,可能面临撞库
例如,注册京东,可以标记jd,注册支付宝,标记zfb。
环境IDEA,JDK1.8,
commons-io
commons-io
2.6
public class assicllDemo {
public static void main(String[] args){
char a='A';
int b=a;
System.out.println(b);
String c="AaZ";
char[] chars=c.toCharArray();
for(char achar:chars){
int asciicode=achar;
System.out.println(asciicode);
}
}
}
实例二 凯撒加密和解密
public class kaisaDemo {
public static void main(String[] args) {
//定义原文
String input = "Hello World";
int key=3;
//将字符串转换成字节数组
char[] chars=input.toCharArray();
StringBuilder sb=new StringBuilder();
for (char aChar : chars) {
int b=aChar;
//往右边移动三位
b=b+key;
char newb=(char)b;
sb.append(newb);
}
System.out.println(sb.toString());
}
}
public class kaisaDemo {
public static void main(String[] args) {
//定义原文
String input = "Hello World";
int key=3;
//加密
String s=kaisajiami(input, key);
System.out.println("加密:"+s);
//解密
String s1=kaisajiemi(s,key);
System.out.println("解密:"+s1);
}
private static String kaisajiemi(String s, int key) {
char[] chars=s.toCharArray();
StringBuilder sb=new StringBuilder();
for (char aChar : chars) {
int b=aChar;
b-=key;
char newb=(char)b;
sb.append(newb);
}
return sb.toString();
}
private static String kaisajiami(String input, int key) {
char[] chars=input.toCharArray();
StringBuilder sb=new StringBuilder();
for (char aChar : chars) {
int b=aChar;
//往右边移动三位
b=b+key;
char newb=(char)b;
sb.append(newb);
}
return sb.toString();
}
}
原理:是把26个字母,进行位移,往左边或者右边进行位移,在位移的时候,需要注意,最多只能移动25位
目的:在不知道密钥的情况下,也想进行破解密文
原理:比如以英文为例:字母e是出现频率最高的,第二个频率最高的是t,然后是a,,,,,
当我们拿到密文的时候,密文里面也会出现一个频率最高的字母,假设密文里边出现频率最高的是j,可以假设密文里边的j就是明文里的e,,,,,
统计的原文字母出现频率
统计的密文的频率
Byte:字节,数据存储的基本单位,比如移动硬盘1T,单位是byte。
bit:比特,又叫位,一个位要么是0要么是1,数据传输的单位,比如家里的宽带100MB,下载速度并没有达到100MB,一般都是12-13MB,那是因为需要使用100/8
关系:1Byte=8bit
public class ByteDemo {
public static void main(String[] args) {
String a="a";
byte[] bytes=a.getBytes();
for (byte aByte : bytes) {
int c=aByte;
System.out.println(c);
//byte字节对应的比特是多少
String s= Integer.toBinaryString(c);
System.out.println(s);
}
}
}
public class byteChineseDemo {
public static void main(String[] args) throws Exception{
//一个中文对应的是三个字节,并不一定全部的所有的中文都是三个字节。
//根据编码格式的不一样,对应的字节也不一样。
//如果是UTF-8,一个中文对应三个字节
//如果是GBK,一个中文对应两个字节
//如果是英文,无所谓编码格式
String a="尚";
byte[] bytes=a.getBytes( “GBK” );
for (byte aByte : bytes) {
System.out.println(aByte);
String s=Integer.toBinaryString(aByte);
System.out.println(s);
}
}
}
对称加密,加密和解密使用同一把钥匙,分成流加密和块加密
例如:要将原文3发给B,设置密钥为108,3*108=324,将324作为密文发送给B,B拿到密文324后,使用324/108=3得到原文。
常见的加密算法
DES:Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,
AES:Advanced Encryption Standard,高级加密标准,在密码学中又称Rijndael加密法,是美国政府采用的一种区块加密标准,这个标准用来代替原先的DES,已经被多方分析且广为全世界所使用。
对称加密特点
加密速度快,可以加密大文件
密文可逆,一旦密钥文件泄露,就会导致数据暴露
加密后编码表找不到对应字符,出现乱码
一般结合Base64使用。
public class des {
public static void main(String[] args) throws Exception{
//原文
String input="硅谷";
//定义key
//使用des加密,密钥必须是8个字节
String key="12345678";
//算法
String transformation="DES";
Cipher cipher =Cipher.getInstance(transformation);
//进行加密初始化
//第一个参数表示key的字节,
//第二个参数表示加密的参数类型
String algorithm="DES";
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(),algorithm);
//第一个参数是模式,加密模式,解密模式
//第二个参数表示加密的规则
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
//调用加密方法
//参数表示原文的字节数组
byte[] bytes = cipher.doFinal(input.getBytes());
//创建base64对象
String encode = Base64.encode(bytes);
System.out.println(encode);
//打印密文
//如果直接打印,可能出现乱码,是因为在编码表上面找不到。
System.out.println(bytes);
}
}
Base64介绍
Base64不是加密算法,是可读性算法,目的不是保护数据,而是为了可读性。
Base64是由64个字符组成,大写A-Z,小写a-z,数字0-9,两个符号,+和/。
Base58一般用在比特币里面的一种编码方式。
Base64和base58区别
在base58里边没有数字0,也没有字母o,没有大写字母I,和小写字母i,也没有+和/。
Base64原理
Base64是三个字节为一组,一共是24位,每组8位,base64把三个字节转换成4组,每组6位,缺少两位,在高位用0补齐,这样做的好处,base64取后面6位,前面的两位去掉,可以把base64控制在0-63之间。
例如:111 111=32+16+8+4+2+1=63
Base64补等号规则说明
在base64里面,需要设置一共三个字节一组,如果在输出的时候,不够三个字节,需要用等号补齐。
public class base64 {
public static void main(String[] args) {
//1是一个字节,不够三个字节
//MQ==。需要注意的是,使用base64编码时,不够三个字节,用等号补齐。
System.out.println(Base64.encode("1".getBytes()));
//硅谷是6个字节,48位,刚好被整除,就没有等号。
System.out.println(Base64.encode("硅谷".getBytes()));
}
}
注意:如果在使用编码进行加密和解密的时候,使用New String这种方式
区别:
toString方法,这个方法调用的实际上是object里面的toString方法,一般在object的toString方法,返回的实际上是哈希值。
New String方法,是根据参数,参数是一个字节数组,使用java虚拟机默认编码格式,会把这个字节数组进行decode,找到对应的字符,如果虚拟机的编码格式,如果是ISO-8859-1,会去找ascii里面的编码进行参照,找对应的字符。
什么时候使用new String,什么时候使用toString
New String(),一般在进行转码的时候,需要使用newString
toString,做对象打印的时候,或者想得到地址的时候,就使用toString
AES加密解密和DES加密解密代码一样,只需要修改加密算法就行,
密钥是16位。
public class AES {
public static void main(String[] args) throws Exception{
//原文
String input="硅谷";
//定义key
//使用Aes加密,密钥必须是16个字节
String key="1234567812345678";
//算法
String transformation="AES";
Cipher cipher =Cipher.getInstance(transformation);
//进行加密初始化
//第一个参数表示key的字节,
//第二个参数表示加密的参数类型
String algorithm="AES";
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(),algorithm);
//第一个参数是模式,加密模式,解密模式
//第二个参数表示加密的规则
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
//调用加密方法
//参数表示原文的字节数组
byte[] bytes = cipher.doFinal(input.getBytes());
//创建base64对象
String encode = Base64.encode(bytes);
System.out.println(encode);
//打印密文
//如果直接打印,可能出现乱码,是因为在编码表上面找不到。
System.out.println(bytes);
}
}
算法/加密模式/填充模式
Cipher c=Cipher.getInstance(“DES, CBC, PKCS5Padding”)
加密模式:
ECB,Electronic codebook,电子密码本,需要加密的消息按照密码块的大小分为数个块,并对每个块进行独立加密。
把一段文本进行分拆加密,使用同一个key,分别进行加密,然后组合到一起。
优点:可以并行处理数据
缺点:使用的是同一个KEY,不安全
CBC,密码块链接,每个明文块先与前一个密文块进行异或后,在进行加密,这种方法中,每个密文块都依赖于它前面的所有明文块。
优点:同样的原文生成的密文不一样
缺点:串行速度慢
填充模式:
当需要按块处理的数据,数据长度不符合块处理需求时,按照一定的方法填充满块长的规则
NoPadding:
不填充
在DES加密算法下,要求原文长度必须是8byte的整数倍
在AES加密算法下,要求原文长度必须是16byte的整数倍
PKCSpadding
数据块的大小位8位,不够就补足。
public class ebcc {
public static void main(String[] args) {
//原文
//如果使用的是不填充的模式,那么原文必须是8byte的整数倍。
String input="硅谷";
//定义key
//使用des加密,密钥必须是8个字节
String key="12345678";
//算法
//ecb表示加密模式,pkcs5padding表示填充模式
//默认情况下,没有写加密模式和填充模式的情况下,默认使用ECB/PKCS5Padding
String transformation="DES/ECB/PKCS5Padding";
Cipher cipher =Cipher.getInstance(transformation);
//进行加密初始化
//第一个参数表示key的字节,
//第二个参数表示加密的参数类型
String algorithm="DES";
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(),algorithm);
//创建iv向量,iv向量是使用cbc加密模式
//在使用iv向量时,iv向量也是8byte
IvParameterSpec iv = new IvParameterSpec("12345678".getBytes());
//第一个参数是模式,加密模式,解密模式
//第二个参数表示加密的规则
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,iv);
//调用加密方法
//参数表示原文的字节数组
byte[] bytes = cipher.doFinal(input.getBytes());
//创建base64对象
String encode = Base64.encode(bytes);
System.out.println(encode);
//打印密文
//如果直接打印,可能出现乱码,是因为在编码表上面找不到。
System.out.println(bytes);
}
}
消息摘要又称为数字摘要,散列函数,
他是一个唯一对应一个消息或文本的固定长度的值,它由一个单向HASH加密函数对消息进行作用而产生。
使用数字摘要生成的值是不可以篡改的,为了保证文件或者值的安全。
特点:
无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。
常见算法:MD5,SHA-1,SHA256,SHA512
MessageDigest类为应用程序提供消息摘要算法的功能,如SHA-1,SHA-256,消息摘要是采用任意大小的数据并输出固定长度散列值的安全单向散列函数。
public class Digest {
public static void main(String[] args) throws Exception{
String input="aa";
//算法
String algorithm="MD5";
//创建消息摘要对象
MessageDigest instance = MessageDigest.getInstance(algorithm);
//执行消息摘要算法
byte[] digest = instance.digest(input.getBytes());
//使用base64进行转码
System.out.println(Base64.encode(digest));
}
}
public class Digest {
public static void main(String[] args) throws Exception{
String input="aa";
//算法
String algorithm="MD5";
//创建消息摘要对象
MessageDigest instance = MessageDigest.getInstance(algorithm);
//执行消息摘要算法
byte[] digest = instance.digest(input.getBytes());
//使用base64进行转码
//System.out.println(Base64.encode(digest));
StringBuilder sb = new StringBuilder();
//对密文进行迭代
for (byte b : digest) {
//把密文转成16进制
String s = Integer.toHexString(b & 0xff );
//判断密文的长度如果是1,需要在高位进行补0
if (s.length()==1){
s="0"+s;
}
sb.append(s);
//System.out.println(sb.toString());
}
return sb.toString();
}
}
简介:
非对称加密又叫做现代加密算法
非对称加密算法,必须有两个密钥,一个公钥,一个私钥
公钥和私钥是一对,我们叫做密钥对
如果使用公钥加密,必须使用私钥解密
如果使用私钥加密,必须使用公钥解密
常见非对称加密算法
RSA,ECC
public class RSADemo {
public static void main(String[] args) throws Exception{
//创建密钥对
// KeyPairGenerator:密钥对生成器对象
String algorithm="RSA";
KeyPairGenerator instance = KeyPairGenerator.getInstance(algorithm);
//生成密钥对
KeyPair keyPair = instance.generateKeyPair();
//生成私钥
PrivateKey aPrivate = keyPair.getPrivate();
//生成公钥
PublicKey aPublic = keyPair.getPublic();
//获取私钥的字节数组
byte[] encoded = aPrivate.getEncoded();
//获取公钥字节数组
byte[] encoded1 = aPublic.getEncoded();
//使用base64进行编码
String encoded2 = Base64.encode(encoded);
String encoded3 = Base64.encode(encoded1);
//打印私钥和公钥
System.out.println(encoded2);
System.out.println(encoded3);
}
}
public class RSADemo {
public static void main(String[] args) throws Exception{
String input="硅谷";
//创建密钥对
// KeyPairGenerator:密钥对生成器对象
String algorithm="RSA";
KeyPairGenerator instance = KeyPairGenerator.getInstance(algorithm);
//生成密钥对
KeyPair keyPair = instance.generateKeyPair();
//生成私钥
PrivateKey aPrivate = keyPair.getPrivate();
//生成公钥
PublicKey aPublic = keyPair.getPublic();
//获取私钥的字节数组
byte[] encoded = aPrivate.getEncoded();
//获取公钥字节数组
byte[] encoded1 = aPublic.getEncoded();
//使用base64进行编码
String encoded2 = Base64.encode(encoded);
String encoded3 = Base64.encode(encoded1);
//打印私钥和公钥
System.out.println(encoded2);
System.out.println(encoded3);
//创建加密对象
Cipher cipher= Cipher.getInstance(algorithm);
//对加密进行初始化
//第一个参数,加密的模式。第二个参数,想使用公钥加密还时私钥加密
cipher.init(Cipher.ENCRYPT_MODE, encoded);
//使用私钥进行加密
byte[] bytes = cipher.doFinal(input.getBytes());
System.out.println( Base64.encode(bytes));
}
}
18.保存公钥和私钥
//保存公钥和私钥
private static void generateKeyToFile(String algorithm, String publicpath, String privatepath) throws Exception{
KeyPairGenerator instance = KeyPairGenerator.getInstance(algorithm);
//生成密钥对
KeyPair keyPair = instance.generateKeyPair();
//生成私钥
PrivateKey aPrivate = keyPair.getPrivate();
//生成公钥
PublicKey aPublic = keyPair.getPublic();
//获取私钥的字节数组
byte[] encoded = aPrivate.getEncoded();
//获取公钥字节数组
byte[] encoded1 = aPublic.getEncoded();
//使用base64进行编码
String encoded2 = Base64.encode(encoded);
String encoded3 = Base64.encode(encoded1);
//把公钥和私钥保存到根目录中
FileUtils.writeStringToFile(new File(publicpath),publicEncodeString, Charset.forName("UTF-8"));
FileUtils.writeStringToFile(new File(privatepath),privateEncodeString, Charset.forName("UTF-8"));
19.
public class RSADemo {
public static void main(String[] args) throws Exception{
String input="硅谷";
//创建密钥对
// KeyPairGenerator:密钥对生成器对象
String algorithm="RSA";
//生成密钥对并保存在本地文件中
generateKeyToFile(algorithm,"a.pub","a.pri");
//读取私钥对象
PrivateKey privatekey =getPrivateKey("a.pri",algorithm);
System.out.println(privatekey);
//读取公钥对象
PublicKey publicKey= getPublicKey("a.pub",algorithm);
System.out.println(publicKey);
/**
KeyPairGenerator instance = KeyPairGenerator.getInstance(algorithm);
//生成密钥对
KeyPair keyPair = instance.generateKeyPair();
//生成私钥
PrivateKey aPrivate = keyPair.getPrivate();
//生成公钥
PublicKey aPublic = keyPair.getPublic();
//获取私钥的字节数组
byte[] encoded = aPrivate.getEncoded();
//获取公钥字节数组
byte[] encoded1 = aPublic.getEncoded();
//使用base64进行编码
String encoded2 = Base64.encode(encoded);
String encoded3 = Base64.encode(encoded1);*/
//打印私钥和公钥
//System.out.println(encoded2);
//System.out.println(encoded3);
//创建加密对象
Cipher cipher= Cipher.getInstance(algorithm);
//对加密进行初始化
//第一个参数,加密的模式。第二个参数,想使用公钥加密还时私钥加密
cipher.init(Cipher.ENCRYPT_MODE, encoded);
//使用私钥进行加密
byte[] bytes = cipher.doFinal(input.getBytes());
System.out.println( Base64.encode(bytes));
//私钥解密
cipher.init(Cipher.DECRYPT_MODE,encoded);
//使用私钥解密
byte[] bytes1 = cipher.doFinal(bytes);
System.out.println(new String(bytes1));
//公钥解密
cipher.init(Cipher.DECRYPT_MODE,encoded1);
//使用公钥解密
byte[] bytes2 = cipher.doFinal(bytes);
System.out.println(new String(bytes2));
}
private static PublicKey getPublicKey(String publicpath, String algorithm) {
String publickey= FileUtils.readFileToString(new File(publicpath),Charset.defaultCharset());
//创建key的工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publickey));
return keyFactory.generatePublic(keySpec);
}
private static PrivateKey getPrivateKey(String privatepath, String algorithm) throws Exception{
String privatekey= FileUtils.readFileToString(new File(privatepath),Charset.defaultCharset());
//创建key的工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
//创建私钥的规则
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(privatekey));
//返回私钥对象
return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
}
//保存公钥和私钥
private static void generateKeyToFile(String algorithm, String publicpath, String privatepath) throws Exception{
KeyPairGenerator instance = KeyPairGenerator.getInstance(algorithm);
//生成密钥对
KeyPair keyPair = instance.generateKeyPair();
//生成私钥
PrivateKey aPrivate = keyPair.getPrivate();
//生成公钥
PublicKey aPublic = keyPair.getPublic();
//获取私钥的字节数组
byte[] encoded = aPrivate.getEncoded();
//获取公钥字节数组
byte[] encoded1 = aPublic.getEncoded();
//使用base64进行编码
String encoded2 = Base64.encode(encoded);
String encoded3 = Base64.encode(encoded1);
//把公钥和私钥保存到根目录中
FileUtils.writeStringToFile(new File(publicpath),publicEncodeString, Charset.forName("UTF-8"));
FileUtils.writeStringToFile(new File(privatepath),privateEncodeString, Charset.forName("UTF-8"));
}
}
20.数字签名
数字签名:公钥数字签名,只有信息的发送者,才能产生别人无法伪造的一段数字串,类似于写在纸上的普通物理签名。
数字签名原理:
数字证书:
上面提到我们对签名进行验证时,需要使用公钥,如果公钥是伪造的,就无法验证数字签名了,需要使用证书。
CA认证中心:
所谓CA(Certificate Authority)认证中心,它是采用PKI(Public Key Infrastructure)公开密钥基础架构技术,专门提供网络身份认证服务,CA可以是民间团体,也可以是政府机构。负责签发和管理数字证书,且具有权威性和公正性的第三方信任机构,它的作用就像我们现实生活中颁发证件的公司,如护照办理机构。国内的CA认证中心主要分为区域性CA认证中心和行业性CA认证中心。