上节我们说到我们主要的算法是在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的数组了。而不同的构造函数,无非是实现方法层面的多态,传递不同的参数,得到的处理结果.
下面的源代码做的归根结底,就是这么一件事情,能够根据传递进来的时间类型来产生了相应的值输出了,当然了,这又有一些的复杂的逻辑判断了,使其不产生了相应重复的数字。
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对象来产生相应值。
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算法后值,起到一个不产生重复值的效果,提高威盾的安全性。