RE常见算法

[TOC] 主要是参考了 这篇博客

1. 古典加密算法

caesar: 凯撒密码

凯撒密码的加密、解密可以通过取模的加减法进行计算。首先将字母用数字替代 A = 0,B = 1, …, Z = 25。 当偏移量为n的时候加密方法是:c=m+n mod26 解密方法是:m=c−n mod26

key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
shift = 3

def encrypt_caesar(plaintext, shift):
    ciphertext = ''
    for char in plaintext:
        if char in key:
            ciphertext += key[(key.index(char) + shift) % 26]
        else:
            ciphertext += char
    return ciphertext

def decrypt_caesar(ciphertext, shift):
    return encrypt_caesar(ciphertext, -shift)


data = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"
encrypt = encrypt_caesar(data, shift)
print(encrypt)
print(decrypt_caesar(encrypt,shift))

vigenere

viginere加密是从caesar引申而来的加密方式:ci=mi+ki (mod26) 其实是把固定的值n 替换成了一组密钥k,解密方式:mi=ci−ki (mod26)

alpha = 'abcdefghijklmnopqrstuvwxyz'
key = 'hhhhh'

def encrypt_vigenere(plain_text, key):
    encrypted_text = ''
    key_length = len(key)
    key_index = 0
    for char in plain_text:
        if char in alpha:
            shift = alpha.index(key[key_index])
            encrypted_text += alpha[(alpha.index(char) + shift) % 26]
            key_index = (key_index + 1) % key_length
        else:
            encrypted_text += char
    return encrypted_text

def decrypt_vigenere(encrypted_text, key):
    decrypted_text = ''
    key_length = len(key)
    key_index = 0
    for char in encrypted_text:
        if char in alpha:
            shift = alpha.index(key[key_index])
            decrypted_text += alpha[(alpha.index(char) - shift) % 26]
            key_index = (key_index + 1) % key_length
        else:
            decrypted_text += char
    return decrypted_text

data = "attackatdawn"
encrypted_data = encrypt_vigenere(data, key)    
print(encrypted_data)
decrypted_data = decrypt_vigenere(encrypted_data, key)
print(decrypted_data)

2. base系列

如果在程序中出现了base64的索引表,大概率是用了base64,有些人可能会对base64的表进行部分更换,问题也不大。

import base64

origin_charset = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
custom_charset = b"0123456789ABCMtuvwxNOPQRabcdefghijklSTUVWXDEFGHIJKLYZmnopqrsyz+/"
#custom_charset = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def base64_encode(data):
    return base64.b64encode(data).translate(data.maketrans(origin_charset, custom_charset))

def base64_decode(data):
    return base64.b64decode(data.translate(data.maketrans(custom_charset, origin_charset)))

data = b"attackatdawn"
# print(data.maketrans(origin_charset, custom_charset))
# print(data.maketrans(custom_charset, origin_charset))
encoded_data = base64_encode(data)
print(encoded_data)
decoded_data = base64_decode(encoded_data)
print(decoded_data)

import base64
#输入的数据必须是比特流
s = b'aaaaa'
enc = base64.b32encode(s)
print(enc)
print(base64.b32decode(enc))

3. TEA及其变种

参考博客 关于TEA算法的识别,如果程序中出现了固定常数0x9e377969/0x61c88647,那么很有可能是tea加密或其变种

TEA

#include <stdio.h>  
#include <stdint.h>  
  
//加密函数  
void encrypt (uint32_t* v, uint32_t* k) {  
    uint32_t v0=v[0], v1=v[1], sum=0, i;//明文          
    uint32_t delta=0x9e3779b9;//delta常数                    
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];//密钥 
    for (i=0; i < 32; i++) {//进行32轮加密                       
        sum += delta;  
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);  
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
    }//加密函数主体                                              
    v[0]=v0; v[1]=v1;//置换  
}

//解密函数  
void decrypt (uint32_t* v, uint32_t* k) {  
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;//密文,此时sum=delta*32
    uint32_t delta=0x9e3779b9;                      
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   
    for (i=0; i<32; i++) {                        
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);  
        sum -= delta;  
    }//解密函数主体 ,倒过来写即可                                          
    v[0]=v0; v[1]=v1;//置换  
}  
  
int main()  
{  
    uint32_t v[2]={1,2},k[4]={2,2,3,4};  
    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    printf("加密前原始数据:%u %u\n",v[0],v[1]);  
    encrypt(v, k);  
    printf("加密后的数据:%u %u\n",v[0],v[1]);  
    decrypt(v, k);  
    printf("解密后的数据:%u %u\n",v[0],v[1]);  
    return 0;  
}  

XTEA

  • 也是分成两组,但是把密钥和sum值关联起来,使得对v[0]和v[1]加密的时候每一轮所用的密钥也不一样,增强了加密算法的安全性。其中sum[i-1]为本轮加密未加delta时的sum值,sum[i]为加上delta的sum值。
