openssl java aes_java aes加解密 使用 php openssl 模仿遇到问题 请大佬赐教

该博客主要讨论如何在PHP中使用openssl库来模仿Java的AES加解密过程,以解决两者结果不一致的问题。作者详细分析了Java代码,发现关键在于Java使用了特定的密钥生成方法。在PHP中,作者通过调整openssl_digest的参数和密钥转换方式,尝试匹配Java的加密结果,但未能成功。博客提供了PHP和Java的加密代码示例,展示了当前遇到的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

现在有个java的加解密程序,需要改成php的方法来实现

现在有对方的java加密程序 我用openssl得到的结果不一样

题目来源及自己的思路

JAVA 示例中:

public static byte[] generateAesKey(int keysize, String key) {

try {

KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);

//防止linux下 随机生成key

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");

secureRandom.setSeed(key.getBytes());

keyGenerator.init(keysize, secureRandom);

SecretKey secretKey = keyGenerator.generateKey();

return secretKey.getEncoded();

} catch (GeneralSecurityException e) {

throw Exceptions.unchecked(e);

}

}

我用PHP获取key如下

$key = base64_encode(substr(openssl_digest(openssl_digest($encryptKey, 'sha1', true), 'sha1', true), 0, 16));

问题:我拿到的key是 "COgmiQhm0EKpD1eDW+kTMA=="同我在 java示例中 String keyStr = Base64.encodeBase64String(key);得到的一样 但是使用 "COgmiQhm0EKpD1eDW+kTMA="加密的结果 与JAVA示例中 使用byte[]类型的data和key 不同 感觉问题就在这里 java示例用的byte[]类型的data和key加密

PHP openssl 是string。

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)

Java 示例 :

public static void aes() {

String data = "{\"notaryOfficeId\":\"cb090588f82711e690a8000c299d85c9\",\"bzjd\":\"5\",\"notaryPersonName\":\"李可\",\"itemName\":\"委托\",\"notaryNumYear\":\"2019\",\"notaryNumSubfix\":\"外字第1000号\",\"notaryNum\":\"(2019)外字第1000号\"}";

String clientId = "d726cfb97e364174a6b8a13bf67a5eea";

String secretKey = "G9uLRtKofu22";

LinkedHashMap map = new LinkedHashMap<>();

map.put("client_id", clientId);

//使用对接工具类里的Cryptos 配合字符串"apiDefault" 生成AES密钥

//我遇到的问题 JAVA获取到的 key 是 byte[]类型 PHP openssl_encrypt 加密 只能使用string

byte[] key = Cryptos.generateAesKey("apiDefault");

//我尝试打印 byte[] key转换成string 得到”COgmiQhm0EKpD1eDW+kTMA==“ 我在PHP中也能拿到 但是这里加密使用的 byte[] PHP不能使用 byte[]

String keyStr = Base64.encodeBase64String(key);

//使用对接工具类里的Cryptos里的aesEncrypt 将byte[]类型的 data 和 key 加密

//我遇到问题 java示例里的加密 使用的是 byte[]类型 PHP不能用byte[]类型加密 我在PHP中 将byte[]转换成string加密 得到的结果就不一样了

byte[] encryptDataByte = Cryptos.aesEncrypt(data.getBytes(), key);

String encodeData = Base64.encodeBase64String(Hexs.parseByte2HexStr(encryptDataByte).getBytes());

map.put("data", encodeData);

//使用SignUtil获取签名

SignUtil.sign(map, secretKey);

System.out.println("========================》"+map.toString());

}

打印MAP得到的结果(期望结果):

{

client_id=d726cfb97e364174a6b8a13bf67a5eea,

data=RDk0MDc3MDk3RUEyNzBGNUY0NTdEMTRBQUQxQzEzMkUwMjU5NjUxREI1ODExNTMwN0M1QTRBMThFOTVDNTczMjg4NzhCOTVEM0Y1OEI1OEIyQ0E1MEZDMkVFNUYwOTE2N0UwNjQxRjBFRDcxOTA2QUQ5NTVGQTgwRDI3MDIwRUQ3QzQ3NTFDN0EwQzVENjMwMkU1MzVCQ0MxRTZFODY2Qjg2MUU5QjAxODg4RDY2MTYwODVBQkQzN0NCOUMzNjY1NDVEODc0RjQ0MUM5QjI1QzE5OUY1RkY5QThEMTM5OTQxMzZDRTg5REUxQzZFOTFDRjY0MEE5RUJERERGMTYxMTRCNTJEQTU5MDdDQ0I2Q0YxNTU0MDEwRTYzNkY1QkI5RTU5OUNGOEVFM0FFOEZBM0E0MTNCMkUwMTc3OTY4NUI3NDIxMTI0MUZBQ0JDNTk2MkNBRjc1QkM0Qjc4MkJGQTkxNzJCMDNFQjdFN0EyNjY1NjY5RDE5RjMwREYzNkFCNjhGODhBM0ZGRERDOEI4MkQ1ODBBNDNFQUI0RjA1MTdBOTVGRkM0ODc3RENCQkE3MzQ1NjlGNDg5RTcyQUVGNw====,

sign=o3MtfqSHKAkyG+BM3iwCPku0Mx0hQAN5GRssgpvrplg=

}

