总结一下计算机中的数学相关内容,便于后续调用
[0] 目录
数学算法
[模乘]
密码学
Stream Cipher
Block Cipher
[1] MATH
[1-1] 模乘
[1-1-1] 蒙哥马利算法
蒙哥马利算法能够提高类似模幂运算的速度而实现的,主要是因为蒙哥马利算法巧妙地避免了大量模运算(除法),极大地降低了运算时间,下面介绍如何减少x*y
mod N的模运算数目。
首先,蒙哥马利算法引入了REDC函数,该函数以大数T,模数N,模数N的逆元的负数N'和整数R(如果N为素数,R一般选取\(2^{n\_bit}\) ,这样就可以在整除前提下用移位运算代替除法运算,也就是将下面代码第三行的整除运算换成移位运算)作为输入,在不使用模运算的情况下输出\(TR^{-1} mod
N\) 。该函数减少了模运算的数目,同时将T的蒙哥马利形式恢复成了普通形式。该函数的低效版python实现如下:
1 2 3 4 5 6 def REDC(R, N, N_inverse, T): m = ((T % R) * N_inverse) % R t = (T + m * N) // R if t >= N: return t - N return t
可以看到m的预计算使得t处于(0,2N)之间,我们可以用一次比较和一次减法代替模运算。如果想要进一步提升效率,可以将m提出这个函数放入查找表中,进一步减少模运算的数目。
接下来介绍大数T的蒙哥马利形式:假设我们有模数N,大整数T。其实T的蒙哥马利形式\(\overline{T}\) 就是TR.其中 R
,且R与模数N互素,这样我们可以通过REDC函数来恢复T mod N。
假设我们有模数N,大数a和大数b,蒙哥马利模乘就是:先将a和b转化为蒙哥马利形式,然后计算\(\overline{a} * \overline{b}\) ,也就是\(a*b*R^2\) ,最后求解\(\overline{c} = REDC(\overline{a} *
\overline{b})\) 即可求得乘积c的蒙哥马利形式。我们可以将\(\overline{c}\) 再丢进REDC函数即可获得c,也可以用\(\overline{c}\) 进行之后的运算。
到目前为止,除了预计算m和求R的模逆元需要几次模运算外,所有运算均不涉及模运算,还保证了所有乘法运算都维持在modN的量级进行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 def extended_gcd (a, b ): if a == 0 : return b, 0 , 1 gcd, x1, y1 = extended_gcd(b % a, a) x = y1 - (b // a) * x1 y = x1 return gcd, x, y def mod_inverse (a, m ): gcd, x, y = extended_gcd(a, m) if gcd != 1 : raise ValueError("Inverse doesn't exist" ) else : return x % m def calc_n_bit (N ): n_bit = 0 while N > 0 : N >>= 1 n_bit += 1 return n_bit def find_N_inverse (N, R ): N_inv = mod_inverse(N, R) N_inverse = (R - N_inv) % R return N_inverse def REDC (R, N, N_inverse, T ): n_bit = calc_n_bit(N) m = ((T % R) * N_inverse) % R t = (T + m * N) >> n_bit if t >= N: return t - N return t def convert_to_montgomery (R, N, T ): return (T * R) % N def montgomery_multiply (T1, T2, N, R ): product = T1 * T2 N_inv = find_N_inverse(N, R) return REDC(R, N, N_inv, product) if __name__ == "__main__" : N = 2 **4096 - 1 n_bit = calc_n_bit(N) R = 1 << n_bit T1 = 231735531420147883 T2 = 8270984215581679609 mont_T1 = convert_to_montgomery(R, N, T1) mont_T2 = convert_to_montgomery(R, N, T2) print ("montgomery_multiply: " , REDC(R, N, find_N_inverse(N, R), montgomery_multiply(mont_T1, mont_T2, N, R)))
[1] Stream Cipher
[1-1] RC4
[1-1-1] 基本原理
加密: 明文与 keystream 异或得到密文
密文: 密文与 keystream 异或得到明文
keystream 与明文等长
由于 RC4 采取逐位异或的加密方式,只要我们知道了密文和key,只需要放到
cyberchef 里再加密一次就能得到原文
[1-1-2] 生成密钥流(keystream)
RC4 的密钥流生成由两部分组成:
KSA(the Key-Scheduling Algorithm)
PRGA(the Pseudo-Random Generation Algorithm)
KSA: 利用key生成S盒 1 2 3 4 5 6 7 8 9 10 11 12 13 int i = 0 ;int j = 0 ;char T[SBOX_LEN] = {0 };for (i = 0 ; i < SBOX_LEN; i++) { Sbox[i] = i; T[i] = key[ i % key_length ]; } for (i = 0 ; i < SBOX_LEN; i++) { j = (j + Sbox[i] + T[i]) % SBOX_LEN; swap(&Sbox[i], &Sbox[j]); }
PRGA: 利用S盒生成密钥流 1 2 3 4 5 6 7 8 9 10 11 int i = 0 ;int j = 0 ;int t = 0 ;for (int k = 0 ; k < data_len; k++) { i = (i + 1 ) % SBOX_LEN; j = (j + Sbox[i]) % SBOX_LEN; swap(&Sbox[i], &Sbox[j]); t = (Sbox[i] + Sbox[j]) % SBOX_LEN; puc_key_stream[k] = Sbox[t]; }
[1-1-3] 完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 #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" ); } 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]); } } 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; 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 ; 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] = {"HeyGap" }; char data[512 ] = "HeyGap" ; 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); rc4_ksa(sbox, (unsigned char *)key, strlen (key)); 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 ; }
[2] Block Cipher
[2-1] Tea/xTea/xxTea
[2-1-1] Tea decrypt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> using namespace std;uint32_t key[4 ] = {1234 ,2341 ,3412 ,4123 };uint32_t delta = 0xDEADBEEF ;void tea_decrypt (uint32_t *encrypted) { uint32_t sum = 0 ; uint32_t enc_tmp1 = encrypted[0 ],enc_tmp2 = encrypted[1 ]; for (int i=0 ;i<32 ;i++) { sum += delta; } for (int i=0 ;i<32 ;i++) { enc_tmp2 -= (sum + enc_tmp1) ^ (16 * enc_tmp1 + key[2 ]) ^ (32 * enc_tmp1 + key[3 ]); enc_tmp1 -= (sum + enc_tmp2) ^ (16 * enc_tmp2 + key[0 ]) ^ (32 * enc_tmp2 + key[1 ]); sum -= delta; } encrypted[0 ] = enc_tmp1; encrypted[1 ] = enc_tmp2; } int main () { unsigned char encflag[] = { 0 }; tea_decrypt ((uint32_t *)encflag+0 ); tea_decrypt ((uint32_t *)encflag+2 ); tea_decrypt ((uint32_t *)encflag+4 ); tea_decrypt ((uint32_t *)encflag+6 ); cout<<(char *)encflag<<endl; system ("pause" ); return 0 ; }
[2-1-2] xTea decrypt
[2-1-3] xxTea decrypt