// Simple examples for net.deweger.crypto
// version 1.0, March 18, 2021
// Copyright: Benne de Weger, TU/e

import net.deweger.crypto.*;
import java.nio.file.*;

public class CryptoExample
{
    // variables
    static byte[] key;
    static byte[] iv;
    static byte[] plaintext;
    static byte[] ciphertext;
    static byte[] decryptedtext;

    // read data from a file to a byte array
    private static byte[] readFile(String fileName) throws Exception
    {
        byte[] data = Files.readAllBytes(Paths.get(fileName));
        System.out.println("file " + fileName + " read (" + data.length + " bytes)");
        return data;
    }

    // write data to a file from a byte array
    private static void writeFile(String fileName, byte[] data) throws Exception
    {
        Files.write(Paths.get(fileName), data);
        System.out.println("file " + fileName + " written (" + data.length + " bytes)");
    }

    // basic encryption of a file
    private static void AESexampleEncrypt(String fileName) throws Exception
    {
        AES aes = new AES();
        // generate a random AES key and iv
        key = aes.generateKey();
        iv = aes.generateIv();
        // set mode and padding
        aes.setMode(AES.MODE_CTR);
        aes.setPadding(AES.PAD_PKCS7);
        // print key and iv in hex
        System.out.println("AES key: " + Util.bytesToHex(key));
        System.out.println("AES IV:  " + Util.bytesToHex(iv));
        // read file
        plaintext = readFile(fileName);
        // encrypt
        ciphertext = aes.encrypt(plaintext);
        // write ciphertext to filename.enc
        writeFile(fileName + ".enc", ciphertext);
    }

    // basic decryption of a file
    private static void AESexampleDecrypt(String fileName) throws Exception
    {
        AES aes = new AES();
        // set AES key and iv
        aes.setKey(key);
        aes.setIv(iv);
        // set mode and padding
        aes.setMode(AES.MODE_CTR);
        aes.setPadding(AES.PAD_PKCS7);
        // read file
        ciphertext = readFile(fileName);
        // decrypt
        decryptedtext = aes.decrypt(ciphertext);
        // write decryptedtext to filename.dec
        writeFile(fileName + ".dec", decryptedtext);
    }

    // basic hashing of a file
    private static void SHA256example(String fileName) throws Exception
    {
        SHA256 sha256 = new SHA256();
        // read file
        byte[] data = readFile(fileName);
        // compute hash
        byte[] hash = sha256.hash(data);
        // print result
        System.out.println("SHA256(" + fileName + "):\n    " + Util.bytesToHex(hash));
        // and now with splitting up data, say 10 bytes at a time
        byte[] datapart = new byte[10];
        int len = data.length;
        sha256.hashInit();
        while (len >= 10)
        {
            System.arraycopy(data, data.length - len, datapart, 0, 10);
            sha256.hashUpdate(datapart);
            System.out.println("processed bytes " + (data.length - len) + " to " + (data.length - len + 9));
            len -= 10;
        }
        if (len > 0)
        {
            datapart = new byte[len];
            System.arraycopy(data, data.length - len, datapart, 0, len);
            sha256.hashUpdate(datapart);
            System.out.println("processed bytes " + (data.length - len) + " to " + (data.length - 1));
        }
        hash = sha256.hashFinal();
        System.out.println("SHA256(" + fileName + "):\n    " + Util.bytesToHex(hash));
    }

    public static void main(String[] args)
    {
        try
        {
            // encrypt example.txt to example.txt.enc
            AESexampleEncrypt("example.txt");
            // decrypt example.txt.enc to example.txt.enc.dec
            AESexampleDecrypt("example.txt.enc");
            // hashes of the three files
            SHA256example("example.txt");
            SHA256example("example.txt.enc");
            SHA256example("example.txt.enc.dec");
            // first and third hash should be identical
        }
        catch (Exception exc)
        {
            System.out.println("ERROR: " + exc.getMessage());
        }
    }
}
