为什么要去看密码学
- 客户端发送给服务器的数据包中,有些参数不知道来源,或许是随机生成、标准算法加密的、自写算法加密的
- 安卓中,标准算法加密一般会呈现在Java、so(C/C++)、JS中
- Java有现成的体系API调用,开发者想要运用这些API,有必要运用固定的办法名去拜访。这些API也便是我们需求学习的内容。
- C/C++没有现成的体系API调用,开发者要么自己去完成算法,要么调用别人写好的模块,算法的运行不依赖体系API,因此办法名能够混淆。你要做的便是依据各种标准算法的特征,去辨认是否标准算法。这些算法的特征,便是我们需求学习的内容。
- JS也没有现成的体系API调用,开发者一般运用CryptoJS、jsencrypt等第三方加密库来加密。
密码学里面要看哪些内容
-
音讯摘要算法(散列函数、哈希函数):MD5、SHA、MAC
-
对称加密算法:DES、3DES、AES
-
非对称加密算法:RSA
-
数字签名算法:MD5withRSA、SHA1withRSA、SHA256withRSA
加密办法
1 Hex编码
什么是hex编码
hex编码是一种用16个字符表明恣意二进制数据的办法
Hex编码的特色
a) 用0-9 a-f 16个字符表明。
b) 每个十六进制字符代表4bit, 也便是2个十六进制字符代表一个字节。
c) 在实践运用中,比如密钥初始化,一定要分清楚传进去的密钥是哪种编码的,采用对应的办法解析,才干得到正确的成果
d) 编程中许多问题,需求从字节甚至二进制位的角度去考虑,才干理解
Hex编码Java完成
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HexEncode {
public static void main(String[] args) {
MessageDigest md5 = null;
try {
// md5 = MessageDigest.getInstance("MD5");
// md5.update("a12345678".getBytes());
// md5.update("a12345678".getBytes(), 1, 3);
// byte[] result1 = md5.digest();
// System.out.println(HexBin.encode(result1));
String data = "Andy";
String salt = "a12345678";
byte[] result2 = MessageDigest.getInstance("SHA-256").digest((data + salt).getBytes());
String hexStr = HexBin.encode(result2);
System.out.println(hexStr);
//System.out.println(Base64.getEncoder().encodeToString(hexStr.getBytes()));
//System.out.println(Base64.getEncoder().encodeToString(result2));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
2 Base64编码
1. 什么是Base64
Base64是一种用64个字符表明恣意二进制数据的办法
是一种编码,而非加密
A-Z a-z 0-9 + / =
2. Base64的运用
RSA密钥、加密后的密文、图片等数据中,会有一些不行见字符,
直接转成文本传输的话,会有乱码、数据过错、数据丢失等状况呈现,就能够运用Base64编码
3. Base64的代码完成和码表
//java.util.Base64 码表 Android8.0以上可用
Base64.getEncoder().encodeToString("Andy".getBytes())
//android.util.Base64 码表
Base64.encodeToString
//okio.ByteString
build.gradle
dependencies {
api 'com.squareup.okhttp3:okhttp:3.10.0'
}
ByteString byteString = ByteString.of("100".getBytes());
byteString.base64(); //码表 okio.Base64 encode
4. Base64码表的妙用
为了传输数据安全,一般会对Base64数据进行URL编码,或者会把+和/替换成-和_
5. Base64编码细节
每个Base64字符代表原数据中的6bit
Base64编码后的字符数,是4的倍数
编码的字节数是3的倍数时,不需求填充
6. Base64编码的特色
a) Base64编码是编码,不是紧缩,编码后只会添加字节数
b) 算法可逆, 解码很便利, 不用于私密信息通信
c) 标准的Base64每行为76个字符,行末添加换行符
d) 加密后的字符串只有65种字符, 不行打印字符也可传输
e) 在Java层能够经过hook对应办法名来快速定位要害代码
f) 在so层能够经过输入输出的数据和码表来确定算法
音讯摘要算法
1. 算法特色
a) 音讯摘要算法/单向散列函数/哈希函数
b) 不同长度的输入,发生固定长度的输出
c) 散列后的密文不行逆
d) 散列后的成果唯一
e) 哈希磕碰
f) 一般用于校验数据完整性、签名sign
由于密文不行逆,所以服务端也无法解密
想要验证,就需求跟前端相同的办法去从头签名一遍
签名算法一般会把源数据和签名后的值一起提交到服务端
要确保在签名时分的数据和提交上去的源数据共同
2. 常见算法
MD5、SHA1、SHA256、SHA512、HmacMD5、HmacSHA1、HmacSHA256、HmacSHA512
RIPEMD160、HmacRIPEMD160、PBKDF2、EvpKDF
MD5
1. MD5的Java完成
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update("Andy".getBytes());
md5.digest();
2 算法特色
1. 加密后的字节数组能够编码成Hex、Base64
2. 没有任何输入,也能核算hash值
3. 碰到加salt的MD5,能够直接输入空的值,得到成果去CMD5查询一下,有或许就得到salt
SHA
1. SHA的Java完成
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update("Andy".getBytes());
sha1.digest();
2 SHA算法的特色
1 加密后的字节数组能够编码成Hex、Base64
2 没有任何输入,也能核算hash值
MAC
1. MAC算法与MD和SHA的区别是多了一个密钥,密钥能够随机给
2. MAC的Java完成
SecretKeySpec secretKeySpec = new SecretKeySpec("a12345678".getBytes(),"HmacSHA1");
Mac mac = Mac.getInstance(secretKeySpec.getAlgorithm());
mac.init(secretKeySpec);
mac.update("Andy".getBytes());
mac.doFinal();
3. 加密后的字节数组能够编码成Hex、Base64
4. 没有任何输入,也能核算hash值
MD5,HEX,MAC通杀算法
note.youdao.com/s/CJT8frzb
对称加密算法
1. 加密/解密的进程可逆的算法,叫做加密算法
2. 加密/解密运用相同的密钥,叫做对称加密算法
3. 对称加密算法的密钥能够随机给,但是有位数要求
4. 对称加密算法的输入数据没有长度要求,加密速度快
5. 各算法的密钥长度
RC4 密钥长度1-256字节
DES 密钥长度8字节
3DES/DESede/TripleDES 密钥长度24字节
AES 密钥长度16、24、32字节
依据密钥长度不同AES又分为AES-128、AES-192、AES-256
6. 对称加密分类
a) 序列加密/流加密: 以字节流的办法,顺次加密(解密)明文(密文)中的每一个字节
RC4
b) 分组加密: 将明文音讯分组(每组有多个字节),逐组进行加密
DES、3DES、AES
DES
DES算法完成
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class DESEncode {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
// DES加密
SecretKeySpec desKey = new SecretKeySpec("12345678".getBytes(), "DES");
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes()); // 长度依照对应算法的分组长度
Cipher des = Cipher.getInstance("DES/CBC/PKCS5Padding");
des.init(Cipher.ENCRYPT_MODE, desKey, ivParameterSpec);
//des.update("1234xiaojianbang1234".getBytes());
byte[] result3 = des.doFinal("xiaojianxiaojian".getBytes());
String hexStr = HexBin.encode(result3);
// 加密成果为hex编码
System.out.println(hexStr);
// 加密成果为base64编码
System.out.println(Base64.getEncoder().encodeToString(result3));
// 将加密成果解码为字符串
des.init(Cipher.DECRYPT_MODE, desKey, ivParameterSpec);
byte[] result4 = des.doFinal(result3);
System.out.println(new String(result4));
}
}
DES算法特色
1. 对称加密算法里,运用NOPadding,加密的明文有必要等于分组长度倍数,不然报错
2. 没有指明加密形式和填充办法,表明运用默许的DES/ECB/PKCS5Padding
3. 加密后的字节数组能够编码成Hex、Base64
4. 要复现一个对称加密算法,需求得到明文、key、iv、mode、padding
5. 明文、key、iv需求注意解析办法,而且不一定是字符串形式
6. 假如加密形式是ECB,则不需求加iv,加了的话会报错
7. ECB形式和CBC形式的区别
8. 假如运用PKCS5Padding,会对加密的明文填充1字节-1个分组的长度
9. DES算法明文按64位进行分组加密
10. 假如明文中有两个分组的内容相同,ECB会得到完全相同的密文,CBC不会
11. 加密算法的成果一般与明文等长或者更长,假如变短了,那或许是gzip、protobuf、音讯摘要算法
DESede
DESede算法完成
DESede加解密的Java完成
//DESedeKeySpec desedeKey = new DESedeKeySpec("123456781234567812345678".getBytes());
//SecretKeyFactory key = SecretKeyFactory.getInstance("DESede");
//SecretKey secretKey = key.generateSecret(desKeySpec);
SecretKeySpec secretKeySpec = new SecretKeySpec("123456781234567812345678".getBytes(), "DESede");
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
Cipher desede = Cipher.getInstance("DESede/CBC/PKCS5Padding");
desede.init(Cipher.ENCRYPT_MODE, desedeKey, ivParameterSpec);
desede.doFinal("xiaojianbang".getBytes());
DESede算法特色
1. DESede实践上是先进行DES加密,再进行DES解密,再进行DES加密
2. DESede的密钥24个字节,第1个8字节密钥用于DES加密,之后类推
3. 假如DESede的3个8字节密钥相同,则加密成果与DES共同
4. 为了确保DESede的安全性,一般前2个或者3个8字节密钥都不共同
5. DESede的其他特征与DES共同
AES
1. 依据密钥长度不同,分为AES128、AES192、AES256
2. AES加解密的Java完成
SecretKeySpec key = new SecretKeySpec("1234567890abcdef".getBytes(),"AES");
AlgorithmParameterSpec iv = new IvParameterSpec("1234567890abcdef".getBytes());
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
aes.init(Cipher.ENCRYPT_MODE, key, iv);
aes.doFinal("xiaojianbang1234xiaojianbang1234".getBytes());
3. AES算法明文按128位进行分组加密,其余特征与DES共同
4. DES、3DES、AES算法通杀hook
https://note.youdao.com/s/7EcfTfzx
非对称加密算法
典型算法:RSA
1. 需求生成一个密钥对,包含公钥和私钥,密钥不是随意写的
密钥对生成 http://web.chacuo.net/netrsakeypair
2. 公钥加密的数据,私钥才干解密
私钥加密的数据,公钥才干解密
3. 一般公钥是揭露的,私钥保密,私钥包含公钥,从公钥无法推导出私钥
4. 加密处理安全,但是性能极差,单次加密长度有约束
5. RSA算法既可用于加密解密,也可用于数据签名
RSA_Base64
1. 私钥的格局
pkcs1格局一般最初是 -----BEGIN RSA PRIVATE KEY-----
pkcs8格局一般最初是 -----BEGIN PRIVATE KEY-----
Java中的私钥有必要是pkcs8格局
2. RSA密钥的解析
byte[] keyBytes = Base64Decoder.decodeBuffer(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
byte[] keyBytes = Base64Decoder.decodeBuffer(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
3. RSA加解密
Cipher cipher = Cipher.getInstance("RSA/None/NOPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bt_encrypted = cipher.doFinal(bt_plaintext);
Cipher cipher = Cipher.getInstance("RSA/None/NOPadding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] bt_original = cipher.doFinal(bt_encrypted);
4. RSA形式和填充细节
a) None形式与ECB形式是共同的
b) NOPadding
明文最多字节数为密钥字节数
填充字节0, 加密后的密文不变
密文与密钥等长
c) PKCS1Padding
明文最大字节数为密钥字节数-11
每一次的填充不相同,使得加密后的密文会变
密文与密钥等长
- 5. 把PKCS1Padding加密后的密文,用NOPadding去解密,会怎么样呢?
-
- 没有指明加密形式和填充办法,表明运用默许的RSA/ECB/NOPadding
-
- 加密后的字节数组能够编码成Hex、Base64
RSA_hex
1. RSA密钥的转换
www.cnblogs.com/wyzhou/p/97…
openssl rsa -pubin -in public.pem -text //以文本格局输出公钥内容
openssl rsa -in private.pem -text //以文本格局输出私钥内容
a) 从PEM格局密钥中提取modulus、publicExponent、privateExponent
b) modulus、publicExponent、privateExponent转PEM格局
c) 还有极少数的modulus、publicExponent、privateExponent用十进制表明
2. RSA密钥的解析
BigInteger N = new BigInteger(stringN, 16); //16改10就能够把十进制转成大数
BigInteger E = new BigInteger(stringE, 16);
RSAPublicKeySpec spec = new RSAPublicKeySpec(N, E);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(spec);
3. RSA_Hex加解密的办法与RSA_Base64共同
4. 多种加密算法的常见结合套路
随机生成AES密钥AESKey
AESKey密钥用于AES加密数据,得到数据密文cipherText
运用RSA对AESKey加密,得到密钥密文cipherKey
提交密钥密文cipherKey和数据密文cipherText给服务器
5 关于AES和RSA加密结合
-
先获取AES随机的秘钥,经过该秘钥将数据进行加密
-
将AES的秘钥进行rsa加密
-
客户端收到AES加密后的数据,以及RSA加密后的key,先将key经过rsa解密,之后拿着加密之后的key将数据体进行解密
- RSA算法通杀hook note.youdao.com/s/1ZcMKaQk
数字签名算法
1. 签名
PrivateKey priK = getPrivateKey(str_priK);
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(priK);
sig.update(data);
sig.sign();
2. 验证
PublicKey pubK = getPublicKey(str_pubK);
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pubK);
sig.update(data);
sig.verify(sign);
3. 数字签名算法通杀hook