]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
totp: Add scripts/totp/totp-gen.py sample
authorJorge Pereira <jpereira@freeradius.org>
Thu, 14 Sep 2023 03:19:28 +0000 (00:19 -0300)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 27 Sep 2023 13:14:55 +0000 (09:14 -0400)
It's helpful to validate rlm_totp in realtime.

scripts/totp/totp-gen.py [new file with mode: 0755]

diff --git a/scripts/totp/totp-gen.py b/scripts/totp/totp-gen.py
new file mode 100755 (executable)
index 0000000..bd3b65b
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+# Author: Jorge Pereira <jpereira@freeradius.org>
+# Simple TOTP generator.
+
+import argparse
+import base64
+import hmac
+import struct
+import sys
+import time
+
+def hotp(key, counter, digits=6, digest='sha1'):
+    key = key.encode('ascii')
+    counter = struct.pack('>Q', counter)
+    mac = hmac.new(key, counter, digest).digest()
+    offset = mac[-1] & 0x0f
+    binary = struct.unpack('>L', mac[offset:offset+4])[0] & 0x7fffffff
+    return str(binary)[-digits:].zfill(digits)
+
+def totp(key, time_step=30, digits=6, digest='sha1'):
+    return hotp(key, int(time.time() / time_step), digits, digest)
+
+def main():
+    parser = argparse.ArgumentParser(description = "Simple TOTP token generator.")
+    parser.add_argument("-k", dest = "key", help = "Key in raw format.", required = True)
+    parser.add_argument("-t", dest = "time_step", help = "time step between time changes.", default = 30, type = int)
+    parser.add_argument("-d", dest = "digits", help = "Length of the one-time password.", default = 6, type = int)
+    parser.add_argument("-e", dest = "encode_base32", help = "Encode the output token in base32.", action='store_true')
+    parser.add_argument("-D", dest = "digest", help = "HMAC algorithm as described by RFC 2104. default: sha1, options: sha1, sha256, sha512", required = False, default = "sha1")
+    args = parser.parse_args()
+    token = totp(args.key, args.time_step, args.digits, args.digest)
+
+    if args.encode_base32:
+        token = base64.b32encode(bytearray(token, 'ascii')).decode('ascii')
+
+    print(token)
+
+if __name__ == '__main__':
+    main()