博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用aerogear生成totp
阅读量:6669 次
发布时间:2019-06-25

本文共 4624 字,大约阅读时间需要 15 分钟。

本文主要讲述一下如何使用aerogear-otp生成otp,以及相关源码分析

otp分类

全称是one time password,通常用来支持双因素认证。主要可以分两类

  • HMAC-Based One-time Password (HOTP) 在规范中

  • Time-based One-time Password (TOTP) 在规范中

这里主要讲TOTP

  • 客户端 其常见的手机客户端有Google Authenticator APP以及阿里云的身份宝。由于google的软件在国内被墙,因此可以使用阿里云的

  • 服务端 服务端的话,google官方有c的代码,java的话很多第三方都有实现,这里选择jboss提供的aerogear-otp-java,其maven如下

org.jboss.aerogear
aerogear-otp-java
1.0.0
复制代码

步骤

主要的步骤如下:

绑定密钥

  • 服务端为每个账户生成一个secret并保存下来
  • 服务端提供该密钥的二维码扫描功能,方便客户端扫描绑定账号
  • 用户手机安装Google Authenticator APP或阿里云的身份宝,扫描二维码绑定该账号的secret

使用otp验证

绑定secret之后,就可以使用one time password进行验证了。

实例

生成客户端密钥的二维码

String secret = Base32.random();Totp totp = new Totp(secret);String uri = totp.uri(account);复制代码

将这个uri作为二维码的信息,即可。

/**     * Prover - To be used only on the client side     * Retrieves the encoded URI to generated the QRCode required by Google Authenticator     *     * @param name Account name     * @return Encoded URI     */    public String uri(String name) {        try {            return String.format("otpauth://totp/%s?secret=%s", URLEncoder.encode(name, "UTF-8"), secret);        } catch (UnsupportedEncodingException e) {            throw new IllegalArgumentException(e.getMessage(), e);        }    }复制代码

它的格式otpauth://totp/%s?secret=%s,Google Authenticator APP或阿里云的身份宝均支持这种格式的识别。

校验

boolean isValid = totp.verify(code);复制代码

其源码如下

/**     * Verifier - To be used only on the server side     * 

* Taken from Google Authenticator with small modifications from * {@see PasscodeGenerator.java} *

* Verify a timeout code. The timeout code will be valid for a time * determined by the interval period and the number of adjacent intervals * checked. * * @param otp Timeout code * @return True if the timeout code is valid *

* Author: sweis@google.com (Steve Weis) */ public boolean verify(String otp) { long code = Long.parseLong(otp); long currentInterval = clock.getCurrentInterval(); int pastResponse = Math.max(DELAY_WINDOW, 0); for (int i = pastResponse; i >= 0; --i) { int candidate = generate(this.secret, currentInterval - i); if (candidate == code) { return true; } } return false; }复制代码

这里有个DELAY_WINDOW参数,是为了防止手机客户端与服务器端的时差引入的。默认值是1,即允许那个code在手机端过期30秒之内到服务端验证还有效。

  • clock aerogear-otp-java-1.0.0-sources.jar!/org/jboss/aerogear/security/otp/api/Clock.java
public class Clock {    private final int interval;    private Calendar calendar;    public Clock() {        interval = 30;    }    public Clock(int interval) {        this.interval = interval;    }    public long getCurrentInterval() {        calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));        long currentTimeSeconds = calendar.getTimeInMillis() / 1000;        return currentTimeSeconds / interval;    }}复制代码

这个interval默认是30,当然你也可以改为1分钟那就是60. 另外这里先把毫秒转为秒,然后再除去interval,由于是使用/,因此是直接取整数部分,因而上面的DELAY_WINDOW的值=N,其实相当于允许过去的N个interval的code还能校验成功

code生成源码

aerogear-otp-java-1.0.0-sources.jar!/org/jboss/aerogear/security/otp/Totp.java

private int generate(String secret, long interval) {        return hash(secret, interval);    }    private int hash(String secret, long interval) {        byte[] hash = new byte[0];        try {            //Base32 encoding is just a requirement for google authenticator. We can remove it on the next releases.            hash = new Hmac(Hash.SHA1, Base32.decode(secret), interval).digest();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (InvalidKeyException e) {            e.printStackTrace();        } catch (Base32.DecodingException e) {            e.printStackTrace();        }        return bytesToInt(hash);    }    private int bytesToInt(byte[] hash) {        // 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);        return binary % Digits.SIX.getValue();    }    /**     * Retrieves the current OTP     *     * @return OTP     */    public String now() {        return leftPadding(hash(secret, clock.getCurrentInterval()));    }    private String leftPadding(int otp) {        return String.format("%06d", otp);    }复制代码

小结

  • interval 默认值为30,在Clock里头可以通过构造器修改interval。不过由于Google Authenticator APP或阿里云的身份宝均为30秒更换一次,因此这个参数可以按默认的来。

  • DELAY_WINDOW aerogear-otp-java本身不提供DELAY_WINDOW的修改,不过你可以继承Totp,自己扩展一下。

doc

转载地址:http://eilxo.baihongyu.com/

你可能感兴趣的文章
as3随机数
查看>>
四种方案解决ScrollView嵌套ListView问题
查看>>
[IIS] IIS Framework "aspnet_regiis.exe" 注册
查看>>
乘法逆元模板
查看>>
为什么要优化你的代码?
查看>>
【杂文】2015年度总结
查看>>
25个可遇不可求的jQuery插件
查看>>
【LeetCode】【Python题解】Single Number &amp; Maximum Depth of Binary Tree
查看>>
uiautomatorviewer 可以查看到android中的web 元素信息
查看>>
当Scheduler拿不到url的 时候,不能立即退出
查看>>
操作系统 进程与线程 图解浅析
查看>>
coursera课程Text Retrieval and Search Engines之Week 2 Overview
查看>>
Redis和Memcache对比及选择
查看>>
HDU 1004 Let the Balloon Rise【STL<map>】
查看>>
Java千百问_05面向对象(006)_is-a,has-a,like-a是什么
查看>>
【Python】python更新数据库脚本两种方法
查看>>
linux进程同步机制_转
查看>>
PHP框架认识初步
查看>>
给 Android 初学者的 Gradle 知识普及
查看>>
分模块开发创建Action子模块——(九)
查看>>