#include <stdio.h>  
#include <stdint.h>  
  
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {  
    unsigned int i;  
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;  
    for (i=0; i < num_rounds; i++) {  
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
        sum += delta;  
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
    }  
    v[0]=v0; v[1]=v1;  
}  
  
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {  
    unsigned int i;  
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;  
    for (i=0; i < num_rounds; i++) {  
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
        sum -= delta;  
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
    }  
    v[0]=v0; v[1]=v1;  
}  
  
int main()  
{  
    uint32_t v[2]={1,2};  
    uint32_t const k[4]={2,2,3,4};  
    unsigned int r=32;//num_rounds建议取值为32  
    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    printf("加密前原始数据:%u %u\n",v[0],v[1]);  
    encipher(r, v, k);  
    printf("加密后的数据:%u %u\n",v[0],v[1]);  
    decipher(r, v, k);  
    printf("解密后的数据:%u %u\n",v[0],v[1]);  
    return 0;  
}  

XXTEA

#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
//一个混淆操作,根据密码学的扩散原理,让算法更安全,同时也是xxtea的特征之一 
void xxtea(uint32_t *v, int n, uint32_t const key[4]){
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    //n是明文长度,sum对应图中的D,p对应图中的密钥下标索引,e是图中的D>>2

    /* Coding Part */
    if (n > 1) {
        rounds = 6 + 52/n;//循环轮数
        sum = 0;
        z = v[n-1];
        do{
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p=0; p<n-1; p++){
                y = v[p+1];
                z = v[p] += MX;//本质上还是双整形加密,用v[p]和v[p+1]对v[p]加密
                /*
                v[p] += MX;
                z = v[p];
                */
            }
            y = v[0];
            z = v[n-1] += MX;//一轮加密的最后用v[n-1]和v[0]对v[n-1]加密
        }
        while (--rounds);
    }
    else if (n < -1)/* Decoding Part */{
        n = -n;
        rounds = 6 + 52/n;
        sum = rounds*DELTA;
        y = v[0];
        do{
            e = (sum >> 2) & 3;
            for (p=n-1; p>0; p--){
                z = v[p-1];
                y = v[p] -= MX;
            }
            z = v[n-1];
            y = v[0] -= MX;
            sum -= DELTA;
        }
        while (--rounds);
    }
}
 
int main()
{
    uint32_t v[2]= {1,2};
    uint32_t const k[4]= {2,2,3,4};
    int n= 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密
    // v为要加密的数据是两个32位无符号整数
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    printf("%#10x %#10x\n",v[0],v[1]);
    xxtea(v, n, k);//n>0为加密
    printf("%#10x %#10x\n",v[0],v[1]);
    xxtea(v, -n, k);//n<0为解密
    printf("%#10x %#10x\n",v[0],v[1]);
    return 0;
}
#通过pip install xxtea-py安装后可以调用
import xxtea
text = "Hello World!"
key = "1234567890"
encrypt_data = xxtea.encrypt(text, key)
decrypt_data = xxtea.decrypt_utf8(encrypt_data, key)
print(text == decrypt_data)

4. RC4

参考博客

  • 在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法

  • 识别方式为,初始代码中会对大小为256的表进行赋值和交换操作

  • RC4算法是可逆的,即encrypt和decrypt是一样的。

  • python中的使用

from Crypto.Cipher import ARC4

key=b"keykeykey"
plain =b"ctf_is_fun"

rc4 = ARC4.new(key)
cipher = rc4.encrypt(plain)
print(cipher)
# 注意,使用RC4时只能加密一次,如果要解密,需要重新初始化RC4对象
rc4 = ARC4.new(key)
dec = rc4.decrypt(cipher)
print(dec)
  • 算法原理
  • 用C实现
#include<stdio.h>
#include<string.h>
 
#define SBOX_LEN 256
 
#define rc4_encrypt rc4_crypt
#define rc4_decrypt rc4_crypt
 
static inline void swap_uchar(unsigned char *puc_x, unsigned char *puc_y)
{
    *puc_x = *puc_x ^ *puc_y;
    *puc_y = *puc_x ^ *puc_y;
    *puc_x = *puc_x ^ *puc_y;
}
 
void hexdump(unsigned char *puc_data, int length)
{
    int i = 0;
 
    for (i = 0; i < length; i++) {
        printf("%02X", puc_data[i]);
        if (i && (i + 1) % 16 == 0) {
            putchar('\n');
        }
    }
    printf("\n");
}
 
/**
 * 利用Key生成S盒
 * the Key-Scheduling Algorithm
 */
static void rc4_ksa(unsigned char *puc_sbox, unsigned char *puc_key, int key_length)
{
    int i = 0;
    int j = 0;
    char tmp[SBOX_LEN] = {0};
 
    for (i = 0; i < SBOX_LEN; i++) {
        puc_sbox[i] = i;
        tmp[i] = puc_key[i % key_length];
    }
 
    for (i = 0; i < SBOX_LEN; i++) {
        j = (j + puc_sbox[i] + tmp[i]) % SBOX_LEN;
        swap_uchar(&puc_sbox[i], &puc_sbox[j]); //交换puc_sbox[i]和puc_sbox[j]
    }
}
 
