• 仿新浪微盾客户端项目简介四


    上节我们说到我们主要的算法是在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算法后值,起到一个不产生重复值的效果,提高威盾的安全性。

  • 相关阅读:
    LeetCode44——用搜索的思路去理解动态规划算法
    在vscode中配置LeetCode插件,从此愉快地刷题
    分布式专题——详解Google levelDB底层原理
    高等数学——求解不定积分经典换元法
    动态规划入门——详解完全背包与多重背包问题
    详解聚类算法Kmeans的两大优化——mini-batch和Kmeans++
    Python专题——详解enumerate和zip
    LeetCode42题,单调栈、构造法、two pointers,这道Hard题的解法这么多?
    零基础学Python--------第11章 使用Python操作数据库
    零基础学Python--------第10章 文件及目录操作
  • 原文地址:https://www.cnblogs.com/manuosex/p/3578140.html
Copyright © 2020-2023  润新知