盘点几个安卓逆向之常用加密算法

2022-06-05 09:39:51 浏览数 (1)

岐王宅里寻常见,崔九堂前几度闻。

大家好,我是码农星期八。本教程只用于学习探讨,不允许任何人使用技术进行违法操作,阅读教程即表示同意!

为什么要学习加密算法

在搞逆向进行抓包的时候,可以经常发现一些莫名其妙的字符串,可能是81dc9bdb52d04dc20036dbd8313ed055等之类的一长串字符,这些是怎么生成呢?

这些其实就是加密,加密算法主要分为两大类

  • 标准加密算法
  • 非标准加密算法

标准加密算法任何语言中的实现,结果都是一样的。

应该是一样的,也可能不一样,如果不一样,说明更改了标准算法的某些变量,但是这种情况比较少。

非标准算法那就是自己写的了,这就具有很大的不确定性了,全靠程序员发挥!

注意:

  1. 在安卓逆向中,加密算法通常出现在Java层和C 中!
  2. 在Java层标准算法是有固定名字的,即使再混淆,固定名字是不能混淆的所以比较好处理!
  3. 在C 层标准加密算法是没有固定名字的,那就只能根据算法特征去识别了!

常用标准算法有哪些?

  1. 消息摘要算法(散列函数、哈希函数) MD5、SHA、MAC
  2. 对称加密算法 DES、3DES、AES
  3. 非对称加密算法 RSA
  4. 数字签名算法 MD5withRSA、SHA1withRSA、SHA256withRSA

因为本次主要是安卓逆向,所以就将常用的标准加密算法使用Android来复现一下!

我的环境

代码语言:javascript复制
AndroidStudio 2020.3.1版本
Jdk 8版本

项目

CryptologyDemo.zip

Hex和Base64

Hex和Base64不是加密,它是一种编码!!!

Hex和Base64编码是加密算法中最常用的编码,任何加密算法最终都要选择它的表现形式,而Hex和Base64是最常用的!

添加依赖

代码语言:javascript复制
api 'com.squareup.okhttp3:okhttp:3.10.0'

记得点击Sync Now

Hex

Hex编码是一种用16个字符(0-9 a-f)表示任意二进制数据的方法!

它是一种编码,而非加密!

Hex主要应用在MD5等加密表现形式上。

代码
代码语言:javascript复制
//从字符串到hex
byte[] bytes = "zhangsan".getBytes(StandardCharsets.UTF_8);
ByteString of = ByteString.of(bytes);
String hex = of.hex();
Log.d(TAG, "hex:"   hex);
示例

Base64

Base64是一种用64个字符(A-Z a-z 0-9 / =)表示任意二进制数据的方法。

它是一种编码,而非加密。

相比较之下,Base64应用就广泛的很多,像图片,,长密文甚至文件,都采用Base64,因为可承载的数据很多!

代码
代码语言:javascript复制
//从字符串到base64
byte[] bytes = "zhangsan".getBytes(StandardCharsets.UTF_8);
ByteString of = ByteString.of(bytes);
 //方式一
String base64 = of.base64();
Log.d(TAG, "base64_1:"   base64);
//方式二
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
    String s = Base64.getEncoder().encodeToString("zhangsan".getBytes(StandardCharsets.UTF_8));
    byte[] encode = Base64.getEncoder().encode("zhangsan".getBytes(StandardCharsets.UTF_8));
    Log.d(TAG, "base64_2:"   s);
    Log.d(TAG, "base64_2:"   new String(encode));
}
//方式三
String s = android.util.Base64.encodeToString("zhangsan".getBytes(StandardCharsets.UTF_8),0);
Log.d(TAG, "base64_3:"   new String(s));
示例

消息摘要算法

消息摘要算法最主要的特征!

密文是不可逆的!

  • 就是说,我在客户端把密码通过md5加密了,服务端也得采用相同的方式加密,进行比较。

不定长度输入,固定长度输出

  • 就是说,不管是123,还是123456...经过加密,加密的结果都是固定的长度!

加密结果唯一!

MD5

这就是最常用的md5加密,在update时压入数据,通过digest获得加密结果,md5一般通过hex展示加密结果!

