也是拿到了第一,可惜后面打的两眼昏花审最后一题代码的时候审差了,或许就可以 ak 了 /(ㄒoㄒ)/~~
相比去年和前年,今年的难度是真的高,代码量也多了很多,打的也是两眼昏花。其中打*的是赛中没有出的。
初始谜题
总共 3 个初始谜题,只有做了其中一个才可以进入下面的密码系统进行做题。
初始谜题1
题目:
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 import binasciifrom pyasn1.codec.der.decoder import decodefrom pyasn1.type import univ, namedtypefrom cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modesfrom cryptography.hazmat.backends import default_backendfrom gmssl import sm3, func, sm2from pyasn1.codec.der.encoder import encodeclass SM2Cipher (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('xCoordinate' , univ.Integer()), namedtype.NamedType('yCoordinate' , univ.Integer()), namedtype.NamedType('hash' , univ.OctetString()), namedtype.NamedType('cipherText' , univ.OctetString()) ) class EncryptedData (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('algorithm' , univ.ObjectIdentifier('1.2.156.10197.1.104.2' )), namedtype.NamedType('iv' , univ.OctetString()), namedtype.NamedType('cipherText' , univ.OctetString()) ) class EnvelopedData (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('encryptedKey' , SM2Cipher()), namedtype.NamedType('encryptedData' , EncryptedData()), namedtype.NamedType('digestAlgorithm' , univ.ObjectIdentifier('1.2.156.10197.1.401.1' )), namedtype.NamedType('digest' , univ.OctetString()) ) def sm4_cbc_encrypt (plaintext: bytes , key: bytes , iv: bytes ): backend = default_backend() cipher = Cipher(algorithms.SM4(key), modes.CBC(iv), backend=backend) encryptor = cipher.encryptor() ciphertext = encryptor.update(plaintext) + encryptor.finalize() return ciphertext def sm2_encrypt (plaintext: bytes ,public_key:bytes ) -> bytes : sm2_crypt = sm2.CryptSM2(private_key="" ,public_key=public_key.hex ()) ciphertext = sm2_crypt.encrypt(plaintext) return ciphertext def sm3_hash (text:bytes ): hash_value = sm3.sm3_hash(func.bytes_to_list(text)) return hash_value def read_key_from_file (file_path ): try : with open (file_path, 'r' ) as file: key = file.read().strip() return key except FileNotFoundError: print (f"错误: 文件 {file_path} 未找到。" ) except Exception as e: print (f"错误: 发生了未知错误 {e} 。" ) return None def sm4_encrypt (plaintext:str ,sm2_public_key: str ,sm4_iv:str ): sm4_key = bytes .fromhex(read_key_from_file("key.txt" )) envelope = EnvelopedData() plaintext_bytes = plaintext.encode('utf-8' ) ciphertext = sm4_cbc_encrypt(plaintext_bytes,sm4_key,bytes .fromhex(sm4_iv)) encrypted_key = sm2_encrypt(sm4_key,bytes .fromhex(sm2_public_key)) digest = sm3_hash(plaintext_bytes) envelope['encryptedData' ] = EncryptedData() envelope['encryptedData' ]['iv' ] = univ.OctetString(bytes .fromhex(sm4_iv)) envelope['encryptedData' ]['cipherText' ] = univ.OctetString(ciphertext) envelope['encryptedKey' ] = SM2Cipher() envelope['encryptedKey' ]['xCoordinate' ] = univ.Integer(int .from_bytes(encrypted_key[:32 ], 'big' )) envelope['encryptedKey' ]['yCoordinate' ] = univ.Integer(int .from_bytes(encrypted_key[32 :64 ], 'big' )) envelope['encryptedKey' ]['hash' ] = univ.OctetString(encrypted_key[64 :96 ]) envelope['encryptedKey' ]['cipherText' ] = univ.OctetString(encrypted_key[96 :]) envelope['digest' ] = univ.OctetString(bytes .fromhex(digest)) return encode(envelope).hex () def asn1_parse (asn1_hex_str:str ,asn1_spec ): der_bytes = binascii.unhexlify(asn1_hex_str) enveloped_data, _ = decode(der_bytes, asn1Spec=asn1_spec) sm2_x = hex (int (enveloped_data['encryptedKey' ]['xCoordinate' ]))[2 :] sm2_y = hex (int (enveloped_data['encryptedKey' ]['yCoordinate' ]))[2 :] sm2_hash = enveloped_data['encryptedKey' ]['hash' ].asOctets().hex () sm2_ciphertext = enveloped_data['encryptedKey' ]['cipherText' ].asOctets().hex () sm4_algorithm = str (enveloped_data['encryptedData' ]['algorithm' ]) sm4_iv = enveloped_data['encryptedData' ]['iv' ].asOctets().hex () sm4_cipherText = enveloped_data['encryptedData' ]['cipherText' ].asOctets().hex () digestAlgorithm = str (enveloped_data['digestAlgorithm' ]) digest = enveloped_data['digest' ].asOctets().hex () print ("asn1格式的16进制字符串:" ) print (f" asn1: {asn1_hex_str} " ) print ("SM2参数:" ) print (f" xCoordinate: {sm2_x} " ) print (f" yCoordinate: {sm2_y} " ) print (f" hash: {sm2_hash} " ) print (f" cipherText: {sm2_ciphertext} " ) print ("SM4参数:" ) print (f" algorithm: {sm4_algorithm} " ) print (f" iv: {sm4_iv} " ) print (f" cipherText: {sm4_cipherText} " ) print ("SM3参数:" ) print (f" digestAlgorithm: {digestAlgorithm} " ) print (f" digest: {digest} " ) if __name__ == "__main__" : plaintext = "6163616263626161626461646464636361626263626464626361616164636462636462646461646461626462646361636264616364646462646462626261636261646163626463636262616462646462616362616363646463646361616263646261636164636263646163646161636164646364646261626463636462636162636162646261626163636161616463616261646264616162646162626162626462616363616161636362616461626463616462646261626264626464626262636363636162616261626163616164616462626163636164646161646361626363646462626261636261636164646262646362616263636363626461636164646261636361646463616161626164626461636163636461646164616161616163616164636164646261646163626163636164616162636263616461636261646264626263626264636164646263616164626463626461646364616362626261616262616264616361626264636264616461646163626364626462636161636262636163616261616262626362636463616263616364616363626163636363636262646363616464626461616363646361626162636261636364646362626462616364626462626161616264636162626263626462626264646162626462616261616264626161616363636364616263626461636162616462616363616461646363636261636363616162646164626361616464646463646263646363636164626164646463646361636364616261626261646461646463626161616361626161626362626262636164626463636163626163616163636262646463646162616363616364636164646364626464626164626162636161616263646164636461626161636262646463636462646161636462626264626463646364636362626264616362646462636263616361626262616464636263616464616363646163616262616162626261626261616461636361636164636162626461646264636162646363636263616363646161636464626161616462636464646164616361646264616361626263646264616162636164636462616164646163616461646362626464" sm2_key = "044f66804d1d30f4499377b96dc8e18faab8300ebddf3eb0fa2065214c260d64c08c6dfe7d9923d6d5baa3a0512a2ede03357c723230ebf77906f82dc1b0fccc1e" iv = "43d4192f9f74e90543d4192f9f74e905" asn1_hex_str = sm4_encrypt(bytes .fromhex(plaintext).decode('utf-8' ),sm2_key,iv) asn1_parse(asn1_hex_str,EnvelopedData())
题目实现了一个数字信封,利用 SM4-CBC 对消息的进行加密得到密文,然后用 SM2 对 SM4-CBC 的密钥进行加密,并且给出消息的 SM3 哈希值。
挑战目标是给出一个组明密文,然后通过其恢复一段密文(两组明文都是 abcd
的随机组合)。首先它给的密文是 asn1 编码格式,不过无所谓,反正也给我们解 asn1 的代码了。然后再审计代码,你会发现——好像这个数字信封实现的也没啥问题哎。当时是直接懵逼了,那要咋打,总不能直接爆破明文然后对照 hash 吧。不过注意到给出的明密文很长,而要恢复的明文很短,这时候就脑洞打开了一下,把要恢复的密文的第一块用 ctrl f 搜索了一下,结果发现竟然给定的密文有一块和它一样的。那就好办了,因为是 CBC 形式的而且 iv 也给我们了,所以可以快速计算出第一块的消息。
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 import binasciifrom pyasn1.codec.der.decoder import decodefrom pyasn1.type import univ, namedtypefrom cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modesfrom cryptography.hazmat.backends import default_backendfrom gmssl import sm3, func, sm2from pyasn1.codec.der.encoder import encodeclass SM2Cipher (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('xCoordinate' , univ.Integer()), namedtype.NamedType('yCoordinate' , univ.Integer()), namedtype.NamedType('hash' , univ.OctetString()), namedtype.NamedType('cipherText' , univ.OctetString()) ) class EncryptedData (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('algorithm' , univ.ObjectIdentifier('1.2.156.10197.1.104.2' )), namedtype.NamedType('iv' , univ.OctetString()), namedtype.NamedType('cipherText' , univ.OctetString()) ) class EnvelopedData (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('encryptedKey' , SM2Cipher()), namedtype.NamedType('encryptedData' , EncryptedData()), namedtype.NamedType('digestAlgorithm' , univ.ObjectIdentifier('1.2.156.10197.1.401.1' )), namedtype.NamedType('digest' , univ.OctetString()) ) def asn1_parse (asn1_hex_str:str ,asn1_spec ): der_bytes = binascii.unhexlify(asn1_hex_str) enveloped_data, _ = decode(der_bytes, asn1Spec=asn1_spec) sm2_x = hex (int (enveloped_data['encryptedKey' ]['xCoordinate' ]))[2 :] sm2_y = hex (int (enveloped_data['encryptedKey' ]['yCoordinate' ]))[2 :] sm2_hash = enveloped_data['encryptedKey' ]['hash' ].asOctets().hex () sm2_ciphertext = enveloped_data['encryptedKey' ]['cipherText' ].asOctets().hex () sm4_algorithm = str (enveloped_data['encryptedData' ]['algorithm' ]) sm4_iv = enveloped_data['encryptedData' ]['iv' ].asOctets().hex () sm4_cipherText = enveloped_data['encryptedData' ]['cipherText' ].asOctets().hex () digestAlgorithm = str (enveloped_data['digestAlgorithm' ]) digest = enveloped_data['digest' ].asOctets().hex () print ("asn1格式的16进制字符串:" ) print (f" asn1: {asn1_hex_str} " ) print ("SM2参数:" ) print (f" xCoordinate: {sm2_x} " ) print (f" yCoordinate: {sm2_y} " ) print (f" hash: {sm2_hash} " ) print (f" cipherText: {sm2_ciphertext} " ) print ("SM4参数:" ) print (f" algorithm: {sm4_algorithm} " ) print (f" iv: {sm4_iv} " ) print (f" cipherText: {sm4_cipherText} " ) print ("SM3参数:" ) print (f" digestAlgorithm: {digestAlgorithm} " ) print (f" digest: {digest} " ) m1 = '6362646264646264646361636463646261636164626362646264616161636162636261616461646263626362626264636163616264626164616161616361616161636163636361626463616361626263626263646462626261616462646362626162646162646461646264626361646264636164626262626264646464626362626462626364646463636362636264616161636461626363626362616263636264636164636261646262626161636161616461616163616461626461646464616363646462636464646464636462636264636464636162616461646263646264636363616263616164646263646362646161616361646261616161626261626462636261646362626362626462636463616164636263646164636461646364646464616461626463616463636362626464646463636461626264636363636263646463626163636362646264616261636464626164646363626164626264616462626264646463646163646162626364616264646163636362646164616263616461626164636261646361636162616162646161646162636364646162626361646362646361626463616262646362636261616464626162636161616362616464616261626363616464626164616362616262616463626364646461636461636164636261626364646362626263636164626161636264646261636264626164626264636463616263646462646464636461626264626262626263626362636463636362636264646262626162626364616363636264626462636163646361636163616464626361616262646361626261646364646461636164626164646361626264616364626361636163626163636363626464626462646364646364616461616161616361646264626364636364626261636363636361616264636262646262616263636361616361616261616162636163646363646264636364616362626362626463616264646261626164646263646164646264616463646462626261616461636461626262636462646163636461646362616363616163616361626162636462616362636361646363626161636362636361616261636362636463' c1 = '308203ec30790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f576503082034006082a811ccf550168020410f414bdfbca9d9e902114536a3b9c443204820320d76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f947706092a811ccf5501831101042024d458eef08943e27b496fd180de68c18f467bee9d3c802bb56d607a364ddc70' c = '3081e830790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f57650303e06082a811ccf550168020410b63a85e103d362fb6247c19e324e97c4042098fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea0010706092a811ccf55018311010420aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79' ''' asn1格式的16进制字符串: asn1: 308203ec30790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f576503082034006082a811ccf550168020410f414bdfbca9d9e902114536a3b9c443204820320d76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f947706092a811ccf5501831101042024d458eef08943e27b496fd180de68c18f467bee9d3c802bb56d607a364ddc70 SM2参数: xCoordinate: 467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da405 yCoordinate: 99f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d8 hash: 4452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b cipherText: 443c9a3f4f7b0083ddd323d6a1f57650 SM4参数: algorithm: 1.2.156.10197.1.104.2 iv: f414bdfbca9d9e902114536a3b9c4432 cipherText: d76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f9477 SM3参数: digestAlgorithm: 1.2.156.10197.1.401.1 digest: 24d458eef08943e27b496fd180de68c18f467bee9d3c802bb56d607a364ddc70 None ''' ''' asn1格式的16进制字符串: asn1: 3081e830790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f57650303e06082a811ccf550168020410b63a85e103d362fb6247c19e324e97c4042098fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea0010706092a811ccf55018311010420aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79 SM2参数: xCoordinate: 467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da405 yCoordinate: 99f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d8 hash: 4452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b cipherText: 443c9a3f4f7b0083ddd323d6a1f57650 SM4参数: algorithm: 1.2.156.10197.1.104.2 iv: b63a85e103d362fb6247c19e324e97c4 cipherText: 98fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea00107 SM3参数: digestAlgorithm: 1.2.156.10197.1.401.1 digest: aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79 None ''' def xor (a, b ): return bytes ([i ^ j for i, j in zip (a, b)]) m1 = '6362646264646264646361636463646261636164626362646264616161636162636261616461646263626362626264636163616264626164616161616361616161636163636361626463616361626263626263646462626261616462646362626162646162646461646264626361646264636164626262626264646464626362626462626364646463636362636264616161636461626363626362616263636264636164636261646262626161636161616461616163616461626461646464616363646462636464646464636462636264636464636162616461646263646264636363616263616164646263646362646161616361646261616161626261626462636261646362626362626462636463616164636263646164636461646364646464616461626463616463636362626464646463636461626264636363636263646463626163636362646264616261636464626164646363626164626264616462626264646463646163646162626364616264646163636362646164616263616461626164636261646361636162616162646161646162636364646162626361646362646361626463616262646362636261616464626162636161616362616464616261626363616464626164616362616262616463626364646461636461636164636261626364646362626263636164626161636264646261636264626164626264636463616263646462646464636461626264626262626263626362636463636362636264646262626162626364616363636264626462636163646361636163616464626361616262646361626261646364646461636164626164646361626264616364626361636163626163636363626464626462646364646364616461616161616361646264626364636364626261636363636361616264636262646262616263636361616361616261616162636163646363646264636364616362626362626463616264646261626164646263646164646264616463646462626261616461636461626262636462646163636461646362616363616163616361626162636462616362636361646363626161636362636361616261636362636463' iv1 = bytes .fromhex('f414bdfbca9d9e902114536a3b9c4432' ) ct1 = 'd76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f9477' iv2 = bytes .fromhex('b63a85e103d362fb6247c19e324e97c4' ) ct2 = '98fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea00107' d = 'aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79' t = ct1.index('98fea6b8123d811480a1add915a34d4f' ) assert ct1[t:t+32 ] == ct2[:32 ]mmm = bytes .fromhex(m1[t:t+32 ]) m2 = xor(xor(mmm, bytes .fromhex(ct1[t-32 :t])), iv2) print (m2)
然后对于第二块,因为长度也不长而且就是明文空间也很小,那就爆吧,时间复杂度也才 2 32 2^{32} 2 3 2 。但是我用 python 实现的话要 300h,那就让队友用 go 给我写了一个,最后用了 8min 就出了。
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 package mainimport ( "fmt" "sync" "time" "github.com/tjfoc/gmsm/sm3" ) var char = []byte ("abcd" )func index_to_char (index uint64 ) []byte { res := []byte {} for { if len (res) == 15 { return append (res, char[index]) } res = append (res, char[index%4 ]) index /= 4 } } var char_set = []byte ("adcddbbadcacabad" )const tar_hex = "aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79" func main () { var j uint64 wg := &sync.WaitGroup{} wg.Add(256 ) time_start := time.Now() defer wg.Wait() for j = 0 ; j <= 0xff ; j++ { go func (j uint64 ) { defer wg.Done() var i uint64 for i = 0 ; i <= 0xffffff ; i++ { data := append (char_set, index_to_char((j << 24 ) + i)...) hash := sm3.New() hash.Write(data) sum := hash.Sum(nil ) sum_hex := fmt.Sprintf("%x" , sum) if sum_hex == tar_hex { fmt.Println(string (data)) return } } }(j) } wg.Wait() time_end := time.Now() fmt.Printf("Time taken: %v\n" , time_end.Sub(time_start)) }
初始谜题2
题目:
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 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 import binasciifrom datetime import datetimefrom pyasn1.type import univ, namedtypefrom pyasn1.codec.der.encoder import encodefrom pyasn1.codec.der.decoder import decodefrom gmssl import sm2from pyasn1.codec.der import decoder, encoderfrom pyasn1_modules import rfc2459from gmssl.sm2 import CryptSM2from pyasn1.type .useful import GeneralizedTimefrom pyasn1.type .univ import Sequence from pyasn1.type import usefulclass ECPrimeFieldConfig (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('fieldType' , univ.ObjectIdentifier('1.2.840.10045.1.1' )), namedtype.NamedType('prime' , univ.Integer()), ) class ECCurveParameters (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('coefficientA' , univ.OctetString()), namedtype.NamedType('coefficientB' , univ.OctetString()), ) class ECDomainParameters (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('version' , univ.Integer(1 )), namedtype.NamedType('fieldParameters' , ECPrimeFieldConfig()), namedtype.NamedType('curveParameters' , ECCurveParameters()), namedtype.NamedType('basePoint' , univ.OctetString()), namedtype.NamedType('order' , univ.Integer()), namedtype.NamedType('cofactor' , univ.Integer(1 )), ) class SM2SignatureValue (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('r' , univ.Integer()), namedtype.NamedType('s' , univ.Integer()), ) class SM2SignedData (univ.Sequence ): componentType = namedtype.NamedTypes( namedtype.NamedType('version' , univ.Integer()), namedtype.NamedType('digestAlgorithms' , univ.ObjectIdentifier()), namedtype.NamedType('sm2Signature' , SM2SignatureValue()), namedtype.NamedType('ecDomainParameters' , ECDomainParameters()), namedtype.NamedType('certificate' , univ.OctetString()), namedtype.NamedType('timestamp' , GeneralizedTime()), ) def asn1_package (version, oid, signature, curve_params, cert_hex, time_stamp ): sm2_signed_data = SM2SignedData() sm2_signed_data['version' ] = version sm2_signed_data['digestAlgorithms' ] = oid sm2_signed_data["sm2Signature" ] = SM2SignatureValue() sm2_signed_data["sm2Signature" ]['r' ] = int (signature[:64 ], 16 ) sm2_signed_data["sm2Signature" ]['s' ] = int (signature[64 :], 16 ) sm2_signed_data["ecDomainParameters" ] = ECDomainParameters() sm2_signed_data["ecDomainParameters" ]["fieldParameters" ] = ECPrimeFieldConfig() sm2_signed_data["ecDomainParameters" ]["fieldParameters" ]["prime" ] = int (curve_params['p' ], 16 ) sm2_signed_data["ecDomainParameters" ]["curveParameters" ] = ECCurveParameters() sm2_signed_data["ecDomainParameters" ]["curveParameters" ]["coefficientA" ] = univ.OctetString( bytes .fromhex(curve_params['a' ])) sm2_signed_data["ecDomainParameters" ]["curveParameters" ]["coefficientB" ] = univ.OctetString( bytes .fromhex(curve_params['b' ])) sm2_signed_data["ecDomainParameters" ]['basePoint' ] = univ.OctetString(bytes .fromhex('04' + curve_params['g' ])) sm2_signed_data["ecDomainParameters" ]['order' ] = int (curve_params['n' ], 16 ) sm2_signed_data["certificate" ] = univ.OctetString(bytes .fromhex(cert_hex)) dt = datetime.strptime(time_stamp, "%Y-%m-%d %H:%M:%S" ) asn1_time_str = dt.strftime("%Y%m%d%H%M%SZ" ) sm2_signed_data["timestamp" ] = GeneralizedTime(asn1_time_str) return encode(sm2_signed_data).hex () class Sm2CertVerifier : def __init__ (self, cert_hex: str ): ca_pubkey = "8E1860588D9900C16BD19A0FE0A5ACC600224DBD794FFD34179E03698D52421F46E6D8C6E8AADE512C7B543395AC39C76384726C7F8BA537ABCA0C129ECD9882" self .sm2_crypt = sm2.CryptSM2(public_key=ca_pubkey, private_key=None ) self .cert_tbs, self .signature_bytes, self .cert = self .parse_cert(bytes .fromhex(cert_hex)) @staticmethod def parse_cert (cert_der_bytes: bytes ): cert, _ = decoder.decode(cert_der_bytes, asn1Spec=rfc2459.Certificate()) tbs = cert.getComponentByName('tbsCertificate' ) signature_bytes = cert.getComponentByName('signatureValue' ).asOctets() return tbs, signature_bytes, cert def decode_rs_from_der (self, signature: bytes ) -> bytes : seq, _ = decode(signature, asn1Spec=Sequence ()) r = int (seq[0 ]) s = int (seq[1 ]) r_bytes = r.to_bytes(32 , byteorder='big' ) s_bytes = s.to_bytes(32 , byteorder='big' ) return r_bytes + s_bytes def verify_signature (self, signature: bytes , tbs: str ): inter_cert_tbs_der = encoder.encode(tbs) inter_signature = self .decode_rs_from_der(signature) return self .sm2_crypt.verify_with_sm3(inter_signature.hex (), inter_cert_tbs_der) def verify_certificate_expiration_date (self, tbs ): validity = tbs.getComponentByName('validity' ) not_before = validity.getComponentByName('notBefore' ).getComponent() not_after = validity.getComponentByName('notAfter' ).getComponent() if isinstance (not_before, useful.UTCTime): not_before_time = datetime.strptime(str (not_before), "%y%m%d%H%M%SZ" ) elif isinstance (not_before, useful.GeneralizedTime): not_before_time = datetime.strptime(str (not_before), "%Y%m%d%H%M%SZ" ) else : raise ValueError("Unsupported notBefore time format" ) if isinstance (not_after, useful.UTCTime): not_after_time = datetime.strptime(str (not_after), "%y%m%d%H%M%SZ" ) elif isinstance (not_after, useful.GeneralizedTime): not_after_time = datetime.strptime(str (not_after), "%Y%m%d%H%M%SZ" ) else : raise ValueError("Unsupported notAfter time format" ) now = datetime.now() return not_before_time <= now <= not_after_time def verify (self ): if not self .verify_certificate_expiration_date(self .cert_tbs): print ("证书已过期或尚未生效" ) return False if not self .verify_signature(self .signature_bytes, self .cert_tbs): print ("证书验证未通过" ) return False return True class SM2Config : def __init__ (self, asn1_str ): self .sm2_signed_data,asn1_acess = self .hex_to_asn1(asn1_str, SM2SignedData()) if len (asn1_acess) != 0 : raise ValueError("asn1长度有问题" ) cert_hex = self .get_hex_value(self .sm2_signed_data['certificate' ]) sm2_cert_verifier = Sm2CertVerifier(cert_hex) valid = sm2_cert_verifier.verify() if not valid: raise TypeError("证书验证不通过" ) g = self .get_hex_value(self .sm2_signed_data['ecDomainParameters' ]['basePoint' ]) g = g[2 :] if g.startswith("04" ) else g self .ecc_table = { 'n' : self .get_hex_value(self .sm2_signed_data['ecDomainParameters' ]['order' ]), 'p' : self .get_hex_value(self .sm2_signed_data['ecDomainParameters' ]['fieldParameters' ]['prime' ]), 'g' : g, 'a' : self .get_hex_value(self .sm2_signed_data['ecDomainParameters' ]['curveParameters' ]['coefficientA' ]), 'b' : self .get_hex_value(self .sm2_signed_data['ecDomainParameters' ]['curveParameters' ]['coefficientB' ]), } public_key = self .extract_public_key(sm2_cert_verifier.cert_tbs) self .sm2_crypt = CryptSM2( private_key="" , public_key=public_key, ecc_table=self .ecc_table ) self .sign = (int (self .sm2_signed_data['sm2Signature' ]['r' ]).to_bytes(32 , 'big' ).hex ().upper() + int (self .sm2_signed_data['sm2Signature' ]['s' ]).to_bytes(32 , 'big' ).hex ().upper()) @staticmethod def hex_to_asn1 (hex_str, asn1_spec ): """ 将16进制字符串转换回ASN.1对象 :param hex_str: 16进制字符串 :param asn1_spec: ASN.1结构定义 :return: ASN.1对象 """ der_bytes = binascii.unhexlify(hex_str) asn1_object, excess = decode(der_bytes, asn1Spec=asn1_spec) return asn1_object,excess @staticmethod def get_hex_value (value ): """通用转换函数:将 ASN.1 值转换为 16 进制字符串(大写,无前缀)""" if isinstance (value, univ.Integer): return format (int (value), 'X' ) elif isinstance (value, univ.OctetString): return value.asOctets().hex ().upper() else : raise TypeError(f"Unsupported type: {type (value)} " ) @staticmethod def extract_public_key (tbs ): spki = tbs.getComponentByName('subjectPublicKeyInfo' ) public_key_bitstring = spki.getComponentByName('subjectPublicKey' ) pubkey_bytes = bytearray (public_key_bitstring.asOctets()) return pubkey_bytes.hex () def verify_misc (self ): if (int (self .sm2_signed_data['version' ]) != 1 or str (self .sm2_signed_data['digestAlgorithms' ]) != '1.2.156.10197.1.401.1' or str (self .sm2_signed_data['timestamp' ]) != "20250520101000Z" ): return False return True def verify (self, data ): valid = self .verify_misc() if not valid: return valid valid = self .sm2_crypt.verify_with_sm3(self .sign, data) return valid def generateSM2SignedDataExample (): version = 1 oid = '1.2.156.10197.1.401.1' signature = '6f8eaff551d0f3fa6de74b75b33e1e58f9fdb4dc58e61c82e11e717ffcf168c4db3d5a90ff3625d12b8b658f8dbab34340c278b412b3aff25489e7feb1c75598' r = signature[:64 ] s = signature[64 :] curve_params = { "n" : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123' , "p" : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF' , "g" : '32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0' , "a" : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC' , "b" : '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93' , } cert_hex = '3082017C30820122A003020102020D00947C8427D3E849B48A7E5136300A06082A811CCF550183753036310B300906035504061302434E31133011060355040A130A5368616E674D6942656931123010060355040313095368616E674D694341301E170D3235303532303035353330365A170D3330303531393035353330365A304D310B300906035504061302434E3110300E060355040A1307496E746572434131173015060355040B130E5368616E674D6942656932303235311330110603550403130A7368616E676D696265693059301306072A8648CE3D020106082A811CCF5501822D03420004CECC0005AED684A1E7E39C316E7F3F39BDD0490936BC0E1AFDDC1B9627A05B4418809E5327746EE1977913F036EF0A9A255C27D73C00E45D0BB205B34D2C80D4300A06082A811CCF5501837503480030450220360779CBF5AA6E5E9CC073D95E22C52C09E81CFC06A3916559063A3C8C1DFDE6022100ED0E5E5E51F3894A3EAC11F247739D9F6A88C961D89F68337972BC3CC6BB6706' time_stamp = '2025-05-20 10:10:00' asn1_package_hex = asn1_package(version, oid, signature, curve_params, cert_hex, time_stamp) return (asn1_package_hex) if __name__ == '__main__' : data = b"Hello, CryptoCup!" asn1_package_hex = generateSM2SignedDataExample() sm2_config = SM2Config(asn1_package_hex) result = sm2_config.verify(data) print (result)
SM2SignedData.txt
1 308202CD02010106092A811CCF5501831101304502206F8EAFF551D0F3FA6DE74B75B33E1E58F9FDB4DC58E61C82E11E717FFCF168C4022100DB3D5A90FF3625D12B8B658F8DBAB34340C278B412B3AFF25489E7FEB1C755983081E0020101302C06072A8648CE3D0101022100FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF30440420FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC042028E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E9304410432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0022100FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123020101048201803082017C30820122A003020102020D00947C8427D3E849B48A7E5136300A06082A811CCF550183753036310B300906035504061302434E31133011060355040A130A5368616E674D6942656931123010060355040313095368616E674D694341301E170D3235303532303035353330365A170D3330303531393035353330365A304D310B300906035504061302434E3110300E060355040A1307496E746572434131173015060355040B130E5368616E674D6942656932303235311330110603550403130A7368616E676D696265693059301306072A8648CE3D020106082A811CCF5501822D03420004CECC0005AED684A1E7E39C316E7F3F39BDD0490936BC0E1AFDDC1B9627A05B4418809E5327746EE1977913F036EF0A9A255C27D73C00E45D0BB205B34D2C80D4300A06082A811CCF5501837503480030450220360779CBF5AA6E5E9CC073D95E22C52C09E81CFC06A3916559063A3C8C1DFDE6022100ED0E5E5E51F3894A3EAC11F247739D9F6A88C961D89F68337972BC3CC6BB6706180F32303235303532303130313030305A
题目代码需要生成一个指定数据的签名,而这个公钥是在证书中,证书链验证时公钥固定,所以无法修改证书,但是题目额外让我们自己指定曲线参数。
直接对给定的证书里面的公钥Q,可以用sagemath计算出 255 G ′ = Q 255G'=Q 2 5 5 G ′ = Q ,然后把基点替换为 G ′ G' G ′ 即可通过验签。
首先计算 G ′ G' G ′
1 2 3 4 5 6 7 8 9 pub = "cecc0005aed684a1e7e39c316e7f3f39bdd0490936bc0e1afddc1b9627a05b4418809e5327746ee1977913f036ef0a9a255c27d73c00e45d0bb205b34d2c80d4" x,y = int (pub[:64 ],16 ), int (pub[64 :], 16 ) P = E(x,y) G = P * inverse_mod(0xff ,n) G x = 36937047021928959731165221160519944594794112257956092575886609274654427603612 y = 104673289685811405702677634451265453400814492624193002291684496503421528948368 hex (x)[2 :].zfill(64 ) + hex (y)[2 :].zfill(64 )
然后调用gmssl库生成签名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from gmssl.sm2 import CryptSM2curve_params = { "n" : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123' , "p" : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF' , "g" : '51a9a0b4050aaa36ea04d9004d0e477dad7dfb19021147a168969748cd46629ce76afb832729a051f24993c9c201921933b29657a070fd6c537fca04af0fbe90' , "a" : 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC' , "b" : '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93' , } sm2_crypt = CryptSM2( private_key="ff" , public_key="cecc0005aed684a1e7e39c316e7f3f39bdd0490936bc0e1afddc1b9627a05b4418809e5327746ee1977913f036ef0a9a255c27d73c00e45d0bb205b34d2c80d4" , ecc_table=curve_params ) msg = b'EUWJSFTFHGQEQVRXZHJYKPUXDPUMRDQQ' sig = sm2_crypt.sign_with_sm3(msg) print (sig)
初始谜题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 from typing import List , Callable from hashlib import sha256def hex_to_32byte_chunks (hex_str ): if len (hex_str) % 64 != 0 : raise ValueError("十六进制字符串长度必须是64的倍数" ) return [bytes .fromhex(hex_str[i:i + 64 ]) for i in range (0 , len (hex_str), 64 )] def openssl_sha256 (message: bytes ) -> bytes : return sha256(message).digest() class WOTSPLUS : def __init__ ( self, w: int = 16 , hashfunction: Callable = openssl_sha256, digestsize: int = 256 , pubkey: List [bytes ] = None , ) -> None : self .w = w if not (2 <= w <= (1 << digestsize)): raise ValueError("规则错误:2 <= w <= 2^digestsize" ) self .msg_key_count = 8 self .cs_key_count = 0 self .key_count = self .msg_key_count + self .cs_key_count self .hashfunction = hashfunction self .digestsize = digestsize self .pubkey = pubkey @staticmethod def number_to_base (num: int , base: int ) -> List [int ]: if num == 0 : return [0 ] digits = [] while num: digits.append(int (num % base)) num //= base return digits[::-1 ] def _chain (self, value: bytes , startidx: int , endidx: int ) -> bytes : for i in range (startidx, endidx): value = self .hashfunction(value) return value def get_signature_base_message (self, msghash: bytes ) -> List [int ]: msgnum = int .from_bytes(msghash, "big" ) msg_to_sign = self .number_to_base(msgnum, self .w) if len (msg_to_sign) > self .msg_key_count: err = ( "The fingerprint of the message could not be split into the" + " expected amount of bitgroups. This is most likely " + "because the digestsize specified does not match to the " + " real digestsize of the specified hashfunction Excepted:" + " {} bitgroups\nGot: {} bitgroups" ) raise IndexError(err.format (self .msg_key_count, len (msg_to_sign))) return msg_to_sign def get_pubkey_from_signature ( self, digest: bytes , signature: List [bytes ] ) -> List [bytes ]: msg_to_verify = self .get_signature_base_message(digest) result = [] for idx, val in enumerate (msg_to_verify): sig_part = signature[idx] chained_val = self ._chain(sig_part, val, self .w - 1 ) result.append(chained_val) return result def verify (self, digest: bytes , signature: List [bytes ] ) -> bool : pubkey = self .get_pubkey_from_signature(digest, signature) return True if pubkey == self .pubkey else False if __name__ == "__main__" : pubkey_hex = "5057432973dc856a7a00272d83ea1c14de52b5eb3ba8b70b373db8204eb2f902450e38dbade5e9b8c2c3f8258edc4b7e8101e94ac86e4b3cba92ddf3d5de2a2b454c067a995060d1664669b45974b15b3423cec342024fe9ccd4936670ec3abaae4f6b97279bd8eb26463a8cb3112e6dcbf6301e4142b9cdc4adfb644c7b114af4f0cf8f80e22c3975ba477dc4769c3ef67ffdf2090735d81d07bc2e6235af1ee41ef332215422d31208c2bc2163d6690bd32f4926b2858ca41c12eec88c0a300571901a3f674288e4a623220fb6b70e558d9819d2f23da6d897278f4056c346d7f729f5f70805ad4e5bd25cfa502c0625ac02185e014cf36db4ebcdb3ed1a38" pubkey_list_bytes = hex_to_32byte_chunks(pubkey_hex) wots = WOTSPLUS(pubkey = pubkey_list_bytes) digest_hex = "84ffb82e" signature_hex = "25d5a0e650d683506bfe9d2eca6a3a99b547a4b99398622f6666ce10131e971b6bd36841c9074fe9b4de2900ebe3fadb3202a173be486da6cf8f3d8c699c95c3454c067a995060d1664669b45974b15b3423cec342024fe9ccd4936670ec3abaae4f6b97279bd8eb26463a8cb3112e6dcbf6301e4142b9cdc4adfb644c7b114a4966398a789b56bdb09ea195925e7e8cde372305d244604c48db08f08a6e8a38951030deb25a7aaf1c07152a302ebc07d5d0893b5e9a5953f3b8500179d138b9aa90c0aaacea0c23d22a25a86c0b747c561b480175b548fcb1f4ad1153413bc74d9c049d43ffe18ceee31e5be8bdb9968103ef32fb4054a4a23c400bbfe0d89f" digest_bytes = bytes .fromhex(digest_hex) signature = hex_to_32byte_chunks(signature_hex) valid = wots.verify(digest_bytes,signature) print (valid)
这个最简单了,它实现了一个 OTS 的验签函数,但是没有给出签名函数。目标是给定一组签名和公钥要求你伪造一组签名可以通过。
我们都知道,OTS 的私钥是不能重用的,这里公钥一样那私钥也肯定一样的。一个简单的想法,我直接令摘要为 ffffffff
那么对于每一组其的签名都是对私钥进行 255 次 hash 操作。但是公钥也是对私钥进行 255 次摘要,那就说明了如果摘要是 ffffffff
,那么签名就是公钥了。所以这题其实只给公钥也可以伪造的。
密码系统
这里总共 6 个flag,其中 flag1
做完了才可以做后面的 2、3、4、5,然后全部做完就会送一个 flag6
。
1-TSP服务器登录
题目:
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 package serviceimport ( "crypto/ecdsa" "encoding/asn1" "encoding/hex" "errors" "fmt" "github.com/tjfoc/gmsm/sm2" "math/big" ) func (s *LoginService) Login(username, authInfo, certStr string ) (token string , err error ) { cert, err := s.CertService.LoadCertificate(certStr) if err != nil { return "" , err } if err := s.CertService.ValidateCertificate(cert, RootCert); err != nil { return "" , err } if cert.Subject.CommonName != username { err = errors.New("username is not valid" ) } ecdsaPubKey, ok := cert.PublicKey.(*ecdsa.PublicKey) if !ok { return "" , errors.New("public key in cert is not sm2" ) } sm2PubKey := sm2.PublicKey{ Curve: ecdsaPubKey.Curve, X: ecdsaPubKey.X, Y: ecdsaPubKey.Y, } if len (authInfo) != 256 { return "" , errors.New("鉴别信息格式有误" ) } randomStr := authInfo[0 :128 ] signature := authInfo[128 :] _, err = ValidateSignature(randomStr, signature, &sm2PubKey) if err != nil { return "" , err } return s.generateToken(username) } func ValidateSignature (messageHex, signatureHex string , publicKey *sm2.PublicKey) (bool , error ) { msg, err := hex.DecodeString(messageHex) if err != nil { return false , errors.New("挑战值格式有误" ) } if len (signatureHex) != 128 { return false , errors.New("签名值格式有误" ) } r, ok := big.NewInt(0 ).SetString(signatureHex[:64 ], 16 ) if !ok { return false , errors.New("签名值格式有误" ) } s, ok := big.NewInt(0 ).SetString(signatureHex[64 :], 16 ) if !ok { return false , errors.New("签名值格式有误" ) } signature, err := asn1.Marshal(struct { R, S *big.Int }{r, s}) if err != nil { return false , errors.New("签名值格式有误" ) } isValid := publicKey.Verify(msg, signature) if isValid { return true , nil } else { return false , fmt.Errorf("签名无效" ) } }
使用智能密码钥匙登录TSP服务器的历史抓包数据.txt
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 智能密码钥匙抓包数据分析备忘:如果一条指令未全部发送完数据,下一条指令继续发送数据时第一个字节为标志位。 Bus Hound 6.00 capture on Windows Vista (x64). Complements of www.perisoft.net Device - Device ID (followed by the endpoint for USB devices) (29) USB Input Device Phase - Phase Type CTL USB control transfer IN Data in transfer OUT Data out transfer Data - Hex dump of the data transferred Descr - Description of the phase Cmd... - Position in the captured data Device Phase Data Description Cmd.Phase.Ofs(rep) ------ ----- ------------------------------------------------------------------------------------------------------ -------------------------------- ------------------ 29.0 CTL 21 0a 00 00 00 00 00 00 SET IDLE 1.1.0(2) 29.1 OUT de fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 01 12 00 07 c0 0a 00 80 00 00 80 00 ................................ 3.1.0 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 ................................ 3.1.32 29.1 IN bf aa aa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 12 00 82 67 6d 33 30 30 30 00 00 ........................gm3000.. 4.1.0 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 ................................ 4.1.32 29.1 IN 3f 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 ?............................... 5.1.0 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 ................................ 5.1.32 29.1 IN 5b 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 90 00 00 00 00 00 [............................... 6.1.0 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 ................................ 6.1.32 29.1 OUT de fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 02 12 00 07 80 04 01 00 00 00 00 00 ................................ 7.1.0 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 ................................ 7.1.32 29.1 IN bf aa aa 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 12 00 46 47 4d 33 30 30 30 00 00 ...I...................FGM3000.. 8.1.0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 37 39 37 33 33 30 41 31 ........................797330A1 8.1.32 29.1 IN 5e 35 30 46 33 36 41 45 45 38 39 33 39 43 42 36 41 36 39 36 39 41 30 44 00 05 00 02 17 90 00 00 ^50F36AEE8939CB6A6969A0D........ 9.1.0 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 ................................ 9.1.32 29.1 OUT de fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 03 12 00 07 80 04 00 00 00 00 00 00 ................................ 10.1.0 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 ................................ 10.1.32 29.1 IN bf aa aa 25 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 12 01 22 01 00 01 00 4c 6f 6e 67 ...%..................."....Long 11.1.0 6d 61 69 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 mai............................. 11.1.32 29.1 IN 3f 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 4c 6f 6e ?............................Lon 12.1.0 67 6d 61 69 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 gmai............................ 12.1.32 29.1 IN 3f 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 47 4d ?.............................GM 13.1.0 33 30 30 30 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 37 39 3000..........................79 13.1.32 29.1 IN 3f 37 33 33 30 41 31 35 30 46 33 36 41 45 45 38 39 33 39 43 42 36 41 36 39 36 39 41 30 44 00 05 ?7330A150F36AEE8939CB6A6969A0D.. 14.1.0 00 02 17 07 07 00 00 00 07 03 00 07 00 00 00 01 04 00 00 00 02 00 00 00 01 ee 80 04 20 00 01 00 ............................ ... 14.1.32 29.1 IN 7d 02 00 00 10 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 ................................ 15.1.0 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 90 00 00 00 ................................ 15.1.32 29.1 OUT de fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 04 12 00 07 80 22 00 00 00 00 00 00 ........................."...... 16.1.0 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 ................................ 16.1.32 29.1 IN e4 aa aa 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 12 00 0d 47 4d 33 30 30 30 52 53 ........................GM3000RS 17.1.0 41 00 00 90 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 A............................... 17.1.32 29.1 OUT e9 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 15 00 00 05 12 00 12 80 26 00 00 00 00 09 47 .........................&.....G 18.1.0 4d 33 30 30 30 52 53 41 00 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 M3000RSA........................ 18.1.32 29.1 IN e3 aa aa 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 12 00 0c ff 00 00 00 00 00 00 00 ................................ 19.1.0 10 00 90 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 ................................ 19.1.32 29.1 OUT de fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 06 12 00 07 80 50 00 00 00 00 08 00 .........................P...... 20.1.0 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 ................................ 20.1.32 29.1 IN e1 aa aa 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 12 00 0a b1 22 84 f7 e6 0f b4 5c .........................".....\ 21.1.0 90 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 ................................ 21.1.32 29.1 OUT f0 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 00 00 07 12 00 19 80 18 00 01 00 00 12 10 ................................ 22.1.0 00 cf 87 86 2f eb 06 65 9e d8 8a 10 61 09 e7 42 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..../..e....a..B................ 22.1.32 29.1 IN d9 aa aa 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 12 00 02 90 00 00 00 00 00 00 00 ................................ 23.1.0 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 ................................ 23.1.32 29.1 OUT e0 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c 00 00 08 12 00 09 80 46 00 00 00 00 02 10 .........................F...... 24.1.0 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 ................................ 24.1.32 29.1 IN eb aa aa 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 12 00 14 44 65 66 61 75 6c 74 43 ........................DefaultC 25.1.0 6f 6e 74 61 69 6e 65 72 00 00 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ontainer........................ 25.1.32 29.1 OUT f2 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 00 09 12 00 1b 80 42 00 00 00 00 12 10 .........................B...... 26.1.0 00 44 65 66 61 75 6c 74 43 6f 6e 74 61 69 6e 65 72 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 .DefaultContainer............... 26.1.32 29.1 IN db aa aa 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 12 00 04 30 01 90 00 00 00 00 00 ........................0....... 27.1.0 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 ................................ 27.1.32 29.1 OUT db fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 0a 12 00 04 c0 52 00 00 00 00 00 00 .........................R...... 28.1.0 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 ................................ 28.1.32 29.1 IN d9 aa aa 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 12 00 02 90 00 00 00 00 00 00 00 ................................ 29.1.0 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 ................................ 29.1.32 29.1 OUT e4 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 0b 12 00 0d 80 4e 01 00 00 00 04 10 .........................N...... 30.1.0 00 30 01 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 .0.............................. 30.1.32 29.1 IN bf aa aa f5 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0b 12 01 f2 00 00 03 82 2d 2d 2d 2d ............................---- 31.1.0 2d 42 45 47 49 4e 20 43 45 52 54 49 46 49 43 41 54 45 2d 2d 2d 2d 2d 0d 0a 4d 49 49 43 58 7a 43 -BEGIN CERTIFICATE-----..MIICXzC 31.1.32 29.1 IN 3f 43 41 67 57 67 41 77 49 42 41 67 49 49 52 64 4f 6f 49 6f 58 58 64 4d 41 77 43 67 59 49 4b 6f ?CAgWgAwIBAgIIRdOoIoXXdMAwCgYIKo 32.1.0 45 63 7a 31 55 42 67 33 55 77 4e 6a 45 4c 4d 41 6b 47 41 31 55 45 42 68 4d 43 0d 0a 51 30 34 78 Ecz1UBg3UwNjELMAkGA1UEBhMC..Q04x 32.1.32 29.1 IN 3f 45 7a 41 52 42 67 4e 56 42 41 6f 54 43 6c 4e 6f 59 57 35 6e 54 57 6c 43 5a 57 6b 78 45 6a 41 ?EzARBgNVBAoTClNoYW5nTWlCZWkxEjA 33.1.0 51 42 67 4e 56 42 41 4d 54 43 56 4e 6f 59 57 35 6e 54 57 6c 44 51 54 41 65 46 77 30 79 0d 0a 4e QBgNVBAMTCVNoYW5nTWlDQTAeFw0y..N 33.1.32 29.1 IN 3f 54 41 32 4d 44 6b 77 4d 6a 55 77 4e 44 6c 61 46 77 30 30 4e 54 45 77 4d 54 41 78 4d 6a 41 78 ?TA2MDkwMjUwNDlaFw00NTEwMTAxMjAx 34.1.0 4d 44 46 61 4d 46 55 78 45 7a 41 52 42 67 4e 56 42 41 6f 54 43 6c 4e 6f 59 57 35 6e 54 57 6c 43 MDFaMFUxEzARBgNVBAoTClNoYW5nTWlC 34.1.32 29.1 IN 3f 0d 0a 5a 57 6b 78 46 7a 41 56 42 67 4e 56 42 41 73 54 44 6c 4e 6f 59 57 35 6e 54 57 6c 43 5a ?..ZWkxFzAVBgNVBAsTDlNoYW5nTWlCZ 35.1.0 57 6b 79 4d 44 49 31 4d 52 67 77 46 67 59 44 56 51 51 44 45 77 39 7a 61 47 46 75 5a 32 31 70 59 WkyMDI1MRgwFgYDVQQDEw9zaGFuZ21pY 35.1.32 29.1 IN 3f 6d 56 70 0d 0a 59 57 52 74 61 57 34 78 43 7a 41 4a 42 67 4e 56 42 41 59 54 41 6b 4e 4f 4d 46 ?mVp..YWRtaW4xCzAJBgNVBAYTAkNOMF 36.1.0 6b 77 45 77 59 48 4b 6f 5a 49 7a 6a 30 43 41 51 59 49 4b 6f 45 63 7a 31 55 42 67 69 30 44 51 67 kwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQg 36.1.32 29.1 IN 3f 41 45 37 2b 74 35 0d 0a 34 51 6f 78 4c 50 48 49 68 78 6b 64 41 54 65 6d 62 45 66 69 52 62 2f ?AE7+t5..4QoxLPHIhxkdATembEfiRb/ 37.1.0 2f 4b 38 48 42 6e 39 4c 34 72 4a 71 56 4d 62 38 64 47 4e 32 51 39 51 38 41 52 75 55 53 75 56 37 /K8HBn9L4rJqVMb8dGN2Q9Q8ARuUSuV7 37.1.32 29.1 IN 3f 71 33 6f 5a 50 78 4a 34 77 0d 0a 73 6b 73 39 56 45 76 55 2f 41 68 6b 39 30 43 79 36 61 4f 42 ?q3oZPxJ4w..sks9VEvU/Ahk90Cy6aOB 38.1.0 33 54 43 42 32 6a 41 4f 42 67 4e 56 48 51 38 42 41 66 38 45 42 41 4d 43 41 34 67 77 48 51 59 44 3TCB2jAOBgNVHQ8BAf8EBAMCA4gwHQYD 38.1.32 29.1 IN 51 56 52 30 6c 42 42 59 77 46 41 59 49 0d 0a 4b 6a 9e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 QVR0lBBYwFAYI..Kj............... 39.1.0 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 ................................ 39.1.32 29.1 OUT e4 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 0c 12 00 0d 80 4e 01 00 00 00 04 10 .........................N...... 40.1.0 00 30 01 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 .0.............................. 40.1.32 29.1 IN bf aa aa 9b 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c 12 01 98 77 59 42 42 51 55 48 41 ........................wYBBQUHA 41.1.0 77 49 47 43 43 73 47 41 51 55 46 42 77 4d 42 4d 41 38 47 41 31 55 64 44 67 51 49 42 41 59 42 41 wIGCCsGAQUFBwMBMA8GA1UdDgQIBAYBA 41.1.32 29.1 IN 3f 67 4d 45 42 51 59 77 44 77 59 44 56 52 30 6a 42 41 67 77 42 6f 41 45 0d 0a 41 51 49 44 42 44 ?gMEBQYwDwYDVR0jBAgwBoAE..AQIDBD 42.1.0 41 75 42 67 4e 56 48 52 45 45 4a 7a 41 6c 67 51 74 6e 61 58 52 41 5a 32 6c 30 4c 6d 4e 76 62 59 AuBgNVHREEJzAlgQtnaXRAZ2l0LmNvbY 42.1.32 29.1 IN 3f 63 45 66 77 41 41 41 59 63 51 49 41 46 49 59 41 41 41 49 41 45 41 41 41 41 41 0d 0a 41 41 41 ?cEfwAAAYcQIAFIYAAAIAEAAAAA..AAA 43.1.0 41 61 44 42 58 42 67 4e 56 48 52 38 45 55 44 42 4f 4d 43 57 67 49 36 41 68 68 68 39 6f 64 48 52 AaDBXBgNVHR8EUDBOMCWgI6Ahhh9odHR 43.1.32 29.1 IN 3f 77 4f 69 38 76 59 33 4a 73 4d 53 35 6c 65 47 46 74 63 47 78 6c 4c 6d 4e 76 62 53 39 6a 0d 0a ?wOi8vY3JsMS5leGFtcGxlLmNvbS9j.. 44.1.0 59 54 45 75 59 33 4a 73 4d 43 57 67 49 36 41 68 68 68 39 6f 64 48 52 77 4f 69 38 76 59 33 4a 73 YTEuY3JsMCWgI6Ahhh9odHRwOi8vY3Js 44.1.32 29.1 IN 3f 4d 69 35 6c 65 47 46 74 63 47 78 6c 4c 6d 4e 76 62 53 39 6a 59 54 45 75 59 33 4a 73 4d 41 6f ?Mi5leGFtcGxlLmNvbS9jYTEuY3JsMAo 45.1.0 47 0d 0a 43 43 71 42 48 4d 39 56 41 59 4e 31 41 30 67 41 4d 45 55 43 49 41 64 2b 6d 6d 50 75 4d G..CCqBHM9VAYN1A0gAMEUCIAd+mmPuM 45.1.32 29.1 IN 3f 2f 43 79 2b 2f 44 31 43 73 38 62 57 47 56 31 65 39 6d 76 72 63 4d 36 52 5a 39 4e 48 78 57 47 ?/Cy+/D1Cs8bWGV1e9mvrcM6RZ9NHxWG 46.1.0 48 50 6c 74 0d 0a 41 69 45 41 6a 76 34 31 34 77 45 6d 6c 5a 64 33 50 55 37 41 6b 59 61 4f 35 44 HPlt..AiEAjv414wEmlZd3PU7AkYaO5D 46.1.32 29.1 IN 75 7a 36 47 62 56 6f 58 78 77 6a 30 52 4f 52 39 4f 48 2b 44 76 77 3d 0d 0a 2d 2d 2d 2d 2d 45 4e uz6GbVoXxwj0ROR9OH+Dvw=..-----EN 47.1.0 44 20 43 45 52 54 49 46 49 43 41 54 45 2d 2d 2d 2d 2d 0d 0a 90 00 00 00 00 00 00 00 00 00 00 00 D CERTIFICATE-----.............. 47.1.32 29.1 OUT e4 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 0d 12 00 0d 80 88 01 00 00 00 04 10 ................................ 48.1.0 00 30 01 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 .0.............................. 48.1.32 29.1 IN bf aa aa 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d 12 00 46 00 00 01 00 ef eb 79 e1 ...I...................F......y. 49.1.0 0a 31 2c f1 c8 87 19 1d 01 37 a6 6c 47 e2 45 bf ff 2b c1 c1 9f d2 f8 ac 9a 95 31 bf 1d 18 dd 90 .1,......7.lG.E..+........1..... 49.1.32 29.1 IN 5e f5 0f 00 46 e5 12 b9 5e ea de 86 4f c4 9e 30 b2 4b 3d 54 4b d4 fc 08 64 f7 40 b2 e9 90 00 00 ^...F...^...O..0.K=TK...d.@..... 50.1.0 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 ................................ 50.1.32 29.1 OUT de fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 0e 12 00 07 80 04 00 00 00 00 00 00 ................................ 51.1.0 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 ................................ 51.1.32 29.1 IN bf aa aa 25 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0e 12 01 22 01 00 01 00 4c 6f 6e 67 ...%..................."....Long 52.1.0 6d 61 69 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 mai............................. 52.1.32 29.1 IN 3f 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 4c 6f 6e ?............................Lon 53.1.0 67 6d 61 69 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 gmai............................ 53.1.32 29.1 IN 3f 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 47 4d ?.............................GM 54.1.0 33 30 30 30 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 37 39 3000..........................79 54.1.32 29.1 IN 3f 37 33 33 30 41 31 35 30 46 33 36 41 45 45 38 39 33 39 43 42 36 41 36 39 36 39 41 30 44 00 05 ?7330A150F36AEE8939CB6A6969A0D.. 55.1.0 00 02 17 07 07 00 00 00 07 03 00 07 00 00 00 01 04 00 00 00 02 00 00 00 01 ee 80 04 20 00 01 00 ............................ ... 55.1.32 29.1 IN 7d 02 00 00 10 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 ................................ 56.1.0 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 90 00 00 00 ................................ 56.1.32 29.1 OUT bf fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 62 00 00 0f 12 00 5f 80 b4 00 01 00 00 58 00 .................b....._......X. 57.1.0 00 01 00 ef eb 79 e1 0a 31 2c f1 c8 87 19 1d 01 37 a6 6c 47 e2 45 bf ff 2b c1 c1 9f d2 f8 ac 9a .....y..1,......7.lG.E..+....... 57.1.32 29.1 OUT 77 95 31 bf 1d 18 dd 90 f5 0f 00 46 e5 12 b9 5e ea de 86 4f c4 9e 30 b2 4b 3d 54 4b d4 fc 08 64 w.1........F...^...O..0.K=TK...d 58.1.0 f7 40 b2 e9 00 00 00 10 31 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 00 00 00 00 00 00 00 00 .@......1234567812345678........ 58.1.32 29.1 IN d9 aa aa 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 12 00 02 90 00 00 00 00 00 00 00 ................................ 59.1.0 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 ................................ 59.1.32 29.1 OUT bf fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4c 00 00 10 12 00 49 80 b6 00 00 00 00 40 61 .................L.....I......@a 60.1.0 73 64 6b 66 68 6a 32 33 73 6c 61 6a 64 66 39 32 33 61 66 64 73 6c 6a 31 33 6b 7a 48 66 31 72 6f sdkfhj23slajdf923afdslj13kzHf1ro 60.1.32 29.1 OUT 61 69 75 6c 73 61 64 6a 66 61 6c 73 31 32 73 6c 64 6a 30 75 32 33 72 32 33 61 6e 73 76 30 6a 32 aiulsadjfals12sldj0u23r23ansv0j2 61.1.0 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 ................................ 61.1.32 29.1 IN f9 aa aa 25 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 12 00 22 b0 e5 68 94 2a 01 d2 2d ...%..................."..h.*..- 62.1.0 2c 7e e4 4c 85 e2 2e 95 f1 78 cd 1f 86 a9 78 ca bc 96 1b a0 24 d8 60 71 90 00 00 00 00 00 00 00 ,..L.....x....x.....$.`q........ 62.1.32 29.1 OUT bf fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 00 00 11 12 00 2b 80 74 02 00 00 00 24 10 .......................+.t....$. 63.1.0 00 30 01 b0 e5 68 94 2a 01 d2 2d 2c 7e e4 4c 85 e2 2e 95 f1 78 cd 1f 86 a9 78 ca bc 96 1b a0 24 .0...h.*..-,..L.....x....x.....$ 63.1.32 29.1 OUT 43 d8 60 71 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 C.`q............................ 64.1.0 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 ................................ 64.1.32 29.1 IN bf aa aa 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 12 00 46 00 00 01 00 8e f2 a9 51 ...I...................F.......Q 65.1.0 b5 19 4e 0b 5c 98 a6 16 0b d7 9e 02 4b b9 58 58 04 ae dc 97 3a 9f ce 6d cd e2 17 03 9e 70 c5 42 ..N.\.......K.XX....:..m.....p.B 65.1.32 29.1 IN 5e 83 63 8b 6f ba 3c 00 3b d9 17 24 47 ce 4f aa 4c 0e 8b b7 89 57 54 ac 7b 0e 55 d0 44 90 00 00 ^.c.o.<.;..$G.O.L....WT...U.D... 66.1.0 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 ................................ 66.1.32 29.1 OUT e2 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0e 00 00 12 12 00 0b 80 44 00 00 00 00 04 10 .........................D...... 67.1.0 00 30 01 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 .0.............................. 67.1.32 29.1 IN d9 aa aa 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 12 00 02 90 00 00 00 00 00 00 00 ................................ 68.1.0 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 ................................ 68.1.32
其实题目目标很简单,我们只要把证书、签名值和 hash 摘要提取出来就好了。
根据 GB-T 0017-2023 ,提证书的话,我们先找 OUT 中 80 4e
字段,然后把下面的值都提取出来
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 29.1 IN bf aa aa f5 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0b 12 01 f2 00 00 03 82 2d 2d 2d 2d ............................---- 31.1.0 2d 42 45 47 49 4e 20 43 45 52 54 49 46 49 43 41 54 45 2d 2d 2d 2d 2d 0d 0a 4d 49 49 43 58 7a 43 -BEGIN CERTIFICATE-----..MIICXzC 31.1.32 29.1 IN 3f 43 41 67 57 67 41 77 49 42 41 67 49 49 52 64 4f 6f 49 6f 58 58 64 4d 41 77 43 67 59 49 4b 6f ?CAgWgAwIBAgIIRdOoIoXXdMAwCgYIKo 32.1.0 45 63 7a 31 55 42 67 33 55 77 4e 6a 45 4c 4d 41 6b 47 41 31 55 45 42 68 4d 43 0d 0a 51 30 34 78 Ecz1UBg3UwNjELMAkGA1UEBhMC..Q04x 32.1.32 29.1 IN 3f 45 7a 41 52 42 67 4e 56 42 41 6f 54 43 6c 4e 6f 59 57 35 6e 54 57 6c 43 5a 57 6b 78 45 6a 41 ?EzARBgNVBAoTClNoYW5nTWlCZWkxEjA 33.1.0 51 42 67 4e 56 42 41 4d 54 43 56 4e 6f 59 57 35 6e 54 57 6c 44 51 54 41 65 46 77 30 79 0d 0a 4e QBgNVBAMTCVNoYW5nTWlDQTAeFw0y..N 33.1.32 29.1 IN 3f 54 41 32 4d 44 6b 77 4d 6a 55 77 4e 44 6c 61 46 77 30 30 4e 54 45 77 4d 54 41 78 4d 6a 41 78 ?TA2MDkwMjUwNDlaFw00NTEwMTAxMjAx 34.1.0 4d 44 46 61 4d 46 55 78 45 7a 41 52 42 67 4e 56 42 41 6f 54 43 6c 4e 6f 59 57 35 6e 54 57 6c 43 MDFaMFUxEzARBgNVBAoTClNoYW5nTWlC 34.1.32 29.1 IN 3f 0d 0a 5a 57 6b 78 46 7a 41 56 42 67 4e 56 42 41 73 54 44 6c 4e 6f 59 57 35 6e 54 57 6c 43 5a ?..ZWkxFzAVBgNVBAsTDlNoYW5nTWlCZ 35.1.0 57 6b 79 4d 44 49 31 4d 52 67 77 46 67 59 44 56 51 51 44 45 77 39 7a 61 47 46 75 5a 32 31 70 59 WkyMDI1MRgwFgYDVQQDEw9zaGFuZ21pY 35.1.32 29.1 IN 3f 6d 56 70 0d 0a 59 57 52 74 61 57 34 78 43 7a 41 4a 42 67 4e 56 42 41 59 54 41 6b 4e 4f 4d 46 ?mVp..YWRtaW4xCzAJBgNVBAYTAkNOMF 36.1.0 6b 77 45 77 59 48 4b 6f 5a 49 7a 6a 30 43 41 51 59 49 4b 6f 45 63 7a 31 55 42 67 69 30 44 51 67 kwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQg 36.1.32 29.1 IN 3f 41 45 37 2b 74 35 0d 0a 34 51 6f 78 4c 50 48 49 68 78 6b 64 41 54 65 6d 62 45 66 69 52 62 2f ?AE7+t5..4QoxLPHIhxkdATembEfiRb/ 37.1.0 2f 4b 38 48 42 6e 39 4c 34 72 4a 71 56 4d 62 38 64 47 4e 32 51 39 51 38 41 52 75 55 53 75 56 37 /K8HBn9L4rJqVMb8dGN2Q9Q8ARuUSuV7 37.1.32 29.1 IN 3f 71 33 6f 5a 50 78 4a 34 77 0d 0a 73 6b 73 39 56 45 76 55 2f 41 68 6b 39 30 43 79 36 61 4f 42 ?q3oZPxJ4w..sks9VEvU/Ahk90Cy6aOB 38.1.0 33 54 43 42 32 6a 41 4f 42 67 4e 56 48 51 38 42 41 66 38 45 42 41 4d 43 41 34 67 77 48 51 59 44 3TCB2jAOBgNVHQ8BAf8EBAMCA4gwHQYD 38.1.32 29.1 IN 51 56 52 30 6c 42 42 59 77 46 41 59 49 0d 0a 4b 6a 9e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 QVR0lBBYwFAYI..Kj............... 39.1.0 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 ................................ 39.1.32 29.1 OUT e4 fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 0c 12 00 0d 80 4e 01 00 00 00 04 10 .........................N...... 40.1.0 00 30 01 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 .0.............................. 40.1.32 29.1 IN bf aa aa 9b 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c 12 01 98 77 59 42 42 51 55 48 41 ........................wYBBQUHA 41.1.0 77 49 47 43 43 73 47 41 51 55 46 42 77 4d 42 4d 41 38 47 41 31 55 64 44 67 51 49 42 41 59 42 41 wIGCCsGAQUFBwMBMA8GA1UdDgQIBAYBA 41.1.32 29.1 IN 3f 67 4d 45 42 51 59 77 44 77 59 44 56 52 30 6a 42 41 67 77 42 6f 41 45 0d 0a 41 51 49 44 42 44 ?gMEBQYwDwYDVR0jBAgwBoAE..AQIDBD 42.1.0 41 75 42 67 4e 56 48 52 45 45 4a 7a 41 6c 67 51 74 6e 61 58 52 41 5a 32 6c 30 4c 6d 4e 76 62 59 AuBgNVHREEJzAlgQtnaXRAZ2l0LmNvbY 42.1.32 29.1 IN 3f 63 45 66 77 41 41 41 59 63 51 49 41 46 49 59 41 41 41 49 41 45 41 41 41 41 41 0d 0a 41 41 41 ?cEfwAAAYcQIAFIYAAAIAEAAAAA..AAA 43.1.0 41 61 44 42 58 42 67 4e 56 48 52 38 45 55 44 42 4f 4d 43 57 67 49 36 41 68 68 68 39 6f 64 48 52 AaDBXBgNVHR8EUDBOMCWgI6Ahhh9odHR 43.1.32 29.1 IN 3f 77 4f 69 38 76 59 33 4a 73 4d 53 35 6c 65 47 46 74 63 47 78 6c 4c 6d 4e 76 62 53 39 6a 0d 0a ?wOi8vY3JsMS5leGFtcGxlLmNvbS9j.. 44.1.0 59 54 45 75 59 33 4a 73 4d 43 57 67 49 36 41 68 68 68 39 6f 64 48 52 77 4f 69 38 76 59 33 4a 73 YTEuY3JsMCWgI6Ahhh9odHRwOi8vY3Js 44.1.32 29.1 IN 3f 4d 69 35 6c 65 47 46 74 63 47 78 6c 4c 6d 4e 76 62 53 39 6a 59 54 45 75 59 33 4a 73 4d 41 6f ?Mi5leGFtcGxlLmNvbS9jYTEuY3JsMAo 45.1.0 47 0d 0a 43 43 71 42 48 4d 39 56 41 59 4e 31 41 30 67 41 4d 45 55 43 49 41 64 2b 6d 6d 50 75 4d G..CCqBHM9VAYN1A0gAMEUCIAd+mmPuM 45.1.32 29.1 IN 3f 2f 43 79 2b 2f 44 31 43 73 38 62 57 47 56 31 65 39 6d 76 72 63 4d 36 52 5a 39 4e 48 78 57 47 ?/Cy+/D1Cs8bWGV1e9mvrcM6RZ9NHxWG 46.1.0 48 50 6c 74 0d 0a 41 69 45 41 6a 76 34 31 34 77 45 6d 6c 5a 64 33 50 55 37 41 6b 59 61 4f 35 44 HPlt..AiEAjv414wEmlZd3PU7AkYaO5D 46.1.32 29.1 IN 75 7a 36 47 62 56 6f 58 78 77 6a 30 52 4f 52 39 4f 48 2b 44 76 77 3d 0d 0a 2d 2d 2d 2d 2d 45 4e uz6GbVoXxwj0ROR9OH+Dvw=..-----EN 47.1.0 44 20 43 45 52 54 49 46 49 43 41 54 45 2d 2d 2d 2d 2d 0d 0a 90 00 00 00 00 00 00 00 00 00 00 00 D CERTIFICATE-----.............. 47.1.32
这里注意对于连续的 IN,从第二个开始第一个字符是多余的要删去。然后我们从第一行的倒数第 8 个字节符开始看, 00 00 03 82
表示证书长度,后面开始才是证书。然后在第一个连续的 IN 的末尾有一个 6a 9e
表示证书还没有传完,那我们就要往下接着看,下面那个 OUT 不用管,然后继续从倒数第 8 个字节开始才是证书,最后末尾是 90 00
表示证书已经传完了。
然后找 hash 值,找 80 b6
字段,可以拿到
1 2 3 4 5 29.1 OUT bf fe 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4c 00 00 10 12 00 49 80 b6 00 00 00 00 40 61 .................L.....I......@a 60.1.0 73 64 6b 66 68 6a 32 33 73 6c 61 6a 64 66 39 32 33 61 66 64 73 6c 6a 31 33 6b 7a 48 66 31 72 6f sdkfhj23slajdf923afdslj13kzHf1ro 60.1.32 29.1 OUT 61 69 75 6c 73 61 64 6a 66 61 6c 73 31 32 73 6c 64 6a 30 75 32 33 72 32 33 61 6e 73 76 30 6a 32 aiulsadjfals12sldj0u23r23ansv0j2 61.1.0 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 ................................ 61.1.32
然后后面就是 hash 值了,直接提取就好了,注意第二个 OUT的第一个字节要删去
最后就是取签名值,还是 80 74
字段,不过在后面的 IN 里
1 2 3 4 29.1 IN bf aa aa 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 12 00 46 00 00 01 00 8e f2 a9 51 ...I...................F.......Q 65.1.0 b5 19 4e 0b 5c 98 a6 16 0b d7 9e 02 4b b9 58 58 04 ae dc 97 3a 9f ce 6d cd e2 17 03 9e 70 c5 42 ..N.\.......K.XX....:..m.....p.B 65.1.32 29.1 IN 5e 83 63 8b 6f ba 3c 00 3b d9 17 24 47 ce 4f aa 4c 0e 8b b7 89 57 54 ac 7b 0e 55 d0 44 90 00 00 ^.c.o.<.;..$G.O.L....WT...U.D... 66.1.0 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 ................................ 66.1.32
同样的,从倒数第 8 个字节开始,00 00 01 00
表模数的 bit 大小,后面就是签名值了,注意连续的 IN 里第一个字符要删去
最后就能登陆了
2-TSP服务器鉴别APP控制端
题目:
auth_client.go
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 package clientimport ( "crypto/elliptic" "crypto/rand" "encoding/base64" "errors" "github.com/tjfoc/gmsm/sm2" "io" "math/big" ) var errZeroParam = errors.New("zero parameter" )var one = new (big.Int).SetInt64(1 )type Point struct { X, Y *big.Int } func randFieldElement (c elliptic.Curve, random io.Reader) (k *big.Int, err error ) { if random == nil { random = rand.Reader } params := c.Params() b := make ([]byte , params.BitSize/8 +8 ) _, err = io.ReadFull(random, b) if err != nil { return } k = new (big.Int).SetBytes(b) n := new (big.Int).Sub(params.N, one) k.Mod(k, n) k.Add(k, one) return } type AuthClient struct { c elliptic.Curve N *big.Int commonPublicKey *sm2.PublicKey D1 *big.Int random io.Reader k1 *big.Int } func ComputeD1 (passwd string ) (*big.Int, error ) { d1Bytes, err := base64.StdEncoding.DecodeString(passwd) if err != nil { return nil , err } return new (big.Int).SetBytes(d1Bytes), nil } func NewAuthClient (commonPublicKey *sm2.PublicKey, D1 *big.Int, random io.Reader) (*AuthClient, error ) { c := sm2.P256Sm2() N := c.Params().N if N.Sign() == 0 { return nil , errZeroParam } return &AuthClient{c: c, N: N, commonPublicKey: commonPublicKey, D1: D1, random: random}, nil } func (signer *AuthClient) GenerateQ1E(msg, uid []byte ) (Q1 *Point, e *big.Int, err error ) { digest, err := signer.commonPublicKey.Sm3Digest(msg, uid) if err != nil { return nil , nil , err } e = new (big.Int).SetBytes(digest) var k1 *big.Int k1, err = randFieldElement(signer.c, signer.random) if err != nil { return nil , nil , err } signer.k1 = k1 x1, y1 := signer.c.ScalarBaseMult(k1.Bytes()) Q1 = &Point{X: x1, Y: y1} return Q1, e, nil } func (signer *AuthClient) GenerateS(r, s2, s3 *big.Int) (s *big.Int, err error ) { t1 := new (big.Int).Mul(signer.D1, signer.k1) t1.Mul(t1, s2) t2 := new (big.Int).Mul(signer.D1, s3) t3 := t1.Add(t1, t2) s = t3.Sub(t3, r) s.Mod(s, signer.N) nMinusR := new (big.Int).Sub(signer.N, r) if s.Sign() != 0 && s.Cmp(nMinusR) != 0 { return s, nil } else { return nil , errors.New("invalid s" ) } }
auth_server.go
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 package serverimport ( "crypto/elliptic" "crypto/rand" "errors" "github.com/tjfoc/gmsm/sm2" "io" "math/big" ) var errZeroParam = errors.New("zero parameter" )var one = new (big.Int).SetInt64(1 )type Point struct { X, Y *big.Int } func randFieldElement (c elliptic.Curve, random io.Reader) (k *big.Int, err error ) { if random == nil { random = rand.Reader } params := c.Params() b := make ([]byte , params.BitSize/8 +8 ) _, err = io.ReadFull(random, b) if err != nil { return } k = new (big.Int).SetBytes(b) n := new (big.Int).Sub(params.N, one) k.Mod(k, n) k.Add(k, one) return } type AuthServer struct { c elliptic.Curve N *big.Int commonPublicKey *sm2.PublicKey D2 *big.Int random io.Reader } func NewAuthServer (commonPublicKey *sm2.PublicKey, D2 *big.Int, random io.Reader) (*AuthServer, error ) { c := sm2.P256Sm2() N := c.Params().N if N.Sign() == 0 { return nil , errZeroParam } return &AuthServer{c: c, N: N, commonPublicKey: commonPublicKey, D2: D2, random: random}, nil } func (signer *AuthServer) GenerateRS2S3(Q1 *Point, e *big.Int) (r, s2, s3 *big.Int, err error ) { x1, y1 := Q1.X, Q1.Y for { var k2 *big.Int k2, err = randFieldElement(signer.c, signer.random) if err != nil { return nil , nil , nil , err } x2, y2 := signer.c.ScalarBaseMult(k2.Bytes()) var k3 *big.Int k3, err = randFieldElement(signer.c, signer.random) if err != nil { return nil , nil , nil , err } tempX, tempY := signer.c.ScalarMult(x1, y1, k3.Bytes()) x3, _ := signer.c.Add(tempX, tempY, x2, y2) r = new (big.Int).Add(x3, e) r.Mod(r, signer.N) if r.Sign() != 0 { s2 = new (big.Int).Mul(signer.D2, k3) s2.Mod(s2, signer.N) s3 = new (big.Int).Add(r, k2) s3.Mul(s3, signer.D2) s3.Mod(s3, signer.N) break } } return r, s2, s3, nil } func (signer *AuthServer) Verify(msg []byte , uid []byte , r *big.Int, s *big.Int) bool { return sm2.Sm2Verify(signer.commonPublicKey, msg, uid, r, s) }
是一个基于 SM2 的协同签名算法,然后其实就是去年熵密杯最后的协同签名算法流程,完全一样的,这里就不再多做叙述了。
当时没有截图,只能简单讲述一下,就是 APP 客户端会给 TSP 服务器发送 Q 1 Q_1 Q 1 和 e e e 。然后 TSP 服务器会生成自己的 r , s 2 , s 3 r,s_2,s_3 r , s 2 , s 3 ,最后你要点击一个按钮,这样子 TSP 服务器会把这些值发送回 APP 客户端然后计算 s s s 。我们的目标是计算 d 1 d_1 d 1
这时候就有个好玩的点了,就是我们要点一个按钮才会传参,那我们可以在这个时候进行抓包重新伪造 r , s 2 , s 3 r,s_2,s_3 r , s 2 , s 3 ,我们注意 s s s 的生成方式
s = d 1 k 1 s 2 + d 1 s 3 − r m o d n s=d_1k_1s_2+d_1s_3-r\mod n
s = d 1 k 1 s 2 + d 1 s 3 − r m o d n
如果我们可以让 s 2 s_2 s 2 为 0,那么这个式子只有 d 1 d_1 d 1 是未知的了。所以我们直接打一个重放攻击,修改 s 2 s_2 s 2 为 0 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from Crypto.Util.number import *from sage.all import *import base64n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123 d = PolynomialRing(Zmod(n), name='d' ).gen() s = 0x8539bcb663238748bfc1fa0f417359d64b46ef6e46abbe7b2cef3f8a4cddc73f r = 0x93b5851e2a534f38a3edf7bada4b50f3c2326273117f956677e5f9ca0219cced s2 = 0 s3 = 0x7a3e83db456607b842aa4a37511a155717f9e3fd82120920d8917edaa1f86a11 f1 = d * s3 - r - s print (base64.b64encode(long_to_bytes(int (f1.roots()[0 ][0 ]))))
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 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 215 216 217 218 219 220 221 222 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include "sdf_cryptoapi.h" void *devHandle = NULL ;void *sessionHandle = NULL ;void *keyHandle = NULL ;const unsigned char encrypt_key_hex[] = "FE61D7ED4A6376AAF13E7D78CB42E645" ;int open_session () { int ret = 0 ; ret = SDF_OpenDeviceWithPath("./sdt_hsmcrypt.conf" , &devHandle); if (ret) { printf ("SDF_OpenDeviceWithPath error, ret=%08x\n" , ret); return ret; } ret = SDF_OpenSession(devHandle, &sessionHandle); if (ret) { printf ("SDF_OpenSession error, ret=%08x\n" , ret); SDF_CloseDevice(devHandle); return ret; } return ret; } int hex_string_to_char_array (const char *hex, unsigned char *out) { size_t hex_len = strlen (hex); if (hex_len % 2 != 0 ) return -1 ; for (size_t i = 0 ; i < hex_len; i += 2 ) { unsigned int byte; if (sscanf (hex + i, "%2X" , &byte) != 1 ) return -1 ; out[i / 2 ] = (unsigned char ) byte; } return hex_len / 2 ; } int import_key () { int ret = 0 ; unsigned char encrypt_key[128 ] = {'\0' }; const unsigned int key_len = 16 ; const int inner_key_index = 1 ; ret = hex_string_to_char_array(encrypt_key_hex, encrypt_key); if (ret < 0 ) { printf ("hex_string_to_char_array error, ret=%08x\n" , ret); return ret; } ret = SDF_ImportKeyWithKEK(sessionHandle, SGD_SM4, inner_key_index, encrypt_key, key_len, &keyHandle); if (ret) { printf ("SDF_ImportKeyWithKEK error, ret=%08x\n" , ret); return ret; } return 0 ; } int init () { int ret = 0 ; ret = open_session(); if (ret) { printf ("open_session error, ret=%08x\n" , ret); return ret; } ret = import_key(); if (ret) { printf ("import_key error, ret=%08x\n" , ret); return ret; } return 0 ; } int close_session () { int ret = 0 ; ret = SDF_CloseSession(sessionHandle); if (ret) { printf ("SDF_CloseSession error, ret=%08x\n" , ret); SDF_CloseDevice(devHandle); return ret; } ret = SDF_CloseDevice(devHandle); if (ret) { printf ("SDF_CloseDevice error, ret=%08x\n" , ret); return ret; } return ret; } int destroy () { int ret = 0 ; ret = SDF_DestroyKey(sessionHandle, keyHandle); if (ret) { printf ("[ts_symm] SDF_DestroyKey error, ret=%08x\n" , ret); return ret; } ret = close_session(); if (ret) { printf ("[ts_symm] close_session error, ret=%08x\n" , ret); return ret; } return 0 ; } int encrypt_with_sm4_cfb (unsigned char *iv, unsigned char *plaintext, unsigned int plaintext_len, unsigned char *ciphertext, unsigned int *ciphertext_len) { return 0 ; } unsigned char *transform (const unsigned char *input, size_t in_len) { if (in_len < 16 ) { return NULL ; } unsigned char *output = malloc (in_len + 1 ); if (output == NULL ) { return NULL ; } memcpy (output, input, 8 ); memcpy (output + 8 , input + in_len - 8 , 8 ); memcpy (output + 8 * 2 , input + 8 , in_len - 8 * 2 ); output[in_len] = '\0' ; return output; } unsigned char *pkcs7_padding (const unsigned char *input, size_t in_len, size_t block_size, size_t *out_len) { return NULL ; } const char hex_table[] = "0123456789ABCDEF" ;void char_array_to_hex_string (const unsigned char *src, size_t len, char *dst) { for (size_t i = 0 ; i < len; i++) { dst[2 * i] = hex_table[(src[i] >> 4 ) & 0x0F ]; dst[2 * i + 1 ] = hex_table[src[i] & 0x0F ]; } dst[2 * len] = '\0' ; } int encrypt_geo_location (unsigned char *iv, const unsigned char *location, unsigned int location_len, char *ciphertext_hex, unsigned int *ciphertext_hex_len) { int ret = 0 ; unsigned char buffer[1024 ] = {0 }; unsigned char *transformed_location = transform(location, location_len); size_t padded_plaintext_len = 0 ; unsigned char *padded_plaintext = pkcs7_padding(transformed_location, location_len, 16 , &padded_plaintext_len); if (padded_plaintext == NULL ) { ret = -1 ; printf ("pkcs7_padding failed!" ); free (transformed_location); return ret; } unsigned int ciphertext_len = 0 ; ret = encrypt_with_sm4_cfb(iv, padded_plaintext, padded_plaintext_len, buffer, &ciphertext_len); if (ret) { printf ("encrypt error, ret=%08x\n" , ret); free (transformed_location); free (padded_plaintext); free (iv); return ret; } char_array_to_hex_string(buffer, ciphertext_len, ciphertext_hex); *ciphertext_hex_len = 2 * ciphertext_len; free (transformed_location); free (padded_plaintext); return ret; } int main (int argc, char *argv[]) { int ret = 0 ; const unsigned char location[] = "xxxxxxxxxxxxxxxxxxxx" ; const unsigned int location_len = sizeof (location) - 1 ; ret = init(); if (ret) { printf ("init error, ret=%08x\n" , ret); return ret; } char ciphertext_hex[1024 ] = {0 }; unsigned int ciphertext_hex_len = 0 ; unsigned char iv[] = {'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' , 'x' }; ret = encrypt_geo_location(iv, location, location_len, ciphertext_hex, &ciphertext_hex_len); if (ret) { printf ("encrypt error, ret=%08x\n" , ret); return ret; } printf ("encrypt ok\n" ); printf ("ciphertext_hex: %s\n" , (char *) ciphertext_hex); ret = destroy(); if (ret) { printf ("destroy error, ret=%08x\n" , ret); } return 0 ; }
然后题目给出了一个 sdk 接口,让你自己去编译。
首先要注意一个坑点,在对消息进行加密的时候会先做一个混淆,python 表示为
1 2 3 4 5 def trans (m ): p1 = m[:8 ] p2 = m[-8 :] p3 = m[8 :-8 ] return p1 + p2 + p3
不过这个是可逆的。
然后题目会给出两组明密文,然后要恢复一个目标密文。
不过题目中 IV 是固定的,然后又是 CFB 模式,所以我们可以算出第一组的密钥流恢复目标密文的第一块
1 2 3 4 5 6 7 8 9 10 11 12 from Crypto.Util.Padding import unpadc1 = "949FBEA9806D720CF8FAC4AF56309A4DDC5554862D8DD597ACD6B41CCA55B8D1" c2 = "949FBFAF806C7507F8F9C4A5543C9D4D260FC54E8492147BA230CCF78F528E9C" c3 = '949FBFA28061720CF3A1D9FB5863C619BB8769FF8994013B98E0D6968EA7B8E08F9B0E1F44FF6C37A185E9A7892FB831BD6D33EB1F586A35CD500C3B867DA2F7' c1 = bytes .fromhex(c1) c3 = bytes .fromhex(c3) m1 = b"(113.8383,34.3784)" m2 = b"(105.9434,37.9543)" key = xor(c1[:16 ], trans(m1)[:16 ]) print (xor(key, c3[:16 ]))
然后就是调用服务器密码机的SDF_Encrypt接口,对密文解密(其实这时候你会发现,好像前面不用 IV 固定先算第一块也没事)
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 int main (int argc, char *argv[]) { int ret = 0 ; const unsigned char location[] = "xxxxxxxxxxxxxxxxxxxx" ; const unsigned int location_len = sizeof (location) - 1 ; ret = init(); if (ret) { printf ("init error, ret=%08x\n" , ret); return ret; } unsigned char cip_hex[1024 ] = "949FBFA28061720CF3A1D9FB5863C619BB8769FF8994013B98E0D6968EA7B8E08F9B0E1F44FF6C37A185E9A7892FB831BD6D33EB1F586A35CD500C3B867DA2F7" ; unsigned char cip[512 ] = {0 }; unsigned int ciphertext_hex_len = 0 ; ret = hex_string_to_char_array(cip_hex, cip); if (ret < 0 ) { printf ("hex_string_to_char_array error, ret=%08x\n" , ret); return ret; } unsigned char key[64 ] = {0 }; unsigned int key_len = 64 ; ret = SDF_Encrypt(sessionHandle, keyHandle, SGD_SM4_ECB, NULL , cip, 64 , key, &key_len); if (ret) { printf ("SDF_OpenDeviceWithPath error, ret=%08x\n" , ret); return ret; } for (int i=0 ;i<64 ;i++) { printf ("%02x" , (unsigned int )key[i]); } printf ("\n" ); ret = destroy(); if (ret) { printf ("destroy error, ret=%08x\n" , ret); } return 0 ; }
4-OTA升级包加密
题目:
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 package mainimport ( "crypto/cipher" "errors" "github.com/tjfoc/gmsm/sm4" ) func encrypt (key, nonce, plaintext, additionalData []byte ) ([]byte , error ) { block, err := sm4.NewCipher(key) if err != nil { return nil , err } gcm, err := cipher.NewGCM(block) if err != nil { return nil , err } ciphertext := gcm.Seal(nil , nonce, plaintext, additionalData) return append (nonce, ciphertext...), nil } func EncryptOTAPackage (plaintextFilePath string , key, nonce []byte ) (ciphertextFilePath string , err error ) { if len (key) != 16 { return "" , errors.New("invalid key" ) } if len (nonce) != 12 { return "" , errors.New("invalid nonce" ) } ciphertextContent, err := encrypt(key, nonce, plaintextContent, nil ) if err != nil { return "" , err } return } func main () { plainFilePath := "./files/firm-v1.0-plain.bin" expectedCipherFilePath := "./files/firm-v1.0.bin" key := []byte ("xxxxxxxxxxxxxxxx" ) nonce := []byte ("xxxxxxxxxxxx" ) cipherFilePath, err := EncryptOTAPackage(plainFilePath, key, nonce) if err != nil { panic (err) } if cipherFilePath != expectedCipherFilePath { panic ("invalid cipherFilePath" ) } }
然后会给出 firm-v1.0.bin
和 firm-v1.1.bin
,要求你构造一个新的 bin 文件使得实现自动驾驶功能使能位。其实就是把明文第 8 位的指定 bit 改成 1 就好了。
首先 两个给我们的文件都是密文,所以我们是读不到明文信息的。不过注意 GCM 对密文的加密就是 CTR,所以是流密码形式的,那我只要对指定 bit 做翻转就好了。然后后面就是伪造 tag 了,因为你把消息改了那 tag 肯定也不会一样了。
审计代码可以发现 GCM 的 key 和 nonce 是重用的,那这就为我们伪造 tag 提供了漏洞。我们要伪造的值是 10 块的,这里为了简单介绍,我假设两组密文都是 4 块的。并且记为 a 0 a_0 a 0 ~ a 3 , b 0 a_3,b_0 a 3 , b 0 ~ b 3 b_3 b 3 ,然后记第一组密文 tag 为 A A A ,第二组密文 tag 为 B B B ,有
A = ( ( ( ( a 0 h + a 1 ) h + a 2 ) h + a 3 ) h + l ) h + s = a 0 h 5 + a 1 h 4 + a 2 h 3 + a 3 h 2 + l h + s B = ( ( ( ( b 0 h + b 1 ) h + b 2 ) h + b 3 ) h + l ) h + s = b 0 h 5 + b 1 h 4 + b 2 h 3 + b 3 h 2 + l h + s A=((((a_0h+a_1)h+a_2)h+a_3)h+l)h+s=a_0h^5+a_1h^4+a_2h^3+a_3h^2+lh+s\\
B=((((b_0h+b_1)h+b_2)h+b_3)h+l)h+s=b_0h^5+b_1h^4+b_2h^3+b_3h^2+lh+s\\
A = ( ( ( ( a 0 h + a 1 ) h + a 2 ) h + a 3 ) h + l ) h + s = a 0 h 5 + a 1 h 4 + a 2 h 3 + a 3 h 2 + l h + s B = ( ( ( ( b 0 h + b 1 ) h + b 2 ) h + b 3 ) h + l ) h + s = b 0 h 5 + b 1 h 4 + b 2 h 3 + b 3 h 2 + l h + s
这里注意因为是在 G F ( 2 128 ) GF(2^{128}) G F ( 2 1 2 8 ) 下所以异或和加是等价的,然后两者相加就是两者异或变为 0,故有
A + B = ( a 0 + b 0 ) h 5 + ( a 1 + b 1 ) h 4 + ( a 2 + b 2 ) h 3 + ( a 3 + b 3 ) h 2 A+B=(a_0+b_0)h^5+(a_1+b_1)h^4+(a_2+b_2)h^3+(a_3+b_3)h^2
A + B = ( a 0 + b 0 ) h 5 + ( a 1 + b 1 ) h 4 + ( a 2 + b 2 ) h 3 + ( a 3 + b 3 ) h 2
注意到在这个等式中我们只有 h h h 是未知的,那我们可以直接解方程就好了。得到 h h h 以后,那么伪造 tag 就是非常简单的事情了。
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 from Crypto.Util.number import *from sage.all import *b1 = open ('firm-v1.0.bin' , 'rb' ).read() b2 = open ('firm-v1.1.bin' , 'rb' ).read() nonce = b1[:12 ] tag1 = b1[-16 :] tag2 = b2[-16 :] c1 = b1[12 :-16 ] c2 = b2[12 :-16 ] assert len (c1) == len (c2) == 160 t = 8 print (bin (c2[t])[2 :].zfill(8 ))ttt = 0b01101100 c3 = c2[:t] + bytes ([ttt]) + c2[t+1 :] x = var('x' ) R = GF(2 **128 , modulus=x**128 + x**7 + x**2 + x + 1 , name='a' ) a = R.gen() F = PolynomialRing(R, name='x' ) x = F.gen() def to_poly (c ): return R.from_integer(int (f'{c:0128b} ' [::-1 ], 2 )) def from_poly (p ): return int (f'{p.to_integer():0128b} ' [::-1 ], 2 ) C1 = [to_poly(int .from_bytes(c1[16 * i:16 * i +16 ])) for i in range (len (c1) // 16 )] C2 = [to_poly(int .from_bytes(c2[16 * i:16 * i +16 ])) for i in range (len (c2) // 16 )] tag1 = to_poly(int .from_bytes(tag1)) tag2 = to_poly(int .from_bytes(tag2)) f = sum ((C1[i] + C2[i]) * x**(len (C1) - i + 1 ) for i in range (len (C1))) - tag1 - tag2 H = f.roots()[0 ][0 ] tag3 = tag2 - C2[0 ] * H**11 + to_poly(int .from_bytes(c3[:16 ])) * H**11 C3 = nonce + c3 + long_to_bytes(from_poly(tag3), 16 ) print (C3)open ('firm-v1.2.bin' , 'wb' ).write(C3)
*5-OTA服务器与OTA升级包签名
题目:
challenge_handler.go
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 package handlersimport ( "crypto/cipher" "crypto/elliptic" _ "embed" "encoding/hex" "errors" "fmt" "github.com/gin-gonic/gin" "github.com/tjfoc/gmsm/sm2" "github.com/tjfoc/gmsm/sm4" "math/big" "net/http" ) var gPrivateHex string var gPublicHex string var errZeroParam = errors.New("zero parameter" )var one = new (big.Int).SetInt64(1 )var key []byte var nonce []byte var gPrivateKey *sm2.PrivateKeyfunc init () { var err error key, err = hex.DecodeString("6c87d37a658ab6b00fee969d4b107ef0" ) if err != nil || len (key) != 16 { panic (fmt.Errorf("key 配置有误" )) } nonce, err = hex.DecodeString("17d77a33826174759e01273c" ) if err != nil || len (nonce) != 12 { panic (fmt.Errorf("nonce 配置有误" )) } gPrivateKey, _, err = HexToSM2Key(gPrivateHex, gPublicHex[2 :]) if err != nil { panic ("密钥加载失败: " + err.Error()) } } func HexToSM2Key (privateHex, publicHex string ) (*sm2.PrivateKey, *sm2.PublicKey, error ) { privateBytes, err := hex.DecodeString(privateHex) if err != nil { return nil , nil , fmt.Errorf("私钥解码失败: %v" , err) } privateKey := new (sm2.PrivateKey) privateKey.D = new (big.Int).SetBytes(privateBytes) publicBytes, err := hex.DecodeString(publicHex) if err != nil { return nil , nil , fmt.Errorf("公钥解码失败: %v" , err) } curve := sm2.P256Sm2() x := new (big.Int).SetBytes(publicBytes[:32 ]) y := new (big.Int).SetBytes(publicBytes[32 :]) privateKey.PublicKey = sm2.PublicKey{ Curve: curve, X: x, Y: y, } return privateKey, &privateKey.PublicKey, nil } func ChallengeHandler (c *gin.Context) { var req struct { Challenge string `json:"challenge" binding:"required,min=1,max=2048"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error" : "参数不合法" }) return } challengeHex := req.Challenge if len (challengeHex)%2 == 1 { challengeHex = "0" + challengeHex } challenge, err := hex.DecodeString(challengeHex) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error" : "参数不合法" }) return } sigHex, err := signMessage(challenge, gPrivateKey) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error" : err.Error()}) return } c.JSON(http.StatusOK, gin.H{"signature" : sigHex}) } func hash (data []byte ) ([]byte , error ) { block, err := sm4.NewCipher(key) if err != nil { return nil , err } gcm, err := cipher.NewGCM(block) if err != nil { return nil , err } authTag := gcm.Seal(nil , nonce, []byte ("" ), data) return authTag, nil } func myRandFieldElement (c elliptic.Curve, msg, d []byte ) (k *big.Int, err error ) { params := c.Params() b := make ([]byte , params.BitSize/8 +8 ) h, err := hash(append (msg, d...)) if err != nil { return } copy (b, h) k = new (big.Int).SetBytes(b) n := new (big.Int).Sub(params.N, one) k.Mod(k, n) k.Add(k, one) return } func mySm2Sign (priv *sm2.PrivateKey, msg, uid []byte ) (r, s *big.Int, err error ) { digest, err := priv.PublicKey.Sm3Digest(msg, uid) if err != nil { return nil , nil , err } e := new (big.Int).SetBytes(digest) c := priv.PublicKey.Curve N := c.Params().N if N.Sign() == 0 { return nil , nil , errZeroParam } var k *big.Int for { for { k, err = myRandFieldElement(c, msg, priv.D.Bytes()) if err != nil { r = nil return } r, _ = priv.Curve.ScalarBaseMult(k.Bytes()) r.Add(r, e) r.Mod(r, N) if r.Sign() != 0 { if t := new (big.Int).Add(r, k); t.Cmp(N) != 0 { break } } } rD := new (big.Int).Mul(priv.D, r) s = new (big.Int).Sub(k, rD) d1 := new (big.Int).Add(priv.D, one) d1Inv := new (big.Int).ModInverse(d1, N) s.Mul(s, d1Inv) s.Mod(s, N) if s.Sign() != 0 { break } } return } func signMessage (message []byte , priv *sm2.PrivateKey) (string , error ) { r, s, err := mySm2Sign(priv, message, nil ) if err != nil { return "" , err } rBytes := r.Bytes() sBytes := s.Bytes() var rPadded [32 ]byte var sPadded [32 ]byte copy (rPadded[32 -len (rBytes):], rBytes) copy (sPadded[32 -len (sBytes):], sBytes) rHex := hex.EncodeToString(rPadded[:]) sHex := hex.EncodeToString(sPadded[:]) rawSignature := rHex + sHex return rawSignature, nil }
generate_auth_sign_key.go
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 package key_generatorimport ( "crypto/cipher" "encoding/hex" "errors" "fmt" "github.com/tjfoc/gmsm/sm4" "math/big" ) var key []byte var nonce []byte var one = new (big.Int).SetInt64(1 )var two = new (big.Int).SetInt64(2 )func init () { var err error key, err = hex.DecodeString("6c87d37a658ab6b00fee969d4b107ef0" ) if err != nil || len (key) != 16 { panic (fmt.Errorf("key 配置有误" )) } nonce, err = hex.DecodeString("17d77a33826174759e01273c" ) if err != nil || len (nonce) != 12 { panic (fmt.Errorf("nonce 配置有误" )) } } func hash (data []byte ) ([]byte , error ) { block, err := sm4.NewCipher(key) if err != nil { return nil , err } gcm, err := cipher.NewGCM(block) if err != nil { return nil , err } authTag := gcm.Seal(nil , nonce, []byte ("" ), data) return authTag, nil } func generateSignKey (masterKey []byte ) ([]byte , error ) { if len (masterKey) != 16 { return nil , errors.New("masterKey must be 16 bytes" ) } masterKeyInt := new (big.Int).SetBytes(masterKey) signKeyHighBytes, err := hash(masterKey) if err != nil { return nil , err } masterKeyInt.Add(masterKeyInt, one) signKeyLowBytes, err := hash(masterKeyInt.Bytes()) if err != nil { return nil , err } signKeyBytes := append (signKeyHighBytes, signKeyLowBytes...) return signKeyBytes, nil } func generateAuthKey (masterKey []byte ) ([]byte , error ) { if len (masterKey) != 16 { return nil , errors.New("masterKey must be 16 bytes" ) } masterKeyInt := new (big.Int).SetBytes(masterKey) masterKeyInt.Add(masterKeyInt, two) authKeyHighBytes, err := hash(masterKeyInt.Bytes()) if err != nil { return nil , err } masterKeyInt.Add(masterKeyInt, one) authKeyLowBytes, err := hash(masterKeyInt.Bytes()) if err != nil { return nil , err } authKeyBytes := append (authKeyHighBytes, authKeyLowBytes...) return authKeyBytes, nil }
sign_package.go
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 package sign_packageimport ( "crypto/rand" "encoding/hex" "fmt" "github.com/tjfoc/gmsm/sm2" "io/ioutil" "math/big" ) func LoadHexFromFile (filename string ) (string , error ) { data, err := ioutil.ReadFile(filename) if err != nil { return "" , fmt.Errorf("文件读取失败: %v" , err) } return string (data), nil } func HexToSM2Key (privateHex, publicHex string ) (*sm2.PrivateKey, *sm2.PublicKey, error ) { privateBytes, err := hex.DecodeString(privateHex) if err != nil { return nil , nil , fmt.Errorf("私钥解码失败: %v" , err) } privateKey := new (sm2.PrivateKey) privateKey.D = new (big.Int).SetBytes(privateBytes) publicBytes, err := hex.DecodeString(publicHex) if err != nil { return nil , nil , fmt.Errorf("公钥解码失败: %v" , err) } curve := sm2.P256Sm2() x := new (big.Int).SetBytes(publicBytes[:32 ]) y := new (big.Int).SetBytes(publicBytes[32 :]) privateKey.PublicKey = sm2.PublicKey{ Curve: curve, X: x, Y: y, } return privateKey, &privateKey.PublicKey, nil } func signMessage (message []byte , priv *sm2.PrivateKey) (string , error ) { r, s, err := sm2.Sm2Sign(priv, message, nil , rand.Reader) if err != nil { return "" , err } rBytes := r.Bytes() sBytes := s.Bytes() var rPadded [32 ]byte var sPadded [32 ]byte copy (rPadded[32 -len (rBytes):], rBytes) copy (sPadded[32 -len (sBytes):], sBytes) rHex := hex.EncodeToString(rPadded[:]) sHex := hex.EncodeToString(sPadded[:]) rawSignature := rHex + sHex return rawSignature, nil } func signPackage (filename string ) string { content, err := ioutil.ReadFile(filename) if err != nil { panic ("读取文件内容失败: " + err.Error()) } privateHex, _ := LoadHexFromFile("sign_private_key.hex" ) publicHex, _ := LoadHexFromFile("sign_public_key.hex" ) privateKey, _, err := HexToSM2Key(privateHex, publicHex[2 :]) if err != nil { panic ("密钥加载失败: " + err.Error()) } sigHex, err := signMessage(content, privateKey) if err != nil { panic (err) } return sigHex }
题目给出了一个APP 控制端的签名端口,你可以输入任意的消息进行签名,然后目标是计算出其的私钥然后回推 masterKey,最后再用 masterKey 计算出 OTA 升级包签名的私钥。
在这次比赛中,我们选择性略过了 generate_auth_sign_key.go
导致最后拿到APP 控制端的私钥后一直大眼瞪小眼,最后注意到时候已经迷迷糊糊了还是没有做出来(T_T)
首先 APP 控制端的签名算法是 SM2 签名算法,流程并没有差错,但是注意随机数的生成,是对消息和私钥进行拼接作为 GCM 的 add ,然后加密空字符,然后将生成的 tag 作为随机数。这时候思路就很明了了,只要构造两个合适的消息,使得生成的随机数一样即可计算出私钥。
我们构造两个消息,使得计算 tag 的时候可以分成两组,那么就可以写作
A 1 h 5 + A 2 h 4 + B A 3 h 5 + A 4 h 4 + B A_1h^5+A_2h^4+B\\
A_3h^5+A_4h^4+B
A 1 h 5 + A 2 h 4 + B A 3 h 5 + A 4 h 4 + B
其中 B 为后面的值(因为都是相等的),我们需要两个等式相等,那么就随便选择一下 A 1 , A 2 , A 3 A_1,A_2,A_3 A 1 , A 2 , A 3 ,就可以拿到 A 4 A_4 A 4 了。
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 from Crypto.Util.number import * import gmalgfrom sage.all import *x = var('x' ) R = GF(2 **128 , modulus=x**128 + x**7 + x**2 + x + 1 , name='a' ) a = R.gen() F = PolynomialRing(R, name='x' ) x = F.gen() def to_poly (c ): return R.from_integer(int (f'{c:0128b} ' [::-1 ], 2 )) def from_poly (p ): return int (f'{p.to_integer():0128b} ' [::-1 ], 2 ) sm4 = gmalg.SM4(b'1' *16 ) key = bytes .fromhex("6c87d37a658ab6b00fee969d4b107ef0" ) nonce = bytes .fromhex("17d77a33826174759e01273c" ) plaintext = b"\x00" *16 cipher = gmalg.SM4(key) ciphertext = cipher.encrypt(plaintext) h = to_poly(int (ciphertext.hex (), 16 )) ciphertext = cipher.encrypt(nonce + b'\x01' .zfill(4 )) s = to_poly(int (ciphertext.hex (), 16 )) x1 = b'1' *16 x1 = to_poly(bytes_to_long(x1)) x2 = x1*h A1 = to_poly(bytes_to_long(b'1' *16 )) A3 = A1 - x1 A2 = to_poly(bytes_to_long(b'1' *16 )) A4 = A2 - x2 def tt (A ): return long_to_bytes(from_poly(A), 16 )tar1,tar2 = tt(A1) + tt(A2), tt(A3) + tt(A4) print (tar1.hex (), tar2.hex ())
拿到两个消息之后,就可以拿到私钥了,后面就简单了对着流程逆就好了。