Clase en PHP para cifrado y descifrado seguro utilizando XChaCha20-Poly1305 (AEAD) y Argon2 para la derivación de claves basadas en contraseñas. Esta clase está diseñada para ser simple, segura y fácil de usar.

Podés encontrar el código completo y la documentación en mi repositorio de GitHub:

https://github.com/kaisarcode/php-crypto

Código

<?php
namespace KaisarCode\Crypto;

class Crypto {

    private static $KEY_SIZE = SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES;
    private static $SALT_SIZE = SODIUM_CRYPTO_PWHASH_SALTBYTES;
    private static $NONCE_SIZE = SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES;
    private static $OPS_LIMIT = SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE;
    private static $MEM_LIMIT = SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE;

    
    public static function encrypt(string $str, string $pwd, string $additionalData = ''): string|false {

        if (empty($str) || empty($pwd)) {
            return false;
        }

        try {

            // Generate random salt and nonce
            $salt = random_bytes(self::$SALT_SIZE);
            $nonce = random_bytes(self::$NONCE_SIZE);

            // Derive key from password
            $key = sodium_crypto_pwhash(
                self::$KEY_SIZE,
                $pwd,
                $salt,
                self::$OPS_LIMIT,
                self::$MEM_LIMIT
            );

            // Encrypt the message
            $ciphertext = sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
                $str,
                $additionalData,
                $nonce,
                $key
            );

            // Clear key from memory
            sodium_memzero($key);

            // Return hex-encoded result
            return bin2hex($salt . $nonce . $ciphertext);

        } catch (SodiumException | Exception $e) {
            return false;
        }
    }

    
    public static function decrypt(string $str, string $pwd, string $additionalData = ''): string|false {

        if (empty($str) || empty($pwd)) {
            return false;
        }

        try {

            // Decode hex to binary
            $decoded = hex2bin($str);

            // Validate minimum length
            if ($decoded === false || strlen($decoded) < self::$SALT_SIZE + self::$NONCE_SIZE + 1) {
                return false;
            }

            // Extract salt, nonce, and ciphertext
            $salt = substr($decoded, 0, self::$SALT_SIZE);
            $nonce = substr($decoded, self::$SALT_SIZE, self::$NONCE_SIZE);
            $ciphertext = substr($decoded, self::$SALT_SIZE + self::$NONCE_SIZE);

            // Return false if extraction fails
            if (empty($salt) || empty($nonce) || empty($ciphertext)) {
                return false;
            }

            // Derive key from password
            $key = sodium_crypto_pwhash(
                self::$KEY_SIZE,
                $pwd,
                $salt,
                self::$OPS_LIMIT,
                self::$MEM_LIMIT
            );

            // Decrypt the message
            $plaintext = sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
                $ciphertext,
                $additionalData,
                $nonce,
                $key
            );

            // Clear key from memory
            sodium_memzero($key);

            // Return plaintext or false on failure
            return $plaintext !== false ? $plaintext : false;

        } catch (SodiumException | Exception $e) {
            return false;
        }
    }
}

Requisitos

Implementación

require 'Crypto.php';

use KaisarCode\Crypto\Crypto;

$plaintext = "This is a secret message.";
$password = "supersecurepassword123";
$additionalData = "contextual-data"; // Optional

// Encrypt
$encrypted = Crypto::encrypt($plaintext, $password, $additionalData);
if ($encrypted === false) {
    die("Encryption failed.");
}
echo "Encrypted (Hex): " . $encrypted . "\n";

// Decrypt
$decrypted = Crypto::decrypt($encrypted, $password, $additionalData);
if ($decrypted === false) {
    die("Decryption failed.");
}
echo "Decrypted: " . $decrypted . "\n";

Output

Encrypted (Hex): 87878aa271530149db28b2677758e6407ec52272b0c8a438c5b0daa1cbae672111d4bd709bb41542f846030ce2101dd0cf14aa26f6acc1ab996ab0c606e8f72fec35f82305d2eaeda274c8e5d706f0ee74
Decrypted: This is a secret message.

Características

  • Cifrado seguro: Usa el algoritmo XChaCha20-Poly1305 para cifrado autenticado.
  • Derivación de clave basada en contraseña: Usa Argon2 (a través de sodium_crypto_pwhash) para derivar claves a partir de contraseñas.
  • Generación automática de salt y nonce: El salt y el nonce se generan internamente y se anteponen al texto cifrado.
  • Codificación en hexadecimal: Los datos cifrados y descifrados están codificados en hexadecimal para facilitar su almacenamiento y transmisión.
  • Seguridad en memoria: Los datos sensibles (por ejemplo, claves) se eliminan de la memoria después de su uso con sodium_memzero.

Licencia

Licenciado bajo la Licencia MIT.


Tags: DesarrolloWeb Programación Criptografía PHP SeguridadInformática Cifrado XChaCha20 Argon2 CódigoSeguro MásConMenos EficienciaDigital


Invitame un café en cafecito.app