MD系列算法

算法

摘要长度

实现

MD2

128

Java6

MD5

128

Java6

MD5

128

Bouncy Castle

代码
代码语言:javascript复制
//md5
public static String md5(String plainText) throws Exception {
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    //1. md5加密的数据可以直接放在digest中
    //2. digest是加密之后的数据,但是有不可见字符,不要使用hex或base64来展示
    md5.update(plainText.getBytes(StandardCharsets.UTF_8));
    byte[] digest = md5.digest();

    //1. 效果完全同上,update可以压入数据,区别是digest是一次性压入,update可以分批次压入
    //byte[] digest = md5.digest(plainText.getBytes(StandardCharsets.UTF_8));

    //使用hex和base64来表示加密之后的数据,因为直接加密的有不可见字符
    ByteString of = ByteString.of(digest);
    String hex = of.hex();
    String base64 = of.base64();
    return hex   "||"   base64;
}
示例

SHA

常用的是sha-1算法,所以本次演示的是sha-1算法。

sha-1算法,甚至来说消息摘要算法基本上api都是通用的。

只需要换一个algorithm即可,所以就不废话了。

SHA系列算法

算法

摘要长度

实现

SHA-1

160

Java6

SHA-256

256

Java6

SHA-384

384

Java6

SHA-512

512

Java6

SHA224

224

Bouncy Castle

代码
代码语言:javascript复制
//SHA-1
public static String sha_1(String plainText) throws Exception {
    MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
    sha1.update(plainText.getBytes(StandardCharsets.UTF_8));
    byte[] digest = sha1.digest();

    ByteString of = ByteString.of(digest);
    String hex = of.hex();
    String base64 = of.base64();
    return hex   "||"   base64;
}
示例

MAC

mac这个名字听着挺牛逼的,其实就是比md5和sha算法多了个密钥而已,不必大惊小怪。

MAC系列算法

算法

消息摘要

实现

HmacMD5

128

Java6

HmacSHA1

160

Java6

HmacSHA256

256

Java6

HmacSHA384

384

Java6

HmacSHA512

512

Java6

HmacMD2

128

Java6

HmacMD4

128

Bouncy Castle

HmacSHA224

224

Bouncy Castle

代码
代码语言:javascript复制
public static String mac(String plainText) throws Exception {
    //生成密钥
    SecretKeySpec hmacMD5 = new SecretKeySpec("123".getBytes(StandardCharsets.UTF_8), "HmacMD5");

    //hmacMD5.getAlgorithm()表示获取算法,此时获取的就是HmacMD5
    Mac instance = Mac.getInstance(hmacMD5.getAlgorithm());
    //同上
    //Mac instance = Mac.getInstance("HmacMD5");

    //初始化
    instance.init(hmacMD5);
    //压入数据
    instance.update(plainText.getBytes(StandardCharsets.UTF_8));
    byte[] doFinal = instance.doFinal();

    //同上
    //byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

    ByteString of = ByteString.of(doFinal);
    String hex = of.hex();
    String base64 = of.base64();
    return hex   "||"   base64;
}
示例

对称加密算法

虽然md5也叫加密算法,但是他是无法解密的,但是对称加密算法是可以进行加密和解密的,这就nice很多了。

因为加密和解密使用的密钥相同,所以叫做对称加密算法,那不同的,就是非对称咯!

注意了啊,对称加密算法的密钥是可以随便给的,但是有长度要求的,不是乱给的,但是加密的内容无限制。

各算法密钥长度

  • RC4 密钥长度1~256字节
  • DES 密钥长度8字节
  • 3DES/DESede/TripleDES 密钥长度24字节
  • AES 密钥长度16,24,32字节

根据密钥长度不同AES又分为AES-128,AES-192,AES-256

DES

ECB和CBC模式主要区别在于CBC模式需要一个iv向量!

