mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
add opt
This commit is contained in:
parent
484d705638
commit
ea96eecd4b
@ -12,6 +12,8 @@
|
||||
* 【extra 】 增加PinyinUtil,封装TinyPinyin
|
||||
* 【extra 】 Ftp和Sftp增加FtpConfig,提供超时等更多可选参数
|
||||
* 【extra 】 SpringUtil增加getActiveProfiles、getBeansOfType、getBeanNamesForType方法(issue#I1FXF3@Gitee)
|
||||
* 【bloomFilter】 避免布隆过滤器数字溢出(pr#119@Gitee)
|
||||
* 【core 】 增加IoUtil.writeObj(issue#I1FZIE)
|
||||
|
||||
### Bug修复
|
||||
* 【core 】 修复URLBuilder中请求参数有`&`导致的问题(issue#850@Github)
|
||||
|
@ -13,35 +13,36 @@ import cn.hutool.core.util.NumberUtil;
|
||||
* 2.散列hash映射到数组的bit位置 <br>
|
||||
* 3.验证<br>
|
||||
* 此实现方式可以指定Hash算法
|
||||
*
|
||||
*
|
||||
* @author Ansj
|
||||
*/
|
||||
public class BitMapBloomFilter implements BloomFilter{
|
||||
public class BitMapBloomFilter implements BloomFilter {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private BloomFilter[] filters;
|
||||
|
||||
/**
|
||||
* 构造,使用默认的5个过滤器
|
||||
*
|
||||
* @param m M值决定BitMap的大小
|
||||
*/
|
||||
public BitMapBloomFilter(int m) {
|
||||
long mNum =NumberUtil.div(String.valueOf(m), String.valueOf(5)).longValue();
|
||||
long mNum = NumberUtil.div(String.valueOf(m), String.valueOf(5)).longValue();
|
||||
long size = mNum * 1024 * 1024 * 8;
|
||||
|
||||
|
||||
filters = new BloomFilter[]{
|
||||
new DefaultFilter(size),
|
||||
new ELFFilter(size),
|
||||
new JSFilter(size),
|
||||
new PJWFilter(size),
|
||||
new SDBMFilter(size)
|
||||
new DefaultFilter(size),
|
||||
new ELFFilter(size),
|
||||
new JSFilter(size),
|
||||
new PJWFilter(size),
|
||||
new SDBMFilter(size)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用自定的多个过滤器建立BloomFilter
|
||||
*
|
||||
* @param m M值决定BitMap的大小
|
||||
*
|
||||
* @param m M值决定BitMap的大小
|
||||
* @param filters Bloom过滤器列表
|
||||
*/
|
||||
public BitMapBloomFilter(int m, BloomFilter... filters) {
|
||||
@ -51,6 +52,7 @@ public class BitMapBloomFilter implements BloomFilter{
|
||||
|
||||
/**
|
||||
* 增加字符串到Filter映射中
|
||||
*
|
||||
* @param str 字符串
|
||||
*/
|
||||
@Override
|
||||
@ -64,6 +66,7 @@ public class BitMapBloomFilter implements BloomFilter{
|
||||
|
||||
/**
|
||||
* 是否可能包含此字符串,此处存在误判
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return 是否存在
|
||||
*/
|
||||
|
@ -984,6 +984,19 @@ public class IoUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将多部分内容写到流中
|
||||
*
|
||||
* @param out 输出流
|
||||
* @param isCloseOut 写入完毕是否关闭输出流
|
||||
* @param obj 写入的对象内容
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.3.3
|
||||
*/
|
||||
public static void writeObj(OutputStream out, boolean isCloseOut, Serializable obj) throws IORuntimeException {
|
||||
writeObjects(out, isCloseOut, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将多部分内容写到流中
|
||||
*
|
||||
|
@ -9,12 +9,12 @@ import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.digest.mac.MacEngine;
|
||||
import cn.hutool.crypto.digest.mac.MacEngineFactory;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* HMAC摘要算法<br>
|
||||
@ -37,7 +37,7 @@ public class HMac implements Serializable {
|
||||
* @param algorithm 算法 {@link HmacAlgorithm}
|
||||
*/
|
||||
public HMac(HmacAlgorithm algorithm) {
|
||||
this(algorithm, (SecretKey)null);
|
||||
this(algorithm, (Key)null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,7 +54,7 @@ public class HMac implements Serializable {
|
||||
* @param algorithm 算法 {@link HmacAlgorithm}
|
||||
* @param key 密钥
|
||||
*/
|
||||
public HMac(HmacAlgorithm algorithm, SecretKey key) {
|
||||
public HMac(HmacAlgorithm algorithm, Key key) {
|
||||
this(algorithm.getValue(), key);
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ public class HMac implements Serializable {
|
||||
* @param key 密钥
|
||||
* @since 4.5.13
|
||||
*/
|
||||
public HMac(String algorithm, SecretKey key) {
|
||||
public HMac(String algorithm, Key key) {
|
||||
this(MacEngineFactory.createEngine(algorithm, key));
|
||||
}
|
||||
|
||||
@ -223,5 +223,23 @@ public class HMac implements Serializable {
|
||||
public String digestHex(InputStream data, int bufferLength) {
|
||||
return HexUtil.encodeHexStr(digest(data, bufferLength));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取MAC算法块长度
|
||||
* @return MAC算法块长度
|
||||
* @since 5.3.3
|
||||
*/
|
||||
public int getMacLength(){
|
||||
return this.engine.getMacLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取算法
|
||||
*
|
||||
* @return 算法
|
||||
* @since 5.3.3
|
||||
*/
|
||||
public String getAlgorithm() {
|
||||
return this.engine.getAlgorithm();
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
package cn.hutool.crypto.digest.mac;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.Mac;
|
||||
import org.bouncycastle.crypto.macs.HMac;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* BouncyCastle的HMAC算法实现引擎,使用{@link Mac} 实现摘要<br>
|
||||
@ -94,4 +93,13 @@ public class BCHMacEngine implements MacEngine {
|
||||
return mac;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMacLength() {
|
||||
return mac.getMacSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return this.mac.getAlgorithmName();
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package cn.hutool.crypto.digest.mac;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* 默认的HMAC算法实现引擎,使用{@link Mac} 实现摘要<br>
|
||||
* 当引入BouncyCastle库时自动使用其作为Provider
|
||||
@ -39,7 +39,7 @@ public class DefaultHMacEngine implements MacEngine {
|
||||
* @param key 密钥
|
||||
* @since 4.5.13
|
||||
*/
|
||||
public DefaultHMacEngine(String algorithm, SecretKey key) {
|
||||
public DefaultHMacEngine(String algorithm, Key key) {
|
||||
init(algorithm, key);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------- Constructor end
|
||||
@ -61,7 +61,7 @@ public class DefaultHMacEngine implements MacEngine {
|
||||
* @return this
|
||||
* @throws CryptoException Cause by IOException
|
||||
*/
|
||||
public DefaultHMacEngine init(String algorithm, SecretKey key){
|
||||
public DefaultHMacEngine init(String algorithm, Key key){
|
||||
try {
|
||||
mac = SecureUtil.createMac(algorithm);
|
||||
if(null == key){
|
||||
@ -106,4 +106,14 @@ public class DefaultHMacEngine implements MacEngine {
|
||||
public Mac getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMacLength() {
|
||||
return mac.getMacLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return this.mac.getAlgorithm();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package cn.hutool.crypto.digest.mac;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* MAC(Message Authentication Code)算法引擎
|
||||
*
|
||||
@ -20,4 +20,18 @@ public interface MacEngine {
|
||||
* @return 摘要bytes
|
||||
*/
|
||||
byte[] digest(InputStream data, int bufferLength);
|
||||
|
||||
/**
|
||||
* 获取MAC算法块大小
|
||||
*
|
||||
* @return MAC算法块大小
|
||||
*/
|
||||
int getMacLength();
|
||||
|
||||
/**
|
||||
* 获取当前算法
|
||||
*
|
||||
* @return 算法
|
||||
*/
|
||||
String getAlgorithm();
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package cn.hutool.crypto.digest.mac;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import cn.hutool.crypto.SmUtil;
|
||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* {@link MacEngine} 实现工厂类
|
||||
*
|
||||
@ -19,7 +19,7 @@ public class MacEngineFactory {
|
||||
* @param key 密钥
|
||||
* @return {@link MacEngine}
|
||||
*/
|
||||
public static MacEngine createEngine(String algorithm, SecretKey key) {
|
||||
public static MacEngine createEngine(String algorithm, Key key) {
|
||||
if(algorithm.equalsIgnoreCase(HmacAlgorithm.HmacSM3.getValue())) {
|
||||
// HmacSM3算法是BC库实现的
|
||||
return SmUtil.createHmacSm3Engine(key.getEncoded());
|
||||
|
@ -0,0 +1,124 @@
|
||||
package cn.hutool.crypto.digest.opt;
|
||||
|
||||
import cn.hutool.crypto.digest.HMac;
|
||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||
|
||||
/**
|
||||
* <p>HMAC-based one-time passwords (HOTP) 一次性密码生成器,
|
||||
* 规范见:<a href="https://tools.ietf.org/html/rfc4226">RFC 4226</a>.</p>
|
||||
*
|
||||
* <p>参考:https://github.com/jchambers/java-otp</p>
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class HOTP {
|
||||
|
||||
/**
|
||||
* 数子量级
|
||||
*/
|
||||
private static final int[] MOD_DIVISORS = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
|
||||
/**
|
||||
* 默认密码长度.
|
||||
*/
|
||||
public static final int DEFAULT_PASSWORD_LENGTH = 6;
|
||||
|
||||
/**
|
||||
* 默认HMAC算法.
|
||||
*/
|
||||
public static final HmacAlgorithm HOTP_HMAC_ALGORITHM = HmacAlgorithm.HmacSHA1;
|
||||
|
||||
private final HMac mac;
|
||||
private final int passwordLength;
|
||||
private final int modDivisor;
|
||||
|
||||
private final byte[] buffer;
|
||||
|
||||
/**
|
||||
* 构造,使用默认密码长度和默认HMAC算法
|
||||
*/
|
||||
public HOTP(byte[] key) {
|
||||
this(DEFAULT_PASSWORD_LENGTH, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造,使用默认HMAC算法
|
||||
*
|
||||
* @param passwordLength 密码长度,可以是6,7,8
|
||||
* @param key 共享密码,RFC 4226要求最少128位
|
||||
*/
|
||||
public HOTP(int passwordLength, byte[] key) {
|
||||
this(passwordLength, HOTP_HMAC_ALGORITHM, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param passwordLength 密码长度,可以是6,7,8
|
||||
* @param algorithm HMAC算法枚举
|
||||
* @param key 共享密码,RFC 4226要求最少128位
|
||||
*/
|
||||
public HOTP(int passwordLength, HmacAlgorithm algorithm, byte[] key) {
|
||||
this.mac = new HMac(algorithm, key);
|
||||
|
||||
this.modDivisor = MOD_DIVISORS[passwordLength];
|
||||
this.passwordLength = passwordLength;
|
||||
this.buffer = new byte[this.mac.getMacLength()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成一次性密码
|
||||
*
|
||||
* @param counter 事件计数的值,8 字节的整数,称为移动因子(moving factor),
|
||||
* 可以是基于计次的动移动因子,也可以是计时移动因子
|
||||
* @return 一次性密码的int值
|
||||
*/
|
||||
public synchronized int generateOneTimePassword(final long counter) {
|
||||
// C 的整数值需要用二进制的字符串表达,比如某个事件计数为 3,
|
||||
// 则C是 "11"(此处省略了前面的二进制的数字0)
|
||||
this.buffer[0] = (byte) ((counter & 0xff00000000000000L) >>> 56);
|
||||
this.buffer[1] = (byte) ((counter & 0x00ff000000000000L) >>> 48);
|
||||
this.buffer[2] = (byte) ((counter & 0x0000ff0000000000L) >>> 40);
|
||||
this.buffer[3] = (byte) ((counter & 0x000000ff00000000L) >>> 32);
|
||||
this.buffer[4] = (byte) ((counter & 0x00000000ff000000L) >>> 24);
|
||||
this.buffer[5] = (byte) ((counter & 0x0000000000ff0000L) >>> 16);
|
||||
this.buffer[6] = (byte) ((counter & 0x000000000000ff00L) >>> 8);
|
||||
this.buffer[7] = (byte) (counter & 0x00000000000000ffL);
|
||||
|
||||
final byte[] digest = this.mac.digest(this.buffer);
|
||||
|
||||
return truncate(digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* 截断
|
||||
*
|
||||
* @param digest HMAC的hash值
|
||||
* @return 截断值
|
||||
*/
|
||||
private int truncate(byte[] digest) {
|
||||
final int offset = digest[digest.length - 1] & 0x0f;
|
||||
return ((digest[offset] & 0x7f) << 24 |
|
||||
(digest[offset + 1] & 0xff) << 16 |
|
||||
(digest[offset + 2] & 0xff) << 8 |
|
||||
(digest[offset + 3] & 0xff)) %
|
||||
this.modDivisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密码长度,可以是6,7,8
|
||||
*
|
||||
* @return 密码长度,可以是6,7,8
|
||||
*/
|
||||
public int getPasswordLength() {
|
||||
return this.passwordLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取HMAC算法
|
||||
*
|
||||
* @return HMAC算法
|
||||
*/
|
||||
public String getAlgorithm() {
|
||||
return this.mac.getAlgorithm();
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* OTP 是 One-Time Password的简写,表示一次性密码。
|
||||
* <p>
|
||||
* 计算OTP串的公式:
|
||||
* <pre>
|
||||
* OTP(K,C) = Truncate(HMAC-SHA-1(K,C))
|
||||
* K:表示秘钥串
|
||||
* C:是一个数字,表示随机数
|
||||
* Truncate:是一个函数,就是怎么截取加密后的串,并取加密后串的哪些字段组成一个数字。
|
||||
* </pre>
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package cn.hutool.crypto.digest.opt;
|
Loading…
Reference in New Issue
Block a user