常见逆向加解密整合

# preface:小做一点整理

# 流密码

# RC4

魔改的点一般就是在里面加别的操作吧,异或之类的

class RC4:
    def __init__(self, key) -> None:
        self.key = key
        self.S = 0
        self.__rc4_init__()
    def __rc4_init__(self):
        S = [i for i in range(256)]
        j = 0
        for i in range(256):
            j = (j + S[i] + key[i % len(key)]) % 256
            S[i], S[j] = S[j], S[i]
        self.S = S
    def rc4_encrypt(self, plain) -> list:
        i = 0
        j = 0
        cipher = []
        for p in plain:
            i = (i + 1) % 256
            j = (j + self.S[i]) % 256
            self.S[i], self.S[j] = self.S[j], self.S[i]
            k = p ^ self.S[(self.S[i] + self.S[j]) % 256]
            cipher.append(k)
        return cipher
key = []
data = []
rc4 = RC4(key)
plain = rc4.rc4_encrypt(data)
for i in plain:
    print(chr(i),end = "")

# Salsa20

需要注意 nonce 的初始填充

from Crypto.Cipher import Salsa20
key = b'\x07\x05\x0B\x0D\x0F\x0D\x0B\x05\x07\x05\x1B\x1D\x1F\x1D\x1B\x05\x07\x05\x0B\x0D\x0F\x37\x35\x3B\x3D\x3F\x07\x05\x0B\x0D\x0F\x0D'
nonce = b'\x00\x00\x00\x00\x00\x00\x00\x00'
plaintext = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_"
cipher = Salsa20.new(key=key , nonce=nonce)
ciphertext = cipher.encrypt(plaintext)
a = [hex(i) for i in ciphertext]
print(a)

完整版

class Salsa:
    def __init__(self, r=20):
        assert r >= 0
        self._r = r  # number of rounds
        self._mask = 0xffffffff  # 32-bit mask
    def __call__(self, key=[0] * 32, nonce=[0] * 8, block_counter=[0] * 8):
        assert len(key) == 32
        assert len(nonce) == 8
        assert len(block_counter) == 8
        # init state
        k = [self._littleendian(key[4 * i:4 * i + 4]) for i in range(8)]
        n = [self._littleendian(nonce[4 * i:4 * i + 4]) for i in range(2)]
        b = [self._littleendian(block_counter[4 * i:4 * i + 4]) for i in range(2)]
        c = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]
        s = [c[0], k[0], k[1], k[2],
             k[3], c[1], n[0], n[1],
             b[0], b[1], c[2], k[4],
             k[5], k[6], k[7], c[3]]
        # the state
        self._s = s[:]
        for i in range(self._r):
            self._round()
        # add initial state to the final one
        self._s = [(self._s[i] + s[i]) & self._mask for i in range(16)]
        return self._s
    def _littleendian(self, b):
        assert len(b) == 4
        return b[0] ^ (b[1] << 8) ^ (b[2] << 16) ^ (b[3] << 24)
    def _round(self):
        # quarterround 1
        self._s[4] ^= self._rotl32((self._s[0] + self._s[12]) & self._mask, 7)
        self._s[8] ^= self._rotl32((self._s[0] + self._s[4]) & self._mask, 9)
        self._s[12] ^= self._rotl32((self._s[4] + self._s[8]) & self._mask, 13)
        self._s[0] ^= self._rotl32((self._s[8] + self._s[12]) & self._mask, 18)
        # quarterround 2
        self._s[9] ^= self._rotl32((self._s[1] + self._s[5]) & self._mask, 7)
        self._s[13] ^= self._rotl32((self._s[5] + self._s[9]) & self._mask, 9)
        self._s[1] ^= self._rotl32((self._s[9] + self._s[13]) & self._mask, 13)
        self._s[5] ^= self._rotl32((self._s[1] + self._s[13]) & self._mask, 18)
        # quarterround 3
        self._s[14] ^= self._rotl32((self._s[6] + self._s[10]) & self._mask, 7)
        self._s[2] ^= self._rotl32((self._s[10] + self._s[14]) & self._mask, 9)
        self._s[6] ^= self._rotl32((self._s[2] + self._s[14]) & self._mask, 13)
        self._s[10] ^= self._rotl32((self._s[2] + self._s[6]) & self._mask, 18)
        # quarterround 4
        self._s[3] ^= self._rotl32((self._s[11] + self._s[15]) & self._mask, 7)
        self._s[7] ^= self._rotl32((self._s[3] + self._s[15]) & self._mask, 9)
        self._s[11] ^= self._rotl32((self._s[3] + self._s[7]) & self._mask, 13)
        self._s[15] ^= self._rotl32((self._s[7] + self._s[11]) & self._mask, 18)
        # transpose
        self._s = [self._s[0], self._s[4], self._s[8], self._s[12],
                   self._s[1], self._s[5], self._s[9], self._s[13],
                   self._s[2], self._s[6], self._s[10], self._s[14],
                   self._s[3], self._s[7], self._s[11], self._s[15]]
    def _rotl32(self, w, r):
        # rotate left for 32-bits
        return (((w << r) & self._mask) | (w >> (32 - r)))
