using GLib;


class Crypt : GLib.Object {
  private uchar[] key_data = (uchar[])"supercalifragilisticexpialidocious123456789012345678890!".to_utf8();
  private uchar[] key = new uchar[32];
  private uchar[] iv  = new uchar[32];

  private int[] salt = { 12345, 54321 };

  private OpenSSL.EVP.CIPHER cipher = OpenSSL.EVP.aes_256_cbc();
  private OpenSSL.EVP.MD     md     = OpenSSL.EVP.sha1();

  public string encrypt(string password) {
    uchar* plaintext = password;
    int plaintext_length = password.length + 1;

    int ciphertext_length = password.length + OpenSSL.AES.BLOCK_SIZE + 1;
    uchar* ciphertext = new uchar[ciphertext_length];

    int final_length = 0;

    OpenSSL.EVP.bytes_to_key(cipher, md, salt, key_data, 5, key, iv);

    var evp = OpenSSL.EVP.init();
    evp.encrypt_init(cipher,null,key,iv);

    int i = 0;

    i = evp.encrypt_update(ciphertext, out ciphertext_length, plaintext, plaintext_length);
    i = evp.encrypt_final(ciphertext + ciphertext_length, out final_length);

    evp.cleanup();

    return Base64.encode( (uchar[])((string)ciphertext).to_utf8() );
  }

  public string decrypt(string text) {
    uchar* ciphertext = Base64.decode(text);
    int ciphertext_length = ((string)ciphertext).length;
    int plaintext_length = ciphertext_length;

    uchar* plaintext = new uchar[plaintext_length];
    int final_length = 0;

    OpenSSL.EVP.bytes_to_key(cipher, md, salt, key_data, 5, key, iv);

    var evp = OpenSSL.EVP.init();
    evp.decrypt_init(cipher,null,key,iv);

    int i = 0;

    i = evp.decrypt_update(plaintext, out plaintext_length, ciphertext, ciphertext_length);
    i = evp.decrypt_final(plaintext + plaintext_length, out final_length);

    evp.cleanup();

    return (string)plaintext;
  }
}

public static int main() {
  var crypt = new Crypt();

  var original = "This is a test";
  message("Original: %s", original);

  var encrypted= crypt.encrypt(original);
  message("Encyrpted/Encoded: %s", encrypted);

  var decrypted= crypt.decrypt(encrypted);
  message("Decyrpted/Decoded: %s", decrypted);


  return 0;
}
