zOTP Bash - Generates/Tests One Time Pins in Bash Scripts
- Current Version : 1.0
- Author : Ze'ev Schurmann
- Git Repo : https://git.3volve.net.za/thisiszeev/zotp-bash
- Reddit : u/thisiszeev
- License : GPL3
One Time Pins generated using newOTP are unique to the minute. So from minute to minute the OTPs will be different. When using testOTP to verify an OTP, you can assign a validity time in minutes from 1 minute to 120 minutes.
You can demo zOTP Bash with the two files demo-makeotp.sh and demo-verifyotp.sh. These two files will create a time based OTP that is unique to a user and verify the same OTP against the same user. With the demo scripts the OTP is valid for 10 minutes. Run demo-makeotp.sh and give it a string unique to a hypothetical user such as an email address. Example
./demo-makeotp.sh "user@domain.tld". It will output an OTP as well as the expiry time of the OTP. Then you can run demo-verifyotp.sh and again give it the same string unique to the hypothetical user as well as the OTP. Example./demoverify.sh "user@domain.tld" 123456. Try different OTPs and different strings and see how it works. After the expiry time has passed and it enters into the next minute, the correct OTP and string will result in the output saying the OTP is invalid or expired.
Either copy and paste the functions to your project or use source /path/to/zotp.inc.sh above your main code. If you copy and paste the functions in your project, please also include the commented out text at the top of the file zotp.inc.za.
Don't forget to declare "thesalt" and "theseed" in your code before you call the functions newOTP and testOTP.
"thesalt" must be a string unique to your project or to each instance of the project. This avoids other projects getting the same OTP at the same time.
declare thesalt="Name of project or service"
Only needs to be declared once, ideally at the start of your code
"theseed" must be a string unique to the user the OTP is for. This avoids other users getting the same OTP at the same time.
declare theseed="user@domain.tld"
Needs to be declared each time the current user changes
I do plan to port these functions to Perl, Python3 and PHP. I will make sure the OTPs created in one language can be verified in another. If there is demand for other languages then I am willing to put it on my to-do list. Send me a chat request on Reddit. Or maybe you keen to do a port to another language, send me a chat request and we can chat. I will link your port in the Git Repo for this project.
function genHash
genHash will calculate a hexidecimal hash string from a provided sting of any length or format using one of several Hashing Algorithms. Outputs the hash as a string of hexadecimal digits.
Used by the functions newOTP and testOTP.
Usage: genHash "{input-string}" {hash}
{input-string} - A string of any kind. Supports ESCAPE codes such as \n \t \r \$ etc. [REQUIRED - MUST BE ENCLOSED IN SINGLE OR DOULBE QUOTES]
{hash-algorithm} - The hashing algorithm used for generating the hexadecimal hash string [OPTIONAL - Defaults to MD5 if omitted]
The above must be given in the order of input-string first and optional hash-algorithm after. The input-string is case sensitive but the hash-algorithm is not case sensitive
Example - Calculate a Blake2 Hash using a short string if text:
variablename="$(genHash "This is a short string of text." b2)"
See the file genhash-singleline.sh to see it in action
Example - Calculate a SHA512 Hash using a multiline string of text:
variablename="$(genHash "
This is the first line of text.
This is the second line of text.
This is the third line of text.
" sha512)"
See the file genhash-multiline.sh to see it in action
Supported Hashing Algorithms:
b2 - Blake2 (up to 512bit) - 128 digits - Very High Entropy - Fast
md5 - Message Digest Algorithm 5 (128bit) - 32 digits - Very Low Entropy - Fast
sha - Secure Hash Algorithm (160bit) - 40 digits - Low Entropy - Fast
sha1 - Secure Hash Algorithm (160bit) - 40 digits - Low Entropy - Fast
sha224 - Secure Hash Algorithm (224bit) - 56 digits - Medium Entropy - Slow
sha256 - Secure Hash Algorithm (256bit) - 64 digits - High Entropy - Slow
sha384 - Secure Hash Algorithm (384bit) - 96 digits - Very High Entropy - Medium
sha512 - Secure Hash Algorithm (512bit) - 128 digits - Very High Entropy - Medium
sha and sha1 are the same algorithm, but I've included both variants as some systems execute it as shasum and others as sha1sum. Not all of these algorithms are available in Bash on all systems. Please test first. The function will output an error message to the terminal and give an exit code 3 if the chosen algorithm is not found on your system.
Exit Codes:
0 - Hash successfully calculated
11 - Function encounted an error and could not calculate the Hash (No data given)
23 - Function encounted an error and could not calculate the Hash (Invalid hashing algorithm given)
29 - Function encounted an error and could not calculate the Hash (Hashing Algorithm not found)
function genOTP
genOTP will calculate an OTP using 1 to 3 hexadecimal hash strings of 32 digits or more. Outputs the OTP as text digits.
Used by the functions newOTP and testOTP.
Usage: genOTP {hash-one} {hash-two} {hash-three} {number-of-digits}
{hash-one} - A hexadecimal hash string of 32 digits or more [REQUIRED]
{hash-two} - A hexadecimal hash string of 32 digits or more [OPTIONAL - Defaults to a string of zeros equal in length to hash-one if omitted]
{hash-three} - A hexadecimal hash string of 32 digits or more [OPTIONAL - Defaults to a string of zeros equal in length to hash-one o hash-two, which ever is shorter, if omitted]
{number-of-digits} - An integer from 4 to 16 [OPTIONAL - Defaults to 6 if omitted]
The above can be given in any order and is not case sensitive**
Example - Calculate a custom 5 digit OTP using a single hash:
variablename="$(genOTP d03d5fc2f2b73c917cee8d0bc1153b5affe4a243 5)"
See the file genotp-onehash.sh to see it in action
Example - Calculate a custom 8 digit OTP using three hashes:
variablename="$(genOTP 09bf8c7563e7d577e07cca414b37c572a5e1676d 7540acafd1bb0ce0383e38859379e2c062cac45c 316fa3932ec66d9778be4df6132b4544d46ab146 8)"
See the file genotp-threehash.sh to see it in action
Exit Codes:
0 - OTP successfully calculated
11 - Function encounted an error and could not calculate OTP (No data given)
12 - Function encounted an error and could not calculate OTP (Too much data given)
13 - Function encounted an error and could not calculate OTP (Invalid data given)
72 - Function encounted an error and could not calculate OTP (Too many OTP size integers given)
81 - Function encounted an error and could not calculate OTP (No hexadecimal hash strings given)
82 - Function encounted an error and could not calculate OTP (Too many hexadecimal hash strings given)
84 - Function encounted an error and could not calculate OTP (Given hexadecimal hash string is too short)
function newOTP
newOTP will create a new OTP based on the current time (to the minute). Outputs the OTP as text digits.
Usage: newOTP {number-of-digits} {hash-algorithm}
{number-of-digits} - An integer from 4 to 16 [OPTIONAL - Defaults to 6 if omitted]
{hash-algorithm} - The hashing algorithm used for generating OTPs [OPTIONAL - Defaults to MD5 if omitted]
See comments provided in the function genHash
The above can be given in any order and is not case sensitive
Example - Create a new 7 digit OTP using Default Hashing Agorithm:
declare thesalt="Name of project or service"
declare theseed="user@domain.tld"
variablename="$(newOTP 7)"
See the file newotp-default.sh to see it in action
Example - Create a new 4 digit OTP using SHA384:
declare thesalt="Name of project or service"
declare theseed="user@domain.tld"
variablename="$(newOTP 4 sha384)"
See the file newotp-sha384.sh to see it in action
Exit Codes:
0 - OTP successfully created
12 - Function encounted an error and could not create OTP (Too much data given)
13 - Function encounted an error and could not create OTP (Invalid data given)
22 - Function encounted an error and could not create OTP (Too many hash algorithm strings given)
72 - Function encounted an error and could not create OTP (Too many OTP size integers given)
function testOTP
testOTP will verify if an OTP is still valid and correct. Outputs the text "VALID" (exit code 0) or "INVALID" (exit code 255).
Usage: testOTP {OTP} {valid-minutes} {hash-algorithm} {quiet}
{OTP} - A 4 to 16 digit OTP to be verified [REQUIRED]
{valid-minutes} - The time in minutes (from 1 to 120) the OTP is valid for [OPTIONAL - Defaults to 30 minutes if omitted]
{hash-algorithm} - The hashing algorithm used for generating OTPs [OPTIONAL - Defaults to MD5 if omitted]
See comments provided in the function genHash
{quiet} - Disables text output when verifying allowing you to rely on exit codes instead. [OPTIONAL]
You can use just the letter "q" as an alternative to "quiet"
The above can be given in any order and is not case sensitive
Example - Using text output for validation over 15 minutes
declare thesalt="Name of project or service"
declare theseed="user@domain.tld"
if [[ "$(testOTP 123456 15)" == "VALID" ]]; then
echo "OTP is valid..."
else
echo "OTP is invalid or expired..."
fi
See the file testotp-textoutput.sh to see it in action
Example - Using exit code for validation over 45 minutes
declare thesalt="Name of project or service"
declare theseed="user@domain.tld"
if testOTP 123456 45 q; then
echo "OTP is valid..."
else
echo "OTP is invalid or expired..."
fi
See the file testotp-exitcode.sh to see it in action
Exit Codes:
0 - OTP is VALID
11 - Function encounted an error and could not verify OTP (No data given)
12 - Function encounted an error and could not verify OTP (Too much data given)
13 - Function encounted an error and could not verify OTP (Invalid data given)
33 - Function encounted an error and could not verify OTP (Too many hash algorithm strings given)
41 - Function encounted an error and could not verify OTP (No OTP given)
43 - Function encounted an error and could not verify OTP (Too many OTPs given)
53 - Function encounted an error and could not verify OTP (Too many minute integers given)
55 - Function encounted an error and could not verify OTP (Minute integer given to high)
63 - Function encounted an error and could not verify OTP (Too many "quiet" strings given)
255 - OTP is INVALID or EXPIRED