为什么要去看密码学

  • 客户端发送给服务器的数据包中,有些参数不知道来源,或许是随机生成、标准算法加密的、自写算法加密的
  • 安卓中,标准算法加密一般会呈现在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层能够经过输入输出的数据和码表来确定算法

05 密码学

05 密码学

音讯摘要算法

1. 算法特色

a) 音讯摘要算法/单向散列函数/哈希函数
b) 不同长度的输入,发生固定长度的输出
c) 散列后的密文不行逆
d) 散列后的成果唯一
e) 哈希磕碰
f) 一般用于校验数据完整性、签名sign
由于密文不行逆,所以服务端也无法解密
想要验证,就需求跟前端相同的办法去从头签名一遍
签名算法一般会把源数据和签名后的值一起提交到服务端
要确保在签名时分的数据和提交上去的源数据共同

2. 常见算法

MD5、SHA1、SHA256、SHA512、HmacMD5、HmacSHA1、HmacSHA256、HmacSHA512
RIPEMD160、HmacRIPEMD160、PBKDF2、EvpKDF

05 密码学

MD5

05 密码学

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

05 密码学

1. SHA的Java完成

MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update("Andy".getBytes());
sha1.digest();

2 SHA算法的特色

1 加密后的字节数组能够编码成Hex、Base64
2 没有任何输入,也能核算hash

MAC

05 密码学

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

05 密码学

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

05 密码学

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

05 密码学

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

05 密码学

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去解密,会怎么样呢?
    1. 没有指明加密形式和填充办法,表明运用默许的RSA/ECB/NOPadding
    1. 加密后的字节数组能够编码成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将数据体进行解密

  1. RSA算法通杀hook note.youdao.com/s/1ZcMKaQk

数字签名算法

05 密码学

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