<?php
/** Authenticated encryption for locally persisted license keys. */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/** Derive a site-local encryption key without storing another secret in wp_options. */
function wpagent_companion_license_encryption_key(): string {
	return hash_hkdf( 'sha256', wp_salt( 'auth' ), 32, 'wpagently-license-key-v1' );
}

/** @return string|WP_Error */
function wpagent_companion_license_encrypt_key( string $key ) {
	try {
		$secret = wpagent_companion_license_encryption_key();
		if ( function_exists( 'sodium_crypto_secretbox' ) ) {
			$nonce      = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
			$ciphertext = sodium_crypto_secretbox( $key, $nonce, $secret );
			return 'v1:sodium:' . base64_encode( $nonce . $ciphertext );
		}
		if ( function_exists( 'openssl_encrypt' ) && in_array( 'aes-256-gcm', openssl_get_cipher_methods(), true ) ) {
			$nonce      = random_bytes( 12 );
			$tag        = '';
			$ciphertext = openssl_encrypt( $key, 'aes-256-gcm', $secret, OPENSSL_RAW_DATA, $nonce, $tag, 'wpagently-license-v1', 16 );
			if ( false !== $ciphertext && 16 === strlen( $tag ) ) {
				return 'v1:aes-256-gcm:' . base64_encode( $nonce . $tag . $ciphertext );
			}
		}
	} catch ( Throwable ) {
		// The caller receives a stable, secret-free persistence error below.
	}
	return new WP_Error(
		'wpagent_license_encryption_unavailable',
		__( 'Der Lizenzschlüssel konnte nicht sicher verschlüsselt werden.', 'wp-agent-companion' ),
		array( 'status' => 500 )
	);
}

/** @return string|WP_Error */
function wpagent_companion_license_decrypt_key( string $encoded ) {
	$parts = explode( ':', $encoded, 3 );
	if ( 3 !== count( $parts ) || 'v1' !== $parts[0] ) {
		return new WP_Error( 'wpagent_license_decryption_failed', __( 'Der gespeicherte Lizenzschlüssel ist beschädigt.', 'wp-agent-companion' ) );
	}
	$payload = base64_decode( $parts[2], true );
	if ( false === $payload ) {
		return new WP_Error( 'wpagent_license_decryption_failed', __( 'Der gespeicherte Lizenzschlüssel ist beschädigt.', 'wp-agent-companion' ) );
	}

	try {
		$secret = wpagent_companion_license_encryption_key();
		if ( 'sodium' === $parts[1] && function_exists( 'sodium_crypto_secretbox_open' ) && strlen( $payload ) > SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ) {
			$nonce     = substr( $payload, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
			$plaintext = sodium_crypto_secretbox_open( substr( $payload, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ), $nonce, $secret );
			if ( is_string( $plaintext ) ) {
				return $plaintext;
			}
		}
		if ( 'aes-256-gcm' === $parts[1]
			&& function_exists( 'openssl_decrypt' )
			&& in_array( 'aes-256-gcm', openssl_get_cipher_methods(), true )
			&& strlen( $payload ) > 28 ) {
			$nonce      = substr( $payload, 0, 12 );
			$tag        = substr( $payload, 12, 16 );
			$ciphertext = substr( $payload, 28 );
			$plaintext  = openssl_decrypt( $ciphertext, 'aes-256-gcm', $secret, OPENSSL_RAW_DATA, $nonce, $tag, 'wpagently-license-v1' );
			if ( is_string( $plaintext ) ) {
				return $plaintext;
			}
		}
	} catch ( Throwable ) {
		// Fall through to one stable, secret-free error.
	}
	return new WP_Error( 'wpagent_license_decryption_failed', __( 'Der gespeicherte Lizenzschlüssel ist beschädigt.', 'wp-agent-companion' ) );
}
