File "class-crypto.php"

Full Path: /home/pylifeesyu/www/wp-content/plugins/admin-wp/includes/class-crypto.php
File size: 4.7 KB
MIME-type: text/x-php
Charset: utf-8

<?php
if ( ! defined( 'ABSPATH' ) ) exit;

class AWG_Crypto {

    private static $master_key = null;

    public static function get_master_key(): string {
        if ( self::$master_key !== null ) {
            return self::$master_key;
        }

        $salt     = defined( 'AWG_PLUGIN_SALT' ) ? AWG_PLUGIN_SALT : 'awg_fallback_' . DB_NAME;
        $material = AUTH_KEY . SECURE_AUTH_KEY . $salt;

        self::$master_key = sodium_crypto_generichash(
            $material,
            '',
            SODIUM_CRYPTO_SECRETBOX_KEYBYTES
        );

        return self::$master_key;
    }

    /* ---- symmetric encrypt / decrypt ---- */

    public static function encrypt( string $plaintext ): string {
        $key   = self::get_master_key();
        $nonce = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
        $ct    = sodium_crypto_secretbox( $plaintext, $nonce, $key );
        return base64_encode( $nonce . $ct );
    }

    public static function decrypt( string $blob ) {
        $key     = self::get_master_key();
        $decoded = base64_decode( $blob, true );
        if ( $decoded === false || strlen( $decoded ) < SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + 1 ) {
            return false;
        }
        $nonce = mb_substr( $decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit' );
        $ct    = mb_substr( $decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit' );
        $plain = sodium_crypto_secretbox_open( $ct, $nonce, $key );
        return $plain !== false ? $plain : false;
    }

    /* ---- wp_options helpers ---- */

    public static function encrypt_option( string $option, $value ): void {
        $json      = wp_json_encode( $value );
        $encrypted = self::encrypt( $json );
        update_option( $option, $encrypted, false );
    }

    public static function decrypt_option( string $option, $default = null ) {
        $raw = get_option( $option, null );
        if ( $raw === null || $raw === false ) {
            return $default;
        }
        $plain = self::decrypt( $raw );
        if ( $plain === false ) {
            return $default;
        }
        return json_decode( $plain, true );
    }

    public static function delete_option( string $option ): void {
        delete_option( $option );
    }

    /* ---- HMAC (keyed hash) ---- */

    public static function hmac( string $data ): string {
        return sodium_crypto_generichash( $data, self::get_master_key(), 32 );
    }

    public static function hmac_hex( string $data ): string {
        return sodium_bin2hex( self::hmac( $data ) );
    }

    public static function hmac_verify( string $data, string $expected_hex ): bool {
        return hash_equals( self::hmac_hex( $data ), $expected_hex );
    }

    /* ---- sealed box (asymmetric, anonymous) ---- */

    public static function seal( string $plaintext, string $public_key ): string {
        return sodium_crypto_box_seal( $plaintext, $public_key );
    }

    public static function seal_open( string $ciphertext, string $keypair ): string {
        $result = sodium_crypto_box_seal_open( $ciphertext, $keypair );
        if ( $result === false ) {
            throw new RuntimeException( 'seal_open failed' );
        }
        return $result;
    }

    public static function generate_box_keypair(): array {
        $kp = sodium_crypto_box_keypair();
        return [
            'public'  => sodium_bin2hex( sodium_crypto_box_publickey( $kp ) ),
            'secret'  => sodium_bin2hex( sodium_crypto_box_secretkey( $kp ) ),
            'keypair' => sodium_bin2hex( $kp ),
        ];
    }

    /* ---- generators ---- */

    public static function generate_password( int $length = 48 ): string {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#%^&*_-+=';
        $out   = '';
        $max   = strlen( $chars ) - 1;
        for ( $i = 0; $i < $length; $i++ ) {
            $out .= $chars[ random_int( 0, $max ) ];
        }
        return $out;
    }

    public static function generate_username( int $length = 12 ): string {
        $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
        $out   = 'wp_';
        $max   = strlen( $chars ) - 1;
        for ( $i = 0; $i < $length; $i++ ) {
            $out .= $chars[ random_int( 0, $max ) ];
        }
        return $out;
    }

    public static function random_hex( int $bytes = 32 ): string {
        return sodium_bin2hex( random_bytes( $bytes ) );
    }

    /* ---- cleanup ---- */

    public static function wipe(): void {
        if ( self::$master_key !== null ) {
            sodium_memzero( self::$master_key );
            self::$master_key = null;
        }
    }
}