DES算法
ECB模式加解密
代码
代码语言:javascript复制
//DES ECB 加密 Cipher
public static String des_encrypt_ECB(String plainText) throws Exception {
    //生成des所需要的key
    SecretKeySpec desKey = new SecretKeySpec("12345678".getBytes(StandardCharsets.UTF_8), "DES");
    //默认工作模式就是ECB,填充模式PKCS5Padding,
    //Cipher instance = Cipher.getInstance("DES");
    //也可以写全
    Cipher instance = Cipher.getInstance("DES/ECB/PKCS5Padding");
    //初始化,指定是加密模式还是解密模式和密钥
    instance.init(Cipher.ENCRYPT_MODE, desKey);
    //关于Cipher的update似乎有些问题,所以用doFinal的多
    //加密内容,返回结果
    byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

    ByteString of = ByteString.of(doFinal);
    String hex = of.hex();
    String base64 = of.base64();
    return hex   "||"   base64;
}

//DES ECB 解密
public static String des_decrypt_ECB(byte[] cipherBytes) throws Exception {
    //生成des所需要的key
    SecretKeySpec desKey = new SecretKeySpec("12345678".getBytes(StandardCharsets.UTF_8), "DES");
    Cipher instance = Cipher.getInstance("DES/ECB/PKCS5Padding");
    instance.init(Cipher.DECRYPT_MODE, desKey);
    byte[] doFinal = instance.doFinal(cipherBytes);
    return new String(doFinal);
}
//ECB
String des_encrypt_ECP = des_encrypt_ECB("zhangsan");
Log.d(TAG, "des加密,ECP模式:"   des_encrypt_ECP);
//加密拿到的des加密,ECP模式base结果为:AtLfLL8jc1n uVm31GQvyw==
byte[] bytes1 = ByteString.decodeBase64("AtLfLL8jc1n uVm31GQvyw==").toByteArray();
String s1 = des_decrypt_ECB(bytes1);
Log.d(TAG, "des解密,ECP模式:"   s1);
示例
CBC模式加解密

CBC模式就比ECB多了个iv向量而已,其他用法一样。

代码
代码语言:javascript复制
//DES CBC,需要iv向量
public static String des_encrypt_CBC(String plainText) throws Exception {
    SecretKeySpec desKey = new SecretKeySpec("12345678".getBytes(StandardCharsets.UTF_8), "DES");
    Cipher instance = Cipher.getInstance("DES/CBC/PKCS5Padding");
    //CBC需要iv向量
    IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
    //初始化时添加上iv向量
    instance.init(Cipher.ENCRYPT_MODE, desKey,ivParameterSpec);
    byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

    ByteString of = ByteString.of(doFinal);
    String hex = of.hex();
    String base64 = of.base64();
    return hex   "||"   base64;
}

//DES CBC 解密
public static String des_decrypt_CBC(byte[] cipherBytes) throws Exception {
    //生成des所需要的key
    SecretKeySpec desKey = new SecretKeySpec("12345678".getBytes(StandardCharsets.UTF_8), "DES");
    Cipher instance = Cipher.getInstance("DES/CBC/PKCS5Padding");
    IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
    instance.init(Cipher.DECRYPT_MODE, desKey,ivParameterSpec);
    byte[] doFinal = instance.doFinal(cipherBytes);
    return new String(doFinal);
}
示例

DESede(3DES/TripleDES)

DESede也分CBC和ECB,使用方法同上,这里将他们合二为一!

DESede算法
代码
代码语言:javascript复制
//DESede
public static String DESede_encrypt(String plainText) throws Exception {
    SecretKeySpec desKey = new SecretKeySpec("123456781234567812345678".getBytes(), "DESede");
    //ECB模式
    //        Cipher instance = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    //        instance.init(Cipher.ENCRYPT_MODE, desKey);
    //        byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

    //CBC模式需要iv向量
    Cipher instance = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
    //初始化时添加上iv向量
    instance.init(Cipher.ENCRYPT_MODE, desKey, ivParameterSpec);
    byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

    ByteString of = ByteString.of(doFinal);
    String hex = of.hex();
    String base64 = of.base64();
    return hex   "||"   base64;
}
//DESede
public static String DESede_decrypt(byte[] cipherBytes) throws Exception {
    //生成des所需要的key
    SecretKeySpec desKey = new SecretKeySpec("123456781234567812345678".getBytes(StandardCharsets.UTF_8), "DESede");
    //ECB模式
    //        Cipher instance = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    //        instance.init(Cipher.DECRYPT_MODE, desKey);
    //        byte[] doFinal = instance.doFinal(cipherBytes);

    //CBC模式
    Cipher instance = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
    instance.init(Cipher.DECRYPT_MODE, desKey,ivParameterSpec);
    byte[] doFinal = instance.doFinal(cipherBytes);
    return new String(doFinal);
}
//DESede
String deSede_encrypt = DESede_encrypt("zhangsan");
Log.d(TAG, "DESede加密:"   deSede_encrypt);
//AtLfLL8jc1n uVm31GQvyw==
byte[] bytes3 = ByteString.decodeBase64("3M7YukhZweaysZBNnqYLBw==").toByteArray();
String s3 = DESede_decrypt(bytes3);
Log.d(TAG, "DESede解密:"   s3);
示例

