簡述 OPT 與 TOTP. 你知道什麼是 OTP 什麼是 TOTP… | by Chung-chun Lo | Skyler Record | Medium

簡述 OPT 與 TOTP

Chung-chun Lo
Skyler Record
Published in
6 min readSep 15, 2023

--

在這個 AI 興起資訊大爆炸的時代,資訊安全已經是大家越來越重視的一個環節,身為在跟資安相關公司工作的我來說呢如何有效的識別身份變成我們基本要解決的問題。

首先我們先來看看以往傳統如何去識別你的身份,在過去我們要登入自己的 Gmail 信箱時都會要求我們輸入帳號密碼來確認身份,但你認為只有帳號密碼就夠了嗎?

當然不夠!!只要帳號密碼不慎外流或被破解了這樣誰都可以登入你的帳號,因此 MFA(Multi-Factor Authentication)的觀念就誕生了,MFA 最常見的方法有以下幾個。

  • 打電話
  • 回答問題
  • 硬體裝置
  • OTP(One-Time Password)

打電話跟回答問題是在註冊時要綁定手機門號或是回答指定問題的答案,在進行登入驗證時只要是當時綁定的門號撥打到指定電話,或是回答當時註冊填入的問題即可。

至於 OTP 的形式就是現在常見透過 Email 或是簡訊的方式傳送一組四位數或六位數的數字,請你在指定時間內填在登入頁面。

你以為這些方式就夠安全了!?

為了強化現有的認證機制越來越多廠商或企業已經改用了 TOTP 或是 WebAuthn 等透過 FIDO2 的認可的身份認證機制。

今天我們先來聊聊 TOTP 等下次有機會我們再來探討 WebAuthn

OTP

在這裡我們就要先了解什麼是 OTP?他的運作方式為何?

OTP 是利用了 HOTP(HMAC-Based One-Tme Password)的算法所計算出來的一種一次性的密碼,公式如下。

HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

K 表示密鑰,C表示計數器 counter,利用 HOTP 取得 OTP 範例程式如下


func HotpGenerateCode(secret string, counter uint64) (string, error) {
// 將密鑰轉換為大寫形式
secret = strings.ToUpper(secret)

// 使用 base32 解碼密鑰字符串
secretBytes, err := base32.StdEncoding.DecodeString(secret)
if err != nil {
return "", fmt.Errorf("HotpGenerateCode: %s", err.Error())
}

// 創建一個 8 字節的緩衝區並將計數器值按大端序寫入其中
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, counter)

var hash = func() hash.Hash { return sha1.New() }
// 使用指定的哈希算法創建一個 HMAC 對象,並將密鑰傳入
mac := hmac.New(hash, secretBytes)

// 將計數器值添加到 HMAC 輸入
mac.Write(buf)

// 計算 HMAC 的結果
sum := mac.Sum(nil)

// 根據 HOTP 標準,從 HMAC 結果中提取一個 32 位的動態值
offset := sum[len(sum)-1] & 0xf
value := int64(((int(sum[offset]) & 0x7f) << 24) |
((int(sum[offset+1] & 0xff)) << 16) |
((int(sum[offset+2] & 0xff)) << 8) |
(int(sum[offset+3]) & 0xff))

// 獲取指定位數的驗證碼
l := opts.Digits
mod := int32(value % int64(math.Pow10(l)))
f := fmt.Sprintf("%%0%dd", l)
return fmt.Sprintf(f, mod), nil
}

TOTP(Time-based One Time Password)

TOTP 的全名是 Time-based One Time Password,有沒有覺得他的名子跟 OTP 很像呢?

如同上面所說 OTP 是基於 HOTP 算出來的一次性算法,至於 TOTP 其實也是使用了 HOTP ,只是將參數 C 換成了時間參數 T,所以公式如下

HOTP(K,C) = Truncate(HMAC-SHA-1(K,T))

至於 T 的部分並不是直接將時間戳帶入就好了, T 的計算公式如下

T = Floor((Current Unix time - T0) / X)

T0 為一個UTC的起始的時間戳 ( 1970/01/01 ),X則為 TOTP 刷新的時間通常默認為 30 秒,但也有 15 秒、60 秒等主要看廠商實作。

因此產生 TOTP 的範例如下

counter := int64(math.Floor(float64(time.Now().UTC().Unix()) / 30))
secret:="test"
totpCode,err := HotpGenerateCode(secret,counter)

驗證

有那麼 TOTP 又是如何被驗證的呢?有沒有印象當你啟動 Google 的 2FA 時他會請你下載一個 APP 並且掃描一個 QRCODE,其實現在市面上常見的幾個 APP ,如:Google Authenticator、Authy 等等的驗證器機制都是一樣的。

其實這個 QR Code 的內容包含一些 Metadata 例如:發行廠商、使用者名稱等等,但最重要的是裡面有用來產生 TOTP Code 的 Secret、period(時間間隔)、hash algorithm、TOTP Code 的長度,有了這些資訊你的 APP 也可以使用一樣的方式產生相同的 TOTP Code 。

因為擁有了 Secret 所以在相同的時間點下,APP 可以產生與 Server 一模一樣 TOTP Code,Server 就會認為你有了 Secret 跟其他相關資訊,所以你就是本人

所以請記得要用經過認可合規的 APP 來當自己的驗證器,才不會導致 secret 等重要資訊外流。

--

--