if __name__ == '__main__':
    salsa20 = Salsa()
    # vectors = [
    #    [[0]*32, [3,1,4,1,5,9,2,6], [7,0,0,0,0,0,0,0],     # 这里就是参数!!!
    #    [ 0xb9a205a3,0x0695e150,0xaa94881a,0xadb7b12c,
    #      0x798942d4,0x26107016,0x64edb1a4,0x2d27173f,
    #      0xb1c7f1fa,0x62066edc,0xe035fa23,0xc4496f04,
    #      0x2131e6b3,0x810bde28,0xf62cb407,0x6bdede3d ] ] ]
    vectors = [
        [[0] * 32, [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]]  # 这里就是参数!!!
    for i in range(len(vectors)):
        v = vectors[i]
        print(f"key => {v[0]}")
        print(f"nonce => {v[1]}")
        print(f"block_counter => {v[2]}")
        s = salsa20(v[0], v[1], v[2])
        stream_key = []
        # for i in s:
        #   print(hex(i),end = " ")
        for i in range(len(s)):
            stream_key.append(s[i] & 0xff)
            stream_key.append((s[i] & 0xff00) >> 8)
            stream_key.append((s[i] & 0xff0000) >> 16)
            stream_key.append((s[i] & 0xff000000) >> 24)
        print()
        cybertext = [1,1,1,1]
        for i in range(len(stream_key)):
            print(chr(stream_key[i] ^ cybertext[i]), end="")

# chacha20

from Crypto.Cipher import ChaCha20
key = b'\x07\x05\x0B\x0D\x0F\x0D\x0B\x05\x07\x05\x1B\x1D\x1F\x1D\x1B\x05\x07\x05\x0B\x0D\x0F\x37\x35\x3B\x3D\x3F\x07\x05\x0B\x0D\x0F\x0D'
plaintext = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_"
nonce = b'\x00\x00\x00\x00\x00\x00\x00\x00'
cipher = ChaCha20.new(key=key,nonce=nonce)
ciphertext = cipher.encrypt(plaintext)
# 获取 nonce(用于解密)
# nonce = cipher.nonce
# 解密
# cipher = ChaCha20.new(key=key, nonce=nonce)
# decrypted_text = cipher.decrypt(ciphertext)
a = [hex(i) for i in ciphertext]
print(a)
#include <stdint.h>
#include <string.h>
#include <bits/stdc++.h>
static inline void u32t8le(uint32_t v, uint8_t p[4]) {
	p[0] = v & 0xff;
	p[1] = (v >> 8) & 0xff;
	p[2] = (v >> 16) & 0xff;
	p[3] = (v >> 24) & 0xff;
}
static inline uint32_t u8t32le(uint8_t p[4]) {
	uint32_t value = p[3];
	
	value = (value << 8) | p[2];
	value = (value << 8) | p[1];
	value = (value << 8) | p[0];
	
	return value;
}
static inline uint32_t rotl32(uint32_t x, int n) {
	// http://blog.regehr.org/archives/1063
	return x << n | (x >> (-n & 31));
}
// https://tools.ietf.org/html/rfc7539##section-2.1
static void chacha20_quarterround(uint32_t *x, int a, int b, int c, int d) {
	x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16);
	x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12);
	x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a],  8);
	x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c],  7);
}
static void chacha20_serialize(uint32_t in[16], uint8_t output[64]) {
	int i;
	for (i = 0; i < 16; i++) {
		u32t8le(in[i], output + (i << 2));
	}
}
static void chacha20_block(uint32_t in[16], uint8_t out[64], int num_rounds) { //num_rounds 一般为 20 
	int i;
	uint32_t x[16];
	
	memcpy(x, in, sizeof(uint32_t) * 16);
	
	for (i = num_rounds; i > 0; i -= 2) {    
		//odd round
		chacha20_quarterround(x, 0, 4,  8, 12);
		chacha20_quarterround(x, 1, 5,  9, 13);
		chacha20_quarterround(x, 2, 6, 10, 14);
		chacha20_quarterround(x, 3, 7, 11, 15);
		//even round 
		chacha20_quarterround(x, 0, 5, 10, 15);
		chacha20_quarterround(x, 1, 6, 11, 12);
		chacha20_quarterround(x, 2, 7,  8, 13);
		chacha20_quarterround(x, 3, 4,  9, 14);
	}
	
	for (i = 0; i < 16; i++) {
		x[i] += in[i];
	}
	
	chacha20_serialize(x, out);
}
// https://tools.ietf.org/html/rfc7539##section-2.3
static void chacha20_init_state(uint32_t s[16], uint8_t key[32], uint32_t counter, uint8_t nonce[12]) {
	int i;
	
	// refer: https://dxr.mozilla.org/mozilla-beta/source/security/nss/lib/freebl/chacha20.c
	// convert magic number to string: "expand 32-byte k"
	s[0] = 0x61707865;
	s[1] = 0x3320646e;
	s[2] = 0x79622d32;
	s[3] = 0x6b206574;
	
	for (i = 0; i < 8; i++) {
		s[4 + i] = u8t32le(key + i * 4);
	}
	
	s[12] = counter;
	
	for (i = 0; i < 3; i++) {
		s[13 + i] = u8t32le(nonce + i * 4);
	}
}
void ChaCha20XOR(uint8_t key[32], uint32_t counter, uint8_t nonce[12], uint8_t *in, uint8_t *out, int inlen) {
	int i, j;
	
	uint32_t s[16];
	uint8_t block[64];
	
	chacha20_init_state(s, key, counter, nonce);
	
	for (i = 0; i < inlen; i += 64) {
		chacha20_block(s, block, 20);
		s[12]++;
		
		for (j = i; j < i + 64; j++) {
			if (j >= inlen) {
				break;
			}
			out[j] = in[j] ^ block[j - i];
		}
	}
}
int main() {
	int i;
	
	uint8_t key[] = {
		0x00, 0x01, 0x02, 0x03,
		0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0a, 0x0b,
		0x0c, 0x0d, 0x0e, 0x0f,
		0x10, 0x11, 0x12, 0x13,
		0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1a, 0x1b,
		0x1c, 0x1d, 0x1e, 0x1f
	};
	
	uint8_t nonce[] = {                // 随机数 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	
	uint8_t input[114] = {
		0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c
	};
	
	uint8_t encrypt[114];
	uint8_t decrypt[114];
	
	int counter = 1;
	
	ChaCha20XOR(key, counter, nonce, input, encrypt, 114);             
	ChaCha20XOR(key, counter, nonce, encrypt, decrypt, 114);
	
	printf("\nkey:");
	for (i = 0; i < 32; i++) {
		if (!(i % 16)) {
			printf("\n");
		}
		printf("%02x ", key[i]);
	}
	
	printf("\n\nnonce:\n");
	for (i = 0; i < 12; i++) {
		printf("%02x ", nonce[i]);
	}
	
	printf("\n\nplaintext:");
	for (i = 0; i < 114; i++) {
		if (!(i % 16)) {
			printf("\n");
		}
		printf("%02x ", input[i]);
	}
	
	printf("\n\nencrypted:");
	for (i = 0; i < 114; i++) {
		if (!(i % 16)) {
			printf("\n");
		}
		printf("%02x ", encrypt[i]);
	}
	
	printf("\n\ndecrypted:");
	for (i = 0; i < 114; i++) {
		if (!(i % 16)) {
			printf("\n");
		}
		printf("%02x ", decrypt[i]);
	}
	
	printf("\n");
	return 0;
}

# ZUC

未测试过,没找到合适的标准库

from math import ceil
 
S0 = [
    0x3E, 0x72, 0x5B, 0x47, 0xCA, 0xE0, 0x00, 0x33, 0x04, 0xD1, 0x54, 0x98, 0x09, 0xB9, 0x6D, 0xCB,
    0x7B, 0x1B, 0xF9, 0x32, 0xAF, 0x9D, 0x6A, 0xA5, 0xB8, 0x2D, 0xFC, 0x1D, 0x08, 0x53, 0x03, 0x90,
    0x4D, 0x4E, 0x84, 0x99, 0xE4, 0xCE, 0xD9, 0x91, 0xDD, 0xB6, 0x85, 0x48, 0x8B, 0x29, 0x6E, 0xAC,
    0xCD, 0xC1, 0xF8, 0x1E, 0x73, 0x43, 0x69, 0xC6, 0xB5, 0xBD, 0xFD, 0x39, 0x63, 0x20, 0xD4, 0x38,
    0x76, 0x7D, 0xB2, 0xA7, 0xCF, 0xED, 0x57, 0xC5, 0xF3, 0x2C, 0xBB, 0x14, 0x21, 0x06, 0x55, 0x9B,
    0xE3, 0xEF, 0x5E, 0x31, 0x4F, 0x7F, 0x5A, 0xA4, 0x0D, 0x82, 0x51, 0x49, 0x5F, 0xBA, 0x58, 0x1C,
    0x4A, 0x16, 0xD5, 0x17, 0xA8, 0x92, 0x24, 0x1F, 0x8C, 0xFF, 0xD8, 0xAE, 0x2E, 0x01, 0xD3, 0xAD,
    0x3B, 0x4B, 0xDA, 0x46, 0xEB, 0xC9, 0xDE, 0x9A, 0x8F, 0x87, 0xD7, 0x3A, 0x80, 0x6F, 0x2F, 0xC8,
    0xB1, 0xB4, 0x37, 0xF7, 0x0A, 0x22, 0x13, 0x28, 0x7C, 0xCC, 0x3C, 0x89, 0xC7, 0xC3, 0x96, 0x56,
    0x07, 0xBF, 0x7E, 0xF0, 0x0B, 0x2B, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xA6, 0x4C, 0x10, 0xFE,
    0xBC, 0x26, 0x95, 0x88, 0x8A, 0xB0, 0xA3, 0xFB, 0xC0, 0x18, 0x94, 0xF2, 0xE1, 0xE5, 0xE9, 0x5D,
    0xD0, 0xDC, 0x11, 0x66, 0x64, 0x5C, 0xEC, 0x59, 0x42, 0x75, 0x12, 0xF5, 0x74, 0x9C, 0xAA, 0x23,
    0x0E, 0x86, 0xAB, 0xBE, 0x2A, 0x02, 0xE7, 0x67, 0xE6, 0x44, 0xA2, 0x6C, 0xC2, 0x93, 0x9F, 0xF1,
    0xF6, 0xFA, 0x36, 0xD2, 0x50, 0x68, 0x9E, 0x62, 0x71, 0x15, 0x3D, 0xD6, 0x40, 0xC4, 0xE2, 0x0F,
    0x8E, 0x83, 0x77, 0x6B, 0x25, 0x05, 0x3F, 0x0C, 0x30, 0xEA, 0x70, 0xB7, 0xA1, 0xE8, 0xA9, 0x65,
    0x8D, 0x27, 0x1A, 0xDB, 0x81, 0xB3, 0xA0, 0xF4, 0x45, 0x7A, 0x19, 0xDF, 0xEE, 0x78, 0x34, 0x60
]
 
S1 = [
    0x55, 0xC2, 0x63, 0x71, 0x3B, 0xC8, 0x47, 0x86, 0x9F, 0x3C, 0xDA, 0x5B, 0x29, 0xAA, 0xFD, 0x77,
    0x8C, 0xC5, 0x94, 0x0C, 0xA6, 0x1A, 0x13, 0x00, 0xE3, 0xA8, 0x16, 0x72, 0x40, 0xF9, 0xF8, 0x42,
    0x44, 0x26, 0x68, 0x96, 0x81, 0xD9, 0x45, 0x3E, 0x10, 0x76, 0xC6, 0xA7, 0x8B, 0x39, 0x43, 0xE1,
    0x3A, 0xB5, 0x56, 0x2A, 0xC0, 0x6D, 0xB3, 0x05, 0x22, 0x66, 0xBF, 0xDC, 0x0B, 0xFA, 0x62, 0x48,
    0xDD, 0x20, 0x11, 0x06, 0x36, 0xC9, 0xC1, 0xCF, 0xF6, 0x27, 0x52, 0xBB, 0x69, 0xF5, 0xD4, 0x87,
    0x7F, 0x84, 0x4C, 0xD2, 0x9C, 0x57, 0xA4, 0xBC, 0x4F, 0x9A, 0xDF, 0xFE, 0xD6, 0x8D, 0x7A, 0xEB,
    0x2B, 0x53, 0xD8, 0x5C, 0xA1, 0x14, 0x17, 0xFB, 0x23, 0xD5, 0x7D, 0x30, 0x67, 0x73, 0x08, 0x09,
    0xEE, 0xB7, 0x70, 0x3F, 0x61, 0xB2, 0x19, 0x8E, 0x4E, 0xE5, 0x4B, 0x93, 0x8F, 0x5D, 0xDB, 0xA9,
    0xAD, 0xF1, 0xAE, 0x2E, 0xCB, 0x0D, 0xFC, 0xF4, 0x2D, 0x46, 0x6E, 0x1D, 0x97, 0xE8, 0xD1, 0xE9,
    0x4D, 0x37, 0xA5, 0x75, 0x5E, 0x83, 0x9E, 0xAB, 0x82, 0x9D, 0xB9, 0x1C, 0xE0, 0xCD, 0x49, 0x89,
    0x01, 0xB6, 0xBD, 0x58, 0x24, 0xA2, 0x5F, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xB8, 0x95, 0xE4,
    0xD0, 0x91, 0xC7, 0xCE, 0xED, 0x0F, 0xB4, 0x6F, 0xA0, 0xCC, 0xF0, 0x02, 0x4A, 0x79, 0xC3, 0xDE,
    0xA3, 0xEF, 0xEA, 0x51, 0xE6, 0x6B, 0x18, 0xEC, 0x1B, 0x2C, 0x80, 0xF7, 0x74, 0xE7, 0xFF, 0x21,
    0x5A, 0x6A, 0x54, 0x1E, 0x41, 0x31, 0x92, 0x35, 0xC4, 0x33, 0x07, 0x0A, 0xBA, 0x7E, 0x0E, 0x34,
    0x88, 0xB1, 0x98, 0x7C, 0xF3, 0x3D, 0x60, 0x6C, 0x7B, 0xCA, 0xD3, 0x1F, 0x32, 0x65, 0x04, 0x28,
    0x64, 0xBE, 0x85, 0x9B, 0x2F, 0x59, 0x8A, 0xD7, 0xB0, 0x25, 0xAC, 0xAF, 0x12, 0x03, 0xE2, 0xF2
]
 
D = [
    0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF,
    0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC
]
 
 
def addition_uint31(a, b):
    c = a + b
    return (c & 0x7FFFFFFF) + (c >> 31)
 
 
def rotl_uint31(a, shift):
    return ((a << shift) | (a >> (31 - shift))) & 0x7FFFFFFF
 
 
def rotl_uint32(a, shift):
    return ((a << shift) | (a >> (32 - shift))) & 0xFFFFFFFF
 
 
def l1(x):
    return (x ^ rotl_uint32(x, 2) ^ rotl_uint32(x, 10) ^ rotl_uint32(x, 18) ^ rotl_uint32(x, 24))
 
 
def l2(x):
    return (x ^ rotl_uint32(x, 8) ^ rotl_uint32(x, 14) ^ rotl_uint32(x, 22) ^ rotl_uint32(x, 30))
 
 
def make_uint32(a, b, c, d):
    return ((a << 24) & 0xffffffff) | ((b << 16) & 0xffffffff) | ((c << 8) & 0xffffffff) | d
 
 
def make_uint31(a, b, c):
    return ((a << 23) & 0x7fffffff) | ((b << 8) & 0x7fffffff) | c
 
 
class ZUC(object):
    def __init__(self, key, iv):
        self.r = [0, 0]
        self.lfsr = [0 for _ in range(16)]
        self.x = [0, 0, 0, 0]
        self.zuc_init(key, iv)
 
    def bit_reorganization(self):
        self.x[0] = ((self.lfsr[15] & 0x7FFF8000) << 1) | (self.lfsr[14] & 0xFFFF)
        self.x[1] = ((self.lfsr[11] & 0xFFFF) << 16) | (self.lfsr[9] >> 15)
        self.x[2] = ((self.lfsr[7] & 0xFFFF) << 16) | (self.lfsr[5] >> 15)
        self.x[3] = ((self.lfsr[2] & 0xFFFF) << 16) | (self.lfsr[0] >> 15)
 
    def lfsr_next(self):
        f = self.lfsr[0]
        v = rotl_uint31(self.lfsr[0], 8)
        f = addition_uint31(f, v)
        v = rotl_uint31(self.lfsr[4], 20)
        f = addition_uint31(f, v)
        v = rotl_uint31(self.lfsr[10], 21)
        f = addition_uint31(f, v)
        v = rotl_uint31(self.lfsr[13], 17)
        f = addition_uint31(f, v)
        v = rotl_uint31(self.lfsr[15], 15)
        f = addition_uint31(f, v)
        return f
 
    def lfsr_append(self, f):
        self.lfsr.append(f)
        if len(self.lfsr) > 16:
            self.lfsr.pop(0)
 
    def lfsr_init(self, u):
        self.lfsr_append(addition_uint31(self.lfsr_next(), u))
 
    def lfsr_shift(self):
        self.lfsr_append(self.lfsr_next())
 
    def f(self):
        W = ((self.x[0] ^ self.r[0]) + self.r[1]) & 0xffffffff
        W1 = (self.r[0] + self.x[1]) & 0xffffffff
        W2 = self.r[1] ^ self.x[2]
        u = l1(((W1 & 0x0000ffff) << 16) | (W2 >> 16))
        v = l2(((W2 & 0x0000ffff) << 16) | (W1 >> 16))
        self.r = [make_uint32(S0[u >> 24], S1[(u >> 16) & 0xFF],
                              S0[(u >> 8) & 0xFF], S1[u & 0xFF]),
                  make_uint32(S0[v >> 24], S1[(v >> 16) & 0xFF],
                              S0[(v >> 8) & 0xFF], S1[v & 0xFF])]
        return W
 
    def zuc_init(self, key, iv):
        # Expand key.
        self.lfsr = [make_uint31(key[i], D[i], iv[i]) for i in range(16)]
        self.r = [0, 0]
        for i in range(32):
            self.bit_reorganization()
            w = self.f()
            self.lfsr_init(w >> 1)
 
    def zuc_generate_keystream(self, length):
        keystream_buffer = []
        self.bit_reorganization()
        self.f()  # Discard the output of F.
 
        def itor():
            self.lfsr_shift()
            self.bit_reorganization()
            return self.f() ^ self.x[-1]
 
        keystream_buffer = [itor() for _ in range(length)]
        self.lfsr_shift()
        return keystream_buffer
 
    def zuc_encrypt(self, input):
        length = len(input)
        key_stream = self.zuc_generate_keystream(length)
        return [inp ^ key_stream[i] for i, inp in enumerate(input)]
 
 
if '__main__' == __name__:
    key = [0x00] * 16
    iv = [0x00] * 16
    zuc = ZUC(key, iv)
    # 加密过程
    out = zuc.zuc_encrypt(b"i love u")
    print("加密得到的字流", ["%08x" % e for e in out])
    # 解密过程
    zuc2 = ZUC(key, iv)
    out2 = zuc2.zuc_encrypt(out)
    print("解密得到的字流", ["%08x" % e for e in out2])
    print(bytes(out2))

# 分组

# TEA

# TEA

#define uint unsigned int
void encrypt(uint *v, uint *key)
{
	uint l = v[0], r = v[1], sum = 0, delta = 0x9e3779b9;
	for (int i = 1; i <= 32; ++i)
	{
		sum += delta;
		l += ((r << 4) + key[0]) ^ (r + sum) ^ ((r >> 5) + key[1]);
		r += ((l << 4) + key[2]) ^ (l + sum) ^ ((l >> 5) + key[3]);
	}
	v[0] = l, v[1] = r;
}
void decrypt(uint *v, uint *key)
{
	uint l = v[0], r = v[1], sum = 0, delta = 0x9e3779b9;
	sum = delta * 32;
	for (int i = 1; i <= 32; ++i)
	{
		r -= ((l << 4) + key[2]) ^ (l + sum) ^ ((l >> 5) + key[3]);
		l -= ((r << 4) + key[0]) ^ (r + sum) ^ ((r >> 5) + key[1]);
		sum -= delta;
	}
	v[0] = l, v[1] = r;
}

# XTEA

#define uint unsigned int
void encrypt(uint *v, uint *key)
{
	uint l = v[0], r = v[1], sum = 0, delta = 0x9e3779b9;
	for (int i = 1; i <= 32; ++i)
	{
		l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
		sum += delta;
		r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
	}
	v[0] = l;
	v[1] = r;
}
void decrypt(uint *v, uint *key)
{
	uint l = v[0], r = v[1], sum = 0, delta = 0x9e3779b9;
	sum = delta * 32;
	for (int i = 1; i <= 32; ++i)
	{
		r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
		sum -= delta;
		l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
	}
	v[0] = l;
	v[1] = r;
}

# XXTEA

#include <cstdio>
#define uint unsigned int
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (k[(i & 3) ^ e] ^ z)))
void xxtea(uint *v, int n, uint *k)  
{
	uint y, z, sum, i, t, e, delta = 0x9e3779b9;;
	if (n > 1) // encrypt
	{
		t = 6 + 52 / n, sum = 0, z = v[n - 1];
		while (t--)
		{
			sum += delta, e = (sum >> 2) & 3;
			for (i = 0; i < n - 1; ++i)
			{
				y = v[i + 1];
				z = v[i] += MX;
			}
			y = v[0];
			z = v[n - 1] += MX;
		}
	}
	else if (n < -1) // decrypt
	{
		n = -n, t = 6 + 52 / n, sum = t * delta, y = v[0];
		while (t--)
		{
			e = (sum >> 2) & 3;
			for (i = n - 1; i > 0; --i)
			{
				z = v[i - 1];
				y = v[i] -= MX;
			}
			z = v[n - 1];
			y = v[0] -= MX;
			sum -= delta;
		}
	}
}
int main()
{
	uint v[2]= {1,2}, k[4]= {2,2,3,4};
	int n = 2; // abs(n) = strlen(v)
	printf("data: %u %u\n",v[0],v[1]);
	xxtea(v, n, k);
	printf("encrypt:%u %u\n",v[0],v[1]);
	xxtea(v, -n, k);
	printf("decrypt: %u %u\n",v[0],v[1]);
	return 0;
}
from ctypes import *
def MX(z, y, total, key, p, e):
    temp1 = (z.value >> 5 ^ y.value << 2) + (y.value >> 3 ^ z.value << 4)
    temp2 = (total.value ^ y.value) + (key[(p & 3) ^ e.value] ^ z.value)
    return c_uint32(temp1 ^ temp2)
