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)