Merge pull request #36 from apache/issue35

update python code for aes and core utils
diff --git a/python/amcl/aes.py b/python/amcl/aes.py
index ab28514..16fc952 100644
--- a/python/amcl/aes.py
+++ b/python/amcl/aes.py
@@ -41,7 +41,9 @@
 
 
 # Constants
-AES_KEY = 32 # Length in bytes of an AES key
+KEYL = 16 # Length in bytes of an AES key
+TAGL = 16 # Length in bytes of tag
+IVL = 12 # Length in bytes of IV
 
 
 def gcm_encrypt(aes_key, iv, header, plaintext):
@@ -69,7 +71,7 @@
     iv1, iv1_val = core_utils.make_octet(None, iv)
     header1, header1_val = core_utils.make_octet(None, header)
     plaintext1, plaintext1_val = core_utils.make_octet(None, plaintext)
-    tag1, tag1_val = core_utils.make_octet(AES_KEY)
+    tag1, tag1_val = core_utils.make_octet(TAGL)
     ciphertext1, ciphertext1_val = core_utils.make_octet(len(plaintext))
     _ = aes_key1_val, iv1_val, header1_val, plaintext1_val, tag1_val, ciphertext1_val # Suppress warnings
 
@@ -118,7 +120,7 @@
     iv1, iv1_val = core_utils.make_octet(None, iv)
     header1, header1_val = core_utils.make_octet(None, header)
     ciphertext1, ciphertext1_val = core_utils.make_octet(None, ciphertext)
-    tag1, tag1_val = core_utils.make_octet(AES_KEY)
+    tag1, tag1_val = core_utils.make_octet(TAGL)
     plaintext1, plaintext1_val = core_utils.make_octet(len(ciphertext))
     _ = aes_key1_val, iv1_val, header1_val, plaintext1_val, tag1_val, ciphertext1_val # Suppress warnings
 
diff --git a/python/amcl/core_utils.py b/python/amcl/core_utils.py
index a7125e9..4b09d65 100644
--- a/python/amcl/core_utils.py
+++ b/python/amcl/core_utils.py
@@ -49,6 +49,7 @@
 extern void RAND_seed(csprng *R,int n,char *b);
 extern void RAND_clean(csprng *R);
 extern void OCT_clear(octet *O);
+extern void generateRandom(csprng* RNG, octet* randomValue);
 """)
 
 if (platform.system() == 'Windows'):
@@ -177,3 +178,30 @@
     _libamcl_core.RAND_clean(rng)
 
     return 0
+
+def generate_random(rng, length):
+    """Generate a random string
+
+    Generate a random string
+
+    Args::
+
+        rng: Pointer to cryptographically secure pseudo-random number generator instance
+        length: length of random byte array
+
+    Returns::
+
+        random_value: Random value
+
+    Raises:
+
+    """
+    random_value1, random_value1_val = make_octet(length)
+    _libamcl_core.generateRandom(rng, random_value1)
+
+    random_value = to_str(random_value1)
+
+    # clear memory
+    _libamcl_core.OCT_clear(random_value1)
+
+    return random_value
diff --git a/python/examples/example_aes.py b/python/examples/example_aes.py
index 7f02fdf..1935628 100755
--- a/python/examples/example_aes.py
+++ b/python/examples/example_aes.py
@@ -24,29 +24,83 @@
 
 sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
 
-from amcl import core_utils, aes
+import amcl.core_utils
+import amcl.aes
 
-key_hex    = "2768a4f5a75344fee0ed46faaf7b020111fe5f0e80a88c0fd27abfcc15bc9d68"
-header_hex = "1554a69ecbf04e507eb6985a234613246206c85f8af73e61ab6e2382a26f457d"
-iv_hex     = "2b213af6b0edf6972bf996fb"
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
 if __name__ == "__main__":
-    key    = bytes.fromhex(key_hex)
-    header = bytes.fromhex(header_hex)
-    iv     = bytes.fromhex(iv_hex)
-    
-    plaintext = b'test message'
-    print(f"Encrypt message '{plaintext.decode('utf-8')}'")
-    print(f'\th  = {header.hex()}')
-    print(f'\tiv = {iv.hex()}')
-    
-    ciphertext, tag = aes.gcm_encrypt(key, iv, header, plaintext)
-    print("\nEncrypted message")
-    print(f'ct  = {ciphertext.hex()}')
-    print(f'tag = {tag.hex()}')
 
-    print("\nDecrypt message")
-    dec_plaintext, dec_tag = aes.gcm_decrypt(key, iv, header, ciphertext)
-    assert tag == dec_tag, '\tInconsistent decryption tag'
+    # CSPRNG
+    seed    = bytes.fromhex(seed_hex)    
+    # seed = os.urandom(16)
+    rng = amcl.core_utils.create_csprng(seed)
+    iv = amcl.core_utils.generate_random(rng, amcl.aes.IVL)
+    key = amcl.core_utils.generate_random(rng, amcl.aes.KEYL)
+    aad = b"hello world"
+    plaintext1 = b'test message'
+
+    print("Encrypt message")    
+    print(f"\tplaintext: {plaintext1.decode('utf-8')}")    
+    print(f"\tiv: {iv.hex()}")
+    print(f"\tkey: {key.hex()}")
+    print(f"\taad: {aad.hex()}")        
+
+    ciphertext, tag1 = amcl.aes.gcm_encrypt(key, iv, aad, plaintext1)
+
+    print("\nEncrypted message")    
+    print(f"\tciphertext: {ciphertext.hex()}")
+    print(f"\ttag: {tag1.hex()}")
+
+    plaintext2, tag2 = amcl.aes.gcm_decrypt(key, iv, aad, ciphertext)
+    assert tag1 == tag2, 'tags are not equal!'
+    assert plaintext1 == plaintext2, 'Plaintext are not equal!'
+
+    print("\nDecrypted message")    
+    print(f"\tplaintext: {plaintext2.decode('utf-8')}")    
+    print(f"\ttag: {tag2.hex()}")
+
+    # Create ciphertext error
+    ciphertext_hex = ciphertext.hex()
+    new = list(ciphertext_hex)
+    new[0] = "a" if (new[0] != "a") else "b"
+    ciphertext_bad_hex = ''.join(new)
+    ciphertext_bad = bytes.fromhex(ciphertext_bad_hex)    
     
-    print(f"\tgot '{dec_plaintext.decode('utf-8')}'")
+    plaintext3, tag3 = amcl.aes.gcm_decrypt(key, iv, aad, ciphertext_bad)
+    assert tag1 != tag3, 'tags are equal!'
+    assert plaintext1 != plaintext3, 'Plaintext not equal!'
+
+    # Create aad error
+    aad_hex = aad.hex()
+    new = list(aad_hex)
+    new[0] = "a" if (new[0] != "a") else "b"
+    aad_bad_hex = ''.join(new)
+    aad_bad = bytes.fromhex(aad_bad_hex)    
+    
+    plaintext4, tag4 = amcl.aes.gcm_decrypt(key, iv, aad_bad, ciphertext)
+    assert tag1 != tag4, 'tags are equal!'
+    assert plaintext1 == plaintext4, 'Plaintext are not equal!'
+
+    # Create iv error
+    iv_hex = iv.hex()
+    new = list(iv_hex)
+    new[0] = "a" if (new[0] != "a") else "b"
+    iv_bad_hex = ''.join(new)
+    iv_bad = bytes.fromhex(iv_bad_hex)    
+    
+    plaintext5, tag5 = amcl.aes.gcm_decrypt(key, iv_bad, aad, ciphertext)
+    assert tag1 != tag5, 'tags are equal!'
+    assert plaintext1 != plaintext5, 'Plaintext are equal!'
+
+    # Create key error
+    key_hex = key.hex()
+    new = list(key_hex)
+    new[0] = "a" if (new[0] != "a") else "b"
+    key_bad_hex = ''.join(new)
+    key_bad = bytes.fromhex(key_bad_hex)    
+    
+    plaintext6, tag6 = amcl.aes.gcm_decrypt(key_bad, iv, aad, ciphertext)
+    assert tag1 != tag6, 'tags are equal!'
+    assert plaintext1 != plaintext6, 'Plaintext are equal!'
+