def encrypt(n, v, key):
    delta = 0x9e3779b9
    rounds = 6 + 52 // n
    total = c_uint32(0)
    z = c_uint32(v[n - 1])
    e = c_uint32(0)
    while rounds > 0:
        total.value += delta
        e.value = (total.value >> 2) & 3
        for p in range(n - 1):
            y = c_uint32(v[p + 1])
            v[p] = c_uint32(v[p] + MX(z, y, total, key, p, e).value).value
            z.value = v[p]
        y = c_uint32(v[0])
        v[n - 1] = c_uint32(v[n - 1] + MX(z, y, total, key, n - 1, e).value).value
        z.value = v[n - 1]
        rounds -= 1
    return v
def decrypt(n, v, key):
    delta = 0x9e3779b9
    rounds = 6 + 52 // n
    total = c_uint32(rounds * delta)
    y = c_uint32(v[0])
    e = c_uint32(0)
    while rounds > 0:
        e.value = (total.value >> 2) & 3
        for p in range(n - 1, 0, -1):
            z = c_uint32(v[p - 1])
            v[p] = c_uint32((v[p] - MX(z, y, total, key, p, e).value)).value
            y.value = v[p]
        z = c_uint32(v[n - 1])
        v[0] = c_uint32(v[0] - MX(z, y, total, key, 0, e).value).value
        y.value = v[0]
        total.value -= delta
        rounds -= 1
    return v
#  test
if __name__ == "__main__":
    # 该算法中每次可加密不只 64bit 的数据,并且加密的轮数由加密数据长度决定
    v = [1374278842, 2136006540, 4191056815, 3248881376]
    k = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
    n = 4
    res = decrypt(n, v, k)
    # print("Data is : ", hex(v[0]), hex(v[1]))
    # res = encrypt(n, v, k)
    # print("Encrypted data is : ", hex(res[0]), hex(res[1]))
    # res = decrypt(n, res, k)
    print("Decrypted data is : ", hex(res[0]), hex(res[1]), hex(res[2]), hex(res[3]))
"""
Data is :  0x12345678 0x78563412
Encrypted data is :  0xef86c2bb 0x25f31b5e
Decrypted data is :  0x12345678 0x78563412
"""

# 其他

# DES

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void encryption(unsigned char * plaintext,unsigned char * ciphertext);
void decryption(unsigned char * ciphertext,unsigned char * plaintext);
void ip_replace(unsigned char * in,unsigned char *out);
void fp_replace(unsigned char * in,unsigned char *out);
void byte2Bit(unsigned char *in,unsigned char *out,int len);
void bit2Byte(unsigned char *in,unsigned char *out,int len);
void f_func(unsigned char *in,unsigned char * out,unsigned char *ki);
void get_subkey(unsigned char *key);
void byteXOR(unsigned char *a,unsigned char *b,int len);
void e_expand(unsigned char * in,unsigned char * out);
void s_replace(unsigned char * in,unsigned char * out);
void p_replace(unsigned char * in,unsigned char * out);
void pc1_replace(unsigned char * in,unsigned char * out);
void pc2_replace(unsigned char *in,unsigned char *out);
const char IP_Table[64]= {
        58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
        62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
        57, 49, 41, 33, 25, 17,  9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
        61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};
const char IPR_Table[64] = {
        40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
        38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
        36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
        34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41,  9, 49, 17, 57, 25
};
const char E_Table[48] = {
        32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,
        8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
        16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
        24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1
};
const char P_Table[32] = {
        16, 7, 20, 21, 29, 12, 28, 17, 1,  15, 23, 26, 5,  18, 31, 10,
        2,  8, 24, 14, 32, 27, 3,  9,  19, 13, 30, 6,  22, 11, 4,  25
};
const char PC1_Table[56] = {
        57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
        10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
        63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
        14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
};
const char PC2_Table[48] = {
        14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
        23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
        41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
        44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};
const char LOOP_Table[16] = {
    1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};
const char S_Box[8][4][16] = {
        // S1
        14, 4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
        0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
        4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
        15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,
        // S2
        15, 1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
        3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
        0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
        13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,
        // S3
        10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
        13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
        13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
        1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,
        // S4
        7,  13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
        13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
        10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
        3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,
        // S5
        2,  12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
        14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
        4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
        11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,
        // S6
        12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
        10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
        9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
        4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,
        // S7
        4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
        13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
        1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
        6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,
        // S8
        13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
        1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
        7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
        2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};
unsigned char subkey[16][48];
unsigned char result[]={0xef,0x34,0xd4,0xa3,0xc6,0x84,0xe4,0x23};
int main()
{
    unsigned char key[9] = "DE3_En1C";
    unsigned char plaintext[20];
	//HarDd3s?
    unsigned char ciphertext[8];
    int i=0;
	puts("give me a string to encrypt:");
	scanf("%s",plaintext);
	if(strlen((const char *)plaintext)!=8){
		system("pause");
		return -1;
	}
    //to generate 16 round subkey
    get_subkey(key);
    //to encrypt plaintext
    encryption(plaintext,ciphertext);
    for(i=0;i<8;++i){
        if(ciphertext[i]!=result[i]){
			puts("Wrong!!");
		    system("pause");
			return -1;
		}
    }
	puts("G00d Job!!");
	system("pause");
    return 0;
}
void encryption(unsigned char * plaintext,unsigned char * ciphertext){
    int i;
    unsigned char array_plaintext[64];
    unsigned char f_result[32];
    unsigned char left_array[32];
    unsigned char right_array[32];
    byte2Bit(plaintext,array_plaintext,8);
    ip_replace(array_plaintext,array_plaintext);
    memcpy(left_array,array_plaintext,32);
    memcpy(right_array,array_plaintext+32,32);
    for(i=0;i<15;++i){
        f_func(right_array,f_result,&subkey[i][0]);
        byteXOR(f_result,left_array,32);
        memcpy(left_array,right_array,32);
        memcpy(right_array,f_result,32);
    }
    f_func(right_array,f_result,&subkey[i][0]);
    byteXOR(left_array,f_result,32);
    memcpy(array_plaintext,left_array,32);
    memcpy(array_plaintext+32,right_array,32);
    fp_replace(array_plaintext,array_plaintext);
    bit2Byte(array_plaintext,ciphertext,8);
}
void byte2Bit(unsigned char *in,unsigned char *out,int len){
    int i,j;
    for(i=0;i<len;++i)
        for(j=0;j<8;++j){
            out[i*8+j] = (in[i]>>(7-j))&0x1;
            }
}
void bit2Byte(unsigned char *in,unsigned char *out,int len){
    int i,j;
    unsigned char temp;
    for(i=0;i<len;++i){
        temp = in[i*8]&0x1;
        for(j=1;j<8;++j){
            temp = temp<<1;
            temp = temp+(in[i*8+j]&0x1);
        }
        out[i]=temp;
    }
}
//change the input 64 bit data to 64 bytes array, use ip table to replace 64 bytes array
void ip_replace(unsigned char * in,unsigned char *out){
    int i;
    unsigned char temp[64];
    memcpy(temp,in,64);
    //use ip table to replace 64 bytes(bit) array
    for(i=0;i<64;++i){
        out[i] = temp[IP_Table[i]-1];
        //printf("%x ",out[i]);
    }
}
void fp_replace(unsigned char *in,unsigned char* out){
    int i;
    unsigned char temp[64];
    memcpy(temp,in,64);
    for(i=0;i<64;++i)
        out[i] = temp[IPR_Table[i]-1];
}
void e_expand(unsigned char * in, unsigned char *out){
    unsigned char temp[48];
    int i;
    memcpy(temp,in,48);
    for(i=0;i<48;++i)
        out[i] = temp[E_Table[i]-1];
}
void s_replace(unsigned char * in,unsigned char *out){
    int i,j;
    int raw,col;
    char temp;
    for(i=0,j=0;i<8;++i){
        raw = ((in[i*6]<<1)|(in[i*6+5]))&0x3;
        col = ((in[i*6+1]<<3)|(in[i*6+2]<<2)|(in[i*6+3]<<1)|(in[i*6+4]))&0xF;
        temp = S_Box[i][raw][col]&0xF;
        out[j] = (temp>>3)&0x1;
        out[j+1] = (temp>>2)&0x1;
        out[j+2] = (temp>>1)&0x1;
        out[j+3] = (temp)&0x1;
        j+=4;
    }
}
void p_replace(unsigned char * in,unsigned char * out){
    unsigned char temp[32];
    int i;
    memcpy(temp,in,32);
    for(i=0;i<32;++i){
        out[i] = temp[P_Table[i]-1];
    }
}
void byteXOR(unsigned char *a,unsigned char *b,int len){
    int i;
    for(i=0;i<len;++i){
        a[i] = (a[i]+b[i])&0x1;
    }
}
void f_func(unsigned char * in,unsigned char * out,unsigned char * ki){
    unsigned char expand_result[48];
    unsigned char replace_result[32];
    e_expand(in,expand_result);
    byteXOR(expand_result,ki,48);
    s_replace(expand_result,replace_result);
    p_replace(replace_result,replace_result);
    memcpy(out,replace_result,32);
}
void pc1_replace(unsigned char * in,unsigned char * out){
    int i;
    for(i=0;i<56;++i)
        out[i]=in[PC1_Table[i]-1];
}
void pc2_replace(unsigned char *in,unsigned char *out){
    int i;
    for(i=0;i<48;++i)
        out[i] = in[PC2_Table[i]-1];
}
void shift_left(unsigned char *in,unsigned char *out,int len){
    unsigned char temp[28];
    int i,j;
    memcpy(temp,in,28);
    for(i=len,j=0;i<28;++i)
        out[j++]=temp[i];
    for(i=0;i<len;++i)
        out[j++]=temp[i];
}
//use user's input key to generate 16 subkey
void get_subkey(unsigned char *key){
    unsigned char key_temp[64];
    unsigned char pc1_result[56];
    unsigned char pc2_result[48];
    int i;
    byte2Bit(key,key_temp,8);
    pc1_replace(key_temp,pc1_result);
    for(i=0;i<16;++i){
        shift_left(pc1_result,pc1_result,LOOP_Table[i]);
        shift_left(pc1_result+28,pc1_result+28,LOOP_Table[i]);
        pc2_replace(pc1_result,pc2_result);
        memcpy(&subkey[i][0],pc2_result,48);
    }
}

# AES