/**
 * 利用S盒生成密钥流
 * The pseudo-random generation algorithm(PRGA)
 */
static void rc4_prga(unsigned char *puc_sbox, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
    int i = 0;
    int j = 0;
    int t = 0;
    unsigned long k = 0;
 
    for (k = 0; k < ul_data_length; k++) {
        i = (i + 1) % SBOX_LEN;
        j = (j + puc_sbox[i]) % SBOX_LEN;
        swap_uchar(&puc_sbox[i], &puc_sbox[j]);
        t = (puc_sbox[i] + puc_sbox[j]) % SBOX_LEN;
        /* 为了更清晰理解rc4算法流程,此处保存keystream,不直接进行XOR运算 */
        puc_key_stream[k] = puc_sbox[t];
    }
}
 
/* 加解密 */
void rc4_crypt(unsigned char *puc_data, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
    unsigned long i = 0;
 
    /* 把PRGA算法放在加解密函数中可以不需要保存keystream */
    for (i = 0; i < ul_data_length; i++) {
        puc_data[i] ^= puc_key_stream[i];
    }
}
 
int main(int argc, char *argv[])
{
    unsigned char sbox[SBOX_LEN] = {0};
    char key[SBOX_LEN] = {"abcdefghijklmnopqrstuvwxyz"}; //秘钥内容随便定义
    char data[512] = "lsRJ@.0 lvfvr#9527";
    unsigned char puc_keystream[512] = {0};
    unsigned long ul_data_length = strlen(data);
 
    printf("key=%s, length=%d\n\n", key, strlen(key));
    printf("Raw data string:%s\n", data);
    printf("Raw data hex:\n");
    hexdump(data, ul_data_length);
 
    /* 生成S-box */
    rc4_ksa(sbox, (unsigned char *)key, strlen(key));
 
    /* 生成keystream并保存,S-box也会被更改 */
    rc4_prga(sbox, puc_keystream, ul_data_length);
 
    printf("S-box final status:\n");
    hexdump(sbox, sizeof(sbox));
 
    printf("key stream:\n");
    hexdump(puc_keystream, ul_data_length);
 
    /* 加密 */
    rc4_encrypt((unsigned char*)data, puc_keystream, ul_data_length);
 
    printf("cipher hexdump:\n");
    hexdump(data, ul_data_length);
 
    /* 解密 */
    rc4_decrypt((unsigned char*)data, puc_keystream, ul_data_length);
 
    printf("decypt data:%s\n", data);
 
    return 0;
}
  • 用python实现
def KSA(key):
    key_length = len(key)
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % key_length]) % 256
        S[i], S[j] = S[j], S[i]
    return S

def PRGA(S, data_length):
    i = 0
    j = 0
    keystream = []
    for _ in range(data_length):
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        K = S[(S[i] + S[j]) % 256]
        keystream.append(K)
    return keystream

def rc4(key, data):
    key = [ord(c) for c in key]
    S = KSA(key)
    keystream = PRGA(S, len(data))
    return [c ^ k for c, k in zip(data, keystream)]

# Example usage
enc = ['\u000E', 'î', '=', 's', '0', 'Ö', 'Í', '\u0012', 'Ð', 'Ý', '\f', 'k', '!', '³', '\u0005', '\\', '×', '§', 'º', '\u008A', 'ã', '\u008D', 'B', '>', '-', 'G', 'Ê', '<', '1', 'G', 'Æ', 'z', 'í', 'h', 'Ò', 'V', '\u0086', 'Ú', '\u009C', '\u000F']
enc = [ord(enc[i]) for i in range(len(enc))]
key = "truelove2u"

# Perform RC4 decryption
decrypted = rc4(key, enc)

# Convert decrypted values to characters
decrypted_message = ''.join([chr(c) for c in decrypted])

print("Decrypted message:", decrypted_message)

5. AES

对aes的识别首先需要知道AES加密的步骤。 首先是根据key生成轮密钥。

1 初始化:即 明文 和 密钥 作异或 前9轮:

一.字节替换(SubBytes): 用s盒对 输入进行字节替换 二.行移位(ShiftRows):输入化成4 * 4矩阵,第i行循环左移i个字节(i=0,1,2,3) 三.列混淆(MixColumns):输入化成4 * 4矩阵,乘以固定的矩阵 四.轮密钥加(AddRoundKey):输入与轮密钥矩阵异或

第10轮: 字节替换、行移位、轮密钥加

因此如果代码中发现了s盒(s盒可以参加仓库的aes的c代码),可以判断是aes加密,具体模式需要自己判断

  • 以AES ECB模式为例
from Crypto.Cipher import AES

key = b'1234567890123456'
aes = AES.new(key, AES.MODE_ECB)

# Encrypt
data = b'Hello, world!!!!'
encrypt=aes.encrypt(data)
print(encrypt)

# decrypt
decrypt=aes.decrypt(encrypt)
print(decrypt)