<?php
declare(strict_types=1);
namespace ParagonIE\Discretion;
use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\Discretion\Data\HiddenString;
/**
* Class SimpleCrypto
*
* This class just encrypts data using XChaCha20-Poly1305, provided by libsodium.
* By default, we opt for Base64url encoding on our ciphertext messages.
*
* Requires: ext/mbstring, paragonie/sodium_compat
* Recommended: ext/sodium 2.0.7+, libsodium 1.0.15+
*
* @package ParagonIE\Discretion
*/
class SimpleCrypto
{
const MIN_CIPHERTEXT_LENGTH = 40;
/**
* Decrypt a message with XChaCha20-Poly1305.
*
* @param string $ciphertext
* @param HiddenString $key
* @return HiddenString
* @throws \Exception
* @throws \InvalidArgumentException
*/
public static function decrypt(string $ciphertext, HiddenString $key): HiddenString
{
/** @var string $realCiphertext */
$realCiphertext = Base64UrlSafe::decode($ciphertext);
if (!\is_string($realCiphertext)) {
throw new \InvalidArgumentException('Invalid encoding');
}
return static::decryptRaw($realCiphertext, $key);
}
/**
* Base64url-encoded encrypted message.
*
* @param HiddenString $message
* @param HiddenString $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
public static function encrypt(HiddenString $message, HiddenString $key): string
{
return Base64UrlSafe::encode(
static::encryptRaw($message, $key)
);
}
/**
* Decrypt a message with XChaCha20-Poly1305.
*
* @param string $ciphertext
* @param HiddenString $key
* @return HiddenString
* @throws \Exception
* @throws \InvalidArgumentException
*/
public static function decryptRaw(string $ciphertext, HiddenString $key): HiddenString
{
if (\mb_strlen($ciphertext, '8bit') < static::MIN_CIPHERTEXT_LENGTH) {
throw new \InvalidArgumentException('Ciphertext is too short.');
}
$nonce = \mb_substr($ciphertext, 0, 24, '8bit');
$message = \mb_substr($ciphertext, 24, null, '8bit');
$plaintext = \ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_decrypt(
$message,
$nonce,
$nonce,
$key->getString()
);
if (!\is_string($plaintext)) {
throw new \Exception('Decryption failed');
}
return new HiddenString($plaintext);
}
/**
* Encrypt a message with XChaCha20-Poly1305.
*
* @param HiddenString $message
* @param HiddenString $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
public static function encryptRaw(HiddenString $message, HiddenString $key): string
{
$nonce = \random_bytes(24);
return $nonce . \ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt(
$message->getString(),
$nonce,
$nonce,
$key->getString()
);
}
}
|