# Reverse learning (I) encryption algorithm

## preface

As a school course, I don't understand. ctf has no teammates and can only sign in pwn hands. Today, I'm ready to open a new pit!

(you pwn are still a vegetable chicken. Why are you opening a new pit)

The following contents are mainly organized according to wiki.

## Topic

### Base64

base64 must be familiar to everyone. After all, it's so well-known, but we used to be b64encode() and Baidu: base64. I've never understood the principle. I'm ashamed to take the opportunity of entering the pit in reverse to record the encryption principle of base64

Base64 is a representation of binary data based on 64 printable characters.

The 64 printable characters are ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 + /. Generally, an index table will be established. If you can find the index table and judge it, you can judge that it is base64

During conversion, 3 bytes of data are successively put into a 24 bit buffer, and the first byte occupies the high position. If the data is less than 3 bytes, the remaining bits in the buffer are supplemented with 0. Take out 6 bits each time (2 ^ 6 = 64), select the characters in the index table according to their values as the encoded output, and know that all data have been converted.

### Tea micro encryption algorithm

The code is as follows:

#include <stdint.h> void encrypt (uint32_t* v, uint32_t* k) { uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */ uint32_t delta=0x9e3779b9; /* a key schedule constant */ uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ for (i=0; i < 32; i++) { /* basic cycle start */ sum += delta; v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); } /* end cycle */ 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; /* set up */ uint32_t delta=0x9e3779b9; /* a key schedule constant */ uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ for (i=0; i<32; i++) { /* basic cycle start */ v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); sum -= delta; } /* end cycle */ v[0]=v0; v[1]=v1; }

The logic of encryption and decryption is very simple. Encryption is that v0 and v1 use each other and secret key K to alternately perform 32 XOR encryption

Decryption can be done in the opposite direction.

wiki:

The most important recognition feature of Tea algorithm is that it has an image number: 0x9e3779b9. Of course, the Tea algorithm is also modified by magic. For those interested, please see 2018 0ctf quals milk Tea.

### RC4

Symmetric encryption includes stream encryption (sequence cipher) and block encryption. When the key is shorter than the plaintext, the two encryption methods have different processing methods.

Stream encryption is to extend the secret key to make it as long as plaintext to complete encryption. Packet encryption is to cut the plaintext into multiple block s and then encrypt it with a secret key

RC4 belongs to stream encryption. The security of stream encryption depends on the randomness after the secret key is extended. RC4 is implemented through an S-box

void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) //Initialization function { int i =0, j = 0; char k[256] = {0}; unsigned char tmp = 0; for (i=0;i<256;i++) { s[i] = i; k[i] = key[i%Len]; } for (i=0; i<256; i++) { j=(j+s[i]+k[i])%256; tmp = s[i]; s[i] = s[j]; //Exchange s[i] and s[j] s[j] = tmp; } } void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) //Encryption and decryption { int i = 0, j = 0, t = 0; unsigned long k = 0; unsigned char tmp; for(k=0;k<Len;k++) { i=(i+1)%256; j=(j+s[i])%256; tmp = s[i]; s[i] = s[j]; //Exchange s[i] and s[i], which destroys the S-box. The original S-box shall be used for actual decryption s[j] = tmp; t=(s[i]+s[j])%256; Data[k] ^= s[t];//Here is encryption, including init, which can be regarded as the generation of pseudo-random numbers in stream ciphers } }

### MD5

Pseudo code:

/Note: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating var int[64] r, k //r specifies the per-round shift amounts r[ 0..15]: = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22} r[16..31]: = {5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20} r[32..47]: = {4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23} r[48..63]: = {6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21} //Use binary integer part of the sines of integers as constants: for i from 0 to 63 k[i] := floor(abs(sin(i + 1)) × 2^32) //Initialize variables: var int h0 := 0x67452301 var int h1 := 0xEFCDAB89 var int h2 := 0x98BADCFE var int h3 := 0x10325476 //Pre-processing: append "1" bit to message append "0" bits until message length in bits ≡ 448 (mod 512) append bit length of message as 64-bit little-endian integer to message //Process the message in successive 512-bit chunks: for each 512-bit chunk of message break chunk into sixteen 32-bit little-endian words w[i], 0 ≤ i ≤ 15 //Initialize hash value for this chunk: var int a := h0 var int b := h1 var int c := h2 var int d := h3 //Main loop: for i from 0 to 63 if 0 ≤ i ≤ 15 then f := (b and c) or ((not b) and d) g := i else if 16 ≤ i ≤ 31 f := (d and b) or ((not d) and c) g := (5×i + 1) mod 16 else if 32 ≤ i ≤ 47 f := b xor c xor d g := (3×i + 5) mod 16 else if 48 ≤ i ≤ 63 f := c xor (b or (not d)) g := (7×i) mod 16 temp := d d := c c := b b := leftrotate((a + f + k[i] + w[g]),r[i]) + b a := temp Next i //Add this chunk's hash to result so far: h0 := h0 + a h1 := h1 + b h2 := h2 + c h3 := h3 + d End ForEach var int digest := h0 append h1 append h2 append h3 //(expressed as little-endian)

The main features are:

h0 = 0x67452301; h1 = 0xefcdab89; h2 = 0x98badcfe; h3 = 0x10325476;

After learning more encryption, I'll add it (set up a flag first)