<?php

namespace App\Controller;
use Exception;
use SodiumException;

/**
 *
 */
class EncryptionController
{
    /**
     * Encrypt a message
     *
     * @param string $message - message to encrypt
     * @param string $key - encryption key
     * @return string
     */
    function safeEncrypt(string $message, string $key): string
    {
        try {
            $binKey = sodium_hex2bin(string: $key);
            $nonce = random_bytes(length: SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

            $cipher = base64_encode(string: $nonce . sodium_crypto_secretbox(message: $message, nonce: $nonce, key: $binKey));
            sodium_memzero(string: $message);
            sodium_memzero(string: $key);
            sodium_memzero(string: $binKey);
            return $cipher;
        } catch (Exception|SodiumException $e) {
            exit($e->getMessage() . PHP_EOL);
        }
    }

    /**
     * Decrypt a message
     *
     * @param string $encrypted - message encrypted with safeEncrypt()
     * @param string $key - encryption key
     * @return string
     */
    function safeDecrypt(string $encrypted, string $key): string
    {
        try {
            $binKey = sodium_hex2bin(string: $key);

            $decoded = base64_decode(string: $encrypted);
            if ($decoded === false) {
                throw new Exception(message: 'Decoding broken. Wrong payload.');
            }

            if (mb_strlen(string: $decoded, encoding: '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
                throw new Exception(message: 'Decoding broken. Incomplete message.');
            }

            $nonce = mb_substr(string: $decoded, start: 0, length: SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, encoding: '8bit');
            $ciphertext = mb_substr(string: $decoded, start: SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, length: null, encoding: '8bit');

            $plain = sodium_crypto_secretbox_open(ciphertext: $ciphertext, nonce: $nonce, key: $binKey);
            if ($plain === false) {
                throw new Exception(message: ' Incorrect key.');
            }
            sodium_memzero(string: $ciphertext);
            sodium_memzero(string: $key);
            return $plain;
        } catch(Exception|SodiumException $e) {
            exit($e->getMessage());
        }
    }

}