<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Hashing Algorithms
The goal is to have a long message as input and produce an output which is much shorter called the hash or message digest. Furthermore, we want it to have certain properties.
Input
Step1:  *<font color=" #6495ED">Exercise</font> *
Let's explore what other hashing algorithms are available and use a different one.
Change "PyCon2017", to PyCon 2017" and see check the result
Python Builtin Support
"Additional algorithms may also be available depending upon the OpenSSL library that Python uses on your platform. On most platforms the sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256() are also available."
source
Step2:  *<font color=" #6495ED">Exercise</font> *
Let's see what other hashing algorithms our python supports.
Hash-based message authentication code (HMAC)
HMACs are used for message authentications combined with a secret key. This provide integrity checking and authentication. An attacker can not forge the digest without knowing the secret key.
<img src="include/SHAhmac.png" width="600">
image source
Step3:  HMAC Verification
<ASSISTANT_TASK:>
Python Code:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
import base64 # to produce human readable encoding of the bytes
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(b"PyCon")
digest.update(b"2017")
msg_digest = digest.finalize()
# Notice the output size of the digest
print ("msg_digest:", len(msg_digest), len(msg_digest) * 8)
print ("base64 encoding:", base64.b64encode(msg_digest))
print()
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(b"PyCon2017")
msg_digest = digest.finalize()
# Notice the output size of the digest
print ("msg_digest:", len(msg_digest), len(msg_digest) * 8)
print ("base64 encoding:", base64.b64encode(msg_digest))
print()
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(b"PyCon 2017")
msg_digest = digest.finalize()
# Notice the output size of the digest
print ("msg_digest:", len(msg_digest), len(msg_digest) * 8)
print ("base64 encoding:", base64.b64encode(msg_digest))
Explanation: Hashing Algorithms
The goal is to have a long message as input and produce an output which is much shorter called the hash or message digest. Furthermore, we want it to have certain properties.
Input: long message
Output: short fixed size block (called hash or message digest)
We want the same input always produces the same output (deterministic)
<font color=" #6495ED">Exercise</font>
A non security related example of hash functions?
A security related example of hash functions?
 There is a difference between hash function and cryptographic hash functions 
Desired properties
Pre-image: Given a hash h it is computationally infeasible to find a message m that produces h
Second preimage: Given message m, it is computationally infeasible to find a message m’, (m ≠ m’) such that, h(m) = h(m’)
Collisions: It is computationally difficult to find any two messages m, m’ (m ≠ m’) such that, h(m) = h(m’)
Examples:
 - Recommended Hash Algorithm (SHA-2, SHA-3) by NIST
 - <strike>SHA-1</strike>: output 160 bits being phased out (shattered.io)
 - <strike>MD2, MD4, and MD5</strike> by Ron Rivest [RFC1319, 1320, 1321]
<br> 
source: shattered.io
<br>
<img src="include/shattered.png" width="550">
<img src="include/shattered_diagram.png" width="700">
<br>
SHA Family
Secure Hash Algorithm (SHA) family, is a series of hashing algorithms. Ranging from SHA-0 to SHA-3. SHA-0 should never be used, it's advised to move from SHA-1 to SHA-2. SHA-3 is the most recent version, published in 2015.
SHA-1: Digest size (160), Block size (512)
SHA-2: Digest size (224, 256, 384, or 512), Block size (512, 1024)
SHA-3: Digest size (224, 256, 384, 512), Block size (1600)
End of explanation
import hashlib
sha256 = hashlib.sha256()
sha256.update(b"PyCon2017")
msg_digest = sha256.digest()
# Notice the output size of the digest
print ("msg_digest:", len(msg_digest), len(msg_digest) * 8)
print ("base64 encoding:", base64.b64encode(msg_digest))
Explanation: *<font color=" #6495ED">Exercise</font> *
Let's explore what other hashing algorithms are available and use a different one.
Change "PyCon2017", to PyCon 2017" and see check the result
Python Builtin Support
"Additional algorithms may also be available depending upon the OpenSSL library that Python uses on your platform. On most platforms the sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256() are also available."
source: https://docs.python.org/3/library/hashlib.html
End of explanation
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hmac, hashes
import os
import base64
hmc_key = k = os.urandom(16)
hmc = hmac.HMAC(hmc_key, hashes.SHA1(), default_backend())
hmc.update(b"PyCon2017")
hmc_sig = hmc.finalize()
print (base64.b64encode(hmc_sig))
Explanation: *<font color=" #6495ED">Exercise</font> *
Let's see what other hashing algorithms our python supports.
Hash-based message authentication code (HMAC)
HMACs are used for message authentications combined with a secret key. This provide integrity checking and authentication. An attacker can not forge the digest without knowing the secret key.
<img src="include/SHAhmac.png" width="600">
image source: wikipedia
$ HMAC(K,m) = H((K\oplus opad) || H((K \oplus ipad) || m))$
HMAC Calculation
End of explanation
# Verification Successufl
hmc = hmac.HMAC(hmc_key, hashes.SHA1(), default_backend())
hmc.update(b"PyCon2017")
hmc.verify(hmc_sig)
# Verification Fails
hmc = hmac.HMAC(hmc_key, hashes.SHA1(), default_backend())
hmc.update(b"PyCon2017")
hmc.verify(hmc_sig+b"1")
Explanation: HMAC Verification
End of explanation
<END_TASK>