Created
November 15, 2014 22:48
-
-
Save davidfischer/67d1e9519cbb00ebe653 to your computer and use it in GitHub Desktop.
A talk on the Python cryptography library (cryptography.io) given by @davidfischer at the San Diego Python Django Unconference on November 15, 2014
This file contains hidden or 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
{ | |
"metadata": { | |
"name": "", | |
"signature": "sha256:ca5245a3f9db179c6310a0aa7b0a84c587f5d6ba79796e2dfef0295c7ef981b9" | |
}, | |
"nbformat": 3, | |
"nbformat_minor": 0, | |
"worksheets": [ | |
{ | |
"cells": [ | |
{ | |
"cell_type": "heading", | |
"level": 1, | |
"metadata": {}, | |
"source": [ | |
"Python Cryptography" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"https://cryptography.io" | |
] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 3, | |
"metadata": {}, | |
"source": [ | |
"Enter cryptography for humans (the high level API)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"import cryptography" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 4, | |
"metadata": {}, | |
"source": [ | |
"Symmetric encryption & decryption" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"from cryptography.fernet import Fernet\n", | |
"\n", | |
"key = Fernet.generate_key() # 32 bytes - urlsafe_base64\n", | |
"f = Fernet(key)\n", | |
"token = f.encrypt(b\"San Diego Python is the best\")\n", | |
"\n", | |
"# Token includes ciphertext, time, and HMAC as urlsafe_base64\n", | |
"print(token)\n", | |
"\n", | |
"# Decryption\n", | |
"print(Fernet(key).decrypt(token)) # raises if token isn't valid\n", | |
"print(Fernet(key).decrypt(token, ttl=5)) # raises if older than ttl seconds" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 4, | |
"metadata": {}, | |
"source": [ | |
"Fernet encryption format" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"import base64, struct, datetime\n", | |
"\n", | |
"token_bytes = base64.urlsafe_b64decode(token)\n", | |
"\n", | |
"# Fernet version (byte #1)\n", | |
"print(struct.unpack('B', token_bytes[:1])[0])\n", | |
"\n", | |
"# Encryption time (bytes #2-9)\n", | |
"print(datetime.datetime.fromtimestamp(struct.unpack('>Q', token_bytes[1:9])[0]))\n", | |
"\n", | |
"# Random initialization vector (bytes #10-17)\n", | |
"print(token_bytes[9:17])\n", | |
"\n", | |
"# Ciphertext (variable len bytes up to last 32 bytes)\n", | |
"\n", | |
"# HMAC - verifies that nothing was tampered with (final 32 bytes)\n", | |
"from cryptography.hazmat.backends import default_backend\n", | |
"from cryptography.hazmat.primitives import hashes, hmac\n", | |
"h = hmac.HMAC(base64.urlsafe_b64decode(key)[:16], hashes.SHA256(), backend=default_backend())\n", | |
"h.update(token_bytes[:-32])\n", | |
"h.finalize() == token_bytes[-32:]" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 3, | |
"metadata": {}, | |
"source": [ | |
"Hazardous materials cryptography" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Lots of potential for error when used improperly. Let's dive in!" | |
] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 4, | |
"metadata": {}, | |
"source": [ | |
"Public key cryptography" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"from cryptography.hazmat.backends import default_backend\n", | |
"from cryptography.hazmat.primitives import hashes\n", | |
"from cryptography.hazmat.primitives.asymmetric import rsa, padding\n", | |
"\n", | |
"# Used to decrypt messages and to sign messages\n", | |
"private_key = rsa.generate_private_key(\n", | |
" public_exponent=65537,\n", | |
" key_size=2048,\n", | |
" backend=default_backend()\n", | |
")\n", | |
"\n", | |
"# Used to encrypt messages and verify signed messages\n", | |
"public_key = private_key.public_key()" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Encryption and decryption\n", | |
"message = b\"Go Chargers!\"\n", | |
"ciphertext = public_key.encrypt(\n", | |
" message,\n", | |
" padding.OAEP(\n", | |
" mgf=padding.MGF1(algorithm=hashes.SHA1()),\n", | |
" algorithm=hashes.SHA1(),\n", | |
" label=None\n", | |
" )\n", | |
")\n", | |
"print('Ciphertext length: {}'.format(len(ciphertext)))\n", | |
"\n", | |
"plaintext = private_key.decrypt(\n", | |
" ciphertext,\n", | |
" padding.OAEP(\n", | |
" mgf=padding.MGF1(algorithm=hashes.SHA1()),\n", | |
" algorithm=hashes.SHA1(),\n", | |
" label=None\n", | |
" )\n", | |
")\n", | |
"print(plaintext)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Signature and verification\n", | |
"signer = private_key.signer(\n", | |
" padding.PSS(\n", | |
" mgf=padding.MGF1(hashes.SHA1()),\n", | |
" salt_length=padding.PSS.MAX_LENGTH\n", | |
" ),\n", | |
" hashes.SHA1()\n", | |
")\n", | |
"data = b\"Python is fun\"\n", | |
"signer.update(data)\n", | |
"signature = signer.finalize()\n", | |
"print(signature)\n", | |
"\n", | |
"verifier = public_key.verifier(\n", | |
" signature,\n", | |
" padding.PSS(\n", | |
" mgf=padding.MGF1(hashes.SHA1()),\n", | |
" salt_length=padding.PSS.MAX_LENGTH\n", | |
" ),\n", | |
" hashes.SHA1()\n", | |
")\n", | |
"verifier.update(data)\n", | |
"verifier.verify() # Raises InvalidSignature on error" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 4, | |
"metadata": {}, | |
"source": [ | |
"Two-factor authentication" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Time-based one time password\n", | |
"import os\n", | |
"import time\n", | |
"from cryptography.hazmat.backends import default_backend\n", | |
"from cryptography.hazmat.primitives.twofactor.totp import TOTP\n", | |
"from cryptography.hazmat.primitives.hashes import SHA256\n", | |
"\n", | |
"OUTPUT_LENGTH = 8 # [6-8] bytes\n", | |
"TIME_STEP = 30\n", | |
"key = os.urandom(16)\n", | |
"totp = TOTP(key, OUTPUT_LENGTH, SHA256(), TIME_STEP, backend=default_backend())\n", | |
"totp.generate(time.time()) # generates the same value during TIME_STEP seconds" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 4, | |
"metadata": {}, | |
"source": [ | |
"Other useful primitives" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# PBKDF2 for password storage\n", | |
"import os\n", | |
"from cryptography.hazmat.primitives import hashes\n", | |
"from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC\n", | |
"from cryptography.hazmat.backends import default_backend\n", | |
"\n", | |
"salt = os.urandom(16)\n", | |
"kdf = PBKDF2HMAC(\n", | |
" algorithm=hashes.SHA256(),\n", | |
" length=32,\n", | |
" salt=salt,\n", | |
" iterations=100000,\n", | |
" backend=default_backend()\n", | |
")\n", | |
"kdf.derive(b\"my secret password\")" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Constant time comparison\n", | |
"from cryptography.hazmat.primitives import constant_time\n", | |
"\n", | |
"constant_time.bytes_eq(b\"foo\", b\"foo\")" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Quite a few more..." | |
] | |
} | |
], | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment