Python开发篇——RSA加密算法和SHA1计算文件校验码

286 阅读2分钟

做过开发的都会接触到加密算法和hash算法,这两者是有区别的,加密算法分为对称加密和非对称加密,目的是、对数据进行加密/解密,而hash则是单向算法,无法还原原始数据。

RSA加密/解密

目前简单的非对称加密是RSA,还有其他的如椭圆等,各位可以自行研究

  1. 首先需要crypto的lib

     $ pip install pycryptodome
     # or
     $ poetry add pycryptodome
    
  2. generate_key.py: 生成公钥和密钥

     from Crypto.PublicKey import RSA
    
     key = RSA.generate(2048)
     private_key = key.export_key()
     file_out = open("private.pem", "wb")
     file_out.write(private_key)
     file_out.close()
    
     public_key = key.publickey().export_key()
     file_out = open("receiver.pem", "wb")
     file_out.write(public_key)
     file_out.close()
    
  3. 加密和解密(文件版)

    官方代码:

     from Crypto.PublicKey import RSA
     from Crypto.Random import get_random_bytes
     from Crypto.Cipher import AES, PKCS1_OAEP
    
     data = "I met aliens in UFO. Here is the map.".encode("utf-8")
     file_out = open("encrypted_data.bin", "wb")
    
     recipient_key = RSA.import_key(open("receiver.pem").read())
     session_key = get_random_bytes(16)
    
     # Encrypt the session key with the public RSA key
     cipher_rsa = PKCS1_OAEP.new(recipient_key)
     enc_session_key = cipher_rsa.encrypt(session_key)
    
     # Encrypt the data with the AES session key
     cipher_aes = AES.new(session_key, AES.MODE_EAX)
     ciphertext, tag = cipher_aes.encrypt_and_digest(data)
     [ file_out.write(x) for x in (enc_session_key, cipher_aes.nonce, tag, ciphertext) ]
     file_out.close()
    
  4. 加密和解密(Data版)

    由于pycryptodome的加密都是基于bytes,所以str需要与bytes的转换, 代码如下:

     from Crypto.PublicKey import RSA
     from Crypto.Random import get_random_bytes
     from Crypto.Cipher import PKCS1_OAEP # AES, 
     from Crypto.Util.Padding import pad, unpad
    
     # RSA public key
     recipient_key = RSA.import_key(open("receiver.pem").read())
     data = '123456'
     # 通过decode转换bytes,另一种方法是bytes(data, 'utf-8'), 但是存在损耗
     session_key = data.encode('utf-8')
     # Encrypt the session key with the public RSA key
     cipher_rsa = PKCS1_OAEP.new(recipient_key)
     enc_session_key = cipher_rsa.encrypt(pad(session_key, 16))
     # 将bytes转str,用于保存与varchar数据字段
     enc_session_key = enc_session_key.decode('raw_unicode_escape')
    
     private_key = RSA.import_key(open("private.pem").read())
    
     # Decrypt the session key with the private RSA key
     cipher_rsa = PKCS1_OAEP.new(private_key)
     # 将str转bytes
     session_key = unpad(cipher_rsa.decrypt(enc_session_key.encode('raw_unicode_escape')), 16)
     decrypted = session_key.decode('utf-8')
     user.passwd = decrypted
    

SHA1计算文件校验码

关于计算文件的校验码,从速度上来说crc32 > sha1 > md5,从安全性角度sha1 > md5 > crc32, 所以在使用中自己取舍, 但是目前许多大厂转向sha256,主要是安全性比sha1更高,但是速度就下降了许多。其选择的原因也是他们的数据已经接近或远远超过ZB了。

  1. 添加

     $ pip install hashlib
     # or
     $ poetry add hashlib
    
  2. 我这里直接引用我写在Flask下的代码, 值的注意的是Flask的文件是FileStorage类型,不是File-like object,需要stream读取,如果读取后需要再读取记得用stream.seek(0),修改偏移量,否则文件读取size为0

     from flask import request, jsonify
     import hashlib
    
     BUF_SIZE = 65536
    
     def post_file():
         file = request.files.get('file')
    
         # 计算文件的checksum值
         sha1 = hashlib.sha1()
         checksum = ""
         try:
             # with open(file.filename, 'rb') as f:
             while True:
                 data = file.stream.read(BUF_SIZE)
                 if not data:
                     break
                 sha1.update(data)
    
             # 获取结果
             checksum=sha1.hexdigest()
         except IOError:
             return jsonify({'message': '演算checksum失败!!!'}), 403
    

参考: