欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发之常用的加密算法讲解

程序员文章站 2022-06-28 17:55:18
> 古典算法:凯撒加密 > ascii编码 > byte和bit:二进制字节和位关系 > base64编码和解密 > 对称加密算法:des、aes > 非对称加密...

> 古典算法:凯撒加密

> 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秒钟