1. 程式人生 > >Python pycryptodome的加解密、簽名驗籤使用心得

Python pycryptodome的加解密、簽名驗籤使用心得

1、載入金鑰

key = Crypto.PublicKey.RSA.import_key(open(key_path).read())

2、簽名與驗籤

用RSA-PSS using SHA-256舉例

def Rsa256_sign_data(data, rsa_key):
	try:
		h = Crypto.Hash.SHA256.new(data)
		rsa_sign = Crypto.Signature.PKCS1_PSS.new(rsa_key)
        #new(rsa_key, mgfunc=None, saltLen=None, randfunc=None)
		if rsa_sign.can_sign():
			return rsa_sign.sign(h)
		else:
			raise Exception
	except Exception as err:
		log_print("RSA sign fail", '', err)
	return signature

def Rsa256_verify_data(data, sig, rsa_key):
	try:
		h = Crypto.Hash.SHA256.new(data)
		Crypto.Signature.PKCS1_PSS.new(rsa_key).verify(h, sig)
		return True
	except Exception as err:
        print("RSA verify fail", '', err)
		return False

new的引數包括rsa_key,mgfunc(回撥函式,不寫的話,預設採用mgf1,且和data採用相同的hash演算法),saltlen(以byte為單位,預設為32,即使256bits),randfunc(沒用過誒),new後將生成類Crypto.Signature.PSS_SigScheme的物件

class PSS_SigScheme:
    """A signature object for ``RSASSA-PSS``.
    Do not instantiate directly.
    Use :func:`Crypto.Signature.pss.new`.
    """

    def __init__(self, key, mgfunc, saltLen, randfunc):
        #程式碼就不貼上了
    def can_sign(self):
        #程式碼就不貼上了
    def sign(self, msg_hash):
        #程式碼就不貼上了
    def verify(self, msg_hash, signature):
        #程式碼就不貼上了
        #raise ValueError: if the signature is not valid.

3、加解密

1)用RSA-OAEP using SHA-256舉例

def Rsa_OAEP_256_Encrypt(data, rsa_key):
	try:
		rsa_oaep = Crypto.Cipher.PKCS1_OAEP.new(rsa_key,Crypto.Hash.SHA256)
        #new(key, hashAlgo=None, mgfunc=None, label=b'', randfunc=None):
		if rsa_oaep.can_encrypt():
			return rsa_oaep.encrypt(data)
		else:
			raise Exception
	except Exception as err:
		print('RSA encrypt fail', '', err)
        return b''
    
def Rsa_OAEP_256_Decrypt(data, rsa_key):
	try:
		rsa_oaep = Crypto.Cipher.PKCS1_OAEP.new(rsa_key,Crypto.Hash.SHA256)
		if rsa_oaep.can_decrypt():
			return rsa_oaep.decrypt(data)
		else :
			raise Exception
	except Exception as err:
		print('RSA decrypt fail', '', err)
		return b''

new的引數包括key,hashAlgo(預設採用Crypto.Hash.SHA1),mgfunc(同上),label(沒用過欸),randfunc(沒用過欸),new後將生成類Crypto.Cipher.PKCS1_OAEP.PKCS1OAEP_Cipher物件

class PKCS1OAEP_Cipher:
    """Cipher object for PKCS#1 v1.5 OAEP.
    Do not create directly: use :func:`new` instead."""

    def __init__(self, key, hashAlgo, mgfunc, label, randfunc):

    def can_encrypt(self):

    def can_decrypt(self):

    def encrypt(self, message):

    def decrypt(self, ciphertext):
        

2)用AES-GCM舉例

key_int =Crypto.Random.random.getrandbits(256)#生成的是一個大數,需要轉換成bytes string
key = key_int.to_bytes(32,byteorder = 'big')#32 = 256/8

iv_int = Crypto.Random.random.getrandbits(96)
iv = iv_int.to_bytes(12,byteorder = 'big')

def aes256gcm_encrypt(data,key,iv,tag_len):
	try:
		aes = Crypto.Cipher.AES.new(key,Crypto.Cipher.AES.MODE_GCM,iv,mac_len=tag_len)
		return aes.encrypt_and_digest(data)
	except Exception as err:
		print("aes256gcm encrypt fail"," ",err)
		return b'',b''#返回密文和tag
    

def aes256gcm_decrypt(data,key,iv,tag):
	try:
		aes = Crypto.Cipher.AES.new(key,Crypto.Cipher.AES.MODE_GCM,iv,mac_len=len(tag))
		return aes.decrypt_and_verify(data,tag)
	except Exception as err
		print("aes256gcm decrypt fail"," ",err)
		return b''

Crypto.Random.random.getrandbits 有點坑,需要轉換成byte string

new包括以下引數key,mode(選擇以下模式),*args(iv或nonce),**kwargs(得需要檢視對應模式的__init__)

AES包含以下模式,MODE_ECB = 1、MODE_CBC = 2、MODE_CFB = 3、MODE_OFB = 5、MODE_CTR = 6、MODE_OPENPGP = 7、MODE_CCM = 8、MODE_EAX = 9、MODE_SIV = 10、MODE_GCM = 11、MODE_OCB = 12

AES-GCM模式下,new返回類Crypto.Cipher._mode_gcm.GcmMode物件

class GcmMode(object):
    """Galois Counter Mode (GCM).

    This is an Authenticated Encryption with Associated Data (`AEAD`_) mode.
    It provides both confidentiality and authenticity.

    The header of the message may be left in the clear, if needed, and it will
    still be subject to authentication. The decryption step tells the receiver
    if the message comes from a source that really knowns the secret key.
    Additionally, decryption detects if any part of the message - including the
    header - has been modified or corrupted.

    This mode requires a *nonce*.

    This mode is only available for ciphers that operate on 128 bits blocks
    (e.g. AES but not TDES).

    See `NIST SP800-38D`_.

    .. _`NIST SP800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
    .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html

    :undocumented: __init__
    """

    def __init__(self, factory, key, nonce, mac_len, cipher_params, ghash_c):

    def update(self, assoc_data):

    def _update(self, data):

    def _pad_cache_and_update(self):

    def encrypt(self, plaintext):

    def decrypt(self, ciphertext):

    def digest(self):

    def _compute_mac(self):

    def hexdigest(self):

    def verify(self, received_mac_tag):

    def hexverify(self, hex_mac_tag):

    def encrypt_and_digest(self, plaintext):

    def decrypt_and_verify(self, ciphertext, received_mac_tag):

參考:

忘了連結在哪,得找找