前语

假如要逆向做一些模仿恳求,加密算法是绕不过去的坎。曾经逆向一个app更多的是破解一些单机的app一般只涉及到一些重打包之类的,现在看更多的是获取到里面的恳求加密算法然后经过python完成一遍进而能够用机器替代人工去恳求去完成一些有商业价值的工作。所以假如了解加密算法的话看逆向的代码会愈加称心如意。

下面的每个算法都会用java和python代码完成一遍。

算法简介

  1. 对称加密算法:在对称加密算法中,加密宽和密运用相同的密钥。常见的对称加密算法有AES、DES、3DES等。
  2. 非对称加密算法:在非对称加密算法中,加密宽和密运用不同的密钥。常见的非对称加密算法有RSA、DSA、ECC等。
  3. 音讯摘要算法:音讯摘要算法能够将恣意长度的音讯压缩成固定长度的摘要。常见的音讯摘要算法有MD5、SHA-1、SHA-256等。
  4. 散列函数:散列函数是一种将恣意长度的数据映射到固定长度的数据的函数。常见的散列函数有SHA-1、SHA-256等。
  5. 数字签名算法:数字签名算法能够用于验证音讯的完整性和身份认证。常见的数字签名算法有RSA、DSA、ECDSA等。

这些加密算法在核算机安全领域中被广泛运用,用于维护数据的机密性、完整性和可用性。

系列文章

  1. 逆向-加密算法总结(1)
  2. 逆向-加密算法总结(2)

音讯摘要算法

这种算法是不行逆的,只能经过运用相同的加密方式比照是否共同,一般用于生成签名或许登录密码

步骤都是类似

  1. 第一步拿到加密器
  2. 第二步update原始数据
  3. 第三步经过加密器供给的方法拿到加密后的摘要
  4. 把摘要转成16进制字符串或许base64字符串

MD5

MD5的核算速度比SHA-1要快,而SHA-256的核算速度比MD5要慢,SHA-512的核算速度则更慢。由于长度只要128位,所以仍是有安全性问题,建议运用SHA256安全性更高。

代码完成
  • java
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Md5Util {
    // 将字符串进行MD5加密
    public static String md5To16StringBuilder(String str, Boolean isComplete) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(str.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                // 是否补齐,这里要注意,输出成果是不一样的
                // 补齐:25d55ad283aa400af464c76d713c07ad
                // 不补齐:25d55ad283aa40 af464c76d713c 7ad
                if (isComplete){
                    sb.append(String.format("%02x", b));
                }else{
                    sb.append(String.format("%2x", b));
                }
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5加密失利", e);
        }
    }
    // 另外一种写法,他人怎样写都有可能,所以要了解,但是用python还原的时候一般就用16进制或许base64转就行
    public static String md5To16Byte(String input) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5加密失利", e);
        }
        // 将MD5摘要转换为一个16进制字符串
        byte[] messageDigest = md.digest(input.getBytes());
        // 为MD5算法生成的哈希值是128位的二进制数,所以需要BigInteger或许StringBuilder。
        // 第一个参数是正负数,1为正,0为负。md5的摘要是疏忽符号的没有负数。这个值会依据内容多而变长
        BigInteger no = new BigInteger(1, messageDigest);
        String hashText = no.toString(16);
        // System.out.println("hashText:" + hashText+"---"+(hashText.length() < 32)+"---"+no);
        while (hashText.length() < 32) {
            // 缺乏32位,在前面补0
            // System.out.println("hashText.while=:" + hashText);
            hashText = "0" + hashText;
        }
        return hashText;
    }
    public static String md5To16ByteToBase64(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : messageDigest) {
                sb.append(String.format("%02x", b));
            }
            String md5Hex = sb.toString();
            byte[] base64EncodedBytes = Base64.getEncoder().encode(md5Hex.getBytes());
            String base64EncodedStr = new String(base64EncodedBytes);
            return base64EncodedStr;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not found");
        }
    }
    public static String md5Base64Hash(String input) {
        try {
            // 创立一个MD5目标
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 更新MD5目标的二进制数据
            byte[] messageDigest = md.digest(input.getBytes("UTF-8"));
            // 将二进制数据转化为base64字符串
            byte[] base64EncodedBytes = Base64.getEncoder().encode(messageDigest);
            String base64EncodedStr = new String(base64EncodedBytes, "UTF-8");
            return base64EncodedStr;
        } catch (Exception e) {
            throw new RuntimeException("MD5 algorithm not found");
        }
    }
    // 测试
    public static void main(String[] args) {
        String str = "12345678";
        System.out.println("原始字符串:" + str);
        System.out.println("md5To16StringBuilder 加密后字符串, 非补齐:" + md5To16StringBuilder(str,false));
        System.out.println("md5To16StringBuilder 加密后字符串:" + md5To16StringBuilder(str,true));
        System.out.println("md5To16Byte 加密后字符串:" + md5To16Byte(str));
        System.out.println("md5Base64Hash 加密后字符串:" + md5Base64Hash(str));
        System.out.println("md5To16ByteToBase64 加密后字符串:" + md5To16ByteToBase64(str));
    }
}

