All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nervousync.utils.OTPUtils Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Licensed to the Nervousync Studio (NSYC) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.nervousync.utils;

import org.nervousync.commons.Globals;
import org.nervousync.exceptions.utils.DataInvalidException;

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * 

OTP(One-time Password Algorithm) Utilities

* * Current utilities implements features: *
    Calculate OTP fixed time value
*
    Generate random key
*
    Generate TOTP/HOTP Code
*
    Verify TOTP/HOTP Code
*
*

一次性密码算法工具集

* * 此工具集实现以下功能: *
    计算一次性密码算法的修正时间值
*
    生成随机密钥
*
    生成基于HMAC算法加密的一次性密码/基于时间戳算法的一次性密码值
*
    验证基于HMAC算法加密的一次性密码/基于时间戳算法的一次性密码值
*
* * @author Steven Wee [email protected] * @version $Revision: 1.1.2 $ $Date: Jun 04, 2019 10:47:28 $ */ public final class OTPUtils { /** * Logger instance * 日志实例 */ private static final LoggerUtils.Logger LOGGER = LoggerUtils.getLogger(OTPUtils.class); // Unit: Second /** * Time Step, Unit: Second * 时间步长,单位:秒 */ private static final int DEFAULT_SYNC_COUNT = 30; // Default 3, Maximum 17 (From Google Docs) /** * Default window size * 默认的最多可偏移时间 */ private static final int DEFAULT_WINDOW_SIZE = 3; /** * Default secret size * 默认的密钥长度 */ private static final int DEFAULT_SECRET_SIZE = 10; /** * Default secret seed character * 默认的密钥种子字符 */ private static final String DEFAULT_SECRET_SEED = "TmVydm91c3luY0RlZmF1bHRTZWNyZXRTZWVk"; /** * Default random algorithm * 默认的随机数算法 */ private static final String DEFAULT_RANDOM_ALGORITHM = "SHA1PRNG"; /** *

Private constructor for OTPUtils

*

一次性密码算法工具集的私有构造方法

*/ private OTPUtils() { } /** *

Calculate fixed time

*

计算修正时间

* * @param secret Secret key string * 随机密钥字符串 * @param authCode Client generated authenticate code * 客户端生成的随机验证码 * * @return Calculated fixed time * 计算出的修正时间 */ public static long calculateFixedTime(final String secret, final int authCode) { return calculateFixedTime(CalcType.HmacSHA1, secret, authCode, Globals.DEFAULT_VALUE_INT); } /** *

Calculate fixed time

*

计算修正时间

* * @param secret Secret key string * 随机密钥字符串 * @param authCode Client generated authenticate code * 客户端生成的随机验证码 * @param syncCount Time Step, Unit: Second * 时间步长,单位:秒 * * @return Calculated fixed time * 计算出的修正时间 */ public static long calculateFixedTime(final String secret, final int authCode, final int syncCount) { return calculateFixedTime(CalcType.HmacSHA1, secret, authCode, syncCount); } /** *

Calculate fixed time

*

计算修正时间

* * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param authCode Client generated authenticate code * 客户端生成的随机验证码 * * @return Calculated fixed time * 计算出的修正时间 */ public static long calculateFixedTime(final CalcType calcType, final String secret, final int authCode) { return calculateFixedTime(calcType, secret, authCode, Globals.DEFAULT_VALUE_INT); } /** *

Calculate fixed time

*

计算修正时间

* * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param authCode Client generated authenticate code * 客户端生成的随机验证码 * @param syncCount Time Step, Unit: Second * 时间步长,单位:秒 * * @return Calculated fixed time * 计算出的修正时间 */ public static long calculateFixedTime(final CalcType calcType, final String secret, final int authCode, final int syncCount) { for (int i = -12 ; i <= 12 ; i++) { long fixedTime = i * 60 * 60 * 1000L; if (validateTOTPCode(authCode, calcType, secret, fixedTime, syncCount, Globals.INITIALIZE_INT_VALUE)) { return fixedTime; } } return Globals.DEFAULT_VALUE_INT; } /** *

Generate TOTP(Time-based One-time Password) code

*

生成基于时间的一次性密码

* * @param secret Secret key string * 随机密钥字符串 * * @return Generated code * 生成的一次性密码 */ public static String generateTOTPCode(final String secret) { return generateTOTPCode(CalcType.HmacSHA1, secret, Globals.INITIALIZE_INT_VALUE, Globals.DEFAULT_VALUE_INT); } /** *

Generate TOTP(Time-based One-time Password) code

*

生成基于时间的一次性密码

* * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * * @return Generated code * 生成的一次性密码 */ public static String generateTOTPCode(final String secret, final long fixedTime) { return generateTOTPCode(CalcType.HmacSHA1, secret, fixedTime, Globals.DEFAULT_VALUE_INT); } /** *

Generate TOTP(Time-based One-time Password) code

*

生成基于时间的一次性密码

* * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * @param syncCount Time Step, Unit: Second * 时间步长,单位:秒 * * @return Generated code * 生成的一次性密码 */ public static String generateTOTPCode(final String secret, final long fixedTime, final int syncCount) { return generateTOTPCode(CalcType.HmacSHA1, secret, fixedTime, syncCount); } /** *

Generate TOTP(Time-based One-time Password) code

*

生成基于时间的一次性密码

* * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * * @return Generated code * 生成的一次性密码 */ public static String generateTOTPCode(final CalcType calcType, final String secret, final long fixedTime) { return generateTOTPCode(calcType, secret, fixedTime, Globals.DEFAULT_VALUE_INT); } /** *

Generate TOTP(Time-based One-time Password) code

*

生成基于时间的一次性密码

* * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * @param syncCount Time Step, Unit: Second * 时间步长,单位:秒 * * @return Generated code * 生成的一次性密码 */ public static String generateTOTPCode(final CalcType calcType, final String secret, final long fixedTime, final int syncCount) { int authCode = OTPUtils.generateTOTPCode(calcType, secret, fixedTime, syncCount, Globals.INITIALIZE_INT_VALUE); if (authCode == Globals.DEFAULT_VALUE_INT) { return Globals.DEFAULT_VALUE_STRING; } StringBuilder returnCode = new StringBuilder(Integer.toString(authCode)); while (returnCode.length() < 6) { returnCode.insert(0, "0"); } return returnCode.toString(); } /** *

Validate TOTP(Time-based One-time Password) code

*

验证基于时间的一次性密码

* * @param authCode Authenticate code * 需要验证的一次性密码 * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * * @return Validate result * 验证结果 */ public static boolean validateTOTPCode(final int authCode, final String secret, final long fixedTime) { return validateTOTPCode(authCode, CalcType.HmacSHA1, secret, fixedTime, Globals.DEFAULT_VALUE_INT, Globals.DEFAULT_VALUE_INT); } /** *

Validate TOTP(Time-based One-time Password) code

*

验证基于时间的一次性密码

* * @param authCode Authenticate code * 需要验证的一次性密码 * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * @param fixWindow Fix window size * 最多可偏移时间 * * @return Validate result * 验证结果 */ public static boolean validateTOTPCode(final int authCode, final String secret, final long fixedTime, final int fixWindow) { return validateTOTPCode(authCode, CalcType.HmacSHA1, secret, fixedTime, Globals.DEFAULT_VALUE_INT, fixWindow); } /** *

Validate TOTP(Time-based One-time Password) code

*

验证基于时间的一次性密码

* * @param calcType Calculate type * 密码算法类型 * @param authCode Authenticate code * 需要验证的一次性密码 * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * @param fixWindow Fix window size * 最多可偏移时间 * * @return Validate result * 验证结果 */ public static boolean validateTOTPCode(final int authCode, final CalcType calcType, final String secret, final long fixedTime, final int syncCount, final int fixWindow) { if (authCode > Globals.INITIALIZE_INT_VALUE) { int minWindow = fixWindow < 0 ? (-1 * DEFAULT_WINDOW_SIZE) : (-1 * fixWindow); int maxWindow = fixWindow < 0 ? DEFAULT_WINDOW_SIZE : fixWindow; for (int i = minWindow ; i <= maxWindow ; i++) { int generateCode = generateTOTPCode(calcType, secret, fixedTime, syncCount, i); if (generateCode == authCode) { return true; } } } return Boolean.FALSE; } /** *

Generate HOTP(HMAC-based One-time Password) code

*

生成基于HMAC算法加密的一次性密码

* * @param secret Secret key string * 随机密钥字符串 * @param randomCode Random number * 随机数 * * @return Generated code * 生成的一次性密码 */ public static int generateHOTPCode(final String secret, final long randomCode) { return generateCode(CalcType.HmacSHA1, secret, randomCode); } /** *

Generate HOTP(HMAC-based One-time Password) code

*

生成基于HMAC算法加密的一次性密码

* * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param randomCode Random number * 随机数 * * @return Generated code * 生成的一次性密码 */ public static int generateHOTPCode(final CalcType calcType, final String secret, final long randomCode) { return generateCode(calcType, secret, randomCode); } /** *

Validate HOTP(HMAC-based One-time Password) code

*

验证基于HMAC算法加密的一次性密码

* * @param authCode Authenticate code * 需要验证的一次性密码 * @param secret Secret key string * 随机密钥字符串 * @param randomCode Random number * 随机数 * * @return Validate result * 验证结果 */ public static boolean validateHOTPCode(final int authCode, final String secret, final long randomCode) { return authCode > Globals.INITIALIZE_INT_VALUE ? authCode == generateHOTPCode(CalcType.HmacSHA1, secret, randomCode) : Boolean.FALSE; } /** *

Validate HOTP(HMAC-based One-time Password) code

*

验证基于HMAC算法加密的一次性密码

* * @param authCode Authenticate code * 需要验证的一次性密码 * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param randomCode Random number * 随机数 * * @return Validate result * 验证结果 */ public static boolean validateHOTPCode(final int authCode, final CalcType calcType, final String secret, final long randomCode) { return authCode > Globals.INITIALIZE_INT_VALUE ? authCode == generateHOTPCode(calcType, secret, randomCode) : Boolean.FALSE; } /** *

Generate random secret key string

*

生成随机的密码字符串

* * @return Generated secret key string * 生成的密码字符串 */ public static String generateRandomKey() { return generateRandomKey(DEFAULT_RANDOM_ALGORITHM, DEFAULT_SECRET_SEED, Globals.DEFAULT_VALUE_INT); } /** *

Generate random secret key string

*

生成随机的密码字符串

* * @param size Secret size * 密钥长度 * * @return Generated secret key string * 生成的密码字符串 */ public static String generateRandomKey(final int size) { return generateRandomKey(DEFAULT_RANDOM_ALGORITHM, DEFAULT_SECRET_SEED, size); } /** *

Generate random secret key string

*

生成随机的密码字符串

* * @param algorithm Secure random algorithm * 安全随机数算法 * @param seed Secret seed character * 密钥种子字符 * @param size Secret size * 密钥长度 * * @return Generated secret key string * 生成的密码字符串 */ public static String generateRandomKey(final String algorithm, final String seed, final int size) { String randomKey = null; try { SecureRandom secureRandom = StringUtils.notBlank(algorithm) ? SecureRandom.getInstance(algorithm) : SecureRandom.getInstance(DEFAULT_RANDOM_ALGORITHM); if (StringUtils.notBlank(seed)) { secureRandom.setSeed(StringUtils.base64Decode(seed)); } byte[] randomKeyBytes = secureRandom.generateSeed(size == Globals.DEFAULT_VALUE_INT ? DEFAULT_SECRET_SIZE : size); randomKey = StringUtils.base32Encode(randomKeyBytes, Boolean.FALSE); } catch (NoSuchAlgorithmException e) { LOGGER.error("Random_Key_Generate_OTP_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } } return randomKey; } /** *

Generate TOTP(Time-based One-time Password) code

*

生成基于时间的一次性密码

* * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param fixedTime Client fixed time * 客户端的修正时间 * @param syncCount Time Step, Unit: Second * 时间步长,单位:秒 * @param fixWindow Fix window size * 最多可偏移时间 * * @return Generated code * 生成的一次性密码 */ private static int generateTOTPCode(final CalcType calcType, final String secret, final long fixedTime, final int syncCount, final int fixWindow) { long currentTime = DateTimeUtils.currentTimeMillis(); long calcTime = (currentTime + fixedTime) / 1000L; if (syncCount > 0) { calcTime /= syncCount; } else { calcTime /= DEFAULT_SYNC_COUNT; } calcTime += fixWindow; return generateCode(calcType, secret, calcTime); } /** *

Generate OTP(One-time Password) code

*

生成基于时间的一次性密码

* * @param calcType Calculate type * 密码算法类型 * @param secret Secret key string * 随机密钥字符串 * @param randomCode Random number * 随机数 * * @return Generated code * 生成的一次性密码 */ private static int generateCode(final CalcType calcType, final String secret, long randomCode) { byte[] signData = new byte[8]; try { RawUtils.writeLong(signData, randomCode); } catch (DataInvalidException e) { LOGGER.error("Process_Signature_Data_OTP_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } return Globals.DEFAULT_VALUE_INT; } byte[] secretBytes = StringUtils.base32Decode(secret); byte[] hash; switch (calcType) { case HmacSHA1: hash = SecurityUtils.HmacSHA1(secretBytes, signData); break; case HmacSHA256: hash = SecurityUtils.HmacSHA256(secretBytes, signData); break; case HmacSHA512: hash = SecurityUtils.HmacSHA512(secretBytes, signData); break; default: return Globals.DEFAULT_VALUE_INT; } int offset = hash[hash.length - 1] & 0xF; long resultCode = 0L; for (int i = 0 ; i < 4 ; ++i) { resultCode = (resultCode << 8) | (hash[offset + i] & 0xFF); } resultCode &= 0x7FFFFFFF; resultCode %= 1000000; return (int)resultCode; } /** *

Enumeration of Calculate type

*

密码算法类型枚举

*/ public enum CalcType { HmacSHA1, HmacSHA256, HmacSHA512 } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy