zoukankan      html  css  js  c++  java
  • TOTP算法 基于时间的一次性密码

    /**
    Copyright (c) 2011 IETF Trust and the persons identified as
    authors of the code. All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, is permitted pursuant to, and subject to the license
    terms contained in, the Simplified BSD License set forth in Section
    4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
    (http://trustee.ietf.org/license-info).
     */
    
    import java.lang.reflect.UndeclaredThrowableException;
    import java.security.GeneralSecurityException;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.math.BigInteger;
    import java.util.TimeZone;
    
    /**
     * This is an example implementation of the OATH TOTP algorithm. Visit
     * www.openauthentication.org for more information.
     * 
     * @author Johan Rydell, PortWise, Inc.
     */
    
    public class TOTP {
    
    	private TOTP() {
    	}
    
    	/**
    	 * This method uses the JCE to provide the crypto algorithm. HMAC computes a
    	 * Hashed Message Authentication Code with the crypto hash algorithm as a
    	 * parameter.
    	 * 
    	 * @param crypto
    	 *            : the crypto algorithm (HmacSHA1, HmacSHA256, HmacSHA512)
    	 * @param keyBytes
    	 *            : the bytes to use for the HMAC key
    	 * @param text
    	 *            : the message or text to be authenticated
    	 */
    	private static byte[] hmac_sha(String crypto, byte[] keyBytes, byte[] text) {
    		try {
    			Mac hmac;
    			hmac = Mac.getInstance(crypto);
    			SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
    			hmac.init(macKey);
    			return hmac.doFinal(text);
    		} catch (GeneralSecurityException gse) {
    			throw new UndeclaredThrowableException(gse);
    		}
    	}
    
    	/**
    	 * This method converts a HEX string to Byte[]
    	 * 
    	 * @param hex
    	 *            : the HEX string
    	 * 
    	 * @return: a byte array
    	 */
    
    	private static byte[] hexStr2Bytes(String hex) {
    		// Adding one byte to get the right conversion
    		// Values starting with "0" can be converted
    		byte[] bArray = new BigInteger("10" + hex, 16).toByteArray();
    
    		// Copy all the REAL bytes, not the "first"
    		byte[] ret = new byte[bArray.length - 1];
    		for (int i = 0; i < ret.length; i++)
    			ret[i] = bArray[i + 1];
    		return ret;
    	}
    
    	private static final int[] DIGITS_POWER
    	// 0 1 2 3 4 5 6 7 8
    	= { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
    
    	/**
    	 * This method generates a TOTP value for the given set of parameters.
    	 * 
    	 * @param key
    	 *            : the shared secret, HEX encoded
    	 * @param time
    	 *            : a value that reflects a time
    	 * @param returnDigits
    	 *            : number of digits to return
    	 * 
    	 * @return: a numeric String in base 10 that includes
    	 *          {@link truncationDigits} digits
    	 */
    
    	public static String generateTOTP(String key, String time,
    			String returnDigits) {
    		return generateTOTP(key, time, returnDigits, "HmacSHA1");
    	}
    
    	/**
    	 * This method generates a TOTP value for the given set of parameters.
    	 * 
    	 * @param key
    	 *            : the shared secret, HEX encoded
    	 * @param time
    	 *            : a value that reflects a time
    	 * @param returnDigits
    	 *            : number of digits to return
    	 * 
    	 * @return: a numeric String in base 10 that includes
    	 *          {@link truncationDigits} digits
    	 */
    
    	public static String generateTOTP256(String key, String time,
    			String returnDigits) {
    		return generateTOTP(key, time, returnDigits, "HmacSHA256");
    	}
    
    	/**
    	 * This method generates a TOTP value for the given set of parameters.
    	 * 
    	 * @param key
    	 *            : the shared secret, HEX encoded
    	 * @param time
    	 *            : a value that reflects a time
    	 * @param returnDigits
    	 *            : number of digits to return
    	 * 
    	 * @return: a numeric String in base 10 that includes
    	 *          {@link truncationDigits} digits
    	 */
    
    	public static String generateTOTP512(String key, String time,
    			String returnDigits) {
    		return generateTOTP(key, time, returnDigits, "HmacSHA512");
    	}
    
    	/**
    	 * This method generates a TOTP value for the given set of parameters.
    	 * 
    	 * @param key
    	 *            : the shared secret, HEX encoded
    	 * @param time
    	 *            : a value that reflects a time
    	 * @param returnDigits
    	 *            : number of digits to return 返回长度 --6
    	 * @param crypto
    	 *            : the crypto function to use
    	 * 
    	 * @return: a numeric String in base 10 that includes
    	 *          {@link truncationDigits} digits
    	 */
    
    	public static String generateTOTP(String key, String time,
    			String returnDigits, String crypto) {
    		int codeDigits = Integer.decode(returnDigits).intValue();
    		String result = null;
    
    		// Using the counter
    		// First 8 bytes are for the movingFactor
    		// Compliant with base RFC 4226 (HOTP)
    		while (time.length() < 16)
    			time = "0" + time;
    
    		// Get the HEX in a Byte[]
    		byte[] msg = hexStr2Bytes(time);
    		byte[] k = hexStr2Bytes(key);
    		byte[] hash = hmac_sha(crypto, k, msg);
    
    		// put selected bytes into result int
    		int offset = hash[hash.length - 1] & 0xf;
    
    		int binary = ((hash[offset] & 0x7f) << 24)
    				| ((hash[offset + 1] & 0xff) << 16)
    				| ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
    
    		int otp = binary % DIGITS_POWER[codeDigits];
    
    		result = Integer.toString(otp);
    		while (result.length() < codeDigits) {
    			result = "0" + result;
    		}
    		return result;
    	}
    
    	public static void main(String[] args) {
    		// Seed for HMAC-SHA1 - 20 bytes
    		String seed = "3132333435363738393031323334353637383930";
    		// Seed for HMAC-SHA256 - 32 bytes
    		String seed32 = "3132333435363738393031323334353637383930"
    				+ "313233343536373839303132";
    		// Seed for HMAC-SHA512 - 64 bytes
    		String seed64 = "3132333435363738393031323334353637383930"
    				+ "3132333435363738393031323334353637383930"
    				+ "3132333435363738393031323334353637383930" + "31323334";
    		long T0 = 0;
    		long X = 30;
    		long testTime[] = { 59L, 1111111109L, 1111111111L, 1234567890L,
    				2000000000L, 20000000000L };
    
    		String steps = "0";
    		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		df.setTimeZone(TimeZone.getTimeZone("UTC"));
    		try {
    			System.out.println("+---------------+-----------------------+"
    					+ "------------------+--------+--------+");
    			System.out.println("|  Time(sec)    |   Time (UTC format)   "
    					+ "| Value of T(Hex)  |  TOTP  | Mode   |");
    			System.out.println("+---------------+-----------------------+"
    					+ "------------------+--------+--------+");
    
    			for (int i = 0; i < testTime.length; i++) {
    				long T = (testTime[i] - T0) / X;
    				steps = Long.toHexString(T).toUpperCase();
    				while (steps.length() < 16)
    					steps = "0" + steps;
    				String fmtTime = String.format("%1$-11s", testTime[i]);
    				String utcTime = df.format(new Date(testTime[i] * 1000));
    				// seed
    				System.out.print("|  " + fmtTime + "  |  " + utcTime + "  | "
    						+ steps + " |");
    				System.out.println(generateTOTP(seed, steps, "8", "HmacSHA1")
    						+ "| SHA1   |");
    
    				// seed32
    				System.out.print("|  " + fmtTime + "  |  " + utcTime + "  | "
    						+ steps + " |");
    				System.out.println(generateTOTP(seed32, steps, "8",
    						"HmacSHA256") + "| SHA256 |");
    
    				// seed64
    				System.out.print("|  " + fmtTime + "  |  " + utcTime + "  | "
    						+ steps + " |");
    				System.out.println(generateTOTP(seed64, steps, "6",
    						"HmacSHA512") + "| SHA512 |");
    
    				System.out.println("+---------------+-----------------------+"
    						+ "------------------+--------+--------+");
    			}
    		} catch (final Exception e) {
    			System.out.println("Error : " + e);
    		}
    	}
    }

  • 相关阅读:
    C盘与D盘中间有个恢复分区,导致C盘不能扩展卷解决
    Win下,QT控制台无输出解决
    QT与ECharts交互,绘制曲线图
    博客园好看的自定义主题
    Qt5之控件在初始化时就触发了槽函数的问题解决方案
    使用QCustomPlot,跟随鼠标动态显示线上点的值
    QCustomPlot下setTickLabelType()函数在新版本被移除如何解决
    记一次QT使用QAxWidget打开.html文件调用显示离线百度地图不能缩放,自定义图片不能显示解决方法
    使用QPainter绘制汽车仪表盘,动态显示
    QT下使用百度地图js,发送角度值给js使小车根据角度值调整车头方向
  • 原文地址:https://www.cnblogs.com/melons/p/5791915.html
Copyright © 2011-2022 走看看