fengketrade/test_java_compat.php

222 lines
9.5 KiB
PHP
Raw Normal View History

2025-10-22 11:34:32 +08:00
<?php
/**
* 完全按照Java demo实现的测试
* 逐步对照验证PHP实现与Java是否一致
*/
// 定义应用目录
define('APP_PATH', __DIR__ . '/application/');
require __DIR__ . '/thinkphp/base.php';
echo "\n========== 按照Java demo逐步测试 ==========\n\n";
// Java RSAUtil.java 中的密钥加载方法
function getPublicKeyFromBase64($keyStr) {
// Java: byte[] keyBytes = decryptBASE64(keyStr);
// Java: X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
// Java: Key publicKey = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(x509KeySpec);
// PHP等价直接格式化为PEM$keyStr已经是BASE64格式
$pem = "-----BEGIN PUBLIC KEY-----\n";
$pem .= rtrim(chunk_split($keyStr, 64, "\n"), "\n") . "\n"; // 移除chunk_split末尾多余的换行
$pem .= "-----END PUBLIC KEY-----\n";
echo " 生成的公钥PEM(前150字符):\n" . substr($pem, 0, 150) . "...\n";
$key = openssl_pkey_get_public($pem);
if (!$key) {
throw new Exception("公钥加载失败: " . openssl_error_string());
}
return $key;
}
function getPrivateKeyFromBase64($keyStr) {
// Java: byte[] keyBytes = decryptBASE64(keyStr);
// Java: PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
// Java: Key privateKey = KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(pkcs8KeySpec);
// PHP等价直接格式化为PEM (PKCS#8格式)
$pem = "-----BEGIN PRIVATE KEY-----\n";
$pem .= rtrim(chunk_split($keyStr, 64, "\n"), "\n") . "\n"; // 移除chunk_split末尾多余的换行
$pem .= "-----END PRIVATE KEY-----\n";
echo " 生成的私钥PEM(前150字符):\n" . substr($pem, 0, 150) . "...\n";
$key = openssl_pkey_get_private($pem);
if (!$key) {
throw new Exception("私钥加载失败: " . openssl_error_string());
}
return $key;
}
// Java RSAUtil.java 的 encrypt 方法
function rsaEncrypt($dataStr, $publicKeyStr) {
$data = $dataStr;
// 加载公钥
$publicKey = getPublicKeyFromBase64($publicKeyStr);
if (!$publicKey) {
throw new Exception("公钥加载失败: " . openssl_error_string());
}
// 获取密钥大小
$keyDetails = openssl_pkey_get_details($publicKey);
$keySize = $keyDetails['bits'] / 8;
$maxEncryptBlock = 117; // Java中定义的 MAX_ENCRYPT_BLOCK
echo " 密钥大小: {$keyDetails['bits']} bits ($keySize bytes)\n";
echo " 最大加密块: $maxEncryptBlock bytes\n";
echo " 明文长度: " . strlen($data) . " bytes\n";
// 分段加密
$encrypted = '';
$inputLen = strlen($data);
$offset = 0;
$i = 0;
while ($inputLen - $offset > 0) {
if ($inputLen - $offset > $maxEncryptBlock) {
$block = substr($data, $offset, $maxEncryptBlock);
} else {
$block = substr($data, $offset, $inputLen - $offset);
}
$encryptedBlock = '';
// Java: cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK)
// PHP等价: openssl_public_encrypt with PKCS1 padding
$success = openssl_public_encrypt($block, $encryptedBlock, $publicKey, OPENSSL_PKCS1_PADDING);
if (!$success) {
throw new Exception("{$i}段加密失败: " . openssl_error_string());
}
$encrypted .= $encryptedBlock;
$i++;
$offset = $i * $maxEncryptBlock;
echo " 加密第{$i}段: " . strlen($block) . " bytes -> " . strlen($encryptedBlock) . " bytes\n";
}
openssl_free_key($publicKey);
// Java: encodedDataStr = new String(encryptBASE64(encryptedData));
$base64Result = base64_encode($encrypted);
echo " 总密文长度: " . strlen($encrypted) . " bytes\n";
echo " BASE64长度: " . strlen($base64Result) . " characters\n\n";
return $base64Result;
}
// Java RSAUtil.java 的 decrypt 方法
function rsaDecrypt($dataStr, $privateKeyStr) {
// Java: byte[] encryptedData = decryptBASE64(dataStr);
$encryptedData = base64_decode($dataStr);
echo " BASE64解码后: " . strlen($encryptedData) . " bytes\n";
// 加载私钥
$privateKey = getPrivateKeyFromBase64($privateKeyStr);
if (!$privateKey) {
throw new Exception("私钥加载失败: " . openssl_error_string());
}
// 获取密钥大小
$keyDetails = openssl_pkey_get_details($privateKey);
$keySize = $keyDetails['bits'] / 8;
$maxDecryptBlock = 128; // Java中定义的 MAX_DECRYPT_BLOCK
echo " 密钥大小: {$keyDetails['bits']} bits ($keySize bytes)\n";
echo " 最大解密块: $maxDecryptBlock bytes\n";
// 分段解密
$decrypted = '';
$inputLen = strlen($encryptedData);
$offset = 0;
$i = 0;
while ($inputLen - $offset > 0) {
if ($inputLen - $offset > $maxDecryptBlock) {
$block = substr($encryptedData, $offset, $maxDecryptBlock);
} else {
$block = substr($encryptedData, $offset, $inputLen - $offset);
}
$decryptedBlock = '';
// Java: cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK)
$success = openssl_private_decrypt($block, $decryptedBlock, $privateKey, OPENSSL_PKCS1_PADDING);
if (!$success) {
$error = openssl_error_string();
throw new Exception("{$i}段解密失败: $error");
}
$decrypted .= $decryptedBlock;
$i++;
$offset = $i * $maxDecryptBlock;
echo " 解密第{$i}段: " . strlen($block) . " bytes -> " . strlen($decryptedBlock) . " bytes\n";
}
openssl_free_key($privateKey);
echo " 总明文长度: " . strlen($decrypted) . " bytes\n\n";
return $decrypted;
}
// 测试数据
$demoPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC+8V1Or6R6H3a7TjuvoDa5k0W/niEGg4N+0Nni+KfwHVX05pI7Qdq1J5+q31yORAoiSSNZNW4uWykmeSltC2mHGkQXClU4JmMXnWFyRCENw1iDIIIEsNax4jFBZUaDCn69PxWgp5wwk+d0V7QRYZ9jkgUaJK+BSYa0KMraxVfJwIDAQAB';
$demoPrivateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAML7xXU6vpHofdrtOO6+gNrmTRb+eIQaDg37Q2eL4p/AdVfTmkjtB2rUnn6rfXI5ECiJJI1k1bi5bKSZ5KW0LaYcaRBcKVTgmYxedYXJEIQ3DWIMgggSw1rHiMUFlRoMKfr0/FaCnnDCT53RXtBFhn2OSBRokr4FJhrQoytrFV8nAgMBAAECgYEAizhN0thw/altQ4YiIoWvZ50M6iAkWN5prp37kNGWrM40etNB1FQ5+ZN636L+3THVUbwqdzLKTy1GX3jqg05VUIf0sKYYepp+skwZmHVprz4EUKsZXRa+3MnMChJcyHdlyuUNs6HriMq6Qc1+fFEOtZFAf3lo2wYNFw5vIKHGQRECQQDxVKa+6m4y7LmWgiGLYghuL/SGXySFhwBh5+zMNl8V7aAbTX/tH6A0s8JXsSI4iChjWPXthKFTrd7h62vJBjeFAkEAztXpNehF18g3e6JEhtjbTmMsgyj13gdSZSRwjO0Y+IsDI1afnZXzwv96OlukGK8185z0bsbhTCOd6rkcRTnduwJBAOqGknlMh4VTylO66PB0d67lSaPgCDT/al67LcOTPzqnMAX4fc6qAl3VJ5Ni39fCckWB6ZVGZCVW/hfdWmUEdqUCQFFWNXuJd82/YnIwAZq1tKhCv8JkXSuO3YwApHIG2wcCQ52l9ubVjSJlrP8+Am3imOjQFB9r/jUe3H7thHyEoPkCQCay3waa0ll2DY+epkrrF/QO7aMa6NIUArRgWUmqw+1/45csBiWPMUrAD/CPDUr9Jvte92NjoAlz649csbgMM3w=';
$plaintext = '{"CLD_HEADER":{"CLD_TX_CHNL":"YSTEST","CLD_TX_TIME":"20191112145911","CLD_TX_CODE":"A3341O031","CLD_TX_SEQ":"1010114131620697023913271"},"CLD_BODY":{"USER_ID":"user123","ORDER_ID":"order123","ORDER_DT":"20191112145811","TOTAL_AMT":"100.00","PAY_AMT":"90.00","DISCOUNT_AMT":"10.00","ORDER_STATUS":"1","REFUND_STATUS":"0","MCT_NM":"XXX商户"}}';
echo "【测试1】PHP加密 + PHP解密验证代码正确性\n";
echo "========================================\n";
try {
echo "原始明文: " . substr($plaintext, 0, 80) . "...\n\n";
echo "步骤1: 用公钥加密\n";
$encrypted = rsaEncrypt($plaintext, $demoPublicKey);
echo "步骤2: 用私钥解密\n";
$decrypted = rsaDecrypt($encrypted, $demoPrivateKey);
echo "========================================\n";
echo "解密结果: " . substr($decrypted, 0, 80) . "...\n\n";
echo "验证结果: " . ($decrypted === $plaintext ? "✓ 成功!加密解密完全一致" : "✗ 失败") . "\n\n";
if ($decrypted === $plaintext) {
echo "【结论】PHP实现的RSA加密解密代码是正确的\n\n";
}
} catch (Exception $e) {
echo "✗ 错误: " . $e->getMessage() . "\n\n";
}
echo "\n【测试2】尝试解密Java demo提供的密文\n";
echo "========================================\n";
$demoCiphertext = 'Y2tFMDFJd2RGMGg5aFdXUGtjVVdaSmo4NHBKQzNNZE1wQTRRSXZVRlhBSWhqVEdXNE1LcE9MOXdxY0hhNUlIZndUU0RLK3NrZ1hpTytJUitpREEwSUp0bktRcWMxRG5hN1R0OEtjcUkxTUFDVE5FY2Z0b3lCeTVTaEo3cmNjSnBOUVFsSjRBR2htSzRheEhNb0p6N215eFViK1ZjeGd5WjVTTjJQcHUxQlBnZXJsQXE2Q1lrQ2VuSmZEYUxVSks5RGx2Yk9YWDlDczJiVVllYjlHSHQrUkFuYTljc2hucGhqVWNwNDgrcThNcGhQOElBL20xNVk5NG9lZEV4SXpmc0pDcDExZjFvQ0E5YkwwOWJOZjM4VHR3TkJkTmhqM3lKSVpWeWVpT0FucGhjS3JpOEs5RnlZbXlNVHF1UER3UjhmQ0p5dk5vYkNMS1BPRmQ3WFdXTVczZ29kSWpLaG5OUnhnaFA3N2txdDU3K2Rkd3hGbDgxUEdYbXJWN1ZKWDFOeXRVUFg2dWp3ZzdsUU1OSTlubU1kVE9nbHZJUHRoS205aEludFc2ZFBVTG1DUlNLNzZDc05qTUIyb1hTR2M2cHBNazMxNDJSa05KR0hvY1ZBNFUzcmc4SVk4ZFlYaTUzZmF3cHRES3pHY2JZVFI0SldRVzRNU2ZmSUxvNFpxTkY=';
try {
echo "demo密文长度: " . strlen($demoCiphertext) . " characters\n\n";
$decrypted = rsaDecrypt($demoCiphertext, $demoPrivateKey);
echo "========================================\n";
echo "✓ 解密成功!\n";
echo "解密结果: $decrypted\n\n";
echo "与原始明文对比: " . ($decrypted === $plaintext ? "✓ 完全一致" : "✗ 不一致") . "\n\n";
} catch (Exception $e) {
echo "✗ 解密失败: " . $e->getMessage() . "\n\n";
echo "【分析】\n";
echo "1. 如果测试1成功说明PHP代码是正确的\n";
echo "2. demo密文无法解密可能因为:\n";
echo " - demo密文不是用demo公钥加密的\n";
echo " - demo密文只是格式示例不是真实密文\n";
echo " - 需要用建行平台公钥加密而不是demo公钥\n\n";
}
echo "========== 测试完成 ==========\n\n";