Memakai Algoritma HOTP & TOTP
Salah satu algoritma yang paling sering digunakan untuk menghasilkan one-time password (OTP) adalah algoritma HMAC-based one-time password (HOTP) dan Time-based one-time password (TOTP). Sebagai contoh, Google Authenticator mendukung kedua algoritma tersebut dimana HOTP disebut sebagai counter based dan TOTP disebut sebagai time based seperti yang diperlihatkan pada gambar berikut ini:
Algoritma HOTP
Algoritma HOTP lebih sering dipakai pada token perangkat keras. Algoritma ini bergantung pada nilai counter yang harus sama antara perangkat yang menghasilkan OTP dan backend yang melakukan validasi (biasanya tanpa komunikasi langsung).
RFC 4226 mendefinisikan algoritma HOTP (HMAC-Based One-Time Password) sebagai:
Agar lebih jelas, saya akan mencoba membuat kode program Go yang melakukan kalkulasi HOTP. Saya akan mulai dengan menulis kode program seperti berikut ini:
Pada kode program di atas, saya menggunakan secret k
dengan nilai "OJQWQYLTNFQWU33DNNUSCIIK"
. Walaupun bukan bagian dari RFC 4226,
Google Authenticator menggunakan versi base32 encoded dari secret yang sesungguhnya. Sebagai contoh, karena nilai secret
saya adalah rahasiajocki!!
, saya bisa mendapatkan nilai base32 encoded dengan memberikan perintah seperti berikut ini:
Hasil dari perintah di atas juga adalah nilai yang valid untuk dipakai sebagai secret key di Google Authenticator.
Nilai c
yang saya pakai berupa 1
. Sesuai spesifikasi RFC 4226, nilai ini bertipe 8 bytes (uint64
). Ini juga
merupakan nilai yang saya sertakan sebagai masukan untuk kalkulasi HMAC-SHA-1. Hasil dari kalkulasi tersebut akan disimpan
di variabel hash
. Nilai hash
selalu memiliki ukuran 160 bits (20 bytes).
Bagian berikutnya adalah melakukan konversi hash
menjadi angka singkat yang mudah diketik oleh pengguna. Sebagai contoh, untuk
menghasilkan 6 digit angka dari hash
, saya melanjutkan kode program di atas dengan menambahkan bagian berikut ini:
Pada kode program di atas, saya melakukan masking dengan 0xf
untuk mendapatkan nilai offset
dari byte paling terakhir dari hash
. Nilai ini
akan selalu berada dalam batasan 0
hingga 15
. Setelah mendapatkan nilai offset
, saya perlu mengambil nilai dari 4 byte hash
mulai dari
posisi offset
hingga offset+3
. Sebagai contoh, bila nilai offset
adalah 3
, saya akan mengambil byte di posisi 3
, 4
, 5
, 6
.
Bila nilai offset
adalah 15
, saya akan mengambil byte di posisi 15
, 16
, 17
, 18
. Saya dapat melakukannya dengan menggunakan
kode program berikut ini:
Saya melakukan masking nilai hash[offset]
dengan 0x7f
karena pada spesifikasi RFC 4226, hanya 31 bit terakhir yang diambil. Karena 4 bytes terdiri
atas 32 bit, saya perlu membuang bit pertama dari hash[offset]
. Setelah ini, saya menambahkan kode program ini untuk menerjemahkan binCode
menjadi
sebuah angka 32 bit dan menggunakan modulus untuk mendapatkan angka 6 digit:
Kode program di atas akan mengembalikan nilai 231384
sebagai token yang perlu dimasukkan oleh pengguna. Bila saya menggunakan Google Authenticator
untuk menambahkan secret key OJQWQYLTNFQWU33DNNUSCIIK
dengan tipe Counter based, saat counter bernilai 1
, saya juga akan memperoleh nilai
231384
yang sama.
Di HOTP, setiap kali saya meminta token baru, nilai counter akan ditingkatkan. Validator di sisi server dan generator HOTP perlu memiliki mekanisme untuk melakukan sinkronisasi counter (tanpa berkomunikasi secara langsung). Bila terjadi perbedaan counter yang terlalu jauh, token juga dapat dikunci untuk mencegah serangan brute-force.
Algoritma TOTP
Time-Based One-Time Password (TOTP) adalah pengembangan dari algoritma HOTP dimana penggunaan counter diganti menjadi waktu. RFC 6238 mendeklarasikan algoritma TOTP sebagai:
Nilai T
sendiri didefinisikan sebagai:
dimana nilai T0
adalah nilai awal dari Unix time yang masuk dalam perhitungan (default-nya adalah 0
) dan nilai X
adalah
nilai step dalam detik (default-nya adalah 30 detik).
Dengan demikian, saya bisa menulis algoritma TOTP sebagai:
Bila saya membandingkan hasil dari kode program di atas dengan nilai dari Google Authenticator, saya akan memperoleh hasil yang sama, seperti yang diperlihatkan pada gambar berikut ini: