# GCM, CCM, SIV, EAX
from Crypto.Cipher import AES
import json
import base64
from Crypto.Random import get_random_bytes

AES256_KEY_SIZE=32
key = get_random_bytes(AES256_KEY_SIZE)

# msg = only_da_i + da_i+confidentiality
# header --> only integrity and data authc
# payload --> confidentiality + integrity and data authc

header = b'This is the authc only part of the message'
payload = b'this is also confidential'

cipher = AES.new(key,AES.MODE_GCM) #iv is generated by the library

cipher.update(header) # iterate on all the input

ciphertext, tag = cipher.encrypt_and_digest(payload) # only once, tag is the name of the MAC in the AEAD field

json_k = [ 'nonce', 'header', 'ciphertext', 'tag' ]
json_v = [ base64.b64encode(x).decode('utf-8') for x in (cipher.nonce, header, ciphertext, tag) ]
json_object  = json.dumps(dict(zip(json_k, json_v)))

# dict = {'nonce':b64encode(cipher.nonce).decode('utf-8'), 'header':b64encode(header).decode('utf-8'),'ciphertext':b64encode(ciphertext).decode('utf-8'), 'tag':b64encode(tag).decode('utf-8')}

print(json_object)


#######################
# recipient knows the key: securely exchanged
# in a public channel: header, ciphertext, tag, iv/nonce

b64 = json.loads(json_object)
json_k = ['nonce','header','ciphertext','tag']
jv = {k:base64.b64decode(b64[k]) for k in json_k}

try:
    cipher2 = AES.new(key, AES.MODE_GCM,nonce=jv['nonce'])
    cipher2.update(jv['header'])
    plaintext = cipher2.decrypt_and_verify(jv['ciphertext'],jv['tag'])
    print("This is the plaintext: "+plaintext.decode('utf-8')+" and is authentic")
except (ValueError, KeyError):
    print("Incorrect verification")