输出成果

原始字符串:12345678
md5To16StringBuilder 加密后字符串, 非补齐:25d55ad283aa40 af464c76d713c 7ad
md5To16StringBuilder 加密后字符串:25d55ad283aa400af464c76d713c07ad
md5To16Byte 加密后字符串:25d55ad283aa400af464c76d713c07ad
md5Base64Hash 加密后字符串:JdVa0oOqQAr0ZMdtcTwHrQ==
md5To16ByteToBase64 加密后字符串:MjVkNTVhZDI4M2FhNDAwYWY0NjRjNzZkNzEzYzA3YWQ=
  • python
import hashlib
import base64
def md5_hash(input_str,is_complete):
    # 创立一个md5目标
    m = hashlib.md5()
    # 更新md5目标的二进制数据
    m.update(input_str.encode('utf-8'))
    # 获取MD5摘要,成果是二进制数据
    md5_binary = m.digest()
    # 将二进制数据转化为十六进制字符串
    if is_complete:
        md5_hex_str = ''.join(format(b, '02x') for b in md5_binary)
    else:
        md5_hex_str = ''.join(format(b, '2x') for b in md5_binary)
    return md5_hex_str
def md5_base64_hash(input_str):
    # 创立一个md5目标
    m = hashlib.md5()
    # 更新md5目标的二进制数据
    m.update(input_str.encode('utf-8'))
    # 获取MD5摘要,成果是二进制数据
    md5_binary = m.digest()
    # 将二进制数据转化为base64字符串
    md5_base64_str = base64.b64encode(md5_binary).decode('utf-8')
    return md5_base64_str
def md5_to_base64(input_str):
    # 创立一个md5目标
    m = hashlib.md5()
    # 更新md5目标的二进制数据
    m.update(input_str.encode('utf-8'))
    # 获取MD5摘要,成果是二进制数据
    md5_binary = m.digest()
    # 将二进制数据转化为十六进制字符串
    md5_hex_str = ''.join(format(b, '02x') for b in md5_binary)
    # 将十六进制字符串编码成字节码
    md5_bytes = md5_hex_str.encode('utf-8')
    # 运用base64进行编码
    base64_encoded_bytes = base64.b64encode(md5_bytes)
    # 将字节码解码成字符串并回来
    return base64_encoded_bytes.decode('utf-8')
if __name__ == '__main__':
    input = '12345678'
    print('原始数据:', input)
    print('转16进制加密后补齐:', md5_hash(input,True))
    print('转16进制加密后不补齐:', md5_hash(input,False))
    print('转Base64进制加密后:', md5_base64_hash(input))
    print('转16进制再转Base64进制加密后:', md5_to_base64(input))

输出成果

原始数据: 12345678
转16进制加密后补齐: 25d55ad283aa400af464c76d713c07ad
转16进制加密后不补齐: 25d55ad283aa40 af464c76d713c 7ad
转Base64进制加密后: JdVa0oOqQAr0ZMdtcTwHrQ==
转16进制再转Base64进制加密后: MjVkNTVhZDI4M2FhNDAwYWY0NjRjNzZkNzEzYzA3YWQ=
注意事项
  1. 逆向时哪怕混杂也会看到有md5的字样,要注意他人是怎样完成的,是16进制仍是base64仍是组合完成。
// java
// 得到md5加密的摘要之后,下面能够转16进制也能够转base64
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(str.getBytes());
...
// 将二进制数据转化为base64字符串
byte[] base64EncodedBytes = Base64.getEncoder().encode(bytes);
// 转16进制
StringBuilder sb = new StringBuilder();
for (byte b : messageDigest) {
    sb.append(String.format("%02x", b));
}
// Python
# 创立一个md5目标0-更新md5目标的二进制数据-获取MD5摘要,成果是二进制数据
md5_binary = hashlib.md5().update(input_str.encode('utf-8')).digest()
# 将二进制数据转化为base64字符串
md5_base64_str = base64.b64encode(md5_binary).decode('utf-8')
# 将二进制数据转化为十六进制字符串
 md5_hex_str = ''.join(format(b, '02x') for b in md5_binary)
  1. 假如是16进制需要看有没有做补齐的操作
