熵密杯2024复现
1.puzzle1
题目
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 def encrypt_message (message, key ): message_with_prefix = MSG_PREFIX + message message_bytes = message_with_prefix.encode('utf-8' ) message_len = len (message_bytes) num_blocks = message_len // 16 + 1 blocks = [message_bytes[i * 16 :(i + 1 ) * 16 ] for i in range (num_blocks)] blocks[-1 ] = blocks[-1 ].ljust(16 , b'\x00' ) encrypted_blocks = [] k = key for block in blocks: block_int = int .from_bytes(block, byteorder='big' ) encrypted_block_int = Mod(block_int * k, MODULUS) encrypted_blocks.append(encrypted_block_int) k += 1 encrypted_message = b'' .join( int (block_int).to_bytes(32 , byteorder='big' ) for block_int in encrypted_blocks ) return encrypted_message
一个简单的块加密,16个字节为一块,加密函数是
k的生成很简单,给一个初始的initial_key,然后每次加1,求出一开始的就行
每个message都带有前缀
CryptoCup message: 一共是18字节
那么也就是CryptoCup
messag为第一个分块,但是分块加密之后,一块是32字节
然后我们又知道密文,取前32个字节,就能得到密钥了
exp
1 2 3 4 5 6 7 enc = encrypted_message prefix = enc[:32 ].hex () message_bytes = MSG_PREFIX.encode('utf-8' )[:16 ].hex () recover_key = int (prefix,16 ) * mod_inverse(int (message_bytes,16 ),MODULUS) % MODULUS print (recover_key)print (decrypt_message(enc,recover_key))
2.puzzle2
题目
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 import binasciifrom gmssl import sm3def read_hmac_key (file_path ): with open (file_path, 'rb' ) as f: hmac_key = f.read().strip() return hmac_key def generate_token (hmac_key, counter ): if len (hmac_key) < 32 : hmac_key = hmac_key.ljust(32 , b'\x00' ) elif len (hmac_key) > 32 : hmac_key = hmac_key[:32 ] counter_bytes = counter.to_bytes((counter.bit_length() + 7 ) // 8 , 'big' ) tobe_hashed = bytearray (hmac_key + counter_bytes) sm3_hash = sm3.sm3_hash(tobe_hashed) token = sm3_hash return token current_counter = 0 def verify_token (hmac_key, counter, token ): generated_token = generate_token(hmac_key, counter) global current_counter if generated_token == token: if counter & 0xFFFFFFFF > current_counter: current_counter = counter & 0xFFFFFFFF print ("current_counter: " , hex (current_counter)) return "Success" else : return "Error: counter must be increasing" else : return "Error: token not match" hmac_key_file = 'hmac_key.txt' counter = 0x12345678 hmac_key = read_hmac_key(hmac_key_file) token = generate_token(hmac_key, counter) print ("Generated token:" , token)print (verify_token(hmac_key, counter, token))
虽然说是HMAC吧,但是他这里实现的其实就是MAC
SM3算法也是基于MD结构的,和MD5的填充基本一致,只有一处不同
那就是SM3算法填充长度是大端序,MD5是小端序
SM3 填充过程
对于消息 "abc" (长度3字节 = 24位):
原始消息: 0x61 0x62 0x63
添加 0x80: 0x61 0x62 0x63 0x80
填充0x00直到长度56字节:
[0x61 0x62 0x63 0x80] + [0x00]*52
添加64位长度(大端序):
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x18
MD5 填充过程
对于同样的消息 "abc":
原始消息: 0x61 0x62 0x63
添加 0x80: 0x61 0x62 0x63 0x80
填充0x00直到长度56字节:
[0x61 0x62 0x63 0x80] + [0x00]*52
添加64位长度(小端序):
0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00
SM3的压缩算法更加复杂,有8个寄存器,不过由于是大端序,倒是少了转换的步骤
我们大体了解一下就行,压缩函数是CF(IV,block)
IV是上一个block算出来的SM3值,然后初值IV是给定的,这都和MD5类似,那么照搬MD5的长度拓展攻击就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def SM3_len_ex_ak (num_block,IV,plaintext ): Vtemp=IV a=(len (plaintext)*4 +1 ) % 512 k=0 B=[] if a<=448 : k=448 -a elif a>448 : k=512 -a+448 m=plaintext+"8" +"0" *int ((k+1 )/4 -1 )+zero_fill(str (hex (len (plaintext)*4 +num_block*512 ))[2 :],16 ) block_len=int ((len (plaintext)*4 + k + 65 ) / 512 ) for i in range (0 ,block_len): B.append(m[128 *i:128 *i+128 ]) for i in range (0 ,block_len): Vtemp=CF(Vtemp,B[i]) return Vtemp
题目要求给定一个counter+hash
然后输出一个更大的counter+hash
我们只要在后面加上一个,这样一定是最大的
exp
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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 def zero_fill (a,n ): if len (a)<n: a="0" *(n-len (a))+a return a def cycle_shift_left ( B, n ): n=n%32 return ((B << n) ^ (B >> (32 - n)))%(2 **32 ) def T (j ): if j>=0 and j<=15 : return int ("79cc4519" ,16 ) elif j>=16 and j<=63 : return int ("7a879d8a" ,16 ) def FF (X,Y,Z,j ): if j>=0 and j<=15 : return X^Y^Z elif j>=16 and j<=63 : return (X&Y)|(X&Z)|(Y&Z) def GG (X,Y,Z,j ): if j >= 0 and j <= 15 : return X ^ Y ^ Z elif j >= 16 and j <= 63 : return (X & Y) | (~X & Z) def P0 (x ): return x^(cycle_shift_left(x,9 ))^cycle_shift_left(x,17 ) def P1 (x ): return x^(cycle_shift_left(x,15 ))^cycle_shift_left(x,23 ) def Message_extension (a ): W1 = [] W2=[] for i in range (int (len (a) / 8 )): W1.append(int (a[8 * i:8 * i + 8 ],16 )) for j in range (16 ,68 ): temp=P1(W1[j-16 ] ^ W1[j-9 ] ^ cycle_shift_left(W1[j-3 ],15 )) ^cycle_shift_left(W1[j-13 ],7 )^W1[j-6 ] W1.append(temp) for j in range (0 ,64 ): W2.append(W1[j]^W1[j+4 ]) W1.append(W2) return W1 def CF (V,Bi ): Bi=zero_fill(Bi,128 ) W=[] W=Message_extension(Bi) A=int (V[0 :8 ],16 ) B = int (V[8 :16 ], 16 ) C = int (V[16 :24 ], 16 ) D = int (V[24 :32 ], 16 ) E = int (V[32 :40 ], 16 ) F = int (V[40 :48 ], 16 ) G = int (V[48 :56 ], 16 ) H = int (V[56 :64 ], 16 ) for j in range (0 ,64 ): temp=(cycle_shift_left(A,12 ) + E +cycle_shift_left(T(j),j)) %(2 **32 ) SS1=cycle_shift_left(temp,7 ) SS2=SS1 ^ cycle_shift_left(A,12 ) TT1=(FF(A,B,C,j) +D +SS2 +W[-1 ][j] ) %(2 **32 ) TT2=(GG(E,F,G,j)+H+SS1+W[j])%(2 **32 ) D=C C=cycle_shift_left(B,9 ) B=A A=TT1 H=G G=cycle_shift_left(F,19 ) F=E E=P0(TT2) t1=zero_fill(hex (A^int (V[0 :8 ],16 ))[2 :],8 ) t2 = zero_fill(hex (B ^ int (V[8 :16 ], 16 ))[2 :], 8 ) t3 = zero_fill(hex (C ^ int (V[16 :24 ], 16 ))[2 :], 8 ) t4 = zero_fill(hex (D ^ int (V[24 :32 ], 16 ))[2 :], 8 ) t5 = zero_fill(hex (E ^ int (V[32 :40 ], 16 ))[2 :], 8 ) t6 = zero_fill(hex (F ^ int (V[40 :48 ], 16 ))[2 :], 8 ) t7 = zero_fill(hex (G ^ int (V[48 :56 ], 16 ))[2 :], 8 ) t8 = zero_fill(hex (H ^ int (V[56 :64 ], 16 ))[2 :], 8 ) t=t1+t2+t3+t4+t5+t6+t7+t8 return t def SM3 (plaintext ): Vtemp=IV a=(len (plaintext)*4 +1 ) % 512 k=0 B=[] if a<=448 : k=448 -a elif a>448 : k=512 -a+448 m=plaintext+"8" +"0" *int ((k+1 )/4 -1 )+zero_fill(str (hex (len (plaintext)*4 ))[2 :],16 ) block_len=int ((len (plaintext)*4 + k + 65 ) / 512 ) for i in range (0 ,block_len): B.append(m[128 *i:128 *i+128 ]) for i in range (0 ,block_len): Vtemp=CF(Vtemp,B[i]) return Vtemp def SM3_len_ex_ak (num_block,IV,plaintext ): Vtemp=IV a=(len (plaintext)*4 +1 ) % 512 k=0 B=[] if a<=448 : k=448 -a elif a>448 : k=512 -a+448 m=plaintext+"8" +"0" *int ((k+1 )/4 -1 )+zero_fill(str (hex (len (plaintext)*4 +num_block*512 ))[2 :],16 ) block_len=int ((len (plaintext)*4 + k + 65 ) / 512 ) for i in range (0 ,block_len): B.append(m[128 *i:128 *i+128 ]) for i in range (0 ,block_len): Vtemp=CF(Vtemp,B[i]) return Vtemp IV="7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e" IV2="f81b58b75c469707402e44054d4d45dcacb0294daba39501f5353e20b6fcfe2a" num_block=1 counter = "fde43312" New_Counter = hex (int ((bin (int (counter,16 ))[2 :].zfill(32 ) + "1" ) + "0" *(448 - 32 *8 - 1 - 4 *8 ) + bin (36 *8 )[2 :].zfill(64 ) , 2 ))[2 :] + "ffffffff" print (New_Counter)print (SM3_len_ex_ak(1 ,IV2,"FFFFFFFF" ))
3.puzzle3
题目
一道lwe,先看看加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 n = 16 q = 251 e = sp.Matrix(sp.randMatrix(n, 1 , min =0 , max =1 )) s = sp.Matrix(sp.randMatrix(n, 1 , min =0 , max =q - 1 )) Temp = sp.Matrix(sp.randMatrix(n, n, min =0 , max =q - 1 )) A = Temp.inv_mod(q) b = (A * s + e) % q def encrypt (message, A, b ): m_bin = bin (message)[2 :].zfill(n) m = sp.Matrix([int (bit) for bit in m_bin]) x = sp.Matrix(sp.randMatrix(n, n, min =0 , max =q // (n * 4 ))) e1 = sp.Matrix(sp.randMatrix(n, 1 , min =0 , max =1 )) c1 = (x * A) % q c2 = (x * b + e1 + m * (q // 2 )) % q return c1, c2
这里A,s,e都是随机的 且 那么 我们看看怎么解密的
1 2 3 4 5 6 7 # 解密函数 def decrypt(c1, c2, s): m_dec = (c2 - c1 * s) % q m_rec = m_dec.applyfunc(lambda x: round(2 * x / q) % 2) # 还原消息 m_bin = ''.join([str(bit) for bit in m_rec]) # 将SymPy矩阵转换为二进制字符串 m_rec_int = int(m_bin, 2) # 将二进制字符串转换为整数 return m_rec_int
由于e,e1都很小,如果我们有私钥s
那么 当然题目不会给我们私钥,我们只能得到公钥A,b
但是,A是可逆的。。
所以根本不用s
exp:
1 2 3 4 5 6 x = (c1 * A.inv_mod(q))%q m_dec = (c2 - x*b) % q m_rec = m_dec.applyfunc(lambda x: round (2 * x / q) % 2 ) m_bin = '' .join([str (bit) for bit in m_rec]) m_rec_int = int (m_bin, 2 ) print (m_rec_int)
4.协同签名flag1
题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void encrypt (unsigned char * password, unsigned int key, unsigned char * ciphertext) { unsigned char roundKeys[16 * ROUND] = {}; derive_round_key (key, roundKeys, 16 * ROUND); unsigned char state[16 ]; memcpy (state, password, 16 ); for (int round = 0 ; round < ROUND; round++) { reverseBits (state); sBoxTransform (state); leftShiftBytes (state); addRoundKey (state, roundKeys, round); } memcpy (ciphertext, state, 16 ); }
先看加密函数,分为四步
reverseBits,sBoxTransform
leftShiftBytes,addRoundKey
看着是类似AES,不过不太一样
addRoundKey不用逆向了,然后看leftShiftBytes
1 2 3 4 5 6 7 8 9 10 11 12 13 void leftShiftBytes (unsigned char * state) { unsigned char temp[16 ]; for (int i = 0 ; i < 16 ; i += 4 ) { temp[i + 0 ] = state[i + 2 ] >> 5 | (state[i + 1 ] << 3 ); temp[i + 1 ] = state[i + 3 ] >> 5 | (state[i + 2 ] << 3 ); temp[i + 2 ] = state[i + 0 ] >> 5 | (state[i + 3 ] << 3 ); temp[i + 3 ] = state[i + 1 ] >> 5 | (state[i + 0 ] << 3 ); } for (int i = 0 ; i < 16 ; i++) { state[i] = temp[i]; } }
s0‘是s1的后5位+s2的前3位
s1’是s2后5位+s3前3位
s2‘是s3后5位+s0前3位
s3’是s0后5位+s1前3位
那么很显然拼起来就行了
s0就是s2‘后3位+s3’前5位
回复一个,其他轮换对称就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 void RightShiftBytes (unsigned char * state) { unsigned char temp[16 ]; for (int i = 0 ; i < 16 ; i += 4 ) { temp[i + 0 ] = state[i + 2 ] << 5 | (state[i + 3 ] >> 3 ); temp[i + 1 ] = state[i + 3 ] << 5 | (state[i + 0 ] >> 3 ); temp[i + 2 ] = state[i + 0 ] << 5 | (state[i + 1 ] >> 3 ); temp[i + 3 ] = state[i + 1 ] << 5 | (state[i + 2 ] >> 3 ); } for (int i = 0 ; i < 16 ; i++) { state[i] = temp[i]; } }
然后再看sBoxTransform
1 2 3 4 5 6 7 void sBoxTransform (unsigned char * state) { for (int i = 0 ; i < 16 ; i++) { int lo = sBox[state[i] & 0xF ]; int hi = sBox[state[i] >> 4 ]; state[i] = (hi << 4 ) | lo; } }
sBox可以理解成把一个16位的数映射到16位的数,那我们求出逆映射就行了
那么显然 只需令
1 2 3 for (int i = 0 ; i < 16 ; i++) { sBoxInv[sBox[i]] = i; }
就能造出inv盒子
然后照抄
1 2 3 4 5 6 7 8 9 10 11 void sBoxTransformInv (unsigned char * state) { int sBoxInv[16 ]; for (int i = 0 ; i < 16 ; i++) { sBoxInv[sBox[i]] = i; } for (int i = 0 ; i < 16 ; i++) { int lo = sBoxInv[state[i] & 0xF ]; int hi = sBoxInv[state[i] >> 4 ]; state[i] = (hi << 4 ) | lo; } }
然后reverseBit也不用逆,自己就是,
关键是不知道key,不过这是块密码,我们已知明文“pwd:”四个字节,刚好就是一个block,那么就可以用这个来求key
爆破,倒着爆破比较好,因为随机生成的密钥一般来说都比较大
exp:
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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <openssl/sha.h> #include <chrono> #define ROUND 16 #include <omp.h> int sBox[16 ] ={ 2 , 10 , 4 , 12 , 1 , 3 , 9 , 14 , 7 , 11 , 8 , 6 , 5 , 0 , 15 , 13 }; void hex_to_bytes (const char * hex_str, unsigned char * bytes, size_t bytes_len) { size_t hex_len = strlen (hex_str); if (hex_len % 2 != 0 || hex_len / 2 > bytes_len) { fprintf (stderr, "Invalid hex string length.\n" ); return ; } for (size_t i = 0 ; i < hex_len / 2 ; i++) { sscanf (hex_str + 2 * i, "%2hhx" , &bytes[i]); } } void derive_round_key (unsigned int key, unsigned char * round_key, int length) { unsigned int tmp = key; for (int i = 0 ; i < length / 16 ; i++) { memcpy (round_key + i * 16 , &tmp, 4 ); tmp++; memcpy (round_key + i * 16 + 4 , &tmp, 4 ); tmp++; memcpy (round_key + i * 16 + 8 , &tmp, 4 ); tmp++; memcpy (round_key + i * 16 + 12 , &tmp, 4 ); tmp++; } } void reverseBits (unsigned char * state) { unsigned char temp[16 ]; for (int i = 0 ; i < 16 ; i++) { unsigned char byte = 0 ; for (int j = 0 ; j < 8 ; j++) { byte |= ((state[i] >> j) & 1 ) << (7 - j); } temp[15 - i] = byte; } for (int i = 0 ; i < 16 ; i++) { state[i] = temp[i]; } } void sBoxTransform (unsigned char * state) { for (int i = 0 ; i < 16 ; i++) { int lo = sBox[state[i] & 0xF ]; int hi = sBox[state[i] >> 4 ]; state[i] = (hi << 4 ) | lo; } } void sBoxTransformInv (unsigned char * state) { int sBoxInv[16 ]; for (int i = 0 ; i < 16 ; i++) { sBoxInv[sBox[i]] = i; } for (int i = 0 ; i < 16 ; i++) { int lo = sBoxInv[state[i] & 0xF ]; int hi = sBoxInv[state[i] >> 4 ]; state[i] = (hi << 4 ) | lo; } } void leftShiftBytes (unsigned char * state) { unsigned char temp[16 ]; for (int i = 0 ; i < 16 ; i += 4 ) { temp[i + 0 ] = state[i + 2 ] >> 5 | (state[i + 1 ] << 3 ); temp[i + 1 ] = state[i + 3 ] >> 5 | (state[i + 2 ] << 3 ); temp[i + 2 ] = state[i + 0 ] >> 5 | (state[i + 3 ] << 3 ); temp[i + 3 ] = state[i + 1 ] >> 5 | (state[i + 0 ] << 3 ); } for (int i = 0 ; i < 16 ; i++) { state[i] = temp[i]; } } void RightShiftBytes (unsigned char * state) { unsigned char temp[16 ]; for (int i = 0 ; i < 16 ; i += 4 ) { temp[i + 0 ] = state[i + 2 ] << 5 | (state[i + 3 ] >> 3 ); temp[i + 1 ] = state[i + 3 ] << 5 | (state[i + 0 ] >> 3 ); temp[i + 2 ] = state[i + 0 ] << 5 | (state[i + 1 ] >> 3 ); temp[i + 3 ] = state[i + 1 ] << 5 | (state[i + 2 ] >> 3 ); } for (int i = 0 ; i < 16 ; i++) { state[i] = temp[i]; } } void printState (unsigned char * state) { for (int i = 0 ; i < 16 ; i++) { printf ("%02X " , state[i]); } printf ("\n" ); } void VerifyShift (unsigned char * state) { printf ("Verify:\n" ); printState (state); leftShiftBytes (state); printState (state); RightShiftBytes (state); printState (state); } void VerifySbox (unsigned char * state) { printf ("Verify:\n" ); printState (state); sBoxTransform (state); printState (state); sBoxTransformInv (state); printState (state); } void addRoundKey (unsigned char * state, unsigned char * roundKey, unsigned int round) { for (int i = 0 ; i < 16 ; i++) { for (int j = 0 ; j < 8 ; j++) { state[i] ^= ((roundKey[i + round * 16 ] >> j) & 1 ) << j; } } } void encrypt (unsigned char * password, unsigned int key, unsigned char * ciphertext) { unsigned char roundKeys[16 * ROUND] = {}; derive_round_key (key, roundKeys, 16 * ROUND); unsigned char state[16 ]; memcpy (state, password, 16 ); for (int round = 0 ; round < ROUND; round++) { reverseBits (state); sBoxTransform (state); leftShiftBytes (state); addRoundKey (state, roundKeys, round); } memcpy (ciphertext, state, 16 ); } void decrypt (unsigned char * ciphertext, unsigned int key, unsigned char * decrypted) { unsigned char roundKeys[16 * ROUND] = {}; derive_round_key (key, roundKeys, 16 * ROUND); unsigned char state[16 ]; memcpy (state, ciphertext, 16 ); for (int round = ROUND - 1 ; round >= 0 ; round--) { addRoundKey (state, roundKeys, round); RightShiftBytes (state); sBoxTransformInv (state); reverseBits (state); } memcpy (decrypted, state, 16 ); } void main () { unsigned char ciphertext[16 ]; hex_to_bytes ("99F2980AAB4BE8640D8F322147CBA409" , ciphertext, 16 ); unsigned int key; unsigned char decrypted[16 ]; int found = 0 ; unsigned int foundkey = 0xFAB7C4D9 ; auto start = std::chrono::high_resolution_clock::now (); printf ("Final key: %08X\n" , foundkey); auto end = std::chrono::high_resolution_clock::now (); auto duration = std::chrono::duration_cast <std::chrono::microseconds>(end - start); decrypt (ciphertext, foundkey, decrypted); printf ("Decryption time: %ld microseconds\n" , duration.count ()); printf ("Decrypted password:\n" ); printf ("%s" , decrypted); }
5.flag2
先看客户端
// 客户端通过用户口令、消息摘要和用户私钥d1,计算客户端协同签名值
p1x, p1y, q1x, q1y, r1, s1
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 const submit = ( ) => { isform.value .validate ((valid: boolean ) => { if (valid) { loading.value = true ; let smPassword = ref ("" ); smPassword.value = sm3 (form.value .password ); var { str_e, str_p1x, str_p1y, str_q1x, str_q1y, str_r1, str_s1, errMessage } = clientSign1 (smPassword.value , form.value .msgdigest ); if (errMessage) { ElMessage .error (errMessage) loading.value = false ; return } let data = { q1x : str_q1x, q1y : str_q1y, e : str_e, r1 : str_r1, s1 : str_s1, p1x : str_p1x, p1y : str_p1y } sign_param_send (data).then ((res: any ) => { let str_s : any = clientSign2 (smPassword.value , res.s2 , res.s3 , res.r ); if (str_s.errMessage ) { ElMessage .error (errMessage) loading.value = false ; return } ElMessage .success ("协同签名成功" ); signature_send ({ client_sign : str_s }).then ((res: any ) => { qmz.value = str_s; loading.value = false ; }).then ((err: any ) => { loading.value = false ; }) }).catch ((err: any ) => { loading.value = false ; }) } }) }
一堆东西扰乱视线了,只保留逻辑部分,报错信息什么的都删了
1 2 3 4 5 6 7 8 9 10 11 let smPassword = ref ("" );smPassword.value = sm3 (form.value .password ); var { str_e, str_p1x, str_p1y, str_q1x, str_q1y, str_r1, str_s1, errMessage } = clientSign1 (smPassword.value , form.value .msgdigest ); sign_param_send (data).then ((res: any ) => { let str_s : any = clientSign2 (smPassword.value , res.s2 , res.s3 , res.r );ElMessage .success ("协同签名成功" );signature_send ({ client_sign : str_s })
用户要求提交
1 2 3 4 const form = ref ({ password : "" , msgdigest : "" , })
password就是私钥d1,msgdigest就是e
然后看client1
椭圆曲线单独拿出来,这是标准的sm2参数
1 2 3 4 5 6 7 8 9 10 const sm2 : any = new elliptic.curve .short ({ p : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF' , a : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC' , b : '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93' , n : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123' , g : [ '32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7' , 'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0' ] } as any);
然后也是删了一些没用的逻辑
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 const clientSign1 : any = (str_d1: any, str_e: any ) => { let d1 = new BN (str_d1, 16 ); let e = new BN (str_e, 16 ); let n = new BN (sm2.n .toString (16 ), 16 ); let G = sm2.g ; const randomBytes = cryptoRandomStringAsync ({ length : 64 }); k1.value = new BN (randomBytes as any, 16 ); k1.value = k1.value .mod (n); d1 = d1.mod (n); let tmp1 = d1.invm (n); let P1 = G.mul (tmp1); let Q1 = G.mul (k1.value ); let x = new BN (Q1 .getX ().toString (16 ), 16 ); let r1 = x.mod (n); tmp1 = d1.invm (n); let tmp2 = tmp1.mul (r1).mod (n); let tmp3 = tmp2.add (e).mod (n); tmp1 = k1.value .invm (n); let s1 = tmp1.mul (tmp3).mod (n); str_e = e.toString (16 ); return { str_e, str_p1x, str_p1y, str_q1x, str_q1y, str_r1, str_s1 } }
随机生成一个
然后我们构造两个点 然后令
接着把这些数发给服务器,然后服务器用d2得到s2,s3,r
1 2 3 4 5 6 7 8 9 const clientSign2 = (str_d1: any, str_s2: any, str_s3: any, str_r: any ) => { let tmp1 = d1.mul (k1.value ).mod (n); let tmp2 = tmp1.mul (s2).mod (n); let tmp3 = d1.mul (s3).mod (n); tmp1 = tmp2.add (tmp3).mod (n); let s = tmp1.sub (r).mod (n); return s; }
然后用d1,s2,s3,r计算 然后我们来看服务端(删了没用的代码),其实只看注释就行了
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 Result server (char * str_e, char * str_p1x, char * str_p1y, char * str_q1x, char * str_q1y, char * str_r1, char * str_s1) { group = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx); generator = EC_POINT_new(group); x="32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" y="BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" generator=(x,y) k3 = k2 G = EC_POINT_new(group); P = EC_POINT_new(group); P1 = EC_POINT_new(group); Q1 = EC_POINT_new(group); TMP = EC_POINT_new(group); print_flag2(d2); rv = 0 ; BN_CTX_free(bn_ctx); return rv; }
计算了这么几个量 计算 验证是否 为什么要验证这个呢,回顾一下 然后令
注意到 那其实x'就是r1
然后再计算 然后 把等式汇总一下,太多了 $$
$$ 把变量捋一下
e, p1x, p1y, q1x, q1y, r1, s1,s2,s3,r 这些都已知
d1,k1,k2=k3,d2不知道
为了求d2,就得求k3,也就是k2,注意到 ,所以我们直接有 那么 很简单,前面都没什么用
exp:
1 2 3 4 5 6 7 from Crypto.Util.number import *s2=0xB9D5131ADE5BD8B11B1D68271184F633D0B236FD680746C3B79B584DEBC4DD8E s3=0xD0DEF51E325FE11A780625A3C8E398060B7F7DBF0E4D91182B0AE6DDF02A3413 r=0xF7A7B5ABE1312F7A2799A27897D7EA57736FA5D00CF81287332D3727677E0EFA n=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123 d = inverse(r,n)*(s3-s2)%n print (hex (d)[2 :])