TOTP Generator

https://greatest.deepsurf.us/zh-CN/scripts/502291 脚本使用

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/511697/1471164/TOTP%20Generator.js

  1. // ==UserScript==
  2. // @name TOTP Generator
  3. // @namespace https://github.com/ChinaGodMan/UserScripts
  4. // @version 2024/10/07
  5. // @description https://greatest.deepsurf.us/zh-CN/scripts/502291 脚本使用
  6. // @author 人民的勤务员 <china.qinwuyuan@gmail.com>
  7. // @license MIT
  8. // @supportURL https://github.com/ChinaGodMan/UserScripts/issues
  9. // @homepageURL https://github.com/ChinaGodMan/UserScripts
  10. // ==/UserScript==
  11. function base32Decode(str) {
  12. const base32chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
  13. let buffer = ''
  14. for (let i = 0; i < str.length; i++) {
  15. const value = base32chars.indexOf(str[i])
  16. if (value < 0) continue
  17. buffer += value.toString(2).padStart(5, '0')
  18. }
  19. const bytes = []
  20. for (let i = 0; i < buffer.length; i += 8) {
  21. bytes.push(parseInt(buffer.substr(i, 8), 2))
  22. }
  23. return new Uint8Array(bytes)
  24. }
  25. async function hmacSHA1(key, message) {
  26. const crypto = window.crypto || window.msCrypto
  27. const keyBuffer = await crypto.subtle.importKey(
  28. "raw",
  29. key,
  30. { name: "HMAC", hash: { name: "SHA-1" } },
  31. false,
  32. ["sign"]
  33. )
  34. const signature = await crypto.subtle.sign("HMAC", keyBuffer, message)
  35. return new Uint8Array(signature)
  36. }
  37. async function generateHOTP(key, counter, digits = 6) {
  38. const counterBuffer = new ArrayBuffer(8)
  39. const view = new DataView(counterBuffer)
  40. view.setBigInt64(0, BigInt(counter), false) // Big-endian
  41. const hmac = await hmacSHA1(key, new Uint8Array(counterBuffer))
  42. const offset = hmac[hmac.length - 1] & 0x0F
  43. let dynamicPassword =
  44. (hmac[offset] & 0x7F) << 24 |
  45. (hmac[offset + 1] & 0xFF) << 16 |
  46. (hmac[offset + 2] & 0xFF) << 8 |
  47. (hmac[offset + 3] & 0xFF)
  48. dynamicPassword = dynamicPassword % Math.pow(10, digits)
  49. return dynamicPassword.toString().padStart(digits, '0')
  50. }
  51. function getCounter(timeStep = 30) {
  52. const currentTime = Math.floor(Date.now() / 1000)
  53. return Math.floor(currentTime / timeStep)
  54. }
  55. async function generateTOTP(secret, timeStep = 30, digits = 6) {
  56. const key = base32Decode(secret)
  57. const counter = getCounter(timeStep)
  58. const totp = await generateHOTP(key, counter, digits)
  59. return totp
  60. }
  61.