相关调用:

/*******************************************************************************

* Copyright (c) 2005, 2014 springside.github.io

*

* Licensed under the Apache License, Version 2.0 (the "License");

*******************************************************************************/

package com.notary.util;

import com.google.common.base.Charsets;

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.Mac;

import javax.crypto.SecretKey;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.security.GeneralSecurityException;

import java.security.SecureRandom;

import java.util.Arrays;

/**

* 支持HMAC-SHA1消息签名 及 DES/AES对称加密的工具类.

*

* 支持Hex与Base64两种编码方式.

*

* @author calvin

*/

public class Cryptos {

private static final String AES = "AES";

private static final String AES_CBC = "AES/CBC/PKCS5Padding";

private static final String HMACSHA1 = "HmacSHA1";

private static final int DEFAULT_HMACSHA1_KEYSIZE = 160; // RFC2401

private static final int DEFAULT_AES_KEYSIZE = 128;

private static final int DEFAULT_IVSIZE = 16;

private static SecureRandom random = new SecureRandom();

// -- HMAC-SHA1 funciton --//

/**

* 使用HMAC-SHA1进行消息签名, 返回字节数组,长度为20字节.

*

* @param input 原始输入字符数组

* @param key HMAC-SHA1密钥

*/

public static byte[] hmacSha1(byte[] input, byte[] key) {

try {

SecretKey secretKey = new SecretKeySpec(key, HMACSHA1);

Mac mac = Mac.getInstance(HMACSHA1);

mac.init(secretKey);

return mac.doFinal(input);

} catch (GeneralSecurityException e) {

throw Exceptions.unchecked(e);

}

}

/**

* 校验HMAC-SHA1签名是否正确.

*

* @param expected 已存在的签名

* @param input 原始输入字符串

* @param key 密钥

*/

public static boolean isMacValid(byte[] expected, byte[] input, byte[] key) {

byte[] actual = hmacSha1(input, key);

return Arrays.equals(expected, actual);

}

/**

* 生成HMAC-SHA1密钥,返回字节数组,长度为160位(20字节). HMAC-SHA1算法对密钥无特殊要求,

* RFC2401建议最少长度为160位(20字节).

*/

public static byte[] generateHmacSha1Key() {

try {

KeyGenerator keyGenerator = KeyGenerator.getInstance(HMACSHA1);

keyGenerator.init(DEFAULT_HMACSHA1_KEYSIZE);

SecretKey secretKey = keyGenerator.generateKey();

return secretKey.getEncoded();

} catch (GeneralSecurityException e) {

throw Exceptions.unchecked(e);

}

}

// -- AES funciton --//

/**

* 使用AES加密原始字符串.

*

* @param input 原始输入字符数组

* @param key 符合AES要求的密钥

*/

public static byte[] aesEncrypt(byte[] input, byte[] key) {

return aes(input, key, Cipher.ENCRYPT_MODE);

}

/**

* 使用AES加密原始字符串.

*

* @param input 原始输入字符数组

* @param key 符合AES要求的密钥

* @param iv 初始向量

*/

public static byte[] aesEncrypt(byte[] input, byte[] key, byte[] iv) {

return aes(input, key, iv, Cipher.ENCRYPT_MODE);

}

/**

* 使用AES解密字符串, 返回原始字符串.

*

* @param input Hex编码的加密字符串

* @param key 符合AES要求的密钥

*/

public static String aesDecrypt(byte[] input, byte[] key) {

byte[] decryptResult = aes(input, key, Cipher.DECRYPT_MODE);

return new String(decryptResult, Charsets.UTF_8);

}

/**

* 使用AES解密字符串, 返回原始字符串.

*

* @param input Hex编码的加密字符串

* @param key 符合AES要求的密钥

* @param iv 初始向量

*/

public static String aesDecrypt(byte[] input, byte[] key, byte[] iv) {

byte[] decryptResult = aes(input, key, iv, Cipher.DECRYPT_MODE);

return new String(decryptResult);

}

/**

* 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.

*

* @param input 原始字节数组

* @param key 符合AES要求的密钥

* @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE

*/

private static byte[] aes(byte[] input, byte[] key, int mode) {

try {

SecretKey secretKey = new SecretKeySpec(key, AES);

Cipher cipher = Cipher.getInstance(AES);

cipher.init(mode, secretKey);

return cipher.doFinal(input);

} catch (GeneralSecurityException e) {

throw Exceptions.unchecked(e);

}

}

/**

* 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.

*

* @param input 原始字节数组

* @param key 符合AES要求的密钥

* @param iv 初始向量

* @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE

*/

private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) {

try {

SecretKey secretKey = new SecretKeySpec(key, AES);

IvParameterSpec ivSpec = new IvParameterSpec(iv);

Cipher cipher = Cipher.getInstance(AES_CBC);

cipher.init(mode, secretKey, ivSpec);

return cipher.doFinal(input);

} catch (GeneralSecurityException e) {

throw Exceptions.unchecked(e);

}

}

/**

* 生成AES密钥,返回字节数组, 默认长度为128位(16字节).

*/

public static byte[] generateAesKey() {

return generateAesKey(DEFAULT_AES_KEYSIZE);

}

public static byte[] generateAesKey(String key) {

return generateAesKey(DEFAULT_AES_KEYSIZE, key);

}

/**

* 生成AES密钥,可选长度为128,192,256位.

*/

public static byte[] generateAesKey(int keysize) {

try {

KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);

keyGenerator.init(keysize);

SecretKey secretKey = keyGenerator.generateKey();

return secretKey.getEncoded();

} catch (GeneralSecurityException e) {

throw Exceptions.unchecked(e);

}

}

public static byte[] generateAesKey(int keysize, String key) {

try {

KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);

//防止linux下 随机生成key

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");

secureRandom.setSeed(key.getBytes());

keyGenerator.init(keysize, secureRandom);

SecretKey secretKey = keyGenerator.generateKey();

return secretKey.getEncoded();

} catch (GeneralSecurityException e) {

throw Exceptions.unchecked(e);

}

}

/**

* 生成随机向量,默认大小为cipher.getBlockSize(), 16字节.

*/

public static byte[] generateIV() {

byte[] bytes = new byte[DEFAULT_IVSIZE];

random.nextBytes(bytes);

return bytes;

}

}

SignUtil

package com.notary.comity.util;

import com.google.common.base.Strings;

import org.apache.commons.codec.binary.Base64;

import org.apache.commons.lang3.exception.ExceptionUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;

import java.util.Map;

/**

* @author daihy

* Created on 2016/6/21.

*/

public class SignUtil {

static Logger logger = LoggerFactory.getLogger(SignUtil.class);

private static String getSign(Map map, String secretKey) {

try {

Mac sha256_HMAC = Mac.getInstance("HmacSHA256");

SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");

sha256_HMAC.init(secretKeySpec);

StringBuffer prepareSign = new StringBuffer();

for (Map.Entry entry : map.entrySet()) {

prepareSign.append(entry.getKey()).append("=");

prepareSign.append(entry.getValue());

}

return Base64.encodeBase64String(sha256_HMAC.doFinal(prepareSign.toString().getBytes()));

} catch (NoSuchAlgorithmException e) {

logger.error(ExceptionUtils.getStackTrace(e));

} catch (InvalidKeyException e) {

logger.error(ExceptionUtils.getStackTrace(e));

}

return "";

}

public static void sign(Map map, String secretKey) {

map.put("sign", getSign(map, secretKey));

}

public static boolean signValidate(Map map, String secretKey, String sign) {

if(Strings.isNullOrEmpty(secretKey) || Strings.isNullOrEmpty(sign)){

return false;

}

if (getSign(map, secretKey).equals(sign)) {

return true;

}

return false;

}

}

你期待的结果是什么?实际看到的错误信息又是什么?

问题描述

问题出现的环境背景及自己尝试过哪些方法

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)

我的php代码:

调用:

$AES = new AES();

$clientId = 'd726cfb97e364174a6b8a13bf67a5eea';

$secretKey = 'G9uLRtKofu22';

$encryptKey = 'apiDefault';

$map = [];

$map['client_id'] = $clientId;

$data = '{"notaryOfficeId":"cb090588f82711e690a8000c299d85c9","bzjd":"5","notaryPersonName":"李可","itemName":"委托","notaryNumYear":"2019","notaryNumSubfix":"外字第1000号","notaryNum":"(2019)外字第1000号"}';

