get_key(); $iv = random_bytes( 12 ); // 96-bit nonce for AES-GCM. $tag = ''; if ( function_exists( 'openssl_encrypt' ) ) { $ciphertext = openssl_encrypt( $plaintext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag ); if ( false !== $ciphertext && '' !== (string) $tag ) { $payload = array( 'v' => 1, 'alg' => 'aes-256-gcm', 'iv' => base64_encode( $iv ), 'tag' => base64_encode( $tag ), 'ct' => base64_encode( $ciphertext ), ); return base64_encode( wp_json_encode( $payload ) ); } } // Last-resort fallback (should not happen on modern WP hosting). // Keep backward compatibility with old storage format by returning base64 of plaintext. return base64_encode( $plaintext ); } /** * Decrypt an encrypted payload. * * @param string $ciphertext Ciphertext (base64). * @return string Plaintext. */ public function decrypt( $ciphertext ) { $decoded = base64_decode( (string) $ciphertext, true ); if ( false === $decoded || '' === $decoded ) { return ''; } // New format: base64( json({v,alg,iv,tag,ct}) ) $maybe = json_decode( $decoded, true ); if ( is_array( $maybe ) && isset( $maybe['alg'], $maybe['iv'], $maybe['tag'], $maybe['ct'] ) && 'aes-256-gcm' === $maybe['alg'] ) { $iv = base64_decode( (string) $maybe['iv'], true ); $tag = base64_decode( (string) $maybe['tag'], true ); $ct = base64_decode( (string) $maybe['ct'], true ); if ( false === $iv || false === $tag || false === $ct ) { return ''; } if ( function_exists( 'openssl_decrypt' ) ) { $pt = openssl_decrypt( $ct, 'aes-256-gcm', $this->get_key(), OPENSSL_RAW_DATA, $iv, $tag ); return false === $pt ? '' : (string) $pt; } return ''; } // Backward-compatible fallback: base64(plaintext). return $decoded; } /** * Derive encryption key from AUTH_SALT. * * @return string 32-byte key. */ private function get_key() { $salt = defined( 'AUTH_SALT' ) ? (string) AUTH_SALT : ''; return hash( 'sha256', $salt, true ); } }