AES

AES算法是对称加密算法中最常用的算法!

AES也分CBC和ECB,这里也合二为一的!

AES算法
代码
代码语言:javascript复制
public static String AES_encrypt(String plainText) throws Exception {
    SecretKeySpec secretKeySpec = new SecretKeySpec("0123456789abcdef".getBytes(), "AES");
    //ECB模式
    Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");
    instance.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

    //CBC模式需要iv向量
    //        Cipher instance = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    //        IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
    //        //初始化时添加上iv向量
    //        instance.init(Cipher.ENCRYPT_MODE, desKey, ivParameterSpec);
    //        byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

    ByteString of = ByteString.of(doFinal);
    String hex = of.hex();
    String base64 = of.base64();
    return hex   "||"   base64;
}

public static String AES_decrypt(byte[] cipherBytes) throws Exception {
    //生成des所需要的key
    SecretKeySpec secretKeySpec = new SecretKeySpec("0123456789abcdef".getBytes(), "AES");
    //ECB模式
    Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");
    instance.init(Cipher.DECRYPT_MODE, secretKeySpec);
    byte[] doFinal = instance.doFinal(cipherBytes);

    //CBC模式
    //        Cipher instance = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    //        IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
    //        instance.init(Cipher.DECRYPT_MODE, desKey, ivParameterSpec);
    //        byte[] doFinal = instance.doFinal(cipherBytes);

    return new String(doFinal);
}
示例

非堆成加密算法

非堆成加密算法中,最常用最典型的加密算法就是RSA。原来说过,对称加密算法是因为加密解密用的是同一个密钥,但是非对称就不是了。

它需要一堆,称为公钥和私钥,当然,密钥不是随便写的!

在线密钥生成网站:http://web.chacuo.net/netrsakeypair

  • 公钥加密,私钥解密。
  • 私钥加密,公钥解密。
  • 一般公钥是公开的,私钥保密,私钥包含公钥。
  • 加密安全,但是性能差,加密长度有限制。
  • RSA可以用于加密解密,也可以用来数据签名。
  • Java中的私钥必须是pkcs8格式。

RSA

RSA算法
代码
代码语言:javascript复制
 //RSA
