仿新浪微盾客戶端項目簡介四

上節咱們說到咱們主要的算法是在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

相關文章
相關標籤/搜索