// java
if (isComplete){
    sb.append(String.format("%02x", b));
}else{
    sb.append(String.format("%2x", b));
}
// python
    # 将二进制数据转化为十六进制字符串
    if is_complete:
        md5_hex_str = ''.join(format(b, '02x') for b in md5_binary)
    else:
        md5_hex_str = ''.join(format(b, '2x') for b in md5_binary)
  1. 一般这种加密还会加盐处理,这种就不在讨论的领域了,依据逆向看到的成果加了什么自己拼上去就好

SHA1和SHA256

SHA-1是一种160位的哈希算法,而SHA-256是一种256位的哈希算法,因而SHA-256的摘要比SHA-1更长,摘要空间更大,磕碰概率更小。此外,SHA-256相对于SHA-1还具有更好的安全性,由于它具有更高的安全强度。同样的他们能够转成16进制输出也能够转成base64输出,下面是代码完成

  • java
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class HashUtil {
    /**
     * 核算SHA-1哈希值,并以16进制编码的方式进行输出
     *
     * @param input 输入字符串
     * @return SHA-1哈希值的16进制编码字符串
     * @throws NoSuchAlgorithmException 当指定的算法不行用时抛出此反常
     */
    public static String sha1ToHex(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] hashBytes = md.digest(input.getBytes());
        StringBuilder sb = new StringBuilder();
        for (byte b : hashBytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    /**
     * 核算SHA-1哈希值,并以Base64编码的方式进行输出
     *
     * @param input 输入字符串
     * @return SHA-1哈希值的Base64编码字符串
     * @throws NoSuchAlgorithmException 当指定的算法不行用时抛出此反常
     */
    public static String sha1ToBase64(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] hashBytes = md.digest(input.getBytes());
        return Base64.getEncoder().encodeToString(hashBytes);
    }
    /**
     * 核算SHA-256哈希值,并以16进制编码的方式进行输出
     *
     * @param input 输入字符串
     * @return SHA-256哈希值的16进制编码字符串
     * @throws NoSuchAlgorithmException 当指定的算法不行用时抛出此反常
     */
    public static String sha256ToHex(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = md.digest(input.getBytes());
        StringBuilder sb = new StringBuilder();
        for (byte b : hashBytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    /**
     * 核算SHA-256哈希值,并以Base64编码的方式进行输出
     *
     * @param input 输入字符串
     * @return SHA-256哈希值的Base64编码字符串
     * @throws NoSuchAlgorithmException 当指定的算法不行用时抛出此反常
     */
    public static String sha256ToBase64(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = md.digest(input.getBytes());
        return Base64.getEncoder().encodeToString(hashBytes);
    }
    public static void main(String[] args) throws NoSuchAlgorithmException {
        String input = "hello world";
        System.out.println("SHA-1 in hex: " + HashUtil.sha1ToHex(input));
        System.out.println("SHA-1 in base64: " + HashUtil.sha1ToBase64(input));
        System.out.println("SHA-256 in hex: " + HashUtil.sha256ToHex(input));
        System.out.println("SHA-256 in base64: " + HashUtil.sha256ToBase64(input));
    }
}

输出

SHA-1 in hex: 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
SHA-1 in base64: Kq5sNclPz7QV2+lfQIuc6R7oRu0=
SHA-256 in hex: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
SHA-256 in base64: uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=
  • python
import hashlib
import base64
def sha1_hex_hash(input_str):
    m = hashlib.sha1()
    m.update(input_str.encode('utf-8'))
    return m.hexdigest()
def sha1_base64_hash(input_str):
    m = hashlib.sha1()
    m.update(input_str.encode('utf-8'))
    return base64.b64encode(m.digest()).decode('utf-8')
def sha256_hex_hash(input_str):
    m = hashlib.sha256()
    m.update(input_str.encode('utf-8'))
    return m.hexdigest()
def sha256_base64_hash(input_str):
    m = hashlib.sha256()
    m.update(input_str.encode('utf-8'))
    return base64.b64encode(m.digest()).decode('utf-8')
def main():
    input_str = 'hello world'
    print('SHA-1 Hex Hash: ', sha1_hex_hash(input_str))
    print('SHA-1 Base64 Hash: ', sha1_base64_hash(input_str))
    print('SHA-256 Hex Hash: ', sha256_hex_hash(input_str))
    print('SHA-256 Base64 Hash: ', sha256_base64_hash(input_str))
if __name__ == '__main__':
    main()

输出成果

SHA-1 Hex Hash:  2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
SHA-1 Base64 Hash:  Kq5sNclPz7QV2+lfQIuc6R7oRu0=
SHA-256 Hex Hash:  b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
SHA-256 Base64 Hash:  uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=
注意事项
  1. 逆向是肯定也是会有SHA的字样,由于这个也是获取加密器时要求写的key。其他的就跟md5类似了
// java
MessageDigest md = MessageDigest.getInstance("SHA-1");
MessageDigest md = MessageDigest.getInstance("SHA-256");
// python
hashlib.sha1()
hashlib.sha256()