Created
May 10, 2016 05:03
-
-
Save jchysk/8c2f44e45f5c9a28c824d03de7aee46e to your computer and use it in GitHub Desktop.
A number of helper functions for common cryptography uses
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
from helpers import generate_RSA, encrypt_RSA, generate_password, decrypt_RSA, generate_AES, decrypt_AES, pad | |
priv, pub = generate_RSA() | |
encrypted = encrypt_RSA(pub, generate_password()) | |
key, iv, encryptor = generate_AES() | |
aes_encrypted = encryptor.encrypt(pad("this is a very long string " * 25)) | |
decrypt_AES(key, iv, aes_encrypted) | |
""" | |
BS = 16 | |
# This padding follows the PKCS#5 standard of padding regardless of current length | |
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) | |
unpad = lambda s: s[0:-ord(s[-1])] if len(s) > 0 and ord(s[-1]) <= 16 else s | |
def generate_number(digits): | |
import random | |
import string | |
rng = random.SystemRandom() | |
vc = string.digits | |
h1 = ''.join([rng.choice(vc) for i in range(digits)]) | |
return h1 | |
def generate_password(length=32): | |
"""Generates a password""" | |
import random | |
import string | |
rng = random.SystemRandom() | |
vc = string.ascii_letters + string.digits | |
return ''.join([rng.choice(vc) for i in range(length)]) | |
def decrypt_AES(cipher, iv, package): | |
from Crypto.Cipher import AES | |
cipher_obj = AES.new(cipher, AES.MODE_CBC, iv) | |
return cipher_obj.decrypt(package) | |
def generate_AES(key=None, iv=None): | |
''' | |
Generates an AES key and encryptor object that can encrypt text using the key | |
:param key: Can manually specify the AES key to be used, or let it be generated | |
:param iv: Can manually specify the IV, or let it be generated | |
''' | |
from Crypto.Cipher import AES | |
if key is None: | |
key = generate_password() | |
if iv is None: | |
iv = generate_password(16) | |
encryptor = AES.new(key, AES.MODE_CBC, iv) | |
return key, iv, encryptor | |
def decrypt_RSA(key, package): | |
''' | |
Decrypt RSA encrypted package with private key | |
:param key: Private key | |
:param package: Base64 encoded string to decrypt | |
:return: String decrypted | |
''' | |
from Crypto.PublicKey import RSA | |
from Crypto.Cipher import PKCS1_OAEP | |
from base64 import b64decode | |
rsakey = RSA.importKey(key) | |
# SHA1 and MGF1 | |
rsakey = PKCS1_OAEP.new(rsakey) | |
decrypted = rsakey.decrypt(b64decode(package)) | |
return decrypted | |
def encrypt_RSA(key, message): | |
''' | |
RSA encrypts the message using the public key | |
:param key: Public key to encrypt with | |
:param message: String to be encrypted | |
:return: Base64 encoded encrypted string | |
''' | |
from Crypto.PublicKey import RSA | |
from Crypto.Cipher import PKCS1_OAEP | |
rsakey = RSA.importKey(key) | |
# SHA1 and MGF1 | |
rsakey = PKCS1_OAEP.new(rsakey) | |
encrypted = rsakey.encrypt(message) | |
return encrypted.encode('base64') | |
def generate_RSA(bits=2048): | |
""" | |
Generate an RSA keypair with exponent of 65537 in PEM format | |
:param bits The key length in bits | |
:return private key and public key | |
""" | |
from Crypto.PublicKey import RSA | |
new_key = RSA.generate(bits, e=65537) | |
public_key = new_key.publickey().exportKey("PEM") | |
private_key = new_key.exportKey("PEM") | |
return private_key.strip(), public_key.strip() | |
def verify_sign(pub_key, signature, data): | |
''' | |
Verifies with a public key from whom the data came that it was indeed | |
signed by their private key. | |
:param pub_key: Public key | |
:param signature: String signature to be verified | |
:param data: The data the signature was created with | |
:return: Boolean. True for verified. False for not verified. | |
''' | |
from Crypto.PublicKey import RSA | |
from Crypto.Signature import PKCS1_v1_5 | |
from Crypto.Hash import SHA256 | |
from base64 import b64decode | |
verified = False | |
try: | |
'''Needs to be in try because signer verify will sometimes run | |
Value exception on improper signature strings instead of just | |
returning false''' | |
rsakey = RSA.importKey(pub_key) | |
signer = PKCS1_v1_5.new(rsakey) | |
digest = SHA256.new() | |
digest.update(b64decode(data)) | |
if signer.verify(digest, b64decode(signature)): | |
verified = True | |
finally: | |
return verified |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment