totp 是基於時間的一次性密碼生成演算法,它由 rfc 6238 定義。和基於事件的一次性密碼生成演算法不同 hotp,totp 是基於時間的,它和 hotp 具有如下關係:
totp = hotp(k, t)
hotp(k,c) = truncate(hmac-sha-1(k,c))
其中:
totp 演算法是基於 hotp 的,對於 hotp 演算法來說,hotp 的輸入一致時始終輸出相同的值,而 totp 是基於時間來算出來的乙個值,可以在一段時間內(官方推薦是30s)保證這個值是固定以實現,在一段時間內始終是同乙個值,以此來達到基於時間的一次性密碼生成演算法,使用下來整體還不錯,有個小問題,如果需要實現乙個密碼只能驗證一次需要自己在業務邏輯裡實現,只能自己實現,totp 只負責生成和驗證。
實現**
using system;
using system.security.cryptography;
using system.text;
namespace weihanli.totp
public totp(otphashalgorithm otphashalgorithm, int codesize)
_codesize = codesize;
}private static readonly encoding encoding = new utf8encoding(false, true);
public virtual string compute(string securitytoken) => compute(encoding.getbytes(securitytoken));
public virtual string compute(byte securitytoken) => compute(securitytoken, getcurrenttimestepnumber());
private string compute(byte securitytoken, long counter)
using (hmac)
// see
var hashresult = hmac.computehash(stepbytes);
var offset = hashresult[hashresult.length - 1] & 0xf;
var p = "";
for (var i = 0; i < 4; i++)
var num = convert.toint64(p, 16) & 0x7fffffff;
//var binarycode = (hashresult[offset] & 0x7f) << 24
// | (hashresult[offset + 1] & 0xff) << 16
// | (hashresult[offset + 2] & 0xff) << 8
// | (hashresult[offset + 3] & 0xff);
return (num % (int)math.pow(10, _codesize)).tostring();}}
public virtual bool verify(string securitytoken, string code) => verify(encoding.getbytes(securitytoken), code);
public virtual bool verify(string securitytoken, string code, timespan timetoleration) => verify(encoding.getbytes(securitytoken), code, timetoleration);
public virtual bool verify(byte securitytoken, string code) => verify(securitytoken, code, timespan.zero);
public virtual bool verify(byte securitytoken, string code, timespan timetoleration)
var totp = compute(securitytoken, step + i);
if (totp == code)
}return false;
}private static readonly datetime _unixepoch = new datetime(1970, 1, 1, 0, 0, 0, datetimekind.utc);
/// /// timestep
/// 30s(recommend)
///
private static readonly long _timestepticks = timespan.tickspersecond * 30;
// more info:
private static long getcurrenttimestepnumber()}}
使用方式:
var otp = new totp(otphashalgorithm.sha1, 4); // 使用 sha1演算法,輸出4位
var secretkey = "12345678901234567890";
var output = otp.compute(secretkey);
console.writeline($"output: ");
thread.sleep(1000 * 30);
var verifyresult = otp.verify(secretkey, output); // 使用預設的驗證方式,30s內有效
console.writeline($"verify result: ");
verifyresult = otp.verify(secretkey, output, timespan.fromseconds(60)); // 指定可容忍的時間差,60s內有效
console.writeline($"verify result: ");
輸出示例:
C及C 中typedef的簡單使用介紹
typedef 宣告程式設計客棧,簡稱 typedef,為現有型別建立乙個新的名字。比如人們常常使用 typedef 來編寫更美觀和可讀的 所謂美觀,意指 typedef 能隱藏笨拙的語法構造以及平台相關的資料型別,從而增強可移植性和以及未來的可維護性。在程式設計中使用typedef目的一般有兩個,...
c 建構函式介紹及實現
假期 2020.02 02學習總結資源 於中國大學mooc,c語言中文網 類的建構函式是類的一種特殊的成員函式,它會在每次建立類的新物件時執行。系統預設建構函式 預設的建構函式沒有任何引數 class complex 編譯器自動生成預設建構函式 complex c1 預設建構函式被呼叫 comple...
演算法 插入排序的簡單介紹及實現
插入排序是一種穩定的原址排序演算法,這意味著它不會改變輸入時就已有序的元素之間的順序。它的基本思想是 選定乙個元素,將它像一張牌從牌堆裡抽出,與它前面的元素一一比較,找到合適的位置,然後插入。由於該選定元素的位置可能將被其它元素所佔據,所以每次比較都應將所有該選定元素之前的元素向選定元素留下的空位移...