技术标签: aes openssl java
题目描述
现在有个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=
}
实际结果:对不上~
题目描述
题目来源及自己的思路
相关代码
// 请把代码文本粘贴到下方(请勿用图片代替代码)
你期待的结果是什么?实际看到的错误信息又是什么?
海量的题库、音视频答题资料、用户数据以及日志,对猿辅导后台数据存储和处理能力都提出了严峻的要求。而由于教育辅导行业的业务特点,猿辅导也面临着业务峰值对于数据库能力的巨大挑战。本文就为大家介绍阿里云POLARDB如何帮助猿辅导打造“孩子喜欢老师好”的网课平台。猿辅导业务背景猿辅导是国内知名在线教育机构,旗下有猿辅导、猿题库、小猿搜题、小猿口算、斑马英语五款核心在线教育APP,为学生和家长...
记yolov3训练自己的数据集前言参考代码数据集标注合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入前言刚接触深度学习,尝试用...
来想一想,当我们使用计算机时,屏幕上面显示的咚咚是由哪里来的?嗯!是由显示卡与屏幕显像的;那么你现在可以藉由网络看到这篇文章,则是藉由 Internet 、网络卡、网络线以及所有相关的电子器材与网络器材所完成的一项任务!如果你要看 VCD 呢?那么就需要光驱、光盘、声卡的发声等等的支持。这么说来的话,所以在『工作』的东西都是『硬件』的工作呀!对了!就是这些计算机硬件在工作的。那么硬件怎么工作呢?那...
MATLAB中LMI程序运行报错:Error using lmiterm (line 271)lhs of LMI #4, block (1,1): terms in diagonal blocks must be square;程序如下:clcclearA=[0.0000000e+00 3.6301310e-21-9.7026387e+00-4.9849839e-05 0.000...
实现方法简介许多文件都支持转换为PDF格式,诸如Word,Excel,PowerPoint,Cad以及图片格式。所以pdf从学校到职场,都可以看到pdf文件的身影。为了保证了文件的安全性,正常情况下无法对pdf的内容进行编辑。但是相应的我们就无法修改pdf的内容,也不便于pdf资料的使用。虽然现在市面上有很多 pdf 转 word 软件,比如 wps,但大多数的软件是要收费的,并且价格不菲。前些天...
优质解答flag是程序员自己起的变量名,一般情况下将其看作为标志位.我们通常将它视为uchar型变量,将flag赋值时,有flag=!1(flag不等于1)和flag=1;它的作用主要是让单片机的一项功能实现不同的操作,不同的操作通常时间先后顺序不等,不同的操作即通过设置flag=!1(flag不等于1)和flag=1予以区别开来.举个例子:我们要在定时器T0中先后实现1秒和2秒的不同定时,在C...
点击上方,选择星标或置顶,每天给你送干货!来自:深度学习的知识小屋Paper: Two are Better Than One: Joint Entity and Relation Ex...
巨杉数据库助力民生银行、广发银行前台智慧化业务今年以来,公有云事故频发,大有“黑天鹅”不断爆发之势头。近期,北京一初创公司清博数控表示,在使用国内某厂商云服务器8个月后,放在云服务器上包括备份的数据全部丢失,导致公司几年来的平台数据全部丢失,造成“近千万元损失”。此后,该云平台对此回应称,向该公司表达歉意,愿意赔偿该公司在平台产生的实际消费共计3569元,本着帮助用户迅速恢复业务的目的...
hiISP_AE_ATTR_EX_S参数说明: enAEMode 自动曝光的优先模式,如帧率优先, 噪声优先。 u8ExpCompensation自动曝光调整时对曝光补偿量。值越大,则自动曝光的目标亮度值越大,图像越亮 u32GainThreshold自动降帧时的系统增益门限值。 取值范围:[0x400, 0xFFFFFFFF]自动降帧时增益门限值u
前言:先给大家简单说一下递归这个东西递归:程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句...
引入Web Cache技术的主要目的:通过对内容副本进行缓存来满足后续相同的用户请求。使用 Cache 可以分担用户对源站点的集中访问负载,从而提高Web 站点请求的响应速度和用户访问并发量。1. Web Cache 关键性能指标并发量在设计Web Cache的初期就应该规划好其能够处理的用户访问并发量,从而在部署完成后能够让其达到预期的并发量。当访问峰值超过Web Cache 和 We...
花了几天的时间,查找了很多资料,基本上没有找到能够编译成功教程特留下此篇博客已做参考:windows编译libtorrent需要依赖于OpenSSL库,和boost库,建议直接下载一. 编译OpenSSL的库 编译OpenSSL网上教程一大堆,自己去找,我这里不介绍 编译好的OpenSSL库下载地址二. 编译boost库 参考地址:https...