public function decrypt(string $encrypted, string $key = null): string
    {
        $key     = $key ?? $this->getKey();
        $decoded = base64_decode($encrypted, true);

        if ($decoded === false) {
            throw new CryptException('The encoding failed');
        }

        if (mb_strlen($decoded, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
            throw new CryptException('The message was truncated');
        }

        $nonce      = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
        $cipherText = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');

        $plain = sodium_crypto_secretbox_open(
            $cipherText,
            $nonce,
            $key
        );

        if ($plain === false) {
            throw new CryptException('The message was tampered with in transit');
        }

        sodium_memzero($cipherText);
        sodium_memzero($key);

        return $plain;
    }