//解析公钥key并返回
public static PublicKey generatePublic(String publicKeyBase64) throws Exception {
    byte[] bytes = ByteString.decodeBase64(publicKeyBase64).toByteArray();
    X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(bytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePublic(x509EncodedKeySpec);
}

public static PrivateKey generatePrivate(String privateKeyBase64) throws Exception {
    byte[] bytes = ByteString.decodeBase64(privateKeyBase64).toByteArray();
    PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
}
//RSA 这里使用私钥解密
public static String RSAPrivateDecrypt(byte[] cipherBytes) throws Exception {
    String BEGIN_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMOVkFb2U8aOxLZrn"  
        "v/R/Vq/8 vB1fp4GnLLmBhH/g343Q5J6/9AVqbflgf9DRgzP/zBUoauRQnvfsUBtn"  
        "6NXKv3t2bkkAkA4ulCqk6 pxW/Zy03LyyADUtkBrDrTfGHqaw6vJSp0qjT56u563n"  
        "V0nOoUboUmj AIZRrzNEcwAKa7B1AgMBAAECgYB4oflDCe mGkzOTys4PIpVRe3on"  
        "/i84fM NsD6yPyz1XlS5NlAuIg5qNI63yOCd6nR1dN26mn tM8159dCUfNcY1W3Fn"  
        "JaTvBZKD5 6fDUKQ5UfHhlrd4rVxWKK kuhdYe67/Y6twrMzL/TE OXmn7jdxuq2n"  
        "Au93oa2kxraM6pGJCQJBAN/P ckCGRl26UraqzP3XwrVPq yGQUMb8y627MXwVJJn"  
        "LsE3c9vuoDkm79rYN8jCXbxSkUbBpxopHYfdSxT/Dt8CQQDftlI8PZXDzJLlJAmmn"  
        "LynoC7OO52sdC PoqndJ04DDjo1rg6fcWaaIXFmOL/WTn5HJt8pa4r7vi54DChZ7n"  
        "ju8rAkBUBUSVdGctyxk7k6mv4Y7Zh0J4PNjtr0SNTBzMN//IP1cBDCs/hm655ecnn"  
        "dgJDKMx9tVV6hZqQ1JyUc7wLDtFrAkB1s6ZmvXw7jTnIR4KwJeZliSqKyGVJ3gSmn"  
        "WHH0rMv1l93 MEG0JJMC8ZvIvKD3b6Azwng8A0q0HAAh1z/m FgLAkEA0PahyHnXn"  
        "ZCzB5ic4QvkiKCqZ SyibYXOGxBGyCXkuirCwqrtaEorrFxgNEssdpHcEmk71 nvn"  
        "gvrL5QkvgcLvMA==";
    PrivateKey privateKey = generatePrivate(BEGIN_PRIVATE_KEY);
    Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    instance.init(Cipher.DECRYPT_MODE,privateKey);
    byte[] doFinal = instance.doFinal(cipherBytes);

    return new String(doFinal);
}
//RSA 使用公钥加密
public static String RSAPublicEncrypt(String plainText) throws Exception {
    String BEGIN_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDlZBW9lPGjsS2a7/0f1av/Prwn"  
        "dX6eBpyy5gYR/4N N0OSev/QFam35YH/Q0YMz/8wVKGrkUJ737FAbejVyr97dm5Jn"  
        "AJAOLpQqpOvqcVv2ctNy8sgA1LZAaw603xh6msOryUqdKo0 eruet1dJzqFG6FJon"  
        "/gCGUa8zRHMACmuwdQIDAQAB";
    PublicKey publicKey = generatePublic(BEGIN_PUBLIC_KEY);
    Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    instance.init(Cipher.ENCRYPT_MODE,publicKey);
    byte[] doFinal = instance.doFinal(plainText.getBytes());

    ByteString of = ByteString.of(doFinal);
    return of.base64();
}
 //RSA
//加密
String rsaPublicEncrypt = RSAPublicEncrypt("zhangsan");
Log.d(TAG, "RSA加密:"   rsaPublicEncrypt);
//解密
byte[] bytes5 = ByteString.decodeBase64(rsaPublicEncrypt).toByteArray();
String rsaPrivateDecrypt = RSAPrivateDecrypt(bytes5);
Log.d(TAG, "RSA解密:"   rsaPrivateDecrypt);
示例

总结

本文讲述的加密算法主要分为三大类,也是最常用的几个加密算法。

  • 消息摘要算法(MD5,SHA1,MAC)
  • 对称加密算法(DES,DESede,AES)
  • 非堆成加密算法(RSA)

经过比较发现,在Java中加密算法有几大特点

  • 通过MessageDigest类生成的算法有MD5,SHA1
  • 通过Mac类生成的算法有MAC
  • 通过Cipher生成的算法有DES,DESede,AES,RSA

嗯,似乎你不太懂什么意思,意思就是可以通过类反推算法。

这样就可以完成自吐算法了,什么算法直接都一把梭哈了,后面再讲!

如果在操作过程中有任何问题,记得下面留言,我们看到会第一时间解决问题。

越努力,越幸运。

我是码农星期八,如果觉得还不错,记得动手点赞一下哈。

感谢你的观看。

最后需要CryptologyDemo.zip文件的小伙伴们,可以私我获取。

小伙伴们,快快用实践一下吧!

------------------- End -------------------

0 人点赞