From 8704175145a05319e363f6d86962673984c34ac6 Mon Sep 17 00:00:00 2001 From: adii1823 <64855277+adii1823@users.noreply.github.com> Date: Thu, 28 Oct 2021 17:39:56 +0530 Subject: [PATCH] ch09 --- ch09/hlib.py | 54 +++++++++++++++++++++++++++++ ch09/hmc.py | 15 ++++++++ ch09/jwt/claims_auth.py | 55 ++++++++++++++++++++++++++++++ ch09/jwt/claims_time.py | 49 ++++++++++++++++++++++++++ ch09/jwt/rsa/key | 27 +++++++++++++++ ch09/jwt/rsa/key.pub | 1 + ch09/jwt/rsa/keypwd | 30 ++++++++++++++++ ch09/jwt/rsa/keypwd.pub | 1 + ch09/jwt/tok.py | 21 ++++++++++++ ch09/jwt/token_rsa.py | 28 +++++++++++++++ ch09/requirements/requirements.in | 2 ++ ch09/requirements/requirements.txt | 14 ++++++++ ch09/secrs/secr_gen.py | 30 ++++++++++++++++ ch09/secrs/secr_rand.py | 31 +++++++++++++++++ ch09/secrs/secr_reset.py | 16 +++++++++ 15 files changed, 374 insertions(+) create mode 100644 ch09/hlib.py create mode 100644 ch09/hmc.py create mode 100644 ch09/jwt/claims_auth.py create mode 100644 ch09/jwt/claims_time.py create mode 100644 ch09/jwt/rsa/key create mode 100644 ch09/jwt/rsa/key.pub create mode 100644 ch09/jwt/rsa/keypwd create mode 100644 ch09/jwt/rsa/keypwd.pub create mode 100644 ch09/jwt/tok.py create mode 100644 ch09/jwt/token_rsa.py create mode 100644 ch09/requirements/requirements.in create mode 100644 ch09/requirements/requirements.txt create mode 100644 ch09/secrs/secr_gen.py create mode 100644 ch09/secrs/secr_rand.py create mode 100644 ch09/secrs/secr_reset.py diff --git a/ch09/hlib.py b/ch09/hlib.py new file mode 100644 index 0000000..88b04c5 --- /dev/null +++ b/ch09/hlib.py @@ -0,0 +1,54 @@ +# hlib.py +# NOT A PYTHON MODULE - DO NOT ATTEMPT TO RUN + +# hlib.py +>>> import hashlib +>>> hashlib.algorithms_available +{'mdc2', 'sha224', 'whirlpool', 'sha1', 'sha3_512', 'sha512_256', + 'sha256', 'md4', 'sha384', 'blake2s', 'sha3_224', 'sha3_384', + 'shake_256', 'blake2b', 'ripemd160', 'sha512', 'md5-sha1', + 'shake_128', 'sha3_256', 'sha512_224', 'md5', 'sm3'} +>>> hashlib.algorithms_guaranteed +{'blake2s', 'md5', 'sha224', 'sha3_512', 'shake_256', 'sha3_256', + 'shake_128', 'sha256', 'sha1', 'sha512', 'blake2b', 'sha3_384', + 'sha384', 'sha3_224'} + +>>> h = hashlib.blake2b() +>>> h.update(b'Hash me') +>>> h.update(b' now!') +>>> h.hexdigest() +'56441b566db9aafcf8cdad3a4729fa4b2bfaab0ada36155ece29f52ff70e1e9d' +'7f54cacfe44bc97c7e904cf79944357d023877929430bc58eb2dae168e73cedf' +>>> h.digest() +b'VD\x1bVm\xb9\xaa\xfc\xf8\xcd\xad:G)\xfaK+\xfa\xab\n\xda6\x15^' +b'\xce)\xf5/\xf7\x0e\x1e\x9d\x7fT\xca\xcf\xe4K\xc9|~\x90L\xf7' +b'\x99D5}\x028w\x92\x940\xbcX\xeb-\xae\x16\x8es\xce\xdf' +>>> h.block_size +128 +>>> h.digest_size +64 +>>> h.name +'blake2b' + +>>> hashlib.sha256(b'Hash me now!').hexdigest() +'10d561fa94a89a25ea0c7aa47708bdb353bbb062a17820292cd905a3a60d6783' + + +>>> import hashlib +>>> h1 = hashlib.blake2b(b'Important data', digest_size=16, +... person=b'part-1') +>>> h2 = hashlib.blake2b(b'Important data', digest_size=16, +... person=b'part-2') +>>> h3 = hashlib.blake2b(b'Important data', digest_size=16) +>>> h1.hexdigest() +'c06b9af95d5aa6307e7e3fd025a15646' +>>> h2.hexdigest() +'9cb03be8f3114d0f06bddaedce2079c4' +>>> h3.hexdigest() +'7d35308ca3b042b5184728d2b1283d0d' + +>>> import os +>>> dk = hashlib.pbkdf2_hmac('sha256', b'Password123', +... salt=os.urandom(16), iterations=100000) +>>> dk.hex() +'f8715c37906df067466ce84973e6e52a955be025a59c9100d9183c4cbec27a9e' diff --git a/ch09/hmc.py b/ch09/hmc.py new file mode 100644 index 0000000..4988683 --- /dev/null +++ b/ch09/hmc.py @@ -0,0 +1,15 @@ +# hmc.py +import hmac +import hashlib + + +def calc_digest(key, message): + key = bytes(key, 'utf-8') + message = bytes(message, 'utf-8') + + dig = hmac.new(key, message, hashlib.sha256) + return dig.hexdigest() + + +mac = calc_digest('secret-key', 'Important Message') +print(mac) diff --git a/ch09/jwt/claims_auth.py b/ch09/jwt/claims_auth.py new file mode 100644 index 0000000..a5b0fc3 --- /dev/null +++ b/ch09/jwt/claims_auth.py @@ -0,0 +1,55 @@ +# jwt/claims_auth.py +import jwt + + +data = {'payload': 'data', 'iss': 'hein', 'aud': 'learn-python'} + + +secret = 'secret-key' +token = jwt.encode(data, secret) + + +def decode(token, secret, issuer=None, audience=None): + try: + print(jwt.decode(token, secret, issuer=issuer, + audience=audience, algorithms=["HS256"])) + except ( + jwt.InvalidIssuerError, jwt.InvalidAudienceError + ) as err: + print(err) + print(type(err)) + + +decode(token, secret) + +# not providing the issuer won't break +decode(token, secret, audience='learn-python') + +# not providing the audience will break +decode(token, secret, issuer='hein') + +# both will break +decode(token, secret, issuer='wrong', audience='learn-python') +decode(token, secret, issuer='hein', audience='wrong') + +decode(token, secret, issuer='hein', audience='learn-python') + + +""" +$ python jwt/claims_time.py +Invalid audience + + +{'payload': 'data', 'iss': 'hein', 'aud': 'learn-python'} + +Invalid audience + + +Invalid issuer + + +Invalid audience + + +{'payload': 'data', 'iss': 'hein', 'aud': 'learn-python'} +""" diff --git a/ch09/jwt/claims_time.py b/ch09/jwt/claims_time.py new file mode 100644 index 0000000..73fafaf --- /dev/null +++ b/ch09/jwt/claims_time.py @@ -0,0 +1,49 @@ +# jwt/claims_time.py +from datetime import datetime, timedelta, timezone +from time import sleep, time + +import jwt + + +iat = datetime.now(tz=timezone.utc) +nfb = iat + timedelta(seconds=1) +exp = iat + timedelta(seconds=3) + + +data = {'payload': 'data', 'nbf': nfb, 'exp': exp, 'iat': iat} + + +def decode(token, secret): + print(time()) + try: + print(jwt.decode(token, secret, algorithms=['HS256'])) + except ( + jwt.ImmatureSignatureError, jwt.ExpiredSignatureError + ) as err: + print(err) + print(type(err)) + + +secret = 'secret-key' +token = jwt.encode(data, secret) + + +decode(token, secret) +sleep(2) +decode(token, secret) +sleep(2) +decode(token, secret) + + +""" +$ python jwt/claims_time.py +1631043839.6459477 +The token is not yet valid (nbf) + +1631043841.6480813 +{'payload': 'data', 'nbf': 1631043840, 'exp': 1631043842, 'iat': +1631043839} +1631043843.6498601 +Signature has expired + +""" diff --git a/ch09/jwt/rsa/key b/ch09/jwt/rsa/key new file mode 100644 index 0000000..036cb83 --- /dev/null +++ b/ch09/jwt/rsa/key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAz87T1pNQnbPZLSxuHP8y0HQDcNsKpwd1LwtghPld9l0lK6f2 +pDNlJYwqI0il8JUfIfWE9VaO9KsxTfBtYPyLO8Tz7Nk+04KDlkQOKgpKJHrYTd+5 +iSre3D68IVHdxBku2VFh57uqBNJCqGBF0OgVHh/ms9f0kDVaaUNSj7kMu5sLVPWR +vnZgyJN0v/LHS2y22tkXncj7wf9kC13qN36MsZ2qH4VF0f8/WTkE6zUSdTwY2ZEv +K66zjmTfuFoQ8df5N5Pj4STQGk+2l6uU/kxNbBNWjYmJNp1EpdJJ3m9A1nDrRRQf +M1HdckOCJVn+eYDrzD2W/bSMm/3SgqzM3o1ONQIDAQABAoIBADv9QgwUlNYhwBUZ +WWRHi3y/sOqYYRfcwEhnaWKZtjVTqFJU949pQs63CscKxtSPx9/+x3Ynmbcp4F7W +hEzWOr9zWNNL16YpbCEp3kjmlYa4a873QdFGLfW4qoiX4IQmnO6hXrkN5MPlitae +jCkFhmse3HOYaQJkVIhEpgXVbsaNMvSa6woAfT5tVPSxDSEdB4a61zwSpssYfLMF +ZFsHEV6mE6hkmfZxw22/I2I7Up0sV6f7KOgjoPaeqL6i5ibEhIWzDyQiKyW6YN3j +moZNrIAHoq8oAP9wWavrpbnslp5c3SculUueVxdUv46LDy9RbmFOajdaJALFdY/D +NI+X7WECgYEA+qBnI0cHmYfOqGeSVUsTPUk0uG8N2fDWh1m4GPRzU4a00Mh7nG+l +8j54FDLqQeoWyWN0808dRMakjeHNzjIEi8paHbrrWIS+4Xp8pVH56iCG9wTtbj6j +ni5CeoKFtRd3NcqwTOWznR+OvE02WzqE8kDQbNmT1Y68MPf/4vEpABkCgYEA1ENo +pKknQv+e9ZapWtHk6DDtq/Xw/R+VadwfGBDdIU1XQsUjlTw/igeElrDQOPVao8xL +SK9vCNvPUi+W0W241ZoMGCIeywGsnixKoRx7DWNxYchcPDWQtoZtrNUwkJBW/Lha +iFMQDdQU7aLYJlwi09KeJB9w7JHNpi4R5N6Kkn0CgYB0jdApOckw/1V+P9xvyiBC +ah8Yfp0Ec9pwy6qwAE750zWXuwSxdcLI64BQdHU4/jJmqdgjpvFHoNG6If7iG6S9 +lfdeyCTW37UdiycYgw0kcsgRbLs2f+77iyvjaXvhAe6wl3hx6okjUx/ANnBG8OoO +91F2raDwuhaO92aLFfgpUQKBgAh1t1H4u+vbrEY1fwJzox/t80sLPlOYUqgpccPP +yEBviK7MlKJ6CD5EFnC7E1Fx1e75UXbQJyi/OgAYjXZDXT6GKT08/uUwZ+TV9xN8 +wxrBf99Z0PNFX0MnEG/2/zyDxDPGVTVhuh4S+dKOzvaYbXrrxgnChwmmtf+NjoEE +rZkxAoGAQvv6ZrKrhUMYIsgPVyjXe5E421cv/pj4KCsqdeclV+3vR87SwOfpej9y +/gpZuEIHxzzgAz5eFgrGJjm/4VGqNEJ3PGxa6i6a0ld3Cv2j/qyjV8BvL+MtFH1r +X4lEs3tRFn9LSqyeQjfDRP+Fv91OgKaRb6wJ8HWBnx8Jpkd19kU= +-----END RSA PRIVATE KEY----- diff --git a/ch09/jwt/rsa/key.pub b/ch09/jwt/rsa/key.pub new file mode 100644 index 0000000..a910cbb --- /dev/null +++ b/ch09/jwt/rsa/key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPztPWk1Cds9ktLG4c/zLQdANw2wqnB3UvC2CE+V32XSUrp/akM2UljCojSKXwlR8h9YT1Vo70qzFN8G1g/Is7xPPs2T7TgoOWRA4qCkokethN37mJKt7cPrwhUd3EGS7ZUWHnu6oE0kKoYEXQ6BUeH+az1/SQNVppQ1KPuQy7mwtU9ZG+dmDIk3S/8sdLbLba2RedyPvB/2QLXeo3foyxnaofhUXR/z9ZOQTrNRJ1PBjZkS8rrrOOZN+4WhDx1/k3k+PhJNAaT7aXq5T+TE1sE1aNiYk2nUSl0kneb0DWcOtFFB8zUd1yQ4IlWf55gOvMPZb9tIyb/dKCrMzejU41 fab@fabmp.local diff --git a/ch09/jwt/rsa/keypwd b/ch09/jwt/rsa/keypwd new file mode 100644 index 0000000..3784570 --- /dev/null +++ b/ch09/jwt/rsa/keypwd @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,6B1FF5E922949C8E4AA51B8F5B0F0CBE + +E6B7lpXoI0SXOImuBllCOoFPonK6JObMVOp2qrEagcVP9loRXOecRi/qG+nF/BJO +W/FnY4OmsCYAgFPB281plp8eVodNr6XxcPZaQx92G9RlA5FSCWICWFfhOlcDo1bR +1OAkmZjzWve3C2XNbOVpMweO3ElFzKy2KPzuBHaDVfuZm6pMMxqn4C+MzL6cYtF/ +a3aJRwRJJYF9OLOSpfoFCCVC/NfOjhczPLgNqRHnpnnAypddwju8R6KPJ1SkZaru +Jd1hwAYzcFY/G21SwCzUp9MOp9faeomWYYiv8BT/65LOY/e8evITh9XDpe83S3KQ +oY+7NiVZdQzjaw8lA9KRWQTsXTLSXAFaHJLmfITr/QnC1HhEPBiux3MY2vjU1QMJ +JtsrlTqBjBIKMJh4RoqvNrcNCCCYaXleNmSObcGR75s41s9yGAaNNKKGfvvPvW5j +69mOEqOmoKdtJuClpkeabqPXVqQLyf3CKZmqZbctmdAytTfZFRSTFw4VZZXKj/nR +7eLPqlg4Q8F057LWlTklsRDZvQOp9Ci5kCFK+5fOQ79CBeBx59i121+tYSpLWos/ +bYOKcvSGfDghJYhGgfIg/H2e409VGkum1wTfEjD88n+wsjDQb94a0kiH2Kk/xqoy +Bv24SSIPMgLHuWTJtkUOGESRm1op4URtVBmPURaAAacnXbr6jXyBrl8leN5T394U +hn9Y9iNTTGBDFZL7gqZpSWzW5kI8Ju66Tt1WExlvHlb3h/0doIwlo0+hR6Rs4C4L +2YuOiiV6IBjDPF2ySg2zaUfGSVkxFL85Jrt8yQCLh3ebGeVkOptx653kVm0wMWcy +a8vxTAI4m8szB272ZzMWKf312q83RjRBHPw7dMM6tq9jQL0Aea9/Ia9fLElA8rH/ +1i3g4zz3yhTqctkqiKIk7CeMQcYC3IL2ddUHftcijWfjvBChhjvWupegFC2DM29r +H0H5lRyQHT8daaNqWYR9PEL+n8Au/FAgtz4U7lgYVdHstTq7Mch+vnWfc/4Y7pEl +UWZBSmyMl2dpDTGCD79XFgXTuoqtkuML788ll5sz8C0Bh+jVfDwPsc8pimABag/s +0N7l3cPHJX5Vv3lSrVtOdsT7Athhkz4klHijou+a1efDNX+aEbC08oy4M3OaV2Ri +o1yHpvZo9Wsw3IMmxuPswWd42BIweUrLeJy1PuO8dONwi4SzT2RBXIV3H56It9Ad +XQK7BYAtOa1sBJ9tYycP/f9Bfg36SpjxNAwBQkQB9V8nNEDwW4818zQs7aLs5NkM +BMIETlGBSMX+OQTOTNPoABlx+c0Xn6NSm3GpHr5biZOhmShQaDDBdnPV8yk1XQ9j +06tO2LvaevhOVfGt0GuPwUQbOwoJ8dAFFM7A7//2vd/QFEtJKXQK3N2cQTDmvTch +dBt4vpqgiZfwomglHqVw/8NHSIIdTHyVYjCCNQvK7OfjricjBIAMGio+XlNiCbwP +Jpo5fRtZ3bJNLiHIDFYjelWJhSN+B/h0DfSo3XF6roncXC2ljZ07TDi66ju0j80Q +/n5pc2m1ckjjf46tkuSsW6kQN1YBdpzLyyAHeuy9rAR/Vo8inPld7zJa7B4oOuow +-----END RSA PRIVATE KEY----- diff --git a/ch09/jwt/rsa/keypwd.pub b/ch09/jwt/rsa/keypwd.pub new file mode 100644 index 0000000..e2b87c5 --- /dev/null +++ b/ch09/jwt/rsa/keypwd.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAvimJusND8agzuXFhG+d4sPrn6AqC69H/icI77baF15/ztE9b/SioeBl2B+1HI/EnkqMpK8vLJOAN27cHUps9yMkjdU4KrRqK9pjHaeiwxZ+24LVt4QzvT6DcpREymB5y1GX34hIFjcXZDZgV8BkWwVW6qrocLtdl9c4vycPbqAYZ7o/hJzlbmhRClpB1FYamlZhuiH+5neWXuWtN7yV91Pi+DS7l0SbX37ElOComvZy9ug2UVqrK4+mPwCAtxnppHZVQsyVd2l2rKARqE3LRn2mbvlUtInDhfCU12GjRqItbbDgrcKoKeAJrExPUfWc9W3Iknh/2Os0FcbJSr6PX fab@fabmp.local diff --git a/ch09/jwt/tok.py b/ch09/jwt/tok.py new file mode 100644 index 0000000..03df9aa --- /dev/null +++ b/ch09/jwt/tok.py @@ -0,0 +1,21 @@ +# jwt/tok.py +import jwt + + +data = {'payload': 'data', 'id': 123456789} +algs = ['HS256', 'HS512'] + +token = jwt.encode(data, 'secret-key') +data_out = jwt.decode(token, 'secret-key', algorithms=algs) +print(token) +print(data_out) + + +# decode without verifying the signature +jwt.decode(token, options={'verify_signature': False}) + + +# let's use another algorithm +token512 = jwt.encode(data, 'secret-key', algorithm='HS512') +data_out = jwt.decode(token512, 'secret-key', algorithms=['HS512']) +print(data_out) diff --git a/ch09/jwt/token_rsa.py b/ch09/jwt/token_rsa.py new file mode 100644 index 0000000..cfe3f31 --- /dev/null +++ b/ch09/jwt/token_rsa.py @@ -0,0 +1,28 @@ +# jwt/token_rsa.py +import jwt +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization + + +data = {'payload': 'data'} + + +def encode(data, priv_filename, algorithm='RS256'): + + with open(priv_filename, 'rb') as key: + private_key = key.read() + + return jwt.encode(data, private_key, algorithm=algorithm) + + +def decode(data, pub_filename, algorithm='RS256'): + + with open(pub_filename, 'rb') as key: + public_key = key.read() + + return jwt.decode(data, public_key, algorithms=[algorithm]) + + +token = encode(data, 'jwt/rsa/key') +data_out = decode(token, 'jwt/rsa/key.pub') +print(data_out) diff --git a/ch09/requirements/requirements.in b/ch09/requirements/requirements.in new file mode 100644 index 0000000..b9bbb44 --- /dev/null +++ b/ch09/requirements/requirements.in @@ -0,0 +1,2 @@ +pyjwt +cryptography diff --git a/ch09/requirements/requirements.txt b/ch09/requirements/requirements.txt new file mode 100644 index 0000000..95f0f7a --- /dev/null +++ b/ch09/requirements/requirements.txt @@ -0,0 +1,14 @@ +# +# This file is autogenerated by pip-compile with python 3.9 +# To update, run: +# +# pip-compile requirements.in +# +cffi==1.14.5 + # via cryptography +cryptography==3.4.7 + # via -r requirements.in +pycparser==2.20 + # via cffi +pyjwt==2.1.0 + # via -r requirements.in diff --git a/ch09/secrs/secr_gen.py b/ch09/secrs/secr_gen.py new file mode 100644 index 0000000..0b04278 --- /dev/null +++ b/ch09/secrs/secr_gen.py @@ -0,0 +1,30 @@ +# secrs/secr_gen.py +import secrets +from string import digits, ascii_letters + + +def generate_pwd(length=8): + chars = digits + ascii_letters + return ''.join(secrets.choice(chars) for c in range(length)) + + +def generate_secure_pwd(length=16, upper=3, digits=3): + if length < upper + digits + 1: + raise ValueError('Nice try!') + + while True: + pwd = generate_pwd(length) + if (any(c.islower() for c in pwd) + and sum(c.isupper() for c in pwd) >= upper + and sum(c.isdigit() for c in pwd) >= digits): + return pwd + + +print(generate_secure_pwd()) +print(generate_secure_pwd(length=3, upper=1, digits=1)) + +""" +$ python secr_gen.py +nsL5voJnCi7Ote3F +J5e +""" diff --git a/ch09/secrs/secr_rand.py b/ch09/secrs/secr_rand.py new file mode 100644 index 0000000..12eb575 --- /dev/null +++ b/ch09/secrs/secr_rand.py @@ -0,0 +1,31 @@ +# secrs/secr_rand.py +import secrets + + +# utils +print(secrets.choice('Choose one of these words'.split())) + +print(secrets.randbelow(10 ** 6)) + +print(secrets.randbits(32)) + + +# tokens +print(secrets.token_bytes(16)) + +print(secrets.token_hex(32)) + +print(secrets.token_urlsafe(32)) + +# compare digests against timing attacks +secrets.compare_digest('abc123', 'abc123') + +""" +$ python secr_rand.py +one +504156 +3172492450 +b'\xda\x863\xeb\xbb|\x8fk\x9b\xbd\x14Q\xd4\x8d\x15}' +9f90fd042229570bf633e91e92505523811b45e1c3a72074e19bbeb2e5111bf7 +bl4qz_Av7QNvPEqZtKsLuTOUsNLFmXW3O03pn50leiY +""" diff --git a/ch09/secrs/secr_reset.py b/ch09/secrs/secr_reset.py new file mode 100644 index 0000000..40cde19 --- /dev/null +++ b/ch09/secrs/secr_reset.py @@ -0,0 +1,16 @@ +# secrs/secr_reset.py +import secrets + + +def get_reset_pwd_url(token_length=16): + token = secrets.token_urlsafe(token_length) + return f'https://example.com/reset-pwd/{token}' + + +print(get_reset_pwd_url()) + + +""" +$ python secr_reset.py +https://example.com/reset-pwd/dfVPEPl_pCkQ8YNV4er-UQ +"""