#include <stdio.h>
#include <stdint.h>
#include <memory.h>
/****************************************************************************************************************/
typedef enum {
	AES_CYPHER_128,
	AES_CYPHER_192,
	AES_CYPHER_256,
} AES_CYPHER_T;
/****************************************************************************************************************/
/*
* Encryption Rounds
*/
int g_aes_key_bits[] = {
	/* AES_CYPHER_128 */ 128,
	/* AES_CYPHER_192 */ 192,
	/* AES_CYPHER_256 */ 256,
};
int g_aes_rounds[] = {
	/* AES_CYPHER_128 */  10,
	/* AES_CYPHER_192 */  12,
	/* AES_CYPHER_256 */  14,
};
int g_aes_nk[] = {
	/* AES_CYPHER_128 */  4,
	/* AES_CYPHER_192 */  6,
	/* AES_CYPHER_256 */  8,
};
int g_aes_nb[] = {
	/* AES_CYPHER_128 */  4,
	/* AES_CYPHER_192 */  4,
	/* AES_CYPHER_256 */  4,
};
/****************************************************************************************************************/
/*
* aes Rcon:
*
* WARNING: Rcon is designed starting from 1 to 15, not 0 to 14.
*          FIPS-197 Page 9: "note that i starts at 1, not 0"
*
* i    |   0     1     2     3     4     5     6     7     8     9    10    11    12    13    14
* -----+------------------------------------------------------------------------------------------
*      | [01]  [02]  [04]  [08]  [10]  [20]  [40]  [80]  [1b]  [36]  [6c]  [d8]  [ab]  [4d]  [9a]
* RCON | [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]
*      | [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]
*      | [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]
*/
static const uint32_t g_aes_rcon[] = {
	0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000,
	0x1b000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0xed000000, 0x9a000000
};
/****************************************************************************************************************/
/*
* aes sbox and invert-sbox
*/
static const uint8_t g_aes_sbox[256] = {
	/* 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F  */
	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
static const uint8_t g_inv_sbox[256] = {
	/* 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F  */
	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
/****************************************************************************************************************/
uint8_t aes_sub_sbox(uint8_t val)
{
	return g_aes_sbox[val];
}
/****************************************************************************************************************/
uint32_t aes_sub_dword(uint32_t val)
{
	uint32_t tmp = 0;
	tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 0) & 0xFF))) << 0;
	tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 8) & 0xFF))) << 8;
	tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 16) & 0xFF))) << 16;
	tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 24) & 0xFF))) << 24;
	return tmp;
}
/****************************************************************************************************************/
uint32_t aes_rot_dword(uint32_t val)
{
	uint32_t tmp = val;
	return (val >> 8) | ((tmp & 0xFF) << 24);
}
/****************************************************************************************************************/
uint32_t aes_swap_dword(uint32_t val)
{
	return (((val & 0x000000FF) << 24) |
		((val & 0x0000FF00) << 8) |
		((val & 0x00FF0000) >> 8) |
		((val & 0xFF000000) >> 24));
}
/****************************************************************************************************************/
/*
* nr: number of rounds
* nb: number of columns comprising the state, nb = 4 dwords (16 bytes)
* nk: number of 32-bit words comprising cipher key, nk = 4, 6, 8 (KeyLength/(4*8))
*/
void aes_key_expansion(AES_CYPHER_T mode, uint8_t *key, uint8_t *round)
{
	uint32_t *w = (uint32_t *)round;
	uint32_t  t;
	int      i = 0;
	do {
		w[i] = *((uint32_t *)&key[i * 4 + 0]);
	} while (++i < g_aes_nk[mode]);
	do {
		if ((i % g_aes_nk[mode]) == 0) {
			t = aes_rot_dword(w[i - 1]);
			t = aes_sub_dword(t);
			t = t ^ aes_swap_dword(g_aes_rcon[i / g_aes_nk[mode] - 1]);
		}
		else if (g_aes_nk[mode] > 6 && (i % g_aes_nk[mode]) == 4) {
			t = aes_sub_dword(w[i - 1]);
		}
		else {
			t = w[i - 1];
		}
		w[i] = w[i - g_aes_nk[mode]] ^ t;
	} while (++i < g_aes_nb[mode] * (g_aes_rounds[mode] + 1));
}
/****************************************************************************************************************/
void aes_add_round_key(AES_CYPHER_T mode, uint8_t *state,
	uint8_t *round, int nr)
{
	uint32_t *w = (uint32_t *)round;
	uint32_t *s = (uint32_t *)state;
	int i;
	for (i = 0; i < g_aes_nb[mode]; i++) {
		s[i] ^= w[nr * g_aes_nb[mode] + i];
	}
}
/****************************************************************************************************************/
void aes_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
	int i, j;
	for (i = 0; i < g_aes_nb[mode]; i++) {
		for (j = 0; j < 4; j++) {
			state[i * 4 + j] = aes_sub_sbox(state[i * 4 + j]);
		}
	}
}
/****************************************************************************************************************/
void aes_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
	uint8_t *s = (uint8_t *)state;
	int i, j, r;
	for (i = 1; i < g_aes_nb[mode]; i++) {
		for (j = 0; j < i; j++) {
			uint8_t tmp = s[i];
			for (r = 0; r < g_aes_nb[mode]; r++) {
				s[i + r * 4] = s[i + (r + 1) * 4];
			}
			s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
		}
	}
}
/****************************************************************************************************************/
uint8_t aes_xtime(uint8_t x)
{
	return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}
