fengketrade/test_java_compat.php
2025-10-22 11:34:32 +08:00

222 lines
9.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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";