get_enc_key() ); $iv = random_bytes( 16 ); $cipher = openssl_encrypt( $plaintext, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv ); return base64_encode( $iv . $cipher ); } /** * Decrypt a blob produced by {@see encrypt()}. * * @param string $blob * @return string Plaintext, or empty string on failure. */ public function decrypt( string $blob ): string { if ( ! function_exists( 'openssl_decrypt' ) ) { return (string) base64_decode( $blob ); } $raw = base64_decode( $blob ); // Need at least 16-byte IV + 1 byte of cipher data. if ( strlen( $raw ) < 17 ) { return ''; } $key = hex2bin( $this->get_enc_key() ); $iv = substr( $raw, 0, 16 ); $cipher = substr( $raw, 16 ); $plain = openssl_decrypt( $cipher, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv ); return $plain !== false ? $plain : ''; } // ----------------------------------------------------------------------- // Private helpers // ----------------------------------------------------------------------- /** * Return (or lazily create) the 256-bit per-site encryption key, * stored as a 64-char hex string in wp_options. */ private function get_enc_key(): string { $key = get_option( self::ENC_KEY_OPTION ); if ( ! $key ) { $key = bin2hex( random_bytes( 32 ) ); // 64-char hex → 256-bit key update_option( self::ENC_KEY_OPTION, $key, false ); } return $key; } }