上節咱們說到咱們主要的算法是在Google的一個開源項目Google Authenticator 修改的。那麼咱們窺探一下Google Authenticator的全貌。算法
咱們經過源代碼來了解,上代碼:數組
首先是一些噼裏啪啦的定義的常量,變量。安全
private static final int PASS_CODE_LENGTH = 6; static final int INTERVAL = 30; private static final int ADJACENT_INTERVALS = 1; private static final int PIN_MODULO = (int) Math.pow(10, PASS_CODE_LENGTH); // pow是求10的PASS_CODE_LENGTH次方 private final Signer signer; private final int codeLength; private final int intervalPeriod; public boolean isCreated; public long timeOffset; private Handler handler;
這些所謂的常量了,定義了他產生的的長度和時間。從這些定義的常量咱們能夠得出來這麼的結果。他是每30秒的中的時間了產生了一個不一樣的code,而且他產生的值是在000000-100000中的值。下面變量主要是判斷他是否建立了,而且由handler來異步處理相應的結果。異步
下面源代碼是一個接口和四個構造函數方法的重載。函數
interface Signer { byte[] sign(byte[] data) throws GeneralSecurityException; } public PasscodeGenerator(Mac mac) { this(mac, PASS_CODE_LENGTH, INTERVAL); } public PasscodeGenerator(final Mac mac, int passCodeLength, int interval) { this(new Signer() { public byte[] sign(byte[] data) { return mac.doFinal(data); } }, passCodeLength, interval); } public PasscodeGenerator(final Mac mac, int passCodeLength, int interval, Handler handler) { this(mac, passCodeLength, interval); this.handler = handler; } public PasscodeGenerator(Signer signer, int passCodeLength, int interval) { this.signer = signer; this.codeLength = passCodeLength; this.intervalPeriod = interval; }
這個接口是實現觀察者模式,能將byte數組轉換成簽名後到底byte的數組了。而不一樣的構造函數,無非是實現方法層面的多態,傳遞不一樣的參數,獲得的處理結果.this
下面的源代碼作的歸根結底,就是這麼一件事情,可以根據傳遞進來的時間類型來產生了相應的值輸出了,固然了,這又有一些的複雜的邏輯判斷了,使其不產生了相應重複的數字。spa
private String padOutput(int value) { String result = Integer.toString(value); for (int i = result.length(); i < codeLength; i++) { result = "0" + result; } return result; } public String generateTimeoutCode(boolean isCreated ,long timeOffset) throws GeneralSecurityException { this.timeOffset = timeOffset; this.isCreated = isCreated; return generateResponseCode(clock.getCurrentInterval()); } public String generateResponseCode(long challenge) throws GeneralSecurityException { byte[] value = ByteBuffer.allocate(8).putLong(challenge).array(); return generateResponseCode(value); } public String generateResponseCode(byte[] challenge) throws GeneralSecurityException { byte[] hash = signer.sign(challenge); int offset = hash[hash.length - 1] & 0xF; int truncatedHash = hashToInt(hash, offset) & 0x7FFFFFFF; int pinValue = truncatedHash % PIN_MODULO; return padOutput(pinValue); } private int hashToInt(byte[] bytes, int start) { DataInput input = new DataInputStream(new ByteArrayInputStream(bytes, start, bytes.length - start)); int val; try { val = input.readInt(); } catch (IOException e) { throw new IllegalStateException(e); } return val; } public boolean verifyResponseCode(long challenge, String response) throws GeneralSecurityException { String expectedResponse = generateResponseCode(challenge); return expectedResponse.equals(response); } public boolean verifyTimeoutCode(String timeoutCode) throws GeneralSecurityException { return verifyTimeoutCode(timeoutCode, ADJACENT_INTERVALS, ADJACENT_INTERVALS); } public boolean verifyTimeoutCode(String timeoutCode, int pastIntervals, int futureIntervals) throws GeneralSecurityException { long currentInterval = clock.getCurrentInterval(); String expectedResponse = generateResponseCode(currentInterval); if (expectedResponse.equals(timeoutCode)) { return true; } for (int i = 1; i <= pastIntervals; i++) { String pastResponse = generateResponseCode(currentInterval - i); if (pastResponse.equals(timeoutCode)) { return true; } } for (int i = 1; i <= futureIntervals; i++) { String futureResponse = generateResponseCode(currentInterval + i); if (futureResponse.equals(timeoutCode)) { return true; } } return false; }
下面的源代碼,是經過了colock對象來產生相應值。code
private IntervalClock clock = new IntervalClock() { public long getCurrentInterval() { long currentTimeSeconds = (System.currentTimeMillis() - timeOffset) / 1000; long count = currentTimeSeconds / getIntervalPeriod(); if (isCreated) { long i = getIntervalPeriod() - (currentTimeSeconds % getIntervalPeriod()); Message msg = new Message(); msg.what = MainActivity.UPDATE_COUNTDOWN; msg.arg1 = (int) i; handler.sendMessage(msg); } return count; } public int getIntervalPeriod() { return intervalPeriod; } }; interface IntervalClock { int getIntervalPeriod(); long getCurrentInterval(); }
觀察源代碼,咱們能夠清晰開出來,相應時間的毫秒經過整除,求摸這些基本的變化,來獲得最終的6位時間格式的值。對象
總之,經過這個類,可以獲得了hopt算法後值,起到一個不產生重複值的效果,提升威盾的安全性。blog