from timer import GenjiTimer
import time

def create_rsa_key( gnjAPI, dngNr):

    print( "    --- Creating a keypair at index 1")

    gtimer=GenjiTimer(gnjAPI, 1234, dngNr)
    gtimer.start()
    ret = gnjAPI.create_rsa_key( 1234,1,dngNr)
    interval=gtimer.stop()

    if ret != 1:
        print( "    Create RSA keypair error")
        return False

    print( "      ---> Successfully created RSA keypair at index 1 Processing time:", interval, " msec")
    time.sleep(2)

    print( "\n    --- Importing a keypair from files to index 2")

    try:
        with open('genji.privkey', 'rb') as file:
            binary_data = file.read()
            
            if 1 != gnjAPI.write_rsa_key(1234, 2, 1, len(binary_data), binary_data, dngNr):
                print("      Failed to import private key from 'genji.privkey' ")
                return False

            print("      --> Successfully imported private key from 'genji.privkey' into key index 2")
            time.sleep(2)

        with open('genji.pubkey', 'rb') as file:
            binary_data = file.read()
            
            if 1 != gnjAPI.write_rsa_key(1234, 2, 0, len(binary_data), binary_data, dngNr):
                print("      Failed to import private key from 'genji.privkey' ")
                return False

            print("      --> Successfully imported public key from 'genji.pubkey' into key index 2")
            time.sleep(2)

    except FileNotFoundError:
        print("\n      xxxxx genji.privkey & genji.pubkey must be in the same folder xxxxx\n")
        return False

    return True


def rsa_external_encrypt_internal_decrypt( gnjAPI, plain_bytes, dngNr):

    print("\n     Encryption by an external public key and decryption by Genji ")
    print("     First, retrieve the public key at index 2")
    time.sleep(2)

    pubkey = bytes(256)
    pubkey_len = [256]

    if 1 != gnjAPI.get_rsa_pubkey( 1234, 2, pubkey, pubkey_len, dngNr):
        print("     Failed to retrieve public key from Genji key index 2")
        return False

    print("\n      --> Successfully retrieved the public key from key index 2")
    time.sleep(2)

    print("     Encyrpting by the retrieve public key")
    cipher = bytes(256)
    cipher_len = [256]

    if 1 != gnjAPI.encrypt_cos_rsa_pubkey( pubkey, pubkey_len[0], plain_bytes, len(plain_bytes), cipher, cipher_len, dngNr):
        print("     Failed to encrypt by the retrieve public key")
        return False

    print("\n      --> Encrypt RSA  by the retrieved public key successful")
    print("     ", cipher[1:cipher_len[0]])
    time.sleep(2)

    print("     Decyrpting by the privat key at index 2")

    # allocate byte array to receive decrypted data into
    # cipher_len must contain the allocation size
    bPlain1 = bytes(256)
    bPlain_len = [256]

    ret = gnjAPI.decrypt_data_rsa( 1234, 2, cipher, cipher_len[0], bPlain1, bPlain_len, dngNr)
    if ret != 1:
        print("     Decrypt RSA error:", ret)
        return False

    print( "\n     Decrypt RSA by Genji private key at index 2 successful:")
    print( "     --->", bPlain1[0:bPlain_len[0]].decode('utf-8'))
    time.sleep(2)


def rsa_encdec_test( gnjAPI, dngNr):

    print( "\n     ***** RSA Encrypt / Decrypt Test *****")

    if create_rsa_key( gnjAPI, dngNr) == False:
        return False

    time.sleep(2)

    try:
        plain = input("\n     Enter text to encrypt: ")
    except KeyboardInterrupt:
        print( "\n\n   Exiting")
        return False

    if len(plain) == 0:
        print("    Skipping RSA Encrypt/Decrypt Test")
        return True

    bPlain=plain.encode('utf-8')

    print("     Encrypting by the public key at index 1")

    # allocate byte array to receive encrypted data into
    # cipher_len must contain the allocation size
    cipher = bytes(256)
    cipher_len = [256]
    
    gtimer=GenjiTimer(gnjAPI, 1234, dngNr)
    gtimer.start()
    ret = gnjAPI.encrypt_data_rsa( 1234, 1, bPlain, len(bPlain), cipher, cipher_len, dngNr)
    interval = gtimer.stop()

    if ret != 1:
        print("     Encrypt RSA error:", ret)
        return False

    print("\n       --> Encrypt RSA successful Processing time:", interval, " msec")
    print("      ", cipher[0:cipher_len[0]])
    time.sleep(2)

    print("     Decrypting by the public key at index 1")

    # allocate byte array to receive decrypted data into
    # cipher_len must contain the allocation size
    bPlain1 = bytes(256)
    bPlain_len = [256]

    gtimer.start()
    ret = gnjAPI.decrypt_data_rsa( 1234, 1, cipher, cipher_len[0], bPlain1, bPlain_len, dngNr)
    interval = gtimer.stop()

    if ret != 1:
        print("     Decrypt RSA error:", ret)
        return False

    print( "\n       --> Decrypt RSA successful  Processing time:", interval, " msec")
    print( "        ", bPlain1[0:bPlain_len[0]].decode('utf-8'))
    time.sleep(2)

    rsa_external_encrypt_internal_decrypt( gnjAPI, bPlain, dngNr)


def rsa_sign_verify_test( gnjAPI, dngNr):

    print( "\n     ***** Sign / Verify Test *****")

    try:
        msg = input("\n     Enter text to sign: ")
    except KeyboardInterrupt:
        print( "\n\n   Exiting")
        return False

    if len(msg) == 0:
        print("\n      Skipping Sign/Verify Test\n")
        return True

    bMsg=msg.encode('utf-8')

    print("     Signing data")
    # allocate byte array to receive signature into
    # sig_len must contain the allocation size
    sig = bytes(256)
    sig_len = [256]
    
    gtimer=GenjiTimer(gnjAPI, 1234, dngNr)
    gtimer.start()
    ret = gnjAPI.sign_data( 1234, 1, bMsg, len(bMsg), sig, sig_len, dngNr)
    interval = gtimer.stop()

    if ret != 1:
        print("     Sign error:", ret)
        return False

    print( "     ---> Successfully signed Processing time:", interval, " msec")
    print( "     ", sig[0:sig_len[0]])
    time.sleep(2)

    print("     Verifying signature")

    gtimer.start()
    ret = gnjAPI.verify_sig( 1234, 1, bMsg, len(bMsg), sig, sig_len[0], dngNr)
    interval = gtimer.stop()

    if ret != 1:
        print("     Verify error:", ret)
        return False

    print( "\n     ---> Verified ok Processing time:", interval, " msec")

    time.sleep(2)

    return True

