Android开发之常用的加密算法讲解
> 古典算法:凯撒加密
> ascii编码
> byte和bit:二进制字节和位关系
> base64编码和解密
> 对称加密算法:des、aes
> 非对称加密rsa
> 消息摘要:md5、sha1、sha256
> 数字签名:避免抓包篡改参数
> 只有是一家公司,有能力,必须使用加密算法
> 目标:独立封装对称加密算法、非对称加密算法、使用md5加密用户登录/注册信息
![](img/usage.png)
### 02.ascii编码
> ascii编码:美国信息标准交互码,就是用来显示西欧字符
![](img/ascii.png)
> 获取字符ascii编码
//获取单个字符ascii
char ch = 'a';
int ascii = ch;
//system.out.println(ascii);
//获取字符串ascii
string str = "hello";
char[] chararray = str.tochararray();
for (char c : chararray) {
int value = c;
system.out.println(value);
}
### 03.凯撒加密解密
> 古罗马大帝凯撒发明:对字符串偏移
![](img/kaiser.png)
public static string encrypt(string input, int key) {
stringbuilder stringbuilder = new stringbuilder();
//获取每一个字符ascii编码
char[] arr = input.tochararray();
for (char c : arr) {
int ascii = c;
//偏移一位
ascii = ascii + key;
//获取ascii对应的字符
char result = (char) ascii;
//system.out.print(result);
stringbuilder.append(result);
}
return stringbuilder.tostring();
}
public static string decrypt(string input, int key) {
stringbuilder stringbuilder = new stringbuilder();
//获取每一个字符ascii编码
char[] arr = input.tochararray();
for (char c : arr) {
int ascii = c;
//偏移一位
ascii = ascii - key;
//获取ascii对应的字符
char result = (char) ascii;
//system.out.print(result);
stringbuilder.append(result);
}
return stringbuilder.tostring();
}
### 04.频度分析法凯撒加密算法
> 根据统计学破解凯撒算法:一篇英文文章字母e出现的概率很高
### 05.byte和bit
> byte:字节,一个byte有8位,1byte=8bit
> bit:位
> 示例代码
string input = "a";//一个英文字母占1个字节(byte)
string input2 = "我爱你";//一个中文utf-8编码表中占3个字节,一个中文gbk编码表中占2个字节
byte[] bytes = input.getbytes();//获取字符对应的byte数组
system.out.println(bytes.length);
byte[] bytes2 = input2.getbytes();
byte[] bytes3 = input2.getbytes("gbk");
system.out.println(bytes2.length);
system.out.println("gbk编码:"+bytes3.length);
char[] chararray = input.tochararray();
for (char c : chararray) {
int ascii = c;
system.out.println(ascii);
//转成二进制
string binarystring = integer.tobinarystring(ascii);
system.out.println(binarystring);
}
### 06.常见对称加密算法介绍
> des:企业级开发使用频率很高,data encryption standard数据加密标准
> aes:advanced encryption standard,高级数据加密标准,比des破解难度大
> 底层机制:操作的不是字符,操作的是二进制(字符二进制显示成矩阵,矩阵变化)
### 07.des加密
> des:data encryption standard数据加密标准
> 掌握参考api文档实现加密算法
> 对称加密三部曲:
* 1.创建cipher对象,cipher加密算法核心类
* 2.初始化加密/解密模式
* 3.加密/解密
> 加密算法、安全领域大量使用getinstance(参数) 方法
public static void main(string[] args) {
string input = "我爱你";
string password = "12345678";//秘钥:des秘钥长度是64个bit(位)
try {
// 1.创建cipher对象,cipher加密算法核心类
cipher cipher = cipher.getinstance("des");
key key = new secretkeyspec(password.getbytes(), "des");
// 2.初始化加密/解密模式:以后只要是对象参数是int,说明有常量
cipher.init(cipher.encrypt_mode, key);//加密模式
// 3.加密
byte[] encrypt = cipher.dofinal(input.getbytes());
system.out.println("des加密="+new string(encrypt));
} catch (exception e) {
e.printstacktrace();
}
}
### 08.des解密
public static byte[] encrypt(string input, string password) {
try {
// 1.创建cipher对象,cipher加密算法核心类
cipher cipher = cipher.getinstance("des");
key key = new secretkeyspec(password.getbytes(), "des");
// 2.初始化加密/解密模式:以后只要是对象参数是int,说明有常量
cipher.init(cipher.encrypt_mode, key);//加密模式
// 3.加密
byte[] encrypt = cipher.dofinal(input.getbytes());
return encrypt;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
/**
* des解密
*/
public static byte[] decrypt(byte[] input, string password) {
try {
// 1.创建cipher对象,cipher加密算法核心类
cipher cipher = cipher.getinstance("des");
key key = new secretkeyspec(password.getbytes(), "des");
// 2.初始化加密/解密模式:以后只要是对象参数是int,说明有常量
cipher.init(cipher.decrypt_mode, key);//解密模式
// 3.加密
byte[] decrypt = cipher.dofinal(input);
return decrypt;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 09.base64编码和解码
> des加密后密文长度是8个整数倍
> 加密后比明文长度变长,所以编码表找不到对应字符,乱码
> 使用base64编码和解密:从apache现在
> 1.加密后密文使用base64编码
> 2.解密前对密文解码
public static string encrypt(string input, string password) {
try {
// 1.创建cipher对象,cipher加密算法核心类
cipher cipher = cipher.getinstance("des");
key key = new secretkeyspec(password.getbytes(), "des");
// 2.初始化加密/解密模式:以后只要是对象参数是int,说明有常量
cipher.init(cipher.encrypt_mode, key);//加密模式
// 3.加密
byte[] encrypt = cipher.dofinal(input.getbytes());
return base64.encode(encrypt);
} catch (exception e) {
e.printstacktrace();
}
return null;
}
/**
* des解密
*/
public static string decrypt(string input, string password) {
try {
// 1.创建cipher对象,cipher加密算法核心类
cipher cipher = cipher.getinstance("des");
key key = new secretkeyspec(password.getbytes(), "des");
// 2.初始化加密/解密模式:以后只要是对象参数是int,说明有常量
cipher.init(cipher.decrypt_mode, key);//解密模式
// 3.加密
byte[] decrypt = cipher.dofinal(base64.decode(input));
return new string(decrypt);
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 10.aes加密解密
public static string encrypt(string input, string password) {
try {
//对称加密三部曲
//1.创建cipher对象
cipher cipher = cipher.getinstance(transformation);
//secretkeyspec:秘钥规范 -> 将字符串秘钥转成对象
key key = new secretkeyspec(password.getbytes(), transformation);
//2.初始化加密/解密模式
cipher.init(cipher.encrypt_mode, key);
//3.加密
byte[] encrypt = cipher.dofinal(input.getbytes());
string encode = base64.encode(encrypt);
return encode;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
/**
* aes解密
*/
public static string decrypt(string input, string password) {
try {
//对称加密三部曲
//1.创建cipher对象
cipher cipher = cipher.getinstance(transformation);
//secretkeyspec:秘钥规范 -> 将字符串秘钥转成对象
key key = new secretkeyspec(password.getbytes(), transformation);
//2.初始化加密/解密模式
cipher.init(cipher.decrypt_mode, key);
//3.加密
byte[] encrypt = cipher.dofinal(base64.decode(input));//解密前对密文解码
//string encode = base64.encode(encrypt);
return new string(encrypt);
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 11.对称加密密钥长度分析
> des秘钥长度:8个字符
> aes秘钥长度:16个字符
> des加密后密文长度是8的整数倍
> aes加密后密文长度是16的整数倍
### 12.工作模式和填充模式
> ios加密,android没有解密:工作模式和填充模式不一致
> 工作模式:如何加密(ecb:并行加密,分段加密,每一段不相互影响;cbc只能串行加密)
> 填充模式:加密后密文长度如果达不到指定整数倍(8个字节、16个字节),填充对应字符
### 13.工作模式填充模式的使用
> 默认工作模式/填充模式:ecb/pkcs5padding
> cbc工作模式:报错parameters missing,cbc模式需求额外参数
> nopadding不填充模式:des原文长度必须是8个字节整数倍,aes原文长度必须是16个字节整数倍
### 14.对称加密应用实战
> 算法:des、aes,企业级开发使用des足够安全,如果要求高使用aes
> 特点:可逆(加密后可以解密)
> 需求:从服务器获取数据,缓存到本地,加密
### 15.非对称加密算法rsa介绍
> rsa:到2008年为止,世界上还没有任何可靠的攻击rsa算法的方式
> 秘钥对:公钥和私钥,秘钥对不能手动指定,必须有生成
> 加密速度慢:必须分段加密,不能加密大文件
> 公钥加密私钥解密;私钥加密公钥解密
> 公钥互换:连个商家合作需要交互公钥,但是私钥不能别人
### 16.非对称加密rsa生成秘钥对
> 不能手动指定,必须由系统生成:公钥和私钥
//非对称加密三部曲
//1.创建cipher对象
cipher cipher = cipher.getinstance(transformation);
//秘钥对生成器
keypairgenerator generator = keypairgenerator.getinstance(algorithm);
//秘钥对
keypair keypair = generator.generatekeypair();
privatekey privatekey = keypair.getprivate();
publickey publickey = keypair.getpublic();
//获取公钥和私钥字符串
string priatekeystr = base64.encode(privatekey.getencoded());
string publickeystr = base64.encode(publickey.getencoded());
### 17.非对称加密rsa加密
> 公钥加密和私钥加密
public static string encryptbyprivatekey(string input, privatekey privatekey) {
string encode;
try {
//非对称加密三部曲
//1.创建cipher对象
cipher cipher = cipher.getinstance(transformation);
//2.初始化加密/解密模式
cipher.init(cipher.encrypt_mode, privatekey);//私钥加密
//3.加密/解密
byte[] encryptbyprivatekey = cipher.dofinal(input.getbytes());
encode = base64.encode(encryptbyprivatekey);
return encode;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
public static string encryptbypublickey(string input, publickey publickey) {
string encode;
try {
//非对称加密三部曲
//1.创建cipher对象
cipher cipher = cipher.getinstance(transformation);
//2.初始化加密/解密模式
cipher.init(cipher.encrypt_mode, publickey);//私钥加密
//3.加密/解密
byte[] encryptbyprivatekey = cipher.dofinal(input.getbytes());
encode = base64.encode(encryptbyprivatekey);
return encode;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 18.非对称加密rsa分段加密
> rsa每次最大只能加密117个字节
> 超过117字节,分段加密
public static string encryptbyprivatekey(string input, privatekey privatekey) {
string encode;
try {
byte[] bytes = input.getbytes();
//非对称加密三部曲
//1.创建cipher对象
cipher cipher = cipher.getinstance(transformation);
//2.初始化加密/解密模式
cipher.init(cipher.encrypt_mode, privatekey);//私钥加密
//3.分段加密
int offset = 0;//当前加密位置
//缓冲区
byte[] buffer = new byte[1024];
bytearrayoutputstream baos = new bytearrayoutputstream();
while(bytes.length - offset > 0){
if(bytes.length - offset >= max_encrypt_size){
//加密完整块
buffer = cipher.dofinal(bytes, offset, max_encrypt_size);//加密117字节
offset += max_encrypt_size;
}else{
//最后一块
buffer = cipher.dofinal(bytes, offset, bytes.length - offset);
offset = bytes.length;
}
baos.write(buffer);
}
encode = base64.encode(baos.tobytearray());
return encode;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 19.非对称加密rsa分段解密
public static string decryptbyprivatekey(string input, privatekey privatekey) {
string encode;
try {
byte[] bytes = base64.decode(input);
//非对称加密三部曲
//1.创建cipher对象
cipher cipher = cipher.getinstance(transformation);
//2.初始化加密/解密模式
cipher.init(cipher.decrypt_mode, privatekey);//私钥解密
//3.分段加密
int offset = 0;//当前加密位置
//缓冲区
byte[] buffer = new byte[1024];
bytearrayoutputstream baos = new bytearrayoutputstream();
while(bytes.length - offset > 0){
if(bytes.length - offset >= max_decrypt_size){
//加密完整块
buffer = cipher.dofinal(bytes, offset, max_decrypt_size);//加密117字节
offset += max_decrypt_size;
}else{
//最后一块
buffer = cipher.dofinal(bytes, offset, bytes.length - offset);
offset = bytes.length;
}
baos.write(buffer);
}
encode = baos.tostring();
return encode;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 20.非对称加密保存秘钥对
> 每次都生成秘钥对:安卓加密有肯能ios不能解密
> 第一次生成存储起来
keyfactory kf = keyfactory.getinstance(algorithm);
//字符串秘钥转成对象类型
privatekey privatekey = kf.generateprivate(new pkcs8encodedkeyspec(base64.decode(private_key)));
publickey publickey = kf.generatepublic(new x509encodedkeyspec(base64.decode(public_key)));
### 21.消息摘要介绍
> messagedigest:消息摘要,摘要信息(唯一的),软件用判断正版盗版软件
> 三个算法:md5、sha1、sha256
> 特点:
* 不可逆(通过密文不能推出明文,只能撞库)
* 加密后密文长度固定,1kb字符串和1g字符串加密结果长度一样
### 22.消息摘要md5的使用
public static string md5(string input) {
try {
stringbuilder stringbuilder = new stringbuilder();
//获取消息摘要对象
messagedigest md5 = messagedigest.getinstance(algorithm);
byte[] digest = md5.digest(input.getbytes());
string hex = hexutils.tohex(digest);
//system.out.println(hex);
return hex;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 23.获取文件md5值
public static string md5file(string filepath){
fileinputstream fis = null;
try {
fis = new fileinputstream(filepath);
messagedigest md5 = messagedigest.getinstance(algorithm);
byte[] buffer = new byte[1024];
int len = 0;
while((len = fis.read(buffer)) != -1){
md5.update(buffer, 0, len);
}
byte[] digest = md5.digest();
//转成16进制
string hex = hexutils.tohex(digest);
return hex;
} catch (exception e) {
e.printstacktrace();
} finally{
ioutils.close(fis);
}
return null;
}
### 24.消息摘要sha1和sha256的使用
> md5:16(加密后密文长度16个字节),32(密文转成16进制32个字节)
> sha1:20(加密后密文长度20个字节),40(密文转成16进制40个字节)
> sha256:32(加密后密文长度32个字节),64(密文转成16进制64个字节)
### 25.消息摘要应用实战
> 开发中使用哪个算法:常用md5
> 应用场景:用户登录/注册,用户密码必须加密传输
> 只要是用户密码必须使用md5(不可逆的),服务器存储的是密文
inputstream ins = null;
string usrename = "heima104";
string password = "123456";
try {
string url = "https://120.77.241.119/encryptserver/login?username="
+ usrename + "&password=" + md5utils.md5(password);
url url2 = new url(url);
httpurlconnection conn = (httpurlconnection) url2.openconnection();
system.out.println(url2.touri().tostring());
ins = conn.getinputstream();
string result = ioutils.convertstreamtostring(ins);
system.out.println(result);
} catch (exception e) {
e.printstacktrace();
} finally {
ioutils.close(ins);
}
> 撞库破解md5:不可能穷尽所有密文,加密多次,加盐
### 26.数字签名
> rsa数字签名:消息摘要和非对称加密的组合(sha256withrsa)
> 作用:校验参数是否被篡改,保证数据传输安全
public static boolean verity(string input, publickey publickey, string sign) {
try {
//1.获取数字签名对象
signature signature = signature.getinstance(algorithm);
//2.初始化校验方法:必须使用公钥
signature.initverify(publickey);
signature.update(input.getbytes());
//3.开始校验
boolean verify = signature.verify(base64.decode(sign));
//system.out.println("校验结果:"+verify);
return verify;
} catch (exception e) {
e.printstacktrace();
}
return false;
}
public static string sign(string input, privatekey privatekey) {
try {
//1.获取数字签名对象
signature signature = signature.getinstance(algorithm);
//2.初始化签名:必须使用使用
signature.initsign(privatekey);
signature.update(input.getbytes());
//3.开始签名
byte[] sign = signature.sign();
string encode = base64.encode(sign);
//system.out.println("sign="+encode);
return encode;
} catch (exception e) {
e.printstacktrace();
}
return null;
}
### 27.数字签名流程图分析
> rsa数字签名流程图:借鉴设计公司加密系统
![](img/rsa-sign.png)
### 28.数字签名应用实战-时间戳
> 登录url,抓包可以重复登录
> 如何避免抓包重复登录:添加时间戳
> 设置登录超时时间:比如20秒钟