gtxyzz

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

gtxyzz 安全防护 2023-01-15 353浏览 0

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

为什么要学习加密算法

在搞逆向进行抓包的时候,可以经常发现一些莫名其妙的字符串,可能是81dc9bdb52d04dc20036dbd8313ed055等之类的一长串字符,这些是怎么生成呢? 这些其实就是加密,加密算法主要分为两大类

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

标准加密算法在任何语言中的实现,结果都是一样的。 是应该是一样的,也可能不一样,如果不一样,说明更改了标准算法的某些变量,但是这种情况比较少。 非标准算法那就是自己写的了,这就具有很大的不确定性了,全靠程序员发挥! 注意:

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

常用标准算法有哪些?

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

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

我的环境

AndroidStudio 2020.3.1版本
Jdk 8版本

项目

CryptologyDemo.zip

Hex和Base64

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

添加依赖

api 'com.squareup.okhttp3:okhttp:3.10.0'

记得点击Sync Now。 盘点几个安卓逆向之常用加密算法

Hex

Hex编码是一种用16个字符(0-9 a-f)表示任意二进制数据的方法! 它是一种编码,而非加密! Hex主要应用在MD5等加密表现形式上。

代码

//从字符串到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,因为可承载的数据很多!

代码

//从字符串到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

代码

//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

代码

//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

代码

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模式加解密

代码

//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向量而已,其他用法一样。

代码

//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);

示例

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

DESede(3DES/TripleDES)

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

DESede算法

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

代码

//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算法

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

代码

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算法

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

代码

//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 = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMOVkFb2U8aOxLZr\n" +
        "v/R/Vq/8+vB1fp4GnLLmBhH/g343Q5J6/9AVqbflgf9DRgzP/zBUoauRQnvfsUBt\n" +
        "6NXKv3t2bkkAkA4ulCqk6+pxW/Zy03LyyADUtkBrDrTfGHqaw6vJSp0qjT56u563\n" +
        "V0nOoUboUmj+AIZRrzNEcwAKa7B1AgMBAAECgYB4oflDCe+mGkzOTys4PIpVRe3o\n" +
        "/i84fM+NsD6yPyz1XlS5NlAuIg5qNI63yOCd6nR1dN26mn+tM8159dCUfNcY1W3F\n" +
        "JaTvBZKD5+6fDUKQ5UfHhlrd4rVxWKK+kuhdYe67/Y6twrMzL/TE+OXmn7jdxuq2\n" +
        "Au93oa2kxraM6pGJCQJBAN/P+ckCGRl26UraqzP3XwrVPq+yGQUMb8y627MXwVJJ\n" +
        "LsE3c9vuoDkm79rYN8jCXbxSkUbBpxopHYfdSxT/Dt8CQQDftlI8PZXDzJLlJAmm\n" +
        "LynoC7OO52sdC+PoqndJ04DDjo1rg6fcWaaIXFmOL/WTn5HJt8pa4r7vi54DChZ7\n" +
        "ju8rAkBUBUSVdGctyxk7k6mv4Y7Zh0J4PNjtr0SNTBzMN//IP1cBDCs/hm655ecn\n" +
        "dgJDKMx9tVV6hZqQ1JyUc7wLDtFrAkB1s6ZmvXw7jTnIR4KwJeZliSqKyGVJ3gSm\n" +
        "WHH0rMv1l93+MEG0JJMC8ZvIvKD3b6Azwng8A0q0HAAh1z/m+FgLAkEA0PahyHnX\n" +
        "ZCzB5ic4QvkiKCqZ+SyibYXOGxBGyCXkuirCwqrtaEorrFxgNEssdpHcEmk71+nv\n" +
        "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/Prw\n" +
        "dX6eBpyy5gYR/4N+N0OSev/QFam35YH/Q0YMz/8wVKGrkUJ737FAbejVyr97dm5J\n" +
        "AJAOLpQqpOvqcVv2ctNy8sgA1LZAaw603xh6msOryUqdKo0+eruet1dJzqFG6FJo\n" +
        "/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

嗯,似乎你不太懂什么意思,意思就是可以通过类反推算法。 这样就可以完成自吐算法了,什么算法直接都一把梭哈了,后面再讲! 如果在操作过程中有任何问题,记得下面留言,我们看到会第一时间解决问题。

继续浏览有关 安全 的文章
发表评论