公司項目需求:爲局域網之外的網站後臺用戶開發動態密保的功能。
在當前的現有設備下,最方便實現的就兩種:一、經過短信獲取動態密碼登陸;二、經過手機令牌來實現。 java
主流的動態令牌技術是時間同步和挑戰/應答兩種形式。 jquery
項目採用:
https://code.google.com/p/androidtoken/ 實現TOTP動態口令登陸
android token 該項目支持HOTP (事件令牌)和TOTP (時間令牌)規範
配置令牌支持:KeyUriFormat和QR碼,以及手動建立;
項目實現:
我這裏採用添加方便的qr碼,也就是常見的二維碼來實現用戶經過手機來綁定一個token;
首先,須要有的就是服務器端和客戶端都共有的一個seed。 android
private final static String NUM_CHAR = "0123456789"; private static int charLen = NUM_CHAR.length(); /** * 根據系統時間得到指定位數的隨機數 * @param randomNumberDigit 隨機數的位數 * @return 得到的隨機數 */ public static String getRandomNumber(int randomNumberDigit) { long seed = System.currentTimeMillis();// 得到系統時間,做爲生成隨機數的種子 StringBuffer sb = new StringBuffer();// 裝載生成的隨機數 Random random = new Random(seed);// 調用種子生成隨機數 for (int i = 0; i < randomNumberDigit; i++) { sb.append(NUM_CHAR.charAt(random.nextInt(charLen))); } return sb.toString(); }
經過http://www.oschina.net/p/jquery-qrcode-js能夠很方便的生成二維碼。
二維碼的內容
otpauth://totp/oa?secret=63985989418859891633&period=60&digits=8(android 支持這個協議,能直接掃描讀取,添加一個token)
secret:密鑰,也就是上面生成的seed;period:每60秒生成一次;digits:生成的隨機碼長度。
經過動態口令驗證之後,服務器端也保存上seed;須要登錄的時候,服務器端生成動態口令和手機的來次對比就好了。 git
服務器端生成動態密碼的方法: 算法
/** * 每60秒生成1個8位動態密碼 * * @param seed * @return */ public static String getTOTP(String seed) { long T0 = 0; long X = 60; Calendar cal = Calendar.getInstance(); long time = cal.getTimeInMillis() / 1000; String steps = "0"; try { long T = (time - T0) / X; steps = Long.toHexString(T).toUpperCase(); while (steps.length() < 16) steps = "0" + steps; return generateTOTP(seed, steps, "8", "HmacSHA1"); } catch (final Exception e) { System.out.println("Error : " + e); return "生成動態口令失敗"; } }
/** * 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 * @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; }ps:直接下載的那個android token有廣告,升級一下就沒了