diff options
Diffstat (limited to 'classes/Crypt.php')
| -rw-r--r-- | classes/Crypt.php | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/classes/Crypt.php b/classes/Crypt.php new file mode 100644 index 000000000..d832e6530 --- /dev/null +++ b/classes/Crypt.php @@ -0,0 +1,62 @@ +<?php +class Crypt { + + /** the only algo supported at the moment */ + private const ENCRYPT_ALGO = 'xchacha20poly1305_ietf'; + + /** currently only generates keys using sodium_crypto_aead_chacha20poly1305_keygen() i.e. one supported Crypt::ENCRYPT_ALGO + * @return string random 256-bit (for ChaCha20-Poly1305) binary string + */ + static function generate_key() : string { + return sodium_crypto_aead_chacha20poly1305_keygen(); + } + + /** encrypts provided ciphertext using Config::ENCRYPTION_KEY into an encrypted object + * + * @return array{'algo': string, 'nonce': string, 'payload': string} encrypted data object containing algo, nonce, and encrypted data + */ + static function encrypt_string(string $ciphertext) : array { + $key = Config::get(Config::ENCRYPTION_KEY); + + if (!$key) + throw new Exception("Crypt::encrypt_string() failed to encrypt - key is not available"); + + $nonce = \random_bytes(\SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES); + + $payload = sodium_crypto_aead_xchacha20poly1305_ietf_encrypt($ciphertext, '', $nonce, hex2bin($key)); + + if ($payload) { + $encrypted_data = [ + 'algo' => self::ENCRYPT_ALGO, + 'nonce' => $nonce, + 'payload' => $payload, + ]; + + return $encrypted_data; + } + + throw new Exception("Crypt::encrypt_string() failed to encrypt ciphertext"); + } + + /** decrypts payload of a valid encrypted object using Config::ENCRYPTION_KEY + * + * @param array{'algo': string, 'nonce': string, 'payload': string} $encrypted_data + * + * @return string decrypted string payload + */ + static function decrypt_string(array $encrypted_data) : string { + $key = Config::get(Config::ENCRYPTION_KEY); + + if (!$key) + throw new Exception("Crypt::decrypt_string() failed to decrypt - key is not available"); + + // only one is supported for the time being + switch ($encrypted_data['algo']) { + case self::ENCRYPT_ALGO: + return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt($encrypted_data['payload'], '', $encrypted_data['nonce'], hex2bin($key)); + } + + throw new Exception('Crypt::decrypt_string() failed to decrypt passed encrypted data object, unsupported algo: ' . $encrypted_data['algo']); + } + +}
\ No newline at end of file |