summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Shkardoon <ss23@ss23.geek.nz>2019-10-06 10:52:32 +0200
committerStephen Shkardoon <ss23@ss23.geek.nz>2019-10-06 10:52:32 +0200
commit361a97d88b28c65d0a658c76fd4190697323ed2e (patch)
tree0bfb331e0f156f3e19d7c2df94644c21a452ee0a
parentAdd decode-qr-uri script (diff)
downloadentrust-identityguard-tools-361a97d88b28c65d0a658c76fd4190697323ed2e.tar
entrust-identityguard-tools-361a97d88b28c65d0a658c76fd4190697323ed2e.tar.gz
entrust-identityguard-tools-361a97d88b28c65d0a658c76fd4190697323ed2e.tar.bz2
entrust-identityguard-tools-361a97d88b28c65d0a658c76fd4190697323ed2e.tar.lz
entrust-identityguard-tools-361a97d88b28c65d0a658c76fd4190697323ed2e.tar.xz
entrust-identityguard-tools-361a97d88b28c65d0a658c76fd4190697323ed2e.tar.zst
entrust-identityguard-tools-361a97d88b28c65d0a658c76fd4190697323ed2e.zip
-rw-r--r--README.md24
-rwxr-xr-xgenerate-otp.py46
2 files changed, 70 insertions, 0 deletions
diff --git a/README.md b/README.md
index 71f8659..5ca3c3a 100644
--- a/README.md
+++ b/README.md
@@ -9,3 +9,27 @@ Example:
$ ./generate-hmacs.py 'igmobileotp://?action=secactivate&enc=VRUq6IoLWQRCMRITZEHtHUSWJiPwgu%2FN1BFyUHE5kxuHIEYoE3zmNTrAHeeUM5S3gzCnTy%2F%2Bdnbu%2FsjjQW%2BNEISx8C4ra8rLpxOl8E8w4KXHgjeBRgdvSzl%2BbzX5RYRrQlWgK8hsBT4pQYE0eFgW2TmRbzXu1Mu7XjKDcwsJLew32jQC2qyPLP8hljnv2rHwwsMfhQwgJUJYfctwLWWEDUFukEckaZ4O&v=1&mac=mhVL8BWKaishMa5%2B' 54998317
{"sn":"48244-13456","ac":"1745-7712-6942-8698","policy":"{\"allowUnsecured\":\"false\",\"trustedExecution\":\"NOT_ALLOWED\"}","regurl":"myid.umc.edu\/igst"}
```
+
+# generate-otp.py
+Once you have the required information from a QR code, you can combine it with a "registration code" to derive the OTP secret. This registration code contains random bytes that were generated on the end-users device (their mobile phone), and are thus required to determine the OTP secret. An example way to obtain all of this information would be through email, if the user recieves a QR code in their email, then responds with their registration code.
+
+Example:
+```
+$ ./generate-otp.py 48244-13456 1745-7712-6942-8698 12211-49352
+9a8eab5ecc9fc413758a92ac223dc6a0
+
+To generate a code immediately, run:
+oathtool -v --totp=sha256 --digits=6 9a8eab5ecc9fc413758a92ac223dc6a0
+
+$ oathtool -v --totp=sha256 --digits=6 9a8eab5ecc9fc413758a92ac223dc6a0
+Hex secret: 9a8eab5ecc9fc413758a92ac223dc6a0
+Base32 secret: TKHKWXWMT7CBG5MKSKWCEPOGUA======
+Digits: 6
+Window size: 0
+Step size (seconds): 30
+Start time: 1970-01-01 00:00:00 UTC (0)
+Current time: 2019-10-06 08:50:31 UTC (1570351831)
+Counter: 0x31EB8E5 (52345061)
+
+814835
+```
diff --git a/generate-otp.py b/generate-otp.py
new file mode 100755
index 0000000..a931a77
--- /dev/null
+++ b/generate-otp.py
@@ -0,0 +1,46 @@
+#!/bin/env python3
+from hashlib import pbkdf2_hmac
+import argparse
+import logging
+
+logging.basicConfig(level=logging.WARNING)
+
+parser = argparse.ArgumentParser(description='Generate an OTP secret for an Entrust IdentityGuard soft token')
+parser.add_argument('Serial', type=str, nargs=1, help='Given to the user (such as through a QR code). Example: 48244-13456')
+parser.add_argument('ActivationCode', type=str, nargs=1, help='Given to the user (such as through a QR code). Example: 1745-7712-6942-8698')
+parser.add_argument('RegistrationCode', type=str, nargs=1, help='The user provides this to the activation service. Example: 12211-49352')
+args = parser.parse_args()
+
+# Remove dashes from input so we can work with the data
+serial = args.Serial[0].replace("-", "")
+activation = args.ActivationCode[0].replace("-", "")
+registration = args.RegistrationCode[0].replace("-", "")
+
+# TODO: Validate all values through the Luhn check digits
+
+activation = activation[0:-1] # remove last digit -- check digit
+activationbytes = int(activation).to_bytes(7, byteorder='big')
+logging.info("Activation bytes: 0x%s", activationbytes.hex())
+
+registration = registration[0:-1] # remove last digit -- check digit
+registrationbytes = int(registration).to_bytes(4, byteorder='big')
+logging.info("Registration bytes: 0x%s", registrationbytes.hex())
+
+# Derive the RNG output from the registration bytes
+# Remaining bits are used for validation, but we can ignore that in our case
+rngbytes = registrationbytes[-2:]
+
+logging.info("RNG Bytes: 0x%s", rngbytes.hex())
+
+# Derive the secret key
+key = pbkdf2_hmac(
+ hash_name='sha256',
+ password=activationbytes + rngbytes,
+ salt=serial.encode("utf-8"),
+ iterations=8,
+ dklen=16
+)
+
+print(key.hex())
+print("To generate a code immediately, run:")
+print("oathtool -v --totp=sha256 --digits=6 " + key.hex())