$enc_key, 'mac' => $mac_key, ); } /** * Encrypt a plain text string using AES-256-CBC + Encrypt-then-MAC (HMAC-SHA256). */ public static function encrypt( $plaintext ) { if ( ! is_string( $plaintext ) || $plaintext === '' ) { return ''; } if ( strpos( $plaintext, 'AIOENCV2:' ) === 0 ) { return $plaintext; } // Upgrade legacy v1 ciphertext seamlessly if passed into encrypt() if ( strpos( $plaintext, 'AIOENC:' ) === 0 ) { $decrypted = self::decrypt( $plaintext ); if ( $decrypted === '' ) { return $plaintext; } $plaintext = $decrypted; } if ( ! function_exists( 'openssl_encrypt' ) ) { return $plaintext; } $method = 'aes-256-cbc'; $keys = self::get_v2_keys(); $ivlen = openssl_cipher_iv_length( $method ); $iv = random_bytes( $ivlen ); $ciphertext = openssl_encrypt( $plaintext, $method, $keys['enc'], OPENSSL_RAW_DATA, $iv ); if ( $ciphertext === false ) { return ''; } $hmac = hash_hmac( 'sha256', $iv . $ciphertext, $keys['mac'], true ); $encrypted = base64_encode( $iv . $hmac . $ciphertext ); return 'AIOENCV2:' . $encrypted; } /** * Decrypt a cipher text string (supports v2 'AIOENCV2:', v1 'AIOENC:', and legacy plaintext). */ public static function decrypt( $encrypted_text ) { if ( ! is_string( $encrypted_text ) || $encrypted_text === '' ) { return ''; } if ( ! function_exists( 'openssl_decrypt' ) ) { return $encrypted_text; } $method = 'aes-256-cbc'; $ivlen = openssl_cipher_iv_length( $method ); // v2 format: separate derived AES & HMAC keys covering IV + Ciphertext if ( strpos( $encrypted_text, 'AIOENCV2:' ) === 0 ) { $raw = base64_decode( substr( $encrypted_text, 9 ), true ); if ( $raw === false || strlen( $raw ) <= $ivlen + 32 ) { return ''; } $iv = substr( $raw, 0, $ivlen ); $hmac = substr( $raw, $ivlen, 32 ); $ciphertext_raw = substr( $raw, $ivlen + 32 ); $keys = self::get_v2_keys(); $calcmac = hash_hmac( 'sha256', $iv . $ciphertext_raw, $keys['mac'], true ); if ( hash_equals( $hmac, $calcmac ) ) { $plain = openssl_decrypt( $ciphertext_raw, $method, $keys['enc'], OPENSSL_RAW_DATA, $iv ); return $plain !== false ? $plain : ''; } return ''; } // Legacy v1 format: 'AIOENC:' if ( strpos( $encrypted_text, 'AIOENC:' ) === 0 ) { $raw = base64_decode( substr( $encrypted_text, 7 ), true ); if ( $raw === false || strlen( $raw ) <= $ivlen + 32 ) { return ''; } $iv = substr( $raw, 0, $ivlen ); $hmac = substr( $raw, $ivlen, 32 ); $ciphertext_raw = substr( $raw, $ivlen + 32 ); $key = substr( hash( 'sha256', self::get_legacy_key(), true ), 0, 32 ); $calcmac = hash_hmac( 'sha256', $ciphertext_raw, $key, true ); if ( hash_equals( $hmac, $calcmac ) ) { $plain = openssl_decrypt( $ciphertext_raw, $method, $key, OPENSSL_RAW_DATA, $iv ); return $plain !== false ? $plain : ''; } return ''; } // Plaintext from older versions prior to encryption return $encrypted_text; } }