//ps 会不会JAVA和php在声明这个data时 就已经不同了

//加密

$encryptionData = $AES->encrypt($data, $encryptKey);

$map['data'] = $encryptionData;

//测试解密

$decryptData = $AES->decrypt($encryptionData, $encryptKey);

//获取签名 因为加密结果不同 所以这里结果也同java示例不同

$sign = $AES->sign($map, $secretKey);

$map['sign'] = $sign;

print_r($map);

exit;

-----------------------AES---------------------------------------

class AES

{

public function encrypt($data, $encryptKey)

{

/*

* 我拿到的key是 "COgmiQhm0EKpD1eDW+kTMA=="

* 同我在 java示例中 String keyStr = Base64.encodeBase64String(key);得到的一样

* 但是使用 "COgmiQhm0EKpD1eDW+kTMA="加密的结果 与JAVA示例中 使用byte[]类型的data和key 不同

* 问题就在这里 如何才能结果相同

*/

$key = base64_encode(substr(openssl_digest(openssl_digest($encryptKey, 'sha1', true), 'sha1', true), 0, 16));

$encRaw = openssl_encrypt($data, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);

$encHex = $this->strToHex($encRaw);

return base64_encode($encHex);

}

public function decrypt($enc, $encryptKey)

{

$key = base64_encode(substr(openssl_digest(openssl_digest($encryptKey, 'sha1', true), 'sha1', true), 0, 16));

$hex = base64_decode($enc);

$enByte = $this->hexToStr($hex);

$dec = openssl_decrypt($enByte, 'AES-128-ECB', $key, OPENSSL_RAW_DATA, '');

return $dec;

}

public function strToHex($str)

{

$hex = '';

for ($i = 0; $i < strlen($str); $i++) {

$he = dechex(ord($str[$i]));

if (strlen($he) == 1) {

$he = '0' . $he;

}

$hex .= $he;

}

$hex = strtoupper($hex);

return $hex;

}

public static function getBytes($string)

{

$bytes = [];

for ($i = 0; $i < strlen($string); $i++) {

$bytes[] = ord($string[$i]);

}

return $bytes;

}

public function hexToStr($hex)

{

$str = '';

for ($i = 0; $i < strlen($hex) - 1; $i += 2) {

$str .= chr(hexdec($hex[$i] . $hex[$i + 1]));

}

return $str;

}

public function sign($arr, $key)

{

$s = '';

foreach ($arr as $k => $v) {

$s .= "{$k}={$v}";

}

$s = hash_hmac('sha256', $s, $key, true);

return base64_encode($s);

}

}

你期待的结果是什么?实际看到的错误信息又是什么?

期望结果能同JAVA的一样

{

client_id=d726cfb97e364174a6b8a13bf67a5eea,

data=RDk0MDc3MDk3RUEyNzBGNUY0NTdEMTRBQUQxQzEzMkUwMjU5NjUxREI1ODExNTMwN0M1QTRBMThFOTVDNTczMjg4NzhCOTVEM0Y1OEI1OEIyQ0E1MEZDMkVFNUYwOTE2N0UwNjQxRjBFRDcxOTA2QUQ5NTVGQTgwRDI3MDIwRUQ3QzQ3NTFDN0EwQzVENjMwMkU1MzVCQ0MxRTZFODY2Qjg2MUU5QjAxODg4RDY2MTYwODVBQkQzN0NCOUMzNjY1NDVEODc0RjQ0MUM5QjI1QzE5OUY1RkY5QThEMTM5OTQxMzZDRTg5REUxQzZFOTFDRjY0MEE5RUJERERGMTYxMTRCNTJEQTU5MDdDQ0I2Q0YxNTU0MDEwRTYzNkY1QkI5RTU5OUNGOEVFM0FFOEZBM0E0MTNCMkUwMTc3OTY4NUI3NDIxMTI0MUZBQ0JDNTk2MkNBRjc1QkM0Qjc4MkJGQTkxNzJCMDNFQjdFN0EyNjY1NjY5RDE5RjMwREYzNkFCNjhGODhBM0ZGRERDOEI4MkQ1ODBBNDNFQUI0RjA1MTdBOTVGRkM0ODc3RENCQkE3MzQ1NjlGNDg5RTcyQUVGNw====,

sign=o3MtfqSHKAkyG+BM3iwCPku0Mx0hQAN5GRssgpvrplg=

}

实际结果:对不上~

题目描述

题目来源及自己的思路

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)

你期待的结果是什么?实际看到的错误信息又是什么?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值