小王同学 - 2018年8月 https://feelncut.com/2018/08/ 希望通过自我加工,成为有点用的人 Python 判断数组中含有某元素的个数 https://feelncut.com/2018/08/09/171.html 2018-08-09T14:04:27+08:00 为了测试uuid1方法批量生成uuid时是否会重复,就把生成的uuid放到了一个数组中,之前不知道数组还有`count`方法... ```python import uuid r = [] for i in range(1000): r.append(str(uuid.uuid1())) for i in r: print(r.count(i)) ``` Python3 中 AES256对称加密解密以及RSA2048签名验签 https://feelncut.com/2018/08/06/170.html 2018-08-06T14:03:00+08:00 # ETH相关流程 ## ETH地址转换 调用`get_key`接口传入私钥`name`和`version`可获取私钥公开部分信息。 将获取私钥公开部分中X与Y合并为一个数组,长度为64字节,经`keccak_256`算法计算hash得到32字节hash,取后20字节,即为以太坊钱包地址。 ```python key_bundle = client.get_key('https://wangke-test-k-v.vault.azure.net/', 'x', 'x') full_pubkey = key_bundle.key.x + key_bundle.key.y import sha3 k = sha3.keccak_256() k.update(full_pubkey) print(k.hexdigest()) print('0x' + k.hexdigest()[24:]) ``` 公钥中是否需要加前缀`0x04`需要进一步验证。 ## ETH交易签名 ### 交易签名流程 ETH`未签名交易信息`包含了: - nonce - gasPrice - gas - value - to - data - chainId 交易签名指:将以上未签名交易信息按照以太坊`RLP`规则序列化得到`rawTransaction`,`rawTransaction`再经过`keccak`得到`hash`,对该`hash`使用私钥进行签名,签名结果包含`R,S,V`三个部分。 再以上未签名交易信息中增加`R,S,V`得到`签名交易信息`: - nonce - gasPrice - gas - value - to - data - chainId - r - s - v 将签名交易信息按照以太坊`RLP`规则序列化得到`rawSignedTransaction`,此`rawSignedTransaction`可使用`web3`接口`sendRawTransaction`直接发送。对此`rawSignedTransaction`进行`keccak`得到交易hash:`txhash`。 ### 使用KV签名 根据交易签名流程可知,只需要将`rawTransaction`经过`keccak`得到的`hash`传入服务端,服务端调用KV的`sign`接口对其进行签名。`sign`接口返回的结果只包含`R,S`,根据公钥信息可计算出`V`。服务端返回`R,S,V`,客户端根据`R,S,V`得到`rawSignedTransaction`。 计算`V`的算法如下: ```python from coincurve import PublicKey for v in range(4): print(bytes([v])) s = s_res.result + bytes([v]) try: public_key_bytes = PublicKey.from_signature_and_message(s, bytes.fromhex(raw), hasher=None).format(compressed=False) print(public_key_bytes==pk) except: print('error') ``` ### EIP155 根据[EIP155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md "BIP155")规则: - 如果`未签名交易信息`中包含`chainId`,则还应包含`r=0,s=0`,签名得到的`v`需要经过`v = v + CHAIN_ID_OFFSET + 2 * chain_id`变换,`CHAIN_ID_OFFSET`为`35`。此时交易只在对应`chain_id`的链上有效。 - 如果`未签名交易信息`中不包含`chainId`,签名得到的`v`需要经过`v = v_raw + V_OFFSET`变换,`V_OFFSET`为`27`。此时交易在所有链上有效。(正式链,几个不同的测试链) # AES256加密解密 使用依赖`pip3 install pycrypto`。 测试代码: ```python from Crypto.Cipher import AES from Crypto import Random import base64 BS = 16 pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) unpad = lambda s : s[0:-s[-1]] # bkey可以是16, 24 或 32 位长度, 其对应 AES-128, AES-196 和 AES-256 bkey = "12345678901234561234567890123456" print(bkey) raw="test raw data 123 456 abcde"; raw = pad(raw) iv ="0102030405060708"; print("iv="+iv) cipher = AES.new(bkey, AES.MODE_CBC, iv ) print(len(raw)) print(raw) ciphertext= cipher.encrypt(raw) print(ciphertext) ciphertext_base64=base64.b64encode(ciphertext) print(ciphertext_base64) print('============================') enc=base64.b64decode(ciphertext_base64) cipher = AES.new(bkey, AES.MODE_CBC, iv ) text=cipher.decrypt(enc); print(len(text)) print(text) print(text.hex()) plaintext= unpad(text) print("%s" % plaintext.decode()) ``` # RSA2048签名验签 使用依赖`pip3 install pycrypto`。 生成公私钥对: ```bash openssl genrsa -out ./myPrivateKey.pem -passout pass:"f00bar" -des3 2048 openssl rsa -pubout -in ./myPrivateKey.pem -passin pass:"f00bar" -out ./myPublicKey.pem ``` 测试代码: ```python from Crypto.PublicKey import RSA from Crypto.Hash import SHA from Crypto.Signature import PKCS1_v1_5 from base64 import b64encode, b64decode def rsa_sign(message): private_key_file = open('./myPrivateKey.pem', 'r') private_key = RSA.importKey(private_key_file.read(), 'f00bar') hash_obj = SHA.new(message) signer = PKCS1_v1_5.new(private_key) d = b64encode(signer.sign(hash_obj)) return d def rsa_verify(message, signature): public_key_file = open('./myPublicKey.pem', 'r') public_key = RSA.importKey(public_key_file.read()) sign = b64decode(signature) h = SHA.new(message) verifier = PKCS1_v1_5.new(public_key) return verifier.verify(h, sign) msg = b'asdasdasdasdasdasd' s = rsa_sign(msg) print(s) v = rsa_verify(msg, s) print(v) v = rsa_verify(msg + b'a', s) print(v) ``` # pkcs8 ```bash openssl pkcs8 -topk8 -inform PEM -in ClientPrivateKey.pem -passin pass:"f00bar" -outform pem -nocrypt -out ClientPrivateKeypkcs8.pem ```