Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AEGIS Implementation #167

Merged
merged 6 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
matrix:
operating-system: ['ubuntu-latest']
php-versions: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']
# php-versions: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']

steps:
- name: Checkout
Expand Down
98 changes: 94 additions & 4 deletions lib/php72compat.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@
'BASE64_VARIANT_ORIGINAL_NO_PADDING',
'BASE64_VARIANT_URLSAFE',
'BASE64_VARIANT_URLSAFE_NO_PADDING',
'CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_ABYTES',
'CRYPTO_AEAD_AESGIS128L_KEYBYTES',
'CRYPTO_AEAD_AESGIS128L_NSECBYTES',
'CRYPTO_AEAD_AESGIS128L_NPUBBYTES',
'CRYPTO_AEAD_AESGIS128L_ABYTES',
'CRYPTO_AEAD_AESGIS256_KEYBYTES',
'CRYPTO_AEAD_AESGIS256_NSECBYTES',
'CRYPTO_AEAD_AESGIS256_NPUBBYTES',
'CRYPTO_AEAD_AESGIS256_ABYTES',
'CRYPTO_AEAD_AES256GCM_KEYBYTES',
'CRYPTO_AEAD_AES256GCM_NSECBYTES',
'CRYPTO_AEAD_AES256GCM_NPUBBYTES',
'CRYPTO_AEAD_AES256GCM_ABYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_ABYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES',
Expand Down Expand Up @@ -176,6 +184,88 @@ function sodium_compare($string1, $string2)
return ParagonIE_Sodium_Compat::compare($string1, $string2);
}
}
if (!is_callable('sodium_crypto_aead_aegis128l_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
*/
function sodium_crypto_aead_aegis128l_decrypt($ciphertext, $additional_data, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis128l_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aegis128l_encrypt($message, $additional_data, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis256_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
*/
function sodium_crypto_aead_aegis256_decrypt($ciphertext, $additional_data, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis256_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aegis256_encrypt($message, $additional_data, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aes256gcm_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt()
Expand Down
220 changes: 220 additions & 0 deletions src/Compat.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ class ParagonIE_Sodium_Compat
const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
const CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
const CRYPTO_AEAD_AES256GCM_ABYTES = 16;
const CRYPTO_AEAD_AEGIS128L_KEYBYTES = 16;
const CRYPTO_AEAD_AEGIS128L_NSECBYTES = 0;
const CRYPTO_AEAD_AEGIS128L_NPUBBYTES = 16;
const CRYPTO_AEAD_AEGIS128L_ABYTES = 32;
const CRYPTO_AEAD_AEGIS256_KEYBYTES = 32;
const CRYPTO_AEAD_AEGIS256_NSECBYTES = 0;
const CRYPTO_AEAD_AEGIS256_NPUBBYTES = 32;
const CRYPTO_AEAD_AEGIS256_ABYTES = 32;
const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
Expand Down Expand Up @@ -299,6 +307,218 @@ public static function compare($left, $right)
return ParagonIE_Sodium_Core_Util::compare($left, $right);
}

/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* AEGIS-128L
*
* @param string $ciphertext Encrypted message (with MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aegis128l_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);

/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS_128L_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
$ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext);
if ($ct_length < self::CRYPTO_AEAD_AEGIS128L_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS128L_ABYTES long');
}

$ct = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
$ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES
);
$tag = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
$ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES,
self::CRYPTO_AEAD_AEGIS128L_ABYTES
);
return ParagonIE_Sodium_Core_AEGIS128L::decrypt($ct, $tag, $assocData, $key, $nonce);
}

/**
* Authenticated Encryption with Associated Data: Encryption
*
* Algorithm:
* AEGIS-128L
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with 32-byte authentication tag appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_aegis128l_encrypt(
$plaintext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);

/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}

list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS128L::encrypt($plaintext, $assocData, $key, $nonce);
return $ct . $tag;
}

/**
* Return a secure random key for use with the AEGIS-128L
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_aegis128l_keygen()
{
return random_bytes(self::CRYPTO_AEAD_AEGIS128L_KEYBYTES);
}

/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* AEGIS-256
*
* @param string $ciphertext Encrypted message (with MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aegis256_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);

/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS256_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS256_KEYBYTES long');
}
$ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext);
if ($ct_length < self::CRYPTO_AEAD_AEGIS256_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS256_ABYTES long');
}

$ct = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
$ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES
);
$tag = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
$ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES,
self::CRYPTO_AEAD_AEGIS256_ABYTES
);
return ParagonIE_Sodium_Core_AEGIS256::decrypt($ct, $tag, $assocData, $key, $nonce);
}

/**
* Authenticated Encryption with Associated Data: Encryption
*
* Algorithm:
* AEGIS-256
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with 32-byte authentication tag appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_aegis256_encrypt(
$plaintext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);

/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}

list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS256::encrypt($plaintext, $assocData, $key, $nonce);
return $ct . $tag;
}

/**
* Return a secure random key for use with the AEGIS-256
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_aegis256_keygen()
{
return random_bytes(self::CRYPTO_AEAD_AEGIS256_KEYBYTES);
}

/**
* Is AES-256-GCM even available to use?
*
Expand Down
Loading
Loading