PyCryptodome Quick Reference
============================

INSTALLATION
  pip install pycryptodome

AES
  from Crypto.Cipher import AES
  from Crypto.Util.Padding import pad, unpad

  # AES-ECB
  cipher = AES.new(key, AES.MODE_ECB)
  ct = cipher.encrypt(pad(data, 16))
  pt = unpad(cipher.decrypt(ct), 16)

  # AES-CBC
  cipher = AES.new(key, AES.MODE_CBC, iv=iv)
  ct = cipher.encrypt(pad(data, 16))
  cipher2 = AES.new(key, AES.MODE_CBC, iv=iv)
  pt = unpad(cipher2.decrypt(ct), 16)

  # AES-CTR
  cipher = AES.new(key, AES.MODE_CTR, nonce=nonce)
  ct = cipher.encrypt(data)   # no padding needed

  # AES-GCM
  cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
  ct, tag = cipher.encrypt_and_digest(data)

RSA
  from Crypto.PublicKey import RSA
  from Crypto.Cipher import PKCS1_OAEP

  # Generate key
  key = RSA.generate(2048)
  pub = key.publickey()

  # Encrypt / Decrypt
  cipher = PKCS1_OAEP.new(pub)
  ct = cipher.encrypt(data)
  cipher = PKCS1_OAEP.new(key)
  pt = cipher.decrypt(ct)

  # RSA math
  key = RSA.import_key(open("key.pem").read())
  n = key.n    # modulus
  e = key.e    # public exponent
  d = key.d    # private exponent
  p = key.p    # prime 1
  q = key.q    # prime 2

  # Textbook RSA
  ct = pow(m, e, n)    # encrypt
  pt = pow(ct, d, n)   # decrypt

HASHING
  from Crypto.Hash import SHA256, MD5, SHA1

  h = SHA256.new(data)
  print(h.hexdigest())

  h = MD5.new(data)
  print(h.hexdigest())

RANDOM
  from Crypto.Random import get_random_bytes
  key = get_random_bytes(16)  # 16 random bytes
  iv  = get_random_bytes(16)

USEFUL MATH
  from Crypto.Util.number import *
  long_to_bytes(n)          Number → bytes
  bytes_to_long(b)          Bytes → number
  getPrime(1024)            Random 1024-bit prime
  isPrime(n)                Primality test
  inverse(e, phi)           Modular inverse
  GCD(a, b)                 Greatest common divisor
