package edu.vtc.cis3720;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class EncryptDecrypt
{
    private static void printByteArray(byte[] array)
    {
        for (byte value: array) {
            System.out.printf("%02X ", value);
        }
        System.out.println();
    }


    private static void doEncryptDecrypt()
            throws java.security.NoSuchAlgorithmException,
                   java.security.InvalidKeyException,
                   javax.crypto.BadPaddingException,
                   javax.crypto.IllegalBlockSizeException,
                   javax.crypto.NoSuchPaddingException,
                   javax.crypto.ShortBufferException
    {
        // The message to encrypt.
        System.out.println("Original message:");
        String message = "Call me Ishmael. Some years ago ";  // Exactly two blocks.
        byte[] rawMessage = message.getBytes(StandardCharsets.US_ASCII);
        System.out.println(message);
        printByteArray(rawMessage);

        // First let's generate a secret key for use with AES.
        //KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        //keyGenerator.init(128);
        //SecretKey key = keyGenerator.generateKey();

        SecretKey key =
                new SecretKeySpec("0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII), "AES");

        // Now create an object that can be used for encryption.
        Cipher encrypt = Cipher.getInstance("AES/ECB/NoPadding");
        encrypt.init(Cipher.ENCRYPT_MODE, key);
        System.out.println(
                "Requires output buffer of size: " + encrypt.getOutputSize(rawMessage.length) + " bytes");
        byte[] encryptedRawMessage = new byte[encrypt.getOutputSize(rawMessage.length)];

        // Do the deed.
        int offset = 0;
        while (offset < rawMessage.length) {
            if (offset < rawMessage.length - 16) {
                encrypt.update(rawMessage, offset, 16, encryptedRawMessage, offset);
            }
            else {
                encrypt.doFinal(rawMessage, offset, 16, encryptedRawMessage, offset);
            }
            offset += 16;
        }

        // Output the result.
        System.out.println("\nAfter encryption:");
        String encrypted = Base64.getEncoder().encodeToString(encryptedRawMessage);
        printByteArray(encryptedRawMessage);
        System.out.println("base64 encoded: " + encrypted);

        // Now create an object that can be used for decryption.
        Cipher decrypt = Cipher.getInstance("AES/ECB/NoPadding");
        decrypt.init(Cipher.DECRYPT_MODE, key);

        // Do the deed.
        offset = 0;
        while (offset < rawMessage.length) {
            if (offset < rawMessage.length - 16) {
                decrypt.update(encryptedRawMessage, offset, 16, rawMessage, offset);
            }
            else {
                decrypt.doFinal(encryptedRawMessage, offset, 16, rawMessage, offset);
            }
            offset += 16;
        }

        // Output the result.
        System.out.println("\nAfter decryption:");
        printByteArray(rawMessage);
        String decrypted = new String(rawMessage, StandardCharsets.US_ASCII);
        System.out.println(decrypted);
    }


    public static void main(String[] args)
            throws java.security.NoSuchAlgorithmException,
                   java.security.InvalidKeyException,
                   javax.crypto.BadPaddingException,
                   javax.crypto.IllegalBlockSizeException,
                   javax.crypto.NoSuchPaddingException,
                   javax.crypto.ShortBufferException
    {
        doEncryptDecrypt();
    }

}
