mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
SM2解密时,兼容GmSSL非压缩省略的04头的密文
This commit is contained in:
parent
c9cac93337
commit
38911594c8
@ -7,12 +7,10 @@
|
|||||||
|
|
||||||
### 计划实现
|
### 计划实现
|
||||||
* 【db 】 增加DDL封装
|
* 【db 】 增加DDL封装
|
||||||
* 【poi 】 CellUtil.getCellIfMergedRegion考虑添加缓存支持,增加最大和最小范围判断,减少遍历
|
|
||||||
* 【http 】 redirect跳转和Cookie
|
* 【http 】 redirect跳转和Cookie
|
||||||
|
|
||||||
### ❌不兼容特性
|
### ❌不兼容特性
|
||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
* 【db 】 优化count查询兼容informix(issue#I713XQ@Gitee)
|
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
@ -34,4 +34,9 @@ public class ConvertToBooleanTest {
|
|||||||
Assertions.assertFalse(bool);
|
Assertions.assertFalse(bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toBooleanWithDefaultTest() {
|
||||||
|
Assertions.assertFalse(ConvertUtil.toBoolean("ddddd", false));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import org.bouncycastle.crypto.signers.SM2Signer;
|
|||||||
import org.bouncycastle.crypto.signers.StandardDSAEncoding;
|
import org.bouncycastle.crypto.signers.StandardDSAEncoding;
|
||||||
import org.bouncycastle.util.BigIntegers;
|
import org.bouncycastle.util.BigIntegers;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.codec.binary.HexUtil;
|
import org.dromara.hutool.core.codec.binary.HexUtil;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
import org.dromara.hutool.crypto.CryptoException;
|
import org.dromara.hutool.crypto.CryptoException;
|
||||||
@ -313,7 +314,20 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
|||||||
* @throws CryptoException 包括InvalidKeyException和InvalidCipherTextException的包装异常
|
* @throws CryptoException 包括InvalidKeyException和InvalidCipherTextException的包装异常
|
||||||
* @since 5.1.6
|
* @since 5.1.6
|
||||||
*/
|
*/
|
||||||
public byte[] decrypt(final byte[] data, final CipherParameters privateKeyParameters) throws CryptoException {
|
public byte[] decrypt(byte[] data, final CipherParameters privateKeyParameters) throws CryptoException {
|
||||||
|
Assert.isTrue(data.length > 1, "Invalid SM2 cipher text, must be at least 1 byte long");
|
||||||
|
// 检查数据,gmssl等库生成的密文不包含04前缀(非压缩数据标识),此处检查并补充
|
||||||
|
// 参考:https://blog.csdn.net/softt/article/details/139978608
|
||||||
|
// 根据公钥压缩形态不同,密文分为两种压缩形式:
|
||||||
|
// C1( 03 + X ) + C3(32个字节)+ C2
|
||||||
|
// C1( 02 + X ) + C3(32个字节)+ C2
|
||||||
|
// 非压缩公钥正常形态为04 + X + Y,由于各个算法库差异,04有时候会省略
|
||||||
|
// 非压缩密文正常形态为04 + C1 + C3 + C2
|
||||||
|
if (data[0] != 0x04 && data[0] != 0x02 && data[0] != 0x03) {
|
||||||
|
// 默认非压缩形态
|
||||||
|
data = ArrayUtil.insert(data, 0, 0x04);
|
||||||
|
}
|
||||||
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
final SM2Engine engine = getEngine();
|
final SM2Engine engine = getEngine();
|
||||||
try {
|
try {
|
||||||
|
@ -32,6 +32,8 @@ import java.security.KeyPair;
|
|||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SM2算法单元测试
|
* SM2算法单元测试
|
||||||
*
|
*
|
||||||
@ -333,4 +335,17 @@ public class SM2Test {
|
|||||||
Assertions.assertNotNull(sm1);
|
Assertions.assertNotNull(sm1);
|
||||||
Assertions.assertNotNull(sm2);
|
Assertions.assertNotNull(sm2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void decryptFromGmSSLTest() {
|
||||||
|
// https://the-x.cn/zh-cn/cryptography/Sm2.aspx
|
||||||
|
// python gmssl加密后的内容无04标识,检查并补充
|
||||||
|
final String privateKey = "MHcCAQEEICxTSOhWA4oYj2DI95zunPqHHEKZSi5QFLvWz57BfIGVoAoGCCqBHM9VAYItoUQDQgAEIGRS/PssvgZ8Paw2YeFaW4VXrkgceBELKPWcXmq/p3iMhHxYfcaFAa5AzvPJOmYmVzVwu9QygMMrg/30Ok1npw==";
|
||||||
|
final SM2 sm2 = new SM2(privateKey, null);
|
||||||
|
sm2.setMode(SM2Engine.Mode.C1C2C3);
|
||||||
|
|
||||||
|
final String encrypt = "x0KA1DKkmuA/YZdmvMr8X+1ZQb7a19Pr5nSxxe2ItUYpDAioa263tm9u7vST38hAEUoOxxXftD+7bRQ7Y8v1tcFXeheKodetA6LrPIuh0QYZMdBqIKSKdmlGeVE0Vdm3excisbtC";
|
||||||
|
final byte[] decrypt = sm2.decrypt(encrypt, KeyType.PrivateKey);
|
||||||
|
assertEquals("123456", StrUtil.utf8Str(decrypt));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ public class DatabaseMetaDataWrapper extends SimpleWrapper<DatabaseMetaData> {
|
|||||||
// issue#I9BANE Oracle中特殊表名需要解包
|
// issue#I9BANE Oracle中特殊表名需要解包
|
||||||
tableName = getPureTableName(tableName);
|
tableName = getPureTableName(tableName);
|
||||||
|
|
||||||
try (final ResultSet rs = this.raw.getTables(catalog, schema, tableName, new String[]{TableType.TABLE.value()})) {
|
try (final ResultSet rs = this.raw.getTables(catalog, schema, tableName, new String[]{TableType.TABLE.getValue()})) {
|
||||||
if (null != rs) {
|
if (null != rs) {
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
return rs.getString("REMARKS");
|
return rs.getString("REMARKS");
|
||||||
|
@ -77,55 +77,127 @@ public class IndexInfo implements Serializable, Cloneable {
|
|||||||
this.tableName = tableName;
|
this.tableName = tableName;
|
||||||
this.schema = schema;
|
this.schema = schema;
|
||||||
this.catalog = catalog;
|
this.catalog = catalog;
|
||||||
this.setColumnIndexInfoList(new ArrayList<>());
|
this.columnIndexInfoList = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查索引是否是非唯一的
|
||||||
|
*
|
||||||
|
* @return 如果索引是非唯一的,返回true;否则返回false
|
||||||
|
*/
|
||||||
public boolean isNonUnique() {
|
public boolean isNonUnique() {
|
||||||
return nonUnique;
|
return nonUnique;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNonUnique(final boolean nonUnique) {
|
/**
|
||||||
|
* 设置索引的非唯一状态
|
||||||
|
*
|
||||||
|
* @param nonUnique 索引的非唯一状态
|
||||||
|
* @return 当前的IndexInfo对象,以支持链式调用
|
||||||
|
*/
|
||||||
|
public IndexInfo setNonUnique(final boolean nonUnique) {
|
||||||
this.nonUnique = nonUnique;
|
this.nonUnique = nonUnique;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取索引名称
|
||||||
|
*
|
||||||
|
* @return 索引名称
|
||||||
|
*/
|
||||||
public String getIndexName() {
|
public String getIndexName() {
|
||||||
return indexName;
|
return indexName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIndexName(final String indexName) {
|
/**
|
||||||
|
* 设置索引名称
|
||||||
|
*
|
||||||
|
* @param indexName 索引名称
|
||||||
|
* @return 当前的IndexInfo对象,以支持链式调用
|
||||||
|
*/
|
||||||
|
public IndexInfo setIndexName(final String indexName) {
|
||||||
this.indexName = indexName;
|
this.indexName = indexName;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取表名称
|
||||||
|
*
|
||||||
|
* @return 表名称
|
||||||
|
*/
|
||||||
public String getTableName() {
|
public String getTableName() {
|
||||||
return tableName;
|
return tableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTableName(final String tableName) {
|
/**
|
||||||
|
* 设置表名称
|
||||||
|
*
|
||||||
|
* @param tableName 表名称
|
||||||
|
* @return 当前的IndexInfo对象,以支持链式调用
|
||||||
|
*/
|
||||||
|
public IndexInfo setTableName(final String tableName) {
|
||||||
this.tableName = tableName;
|
this.tableName = tableName;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 schema 名称
|
||||||
|
*
|
||||||
|
* @return schema 名称
|
||||||
|
*/
|
||||||
public String getSchema() {
|
public String getSchema() {
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSchema(final String schema) {
|
/**
|
||||||
|
* 设置 schema 名称
|
||||||
|
*
|
||||||
|
* @param schema schema 名称
|
||||||
|
* @return 当前的IndexInfo对象,以支持链式调用
|
||||||
|
*/
|
||||||
|
public IndexInfo setSchema(final String schema) {
|
||||||
this.schema = schema;
|
this.schema = schema;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目录名称
|
||||||
|
*
|
||||||
|
* @return 目录名称
|
||||||
|
*/
|
||||||
public String getCatalog() {
|
public String getCatalog() {
|
||||||
return catalog;
|
return catalog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCatalog(final String catalog) {
|
/**
|
||||||
|
* 设置目录名称
|
||||||
|
*
|
||||||
|
* @param catalog 目录名称
|
||||||
|
* @return 当前的IndexInfo对象,以支持链式调用
|
||||||
|
*/
|
||||||
|
public IndexInfo setCatalog(final String catalog) {
|
||||||
this.catalog = catalog;
|
this.catalog = catalog;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取列索引信息列表
|
||||||
|
*
|
||||||
|
* @return 列索引信息列表
|
||||||
|
*/
|
||||||
public List<ColumnIndexInfo> getColumnIndexInfoList() {
|
public List<ColumnIndexInfo> getColumnIndexInfoList() {
|
||||||
return columnIndexInfoList;
|
return columnIndexInfoList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColumnIndexInfoList(final List<ColumnIndexInfo> columnIndexInfoList) {
|
/**
|
||||||
|
* 设置列索引信息列表
|
||||||
|
*
|
||||||
|
* @param columnIndexInfoList 列索引信息列表
|
||||||
|
* @return 当前的IndexInfo对象,以支持链式调用
|
||||||
|
*/
|
||||||
|
public IndexInfo setColumnIndexInfoList(final List<ColumnIndexInfo> columnIndexInfoList) {
|
||||||
this.columnIndexInfoList = columnIndexInfoList;
|
this.columnIndexInfoList = columnIndexInfoList;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -138,7 +210,7 @@ public class IndexInfo implements Serializable, Cloneable {
|
|||||||
}
|
}
|
||||||
final IndexInfo indexInfo = (IndexInfo) o;
|
final IndexInfo indexInfo = (IndexInfo) o;
|
||||||
return ObjUtil.equals(indexName, indexInfo.indexName)
|
return ObjUtil.equals(indexName, indexInfo.indexName)
|
||||||
&& ObjUtil.equals(tableName, indexInfo.tableName);
|
&& ObjUtil.equals(tableName, indexInfo.tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -154,12 +226,12 @@ public class IndexInfo implements Serializable, Cloneable {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "IndexInfo{" +
|
return "IndexInfo{" +
|
||||||
"nonUnique=" + nonUnique +
|
"nonUnique=" + nonUnique +
|
||||||
", indexName='" + indexName + '\'' +
|
", indexName='" + indexName + '\'' +
|
||||||
", tableName='" + tableName + '\'' +
|
", tableName='" + tableName + '\'' +
|
||||||
", schema='" + schema + '\'' +
|
", schema='" + schema + '\'' +
|
||||||
", catalog='" + catalog + '\'' +
|
", catalog='" + catalog + '\'' +
|
||||||
", columnIndexInfoList=" + columnIndexInfoList +
|
", columnIndexInfoList=" + columnIndexInfoList +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,33 @@ package org.dromara.hutool.db.meta;
|
|||||||
* @author Looly
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public enum TableType {
|
public enum TableType {
|
||||||
|
/**
|
||||||
|
* 数据库表
|
||||||
|
*/
|
||||||
TABLE("TABLE"),
|
TABLE("TABLE"),
|
||||||
|
/**
|
||||||
|
* 视图
|
||||||
|
*/
|
||||||
VIEW("VIEW"),
|
VIEW("VIEW"),
|
||||||
|
/**
|
||||||
|
* 系统表
|
||||||
|
*/
|
||||||
SYSTEM_TABLE("SYSTEM TABLE"),
|
SYSTEM_TABLE("SYSTEM TABLE"),
|
||||||
|
/**
|
||||||
|
* 全局临时表
|
||||||
|
*/
|
||||||
GLOBAL_TEMPORARY("GLOBAL TEMPORARY"),
|
GLOBAL_TEMPORARY("GLOBAL TEMPORARY"),
|
||||||
|
/**
|
||||||
|
* 本地临时表
|
||||||
|
*/
|
||||||
LOCAL_TEMPORARY("LOCAL TEMPORARY"),
|
LOCAL_TEMPORARY("LOCAL TEMPORARY"),
|
||||||
|
/**
|
||||||
|
* 别名
|
||||||
|
*/
|
||||||
ALIAS("ALIAS"),
|
ALIAS("ALIAS"),
|
||||||
|
/**
|
||||||
|
* 快捷方式
|
||||||
|
*/
|
||||||
SYNONYM("SYNONYM");
|
SYNONYM("SYNONYM");
|
||||||
|
|
||||||
private final String value;
|
private final String value;
|
||||||
@ -46,12 +67,12 @@ public enum TableType {
|
|||||||
*
|
*
|
||||||
* @return 值
|
* @return 值
|
||||||
*/
|
*/
|
||||||
public String value() {
|
public String getValue() {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.value();
|
return this.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user