/****************************************************************************************************************/
uint8_t aes_xtimes(uint8_t x, int ts)
{
	while (ts-- > 0) {
		x = aes_xtime(x);
	}
	return x;
}
/****************************************************************************************************************/
uint8_t aes_mul(uint8_t x, uint8_t y)
{
	/*
	* encrypt: y has only 2 bits: can be 1, 2 or 3
	* decrypt: y could be any value of 9, b, d, or e
	*/
	return ((((y >> 0) & 1) * aes_xtimes(x, 0)) ^
		(((y >> 1) & 1) * aes_xtimes(x, 1)) ^
		(((y >> 2) & 1) * aes_xtimes(x, 2)) ^
		(((y >> 3) & 1) * aes_xtimes(x, 3)) ^
		(((y >> 4) & 1) * aes_xtimes(x, 4)) ^
		(((y >> 5) & 1) * aes_xtimes(x, 5)) ^
		(((y >> 6) & 1) * aes_xtimes(x, 6)) ^
		(((y >> 7) & 1) * aes_xtimes(x, 7)));
}
/****************************************************************************************************************/
void aes_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
	uint8_t y[16] = { 2, 3, 1, 1,  1, 2, 3, 1,  1, 1, 2, 3,  3, 1, 1, 2 };
	uint8_t s[4];
	int i, j, r;
	for (i = 0; i < g_aes_nb[mode]; i++) {
		for (r = 0; r < 4; r++) {
			s[r] = 0;
			for (j = 0; j < 4; j++) {
				s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
			}
		}
		for (r = 0; r < 4; r++) {
			state[i * 4 + r] = s[r];
		}
	}
}
/****************************************************************************************************************/
int aes_encrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
	uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
	uint8_t s[4 * 4] = { 0 }; /* state */
	int nr, i, j;
	/* key expansion */
	aes_key_expansion(mode, key, w);
	/* start data cypher loop over input buffer */
	for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {
		/* init state from user buffer (plaintext) */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++)
			s[j] = data[i + j];
		/* start AES cypher loop over all AES rounds */
		for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {
			if (nr > 0) {
				/* do SubBytes */
				aes_sub_bytes(mode, s);
				/* do ShiftRows */
				aes_shift_rows(mode, s);
				if (nr < g_aes_rounds[mode]) {
					/* do MixColumns */
					aes_mix_columns(mode, s);
				}
			}
			/* do AddRoundKey */
			aes_add_round_key(mode, s, w, nr);
		}
		/* save state (cypher) to user buffer */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++)
			data[i + j] = s[j];
	}
	return 0;
}
/****************************************************************************************************************/
int aes_encrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
	return aes_encrypt(mode, data, len, key);
}
/****************************************************************************************************************/
int aes_encrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
	uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
	uint8_t s[4 * 4] = { 0 }; /* state */
	uint8_t v[4 * 4] = { 0 }; /* iv */
	int nr, i, j;
	/* key expansion */
	aes_key_expansion(mode, key, w);
	memcpy(v, iv, sizeof(v));
	/* start data cypher loop over input buffer */
	for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {
		/* init state from user buffer (plaintext) */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++)
			s[j] = data[i + j] ^ v[j];
		/* start AES cypher loop over all AES rounds */
		for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {
			if (nr > 0) {
				/* do SubBytes */
				aes_sub_bytes(mode, s);
				/* do ShiftRows */
				aes_shift_rows(mode, s);
				if (nr < g_aes_rounds[mode]) {
					/* do MixColumns */
					aes_mix_columns(mode, s);
				}
			}
			/* do AddRoundKey */
			aes_add_round_key(mode, s, w, nr);
		}
		/* save state (cypher) to user buffer */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++)
			data[i + j] = v[j] = s[j];
	}
	return 0;
}
/****************************************************************************************************************/
void inv_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
	uint8_t *s = (uint8_t *)state;
	int i, j, r;
	for (i = 1; i < g_aes_nb[mode]; i++) {
		for (j = 0; j < g_aes_nb[mode] - i; j++) {
			uint8_t tmp = s[i];
			for (r = 0; r < g_aes_nb[mode]; r++) {
				s[i + r * 4] = s[i + (r + 1) * 4];
			}
			s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
		}
	}
}
/****************************************************************************************************************/
uint8_t inv_sub_sbox(uint8_t val)
{
	return g_inv_sbox[val];
}
/****************************************************************************************************************/
void inv_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
	int i, j;
	for (i = 0; i < g_aes_nb[mode]; i++) {
		for (j = 0; j < 4; j++) {
			state[i * 4 + j] = inv_sub_sbox(state[i * 4 + j]);
		}
	}
}
/****************************************************************************************************************/
void inv_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
	uint8_t y[16] = { 0x0e, 0x0b, 0x0d, 0x09,  0x09, 0x0e, 0x0b, 0x0d,
		0x0d, 0x09, 0x0e, 0x0b,  0x0b, 0x0d, 0x09, 0x0e };
	uint8_t s[4];
	int i, j, r;
	for (i = 0; i < g_aes_nb[mode]; i++) {
		for (r = 0; r < 4; r++) {
			s[r] = 0;
			for (j = 0; j < 4; j++) {
				s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
			}
		}
		for (r = 0; r < 4; r++) {
			state[i * 4 + r] = s[r];
		}
	}
}
/****************************************************************************************************************/
int aes_decrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
	uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
	uint8_t s[4 * 4] = { 0 }; /* state */
	int nr, i, j;
	/* key expansion */
	aes_key_expansion(mode, key, w);
	/* start data cypher loop over input buffer */
	for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {
		/* init state from user buffer (cyphertext) */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++)
			s[j] = data[i + j];
		/* start AES cypher loop over all AES rounds */
		for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {
			/* do AddRoundKey */
			aes_add_round_key(mode, s, w, nr);
			if (nr > 0) {
				if (nr < g_aes_rounds[mode]) {
					/* do MixColumns */
					inv_mix_columns(mode, s);
				}
				/* do ShiftRows */
				inv_shift_rows(mode, s);
				/* do SubBytes */
				inv_sub_bytes(mode, s);
			}
		}
		/* save state (cypher) to user buffer */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++)
			data[i + j] = s[j];
	}
	return 0;
}
/****************************************************************************************************************/
int aes_decrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
	return aes_decrypt(mode, data, len, key);
}
/****************************************************************************************************************/
int aes_decrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
	uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
	uint8_t s[4 * 4] = { 0 }; /* state */
	uint8_t v[4 * 4] = { 0 }; /* iv */
	int nr, i, j;
	/* key expansion */
	aes_key_expansion(mode, key, w);
	memcpy(v, iv, sizeof(v));
	/* start data cypher loop over input buffer */
	for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {
		/* init state from user buffer (cyphertext) */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++)
			s[j] = data[i + j];
		/* start AES cypher loop over all AES rounds */
		for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {
			/* do AddRoundKey */
			aes_add_round_key(mode, s, w, nr);
			if (nr > 0) {
				if (nr < g_aes_rounds[mode]) {
					/* do MixColumns */
					inv_mix_columns(mode, s);
				}
				/* do ShiftRows */
				inv_shift_rows(mode, s);
				/* do SubBytes */
				inv_sub_bytes(mode, s);
			}
		}
		/* save state (cypher) to user buffer */
		for (j = 0; j < 4 * g_aes_nb[mode]; j++) {
			uint8_t p = s[j] ^ v[j];
			v[j] = data[i + j];
			data[i + j] = p;
		}
	}
	return 0;
}
/****************************************************************************************************************/
void aes_cypher_128_test()
{
#if 1
	uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
	uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
#else
	uint8_t buf[] = { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d,
		0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
	uint8_t key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
		0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
#endif
	aes_encrypt(AES_CYPHER_128, buf, sizeof(buf), key);
	aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
void aes_cypher_192_test()
{
	uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
	uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
	aes_encrypt(AES_CYPHER_192, buf, sizeof(buf), key);
	aes_decrypt(AES_CYPHER_192, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
void aes_cypher_256_test()
{
	uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
	uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
	aes_encrypt(AES_CYPHER_256, buf, sizeof(buf), key);
	aes_decrypt(AES_CYPHER_256, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
int main()
{
	// 数据
	uint8_t buf[] = { 78, 204, 144, 217, 57, 62, 169, 79, 165, 219, 206, 216, 180, 137, 206, 138 };
	// 密钥
	uint8_t key[] = { 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 };
	// 向量
	//uint8_t iv[] = {};
	switch (sizeof(key))
	{
	//ECB
	case 16:aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key); break;
	case 24:aes_decrypt(AES_CYPHER_192, buf, sizeof(buf), key); break;
	case 32:aes_decrypt(AES_CYPHER_256, buf, sizeof(buf), key); break;
	//CBC
	/*
	case 16:aes_decrypt_cbc(AES_CYPHER_128, buf, sizeof(buf), key, iv); break;
	case 24:aes_decrypt_cbc(AES_CYPHER_192, buf, sizeof(buf), key, iv); break;
	case 32:aes_decrypt_cbc(AES_CYPHER_256, buf, sizeof(buf), key, iv); break;
	*/
	}
	for (int i = 0; i < sizeof(buf); i++)
	{
		printf("%c", buf[i] & 0xFF);
	}
	printf("\n");
	return 0;
}
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
def add_to_16(text):
    if len(text.encode('utf-8')) % 16:
        add = 16 - (len(text.encode('utf-8')) % 16)
    else:
        add = 0
    text = text + ('\0' * add)
    return text.encode('utf-8')
def encrypt(text):
    key = '\x4D\x4C\x57\x4E\x46\x7C\x19\x0A\x4D\x4C\x57\x4E\x46\x7C\x7B\x67'.encode('utf-8')
    mode = AES.MODE_ECB
    text = add_to_16(text)
    cryptos = AES.new(key, mode)
    cipher_text = cryptos.encrypt(text)
    return cipher_text
def decrypt(text):
    key = '\x4D\x4C\x57\x4E\x46\x7C\x19\x0A\x4D\x4C\x57\x4E\x46\x7C\x7B\x67'.encode('utf-8')
    mode = AES.MODE_ECB
    cryptor = AES.new(key, mode)
    plain_text = cryptor.decrypt(a2b_hex(text))
    return bytes.decode(plain_text).rstrip('\0')
data = b'\x96\x7f\x37\x7c\x26\x30\x03\xeb\x61\x6d\xa3\xda\x0c\x77\x3e\x7c\xdf\x18\x5d\x4e\xd9\xbe\x0a\x5c\x02\x36\x87\x37\xb4\x2f\xb1\x9f'
data = b2a_hex(data)
ans = decrypt(data)
print(ans)

# RC5

# RC6

# SM4

#include <string.h>
#include <stdio.h>
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i) \
	{ \
		(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
		      | ( (unsigned long) (b)[(i) + 1] << 16 ) \
		      | ( (unsigned long) (b)[(i) + 2] << 8 ) \
		      | ( (unsigned long) (b)[(i) + 3] ); \
	}
#endif
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \
	{ \
		(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
		(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
		(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
		(b)[(i) + 3] = (unsigned char) ( (n) ); \
	}
#endif
#define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))
#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }
static const unsigned char SboxTable[16][16] = {
	{0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05},
	{0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99},
	{0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62},
	{0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6},
	{0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8},
	{0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35},
	{0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87},
	{0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e},
	{0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1},
	{0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3},
	{0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f},
	{0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51},
	{0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8},
	{0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0},
	{0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84},
	{0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48}
};
static const unsigned long FK[4] = {0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc};
static const unsigned long CK[32] = {
	0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
	0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
	0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
	0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
	0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
	0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
	0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
	0x10171e25,0x2c333a41,0x484f565d,0x646b7279
};
static unsigned char sm4Sbox(unsigned char inch) {
	unsigned char *pTable = (unsigned char *)SboxTable;
	unsigned char retVal = (unsigned char)(pTable[inch]);
	return retVal;
}
static unsigned long sm4Lt(unsigned long ka) {
	unsigned long bb = 0;
	unsigned long c = 0;
	unsigned char a[4];
	unsigned char b[4];
	PUT_ULONG_BE(ka,a,0)
	b[0] = sm4Sbox(a[0]);
	b[1] = sm4Sbox(a[1]);
	b[2] = sm4Sbox(a[2]);
	b[3] = sm4Sbox(a[3]);
	GET_ULONG_BE(bb,b,0)
	c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));
	return c;
}
static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk) {
	return (x0^sm4Lt(x1^x2^x3^rk));
}
static void sm4_one_round( unsigned long sk[32],
                           unsigned char input[16],
                           unsigned char output[16] ) {
	unsigned long i = 0;
	unsigned long ulbuf[36];
	memset(ulbuf, 0, sizeof(ulbuf));
	GET_ULONG_BE( ulbuf[0], input, 0 )
	GET_ULONG_BE( ulbuf[1], input, 4 )
	GET_ULONG_BE( ulbuf[2], input, 8 )
	GET_ULONG_BE( ulbuf[3], input, 12 )
	while(i<32) {
		ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
		i++;
	}
	PUT_ULONG_BE(ulbuf[35],output,0);
	PUT_ULONG_BE(ulbuf[34],output,4);
	PUT_ULONG_BE(ulbuf[33],output,8);
	PUT_ULONG_BE(ulbuf[32],output,12);
}
static unsigned long sm4CalciRK(unsigned long ka) {
	unsigned long bb = 0;
	unsigned long rk = 0;
	unsigned char a[4];
	unsigned char b[4];
	PUT_ULONG_BE(ka,a,0)
	b[0] = sm4Sbox(a[0]);
	b[1] = sm4Sbox(a[1]);
	b[2] = sm4Sbox(a[2]);
	b[3] = sm4Sbox(a[3]);
	GET_ULONG_BE(bb,b,0)
	rk = bb^(ROTL(bb, 13))^(ROTL(bb, 23));
	return rk;
}
static void sm4_setkey( unsigned long sk[32], unsigned char key[16] ) {
	unsigned long MK[4];
	unsigned long k[36];
	unsigned long i = 0;
	GET_ULONG_BE( MK[0], key, 0 );
	GET_ULONG_BE( MK[1], key, 4 );
	GET_ULONG_BE( MK[2], key, 8 );
	GET_ULONG_BE( MK[3], key, 12 );
	k[0] = MK[0]^FK[0];
	k[1] = MK[1]^FK[1];
	k[2] = MK[2]^FK[2];
	k[3] = MK[3]^FK[3];
	for(; i<32; i++) {
		k[i+4] = k[i] ^ (sm4CalciRK(k[i+1]^k[i+2]^k[i+3]^CK[i]));
		sk[i] = k[i+4];
	}
}
int main() {
	unsigned char key[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
	unsigned char input[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
	unsigned char output[16];
	unsigned long sk[32];
	unsigned long i;
	sm4_setkey(sk,key);
	sm4_one_round(sk, input,output);
	for(i=0; i<16; i++)
		printf("%02x ", output[i]);
	printf("\n");
	return 0;
}

# Blowfish

# Twofish

# Serpent

在线工具请:
http://serpent.online-domain-tools.com/

# PRESENT

Sbox = [12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2]
Sbox_inv = [Sbox.index(x) for x in range(16)]
PBox = [
    0, 16, 32, 48, 1, 17, 33, 49, 2, 18, 34, 50, 3, 19, 35, 51,
    4, 20, 36, 52, 5, 21, 37, 53, 6, 22, 38, 54, 7, 23, 39, 55,
    8, 24, 40, 56, 9, 25, 41, 57, 10, 26, 42, 58, 11, 27, 43, 59,
    12, 28, 44, 60, 13, 29, 45, 61, 14, 30, 46, 62, 15, 31, 47, 63
]
PBox_inv = [PBox.index(x) for x in range(64)]
def addRoundKey(state, roundkey):
    return state ^ roundkey
def sBoxLayer(state):
    output = 0
    for i in range(16):
        output += Sbox[(state >> (i * 4)) & 15] << (i * 4)
    return output
def pLayer(state):
    output = 0
    for i in range(64):
        output += ((state >> i) & 1) << PBox[i]
    return output
def string2number(i):
    return sum([(ord(i[c]) << (8 * c)) for c in range(8)])
def generateRoundkeys80(key, rounds):
    roundkeys = []
    for i in range(1, rounds + 1):
        roundkeys.append(key >> 16)
        key = ((key & 524287) << 61) + (key >> 19)
        key = (Sbox[key >> 76] << 76) + (key & ((2 ** 76) - 1))
        key ^= i << 15
    return roundkeys
def encrypt(blocks):
    rounds = 32
    roundkeys = generateRoundkeys80(85354531916197809168417, rounds)
    out = []
    for block in blocks:
        state = string2number(block)
        for i in range(rounds - 1):
            state = addRoundKey(state, roundkeys[i])
            state = sBoxLayer(state)
            state = pLayer(state)
        cipher = addRoundKey(state, roundkeys[-1])
        out.append(cipher)
    return out
inp = input('pls input ur flag:')
if len(inp) != 32:
    print('wrong!')
    exit(0)
blocks = [inp[:8], inp[8:16], inp[16:24], inp[24:32]]
out_blocks = encrypt(blocks)
解密脚本直接逆着写就行,这里的输入是32位的,然后分块。
```python
Sbox = [12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2]
Sbox_inv = [Sbox.index(x) for x in range(16)]
PBox = [
    0, 16, 32, 48, 1, 17, 33, 49, 2, 18, 34, 50, 3, 19, 35, 51,
    4, 20, 36, 52, 5, 21, 37, 53, 6, 22, 38, 54, 7, 23, 39, 55,
    8, 24, 40, 56, 9, 25, 41, 57, 10, 26, 42, 58, 11, 27, 43, 59,
    12, 28, 44, 60, 13, 29, 45, 61, 14, 30, 46, 62, 15, 31, 47, 63
]
PBox_inv = [PBox.index(x) for x in range(64)]
def addRoundKey(state, roundkey):
    return state ^ roundkey
def generateRoundkeys80(key, rounds):
    roundkeys = []
    for i in range(1, rounds + 1):
        roundkeys.append(key >> 16)
        key = ((key & 524287) << 61) + (key >> 19)
        key = (Sbox[key >> 76] << 76) + (key & ((2 ** 76) - 1))
        key ^= (i << 15)
    return roundkeys
def inv_sBoxLayer(state):
    output = 0
    for i in range(16):
        output += Sbox_inv[(state >> (i * 4)) & 15] << (i * 4)
    return output
def inv_pLayer(state):
    output = 0
    for i in range(64):
        output += ((state >> i) & 1) << PBox_inv[i]
    return output
def number2string(n):
    chars = []
    for i in range(8):
        chars.append(chr((n >> (i * 8)) & 0xFF))
    return ''.join(chars)
def decrypt(ciphers):
    rounds = 32
    roundkeys = generateRoundkeys80(85354531916197809168417, rounds)
    out = []
    for cipher in ciphers:
        state = cipher
        for i in range(rounds - 1, 0, -1):
            state = addRoundKey(state, roundkeys[i])
            state = inv_pLayer(state)
            state = inv_sBoxLayer(state)
        block = addRoundKey(state, roundkeys[0])
        out.append(number2string(block))
    return ''.join(out)
cmps = [120617461261311902, 16357837616839286114, 312508749794633008, 1843701600916795272]
decrypted_flag = decrypt(cmps)
print(decrypted_flag)
## 非对称
#### RSA
```python
import gmpy2
from Crypto.Util.number import long_to_bytes
e = 65537
n = 36618139579386063246087882054063631367923586826293230665209915187491823328978276724908066032487515386697740611819366867179565337532194305783987450587518624526250530134446397
c = 3053043969587277731075013823380664207370991627277672374256662715889363487017560381573682876563907215099359894935326265406537547932246927604121814198201993671878573628633125
p=[521,521,521,541,547,557,557,577,587,593,601,607,631,631,631,631,641,643,683,701,701,719,727,727,727,733,739,739,743,757,761,769,773,787,787,809,821,821,821,863,877,877,881,907,907,907,907,907,919,919,929,937,953,953,967,967,991,997,997,1019]
p.append(521)
phi=1
a=0
for i in p:
    if (a==i):
        phi*=i
    phi*=i-1
    a=i
# phi = (p - 1) * (q - 1)
# n = p * q
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

# 校验

# sha 系列

cyberchef 本地请

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <math.h>
#define GROUP_SIZE 64 
#define MAX_SIZE 1024
unsigned int const K[64] ={
        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,  
        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,  
        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,  
        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,  
        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,  
        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,  
        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,  
        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2  
   };
unsigned int ROR(unsigned int x, unsigned int n);
unsigned int SHR(unsigned int x,unsigned int n);
unsigned int Ch(unsigned int E,unsigned int F,unsigned int G);
unsigned int Maj(unsigned int A,unsigned int B,unsigned int C);
unsigned int Lsigma_0(unsigned int A);
unsigned int Lsigma_1(unsigned int E);
unsigned int Ssigma_0(unsigned int x);
unsigned int Ssigma_1(unsigned int x);
void sha_init(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *E,unsigned int *F,unsigned int *G,unsigned int *H);
size_t sha_update(unsigned char **out, char const *input, size_t inLen);
void sha_transform(unsigned int *out,  char *input);
void data_round(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *E,unsigned int *F,unsigned int *G,unsigned int *H,unsigned int const *M);
void sha_calc(char *out, char const *input, size_t inLen);

# CRC32

uint32_t crc32(const void* buf, size_t size) {
	const uint8_t* p = buf;
	uint32_t crc = ~0U;
	while (size--) {
		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
	}
	return ~crc;
}
uint crc32(byte *data, int size)
{
	uint r = ~0; byte *end = data + size;
	while(data < end)
	{
		r ^= *data++;
		for(int i = 0; i < 8; i++)
		{
			uint t = ~((r&1)1); r = (r>>1) ^ (0xEDB88320 & t);
		}
	}
	return ~r;
}

# md5

cyberchef 本地请

#include "md5.h"
unsigned int ROTATE_LEFT(unsigned int x, unsigned int n) {
	return ((x << n) | (x >> (32 - n)));
}
unsigned int F(unsigned int X, unsigned int Y, unsigned int Z) {
	return (X & Y) | ((~X) & Z);
}
unsigned int G(unsigned int X, unsigned int Y, unsigned int Z) {
	return (X & Z) | (Y & (~Z));
}
unsigned int H(unsigned int X, unsigned int Y, unsigned int Z) {
	return (X ^ Y ^ Z);
}
unsigned int I(unsigned int X, unsigned int Y, unsigned int Z) {
	return (Y ^ (X | (~Z)));
}
void FF(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
	*a += F(b,c,d) + m + t;
	*a = ROTATE_LEFT(*a,s);
	*a += b;
	
	return;
}
void GG(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
	*a += G(b,c,d) + m + t;
	*a = ROTATE_LEFT(*a,s);
	*a += b;
	
	return;
}
void HH(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
	*a += H(b,c,d) + m + t;
	*a = ROTATE_LEFT(*a,s);
	*a += b;
	
	return;
}
void II(unsigned int *a,unsigned int b,unsigned int c,unsigned int d,unsigned int m,unsigned int const t,unsigned int s){
	*a += I(b,c,d) + m + t;
	*a = ROTATE_LEFT(*a,s);
	*a += b;
	
	return;
}
unsigned int shift(unsigned int a){
	unsigned int t1,t2,t3,t4;
	t1 = (a & 0xFF) << 24;
	t2 = (a & 0xFF00) << 8;
	t3 = (a >> 8) & 0xFF00;
	t4 = (a >> 24) & 0xFF;
	//printf("%x\n",t1 + t2 + t3 + t4);
	return (t1 + t2 + t3 + t4);
}
	
/* MD5 initialization */
void md5_init(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D){
    unsigned char data[] = {
		0x01, 0x23, 0x45, 0x67,
		0x89, 0xAB, 0xCD, 0xEF,
		0xFE, 0xDC, 0xBA, 0x98,
		0x76, 0x54, 0x32, 0x10
	};
	memcpy(A, data, 4);
	memcpy(B, data + 4, 4);
	memcpy(C, data + 8, 4);
	memcpy(D, data + 12, 4);
	return;
}
size_t md5_update(char **out, char const *input, size_t inLen){
	int i;
	int j;
	size_t bitLen = inLen * 8; // the bit length of input
	//size_t fillLen = 64 - (inLen - 56) % 64;  // the length of padding 
	//printf("len:%d\n",fillLen);
	size_t fillLen = 56 - (inLen % 64);
	//printf("temp:%d\n",temp);
	size_t filledLen = inLen + fillLen + 8; // the length after padding
	char *outBuf = (char*)calloc(filledLen, sizeof(char));
	memcpy(outBuf, input, inLen);
	outBuf[inLen] = 0x80;// padding 1
	
	j = sizeof(inLen);  // the length of input_lengh
	for (i = 0; i < j; i++) {
		memcpy(outBuf + filledLen - 8 + i, (char*)(&bitLen) + i, 1); // LittleEndian
		//memcpy(outBuf + filledLen - 4 + i, (char*)(&bitLen) + j - 1 - i, 1);
		
	}
	*out = outBuf;  // the data after padding
	return filledLen; 
}
void md5_transform(unsigned int *out,  char *input){
	memcpy(out,input,GROUP_SIZE);
	return;
}
void data_round(unsigned int *A, unsigned int *B, unsigned int *C, unsigned int *D, unsigned int const *m){
	//int k;
	unsigned int a = *A;
	unsigned int b = *B;
	unsigned int c = *C;
	unsigned int d = *D;
	/* round 1 */
	FF(&a,b,c,d,m[0],T[0],S[0]);
	FF(&d,a,b,c,m[1],T[1],S[1]);
	FF(&c,d,a,b,m[2],T[2],S[2]);
    FF(&b,c,d,a,m[3],T[3],S[3]);
	FF(&a,b,c,d,m[4],T[4],S[0]);
	FF(&d,a,b,c,m[5],T[5],S[1]);
	FF(&c,d,a,b,m[6],T[6],S[2]);
	FF(&b,c,d,a,m[7],T[7],S[3]);	
	FF(&a,b,c,d,m[8],T[8],S[0]);
	FF(&d,a,b,c,m[9],T[9],S[1]);
	FF(&c,d,a,b,m[10],T[10],S[2]);
	FF(&b,c,d,a,m[11],T[11],S[3]);
	FF(&a,b,c,d,m[12],T[12],S[0]);
	FF(&d,a,b,c,m[13],T[13],S[1]);
	FF(&c,d,a,b,m[14],T[14],S[2]);
	FF(&b,c,d,a,m[15],T[15],S[3]);
    
	/* round 2 */
    GG(&a,b,c,d,m[1],T[16],S[4]);
    GG(&d,a,b,c,m[6],T[17],S[5]);
	GG(&c,d,a,b,m[11],T[18],S[6]);
	GG(&b,c,d,a,m[0],T[19],S[7]);
	GG(&a,b,c,d,m[5],T[20],S[4]);
	GG(&d,a,b,c,m[10],T[21],S[5]);
	GG(&c,d,a,b,m[15],T[22],S[6]);
	GG(&b,c,d,a,m[4],T[23],S[7]);
	GG(&a,b,c,d,m[9],T[24],S[4]);
	GG(&d,a,b,c,m[14],T[25],S[5]);
	GG(&c,d,a,b,m[3],T[26],S[6]);
	GG(&b,c,d,a,m[8],T[27],S[7]);
	GG(&a,b,c,d,m[13],T[28],S[4]);
	GG(&d,a,b,c,m[2],T[29],S[5]);
	GG(&c,d,a,b,m[7],T[30],S[6]);
	GG(&b,c,d,a,m[12],T[31],S[7]);
    /* round 3 */
 	HH(&a,b,c,d,m[5],T[32],S[8]);
 	HH(&d,a,b,c,m[8],T[33],S[9]);
 	HH(&c,d,a,b,m[11],T[34],S[10]);
 	HH(&b,c,d,a,m[14],T[35],S[11]);
 	HH(&a,b,c,d,m[1],T[36],S[8]);
 	HH(&d,a,b,c,m[4],T[37],S[9]);
 	HH(&c,d,a,b,m[7],T[38],S[10]);
 	HH(&b,c,d,a,m[10],T[39],S[11]);
 	HH(&a,b,c,d,m[13],T[40],S[8]);
 	HH(&d,a,b,c,m[0],T[41],S[9]);
 	HH(&c,d,a,b,m[3],T[42],S[10]);
 	HH(&b,c,d,a,m[6],T[43],S[11]);
 	HH(&a,b,c,d,m[9],T[44],S[8]);
 	HH(&d,a,b,c,m[12],T[45],S[9]);
 	HH(&c,d,a,b,m[15],T[46],S[10]);
 	HH(&b,c,d,a,m[2],T[47],S[11]);
  
	/* round 4 */
	II(&a,b,c,d,m[0],T[48],S[12]);
	II(&d,a,b,c,m[7],T[49],S[13]);
	II(&c,d,a,b,m[14],T[50],S[14]);
	II(&b,c,d,a,m[5],T[51],S[15]);
	II(&a,b,c,d,m[12],T[52],S[12]);
	II(&d,a,b,c,m[3],T[53],S[13]);
	II(&c,d,a,b,m[10],T[54],S[14]);
	II(&b,c,d,a,m[1],T[55],S[15]);
	II(&a,b,c,d,m[8],T[56],S[12]);
	II(&d,a,b,c,m[15],T[57],S[13]);
	II(&c,d,a,b,m[6],T[58],S[14]);
	II(&b,c,d,a,m[13],T[59],S[15]);
	II(&a,b,c,d,m[4],T[60],S[12]);
	II(&d,a,b,c,m[11],T[61],S[13]);
	II(&c,d,a,b,m[2],T[62],S[14]);
	II(&b,c,d,a,m[9],T[63],S[15]);
	*A += a;
	*B += b;
	*C += c;
	*D += d;
}
void md5_calc(char *out, char const *input, size_t inLen){
	int i;
    size_t filledLen;
	char *filledData; 
	unsigned int A,B,C,D;
    unsigned int *M = (unsigned int*)malloc(GROUP_SIZE);
	filledLen = md5_update(&filledData,input,inLen);  
	//printf("input:%s\n",input);
    
    md5_init(&A,&B,&C,&D);
    //printf("%x\n%x\n%x\n%x\n",A,B,C,D);
	for(i = 0;i < filledLen / GROUP_SIZE;i++){
		md5_transform(M, filledData + i * 64);  //char to int 
		data_round(&A,&B,&C,&D,M);
	}
	//printf("%x\n%x\n%x\n%x\n",A,B,C,D); 
	sprintf(out,"%08x%08x%08x%08x",shift(A),shift(B),shift(C),shift(D));
    free(M);
	M = NULL;
	free(filledData);
	filledData = NULL;
	return;
}

# 其他

# 大数计算

# base 系列

# base64 换表

"""
Customized base64 algorithm
You can set you own indexing string using the config() method.
Usage:
    b = CusBase64()
    b.encode('binary\x00string')  # Output: YmluYXJ5AHN0cmluZw==
    b.decode('YmluYXJ5AHN0cmluZw==') # Output: binary\x00string
    b.config('aABCDEFGHIJKLMNOPQRSTUVWXYZbcdefghijklmnopqrstuvwxyz0123456789+/')
    b.decode('c2UsYi1kYWM0cnUjdFlvbiAjb21wbFU0YP==') # Output: self-destruction complete
"""
class CusBase64(object):
    DEFAULT = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    def __init__(self):
        self.idx_str = CusBase64.DEFAULT
    def encode(self, str):
        """
        Encode string using the customized indexing string.
        - args:
            str: String to be encoded
        """
        # Get the binary string
        binary = ''.join([format(ord(c),'0>8b') for c in str])
        # Add additional zero
        binary = self.padding(binary)
        # Get the index in indexing string
        idxs = [int(binary[6*i:6*i+6], 2) for i in range(len(binary)//6)]
        result = ''.join([self.idx_str[i] for i in idxs])
        # add '='
        if len(str)%3 != 0:
            result = result + (3-len(str)%3)*'='
        print("%r" % result)
    def decode(self, str):
        """
        Decode string using the customized indexing string.
        - args:
            str: String to be decoded
        """
        if len(str) == 0:
            return
        # remove '='
        while str[-1]=='=':
            str = str[:-1]
        try:
            # Get the binary string
            binary = ''.join([format(self.idx_str.index(c), '0>6b') for c in str])
            # Remove additional zero
            binary = self.remove(binary)
            result = ''.join([chr(int(binary[8*i:8*i+8], 2)) for i in range(len(binary)//8)])
        except ValueError:
            result = "Please check again!"
        print("%r" % result)
    def remove(self, binary):
        """
        Remove additional zero while decoding string.
        - args:
            binary: Binary format of the index.
        - returns:
            Binary string without additional zero.
        """
        if len(binary)%8 == 0:
            return binary
        else:
            return binary[:-(len(binary)%8)]
    def padding(self, binary):
        """
        Add additional zero while encoding string.
        - args:
            binary: Binary format of the string.
        - returns:
            Binary string with additional zero.
        """
        if len(binary)%6 == 0:
            return binary
        n = 6 - len(binary)%6
        binary = binary + n * '0'
        return binary
    def config(self, str):
        """
        Set customized indexing string.
        """
        self.idx_str = str
        print("New indexing string is %r" % self.idx_str)
b = CusBase64()
b.config('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')
b.encode('flag{this_is_a_sample_flag}')
b.decode('mg6CITV6GEaFDTYnObFmENOAVjKcQmGncF90WhqvCFyhhsyqq1s=')

# base58

package main
import (
    "bytes"
    "math/big"
)
var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
func Base58Encode(input []byte) []byte {
    var result []byte
    x := big.NewInt(0).SetBytes(input)
    base := big.NewInt(int64(len(b58Alphabet)))
    zero := big.NewInt(0)
    mod := &big.Int{}
    for x.Cmp(zero) != 0 {
        x.DivMod(x, base, mod)
        result = append(result, b58Alphabet[mod.Int64()])
    }
    ReverseBytes(result)
    for _, b := range input {
        if b == 0x00 {
            result = append([]byte{b58Alphabet[0]}, result...)
        } else {
            break
        }
    }
    return result
}
func Base58Decode(input []byte) []byte {
    result := big.NewInt(0)
    zeroBytes := 0
    for _, b := range input {
        if b != b58Alphabet[0] {
            break
        }
        zeroBytes++
    }
    payload := input[zeroBytes:]
    for _, b := range payload {
        charIndex := bytes.IndexByte(b58Alphabet, b)
        result.Mul(result, big.NewInt(int64(len(b58Alphabet))))
        result.Add(result, big.NewInt(int64(charIndex)))
    }
    decoded := result.Bytes()
    decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...)
    return decoded
}