520 lines
21 KiB
Bash
520 lines
21 KiB
Bash
#!/bin/bash
|
|
|
|
## zOTP Bash - Generates/Tests One Time Pins in Bash Scripts
|
|
## 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.
|
|
##
|
|
## 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 this commented out text.
|
|
##
|
|
## 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.
|
|
## Example:
|
|
## 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.
|
|
## Example:
|
|
## 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 cmdAwk1 {
|
|
## cmdAwk1 is a pre/post command pipeline used by the function genHash.
|
|
awk '{print $1}'
|
|
}
|
|
|
|
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**
|
|
##
|
|
## Examples:
|
|
## Calculate a Blake2 Hash using a short string if text:
|
|
## variablename="$(genHash "This is a short string of text." b2)"
|
|
##
|
|
## 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)"
|
|
##
|
|
## 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)
|
|
|
|
local -A hashcmds=(
|
|
[b2]="b2sum"
|
|
[md5]="md5sum"
|
|
[sha]="shasum"
|
|
[sha1]="sha1sum"
|
|
[sha224]="sha224sum"
|
|
[sha256]="sha256sum"
|
|
[sha384]="sha384sum"
|
|
[sha512]="sha512sum"
|
|
)
|
|
|
|
local -A precmds=(
|
|
[b2]=""
|
|
[md5]=""
|
|
[sha]=""
|
|
[sha1]=""
|
|
[sha224]=""
|
|
[sha256]=""
|
|
[sha384]=""
|
|
[sha512]=""
|
|
)
|
|
|
|
local -A postcmds=(
|
|
[b2]="cmdAwk1"
|
|
[md5]="cmdAwk1"
|
|
[sha]="cmdAwk1"
|
|
[sha1]="cmdAwk1"
|
|
[sha224]="cmdAwk1"
|
|
[sha256]="cmdAwk1"
|
|
[sha384]="cmdAwk1"
|
|
[sha512]="cmdAwk1"
|
|
)
|
|
|
|
if [[ -z "${1}" ]]; then
|
|
echo "ERROR: function genHash - No data given... Must give string input..." >&2
|
|
return 11
|
|
fi
|
|
|
|
if [[ -z "${2}" ]]; then
|
|
local hashcmd="md5sum"
|
|
local precmd=""
|
|
local postcmd="cmdAwk1"
|
|
else
|
|
if [[ -z "${hashcmds[${2,,}]}" ]]; then
|
|
echo "ERROR: function genHash - Invalid hashing algorithm given..." >&2
|
|
return 23
|
|
else
|
|
local hashcmd="${hashcmds[${2,,}]}"
|
|
local precmd="${precmds[${2,,}]}"
|
|
local postcmd="${postcmds[${2,,}]}"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$(whereis "${hashcmd}" | awk '{print $2}')" ]]; then
|
|
echo "ERROR: function genHash - Hashing Algorithm not found... ${hashcmd} is not supported on this system..." >&2
|
|
return 29
|
|
fi
|
|
|
|
if [[ -z "${precmd}" ]] && [[ -z "${postcmd}" ]]; then
|
|
echo -e "${1}" | ${hashcmd}
|
|
elif [[ -z "${precmd}" ]] && [[ -n "${postcmd}" ]]; then
|
|
echo -e "${1}" | ${hashcmd} | ${postcmd}
|
|
elif [[ -n "${precmd}" ]] && [[ -z "${postcmd}" ]]; then
|
|
echo -e "${1}" | ${precmd} | ${hashcmd}
|
|
elif [[ -n "${precmd}" ]] && [[ -n "${postcmd}" ]]; then
|
|
echo -e "${1}" | ${precmd} | ${hashcmd} | ${postcmd}
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
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**
|
|
##
|
|
## Examples:
|
|
## Calculate a custom 5 digit OTP using a single hash:
|
|
## variablename="$(genOTP d03d5fc2f2b73c917cee8d0bc1153b5affe4a243 5)"
|
|
##
|
|
## Calculate a custom 8 digit OTP using three hashes:
|
|
## variablename="$(genOTP 09bf8c7563e7d577e07cca414b37c572a5e1676d 7540acafd1bb0ce0383e38859379e2c062cac45c 316fa3932ec66d9778be4df6132b4544d46ab146 8)"
|
|
##
|
|
## 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)
|
|
|
|
local optdigits=1
|
|
local opthashes=3
|
|
local digits=6
|
|
local -a hashes
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
echo "ERROR: function genOTP - No data given... Must give at least one hexadecimal hash string of at least 32 digits..." >&2
|
|
return 11
|
|
fi
|
|
|
|
while [ $# -gt 0 ]; do
|
|
if [[ ${optdigits} -eq 0 ]] && [[ ${opthashes} -eq 0 ]]; then
|
|
echo "ERROR: function genOTP - Too much data given... Only one integer from 4 to 16 for number of OTP digits and one to three hexadecimal hash strings of 32 digits or more can be given..." >&2
|
|
return 12
|
|
fi
|
|
if [[ "${1}" =~ ^([4-9]|1[0-6])$ ]]; then
|
|
if [[ ${optdigits} -gt 0 ]]; then
|
|
digits=${1}
|
|
((optdigits--))
|
|
else
|
|
echo "ERROR: function genOTP - Too many OTP size integers given... Only one integer from 4 to 16 for number of OTP digits can be given..." >&2
|
|
return 72
|
|
fi
|
|
elif [[ "${1}" =~ ^[0-9a-fA-F]+$ ]]; then
|
|
if [[ ${opthashes} -gt 0 ]]; then
|
|
if [[ ${#1} -lt 32 ]]; then
|
|
echo "ERROR: function genOTP - Given hexadecimal hash string is too short... Only hexadecimal hash strings of 32 digits or more can be given..." >&2
|
|
return 84
|
|
fi
|
|
hashes+=("${1,,}")
|
|
((opthashes--))
|
|
else
|
|
echo "ERROR: function genOTP - Too many hexadecimal hash strings given... Only one to three hexadecimal hash strings of 32 digits or more can be given..." >&2
|
|
return 82
|
|
fi
|
|
elif [[ "${1}" == "" ]]; then
|
|
local donothing=0
|
|
else
|
|
echo "ERROR: function genOTP - Invalid data given... Only one integer from 4 to 16 for number of OTP digits and one to three hexadecimal hash strings of 32 digits or more can be given..." >&2
|
|
return 13
|
|
fi
|
|
shift
|
|
done
|
|
|
|
if [[ ${#hashes[@]} -eq 0 ]]; then
|
|
echo "ERROR: function genOTP - No hexadecimal hash strings given... Must give at least one hexadecimal string of at least 32 digits..." >&2
|
|
return 81
|
|
fi
|
|
|
|
local hashlength=${#hashes[0]}
|
|
|
|
while [[ ${#hashes[@]} -lt 3 ]]; do
|
|
hashes+=("$(printf '%0*d\n' "${hashlength}" 0)")
|
|
done
|
|
|
|
local n
|
|
|
|
for ((n=1; n<3; n++)); do
|
|
if [[ ${#hashes[${n}]} -lt ${hashlength} ]]; then
|
|
hashlength=${#hashes[${n}]}
|
|
fi
|
|
done
|
|
|
|
local -A hex2dec=(
|
|
[0]=0
|
|
[1]=1
|
|
[2]=2
|
|
[3]=3
|
|
[4]=4
|
|
[5]=5
|
|
[6]=6
|
|
[7]=7
|
|
[8]=8
|
|
[9]=9
|
|
[a]=10
|
|
[b]=11
|
|
[c]=12
|
|
[d]=13
|
|
[e]=14
|
|
[f]=15
|
|
)
|
|
|
|
local -a values
|
|
local position
|
|
local sum
|
|
|
|
for ((position=0; position<hashlength; position++)); do
|
|
(( sum =
|
|
hex2dec[${hashes[0]:position:1}] +
|
|
hex2dec[${hashes[1]:position:1}] +
|
|
hex2dec[${hashes[2]:position:1}]
|
|
))
|
|
(( value = (sum + sum % 3 + 1) % 16 ))
|
|
values+=(${value})
|
|
done
|
|
|
|
local offset=$((hashlength/digits))
|
|
local value
|
|
|
|
for ((digit=0; digit<digits; digit++)); do
|
|
value=0
|
|
for ((position=0; position<offset; position++)); do
|
|
value=$((value+${values[$((position*digits+digit))]}))
|
|
done
|
|
value=$((value%10))
|
|
echo -n ${value}
|
|
done
|
|
echo
|
|
|
|
return 0
|
|
}
|
|
|
|
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**
|
|
##
|
|
## Examples:
|
|
## 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)"
|
|
##
|
|
## Create a new 4 digit OTP using SHA384:
|
|
## declare thesalt="Name of project or service"
|
|
## declare theseed="user@domain.tld"
|
|
## variablename="$(newOTP 4 sha384)"
|
|
##
|
|
## 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)
|
|
|
|
local optdigits=1
|
|
local optsums=1
|
|
local digits=6
|
|
local hashsum="md5"
|
|
|
|
while [ $# -gt 0 ]; do
|
|
if [[ ${optdigits} -eq 0 ]] && [[ ${optsums} -eq 0 ]]; then
|
|
echo "ERROR: function newOTP - Too much data given... Only one integer from 4 to 16 for number of OTP digits and one string of 2 characters or more for Hash Algorithm can be given..." >&2
|
|
return 12
|
|
fi
|
|
if [[ "${1}" =~ ^([4-9]|1[0-6])$ ]]; then
|
|
if [[ ${optdigits} -gt 0 ]]; then
|
|
digits=${1}
|
|
((optdigits--))
|
|
else
|
|
echo "ERROR: function newOTP - Too many OTP size integers given... Only one integer from 4 to 16 for number of OTP digits can be given..." >&2
|
|
return 72
|
|
fi
|
|
elif [[ "${1}" =~ ^[0-9a-zA-Z][0-9a-zA-Z]+$ ]]; then
|
|
if [[ ${optsums} -gt 0 ]]; then
|
|
hashsum="${1,,}"
|
|
((optsums--))
|
|
else
|
|
echo "ERROR: function newOTP - Too many hash algorithm strings given... Only one string of 2 characters or more for Hash Algorithm can be given..." >&2
|
|
return 22
|
|
fi
|
|
elif [[ "${1}" == "" ]]; then
|
|
local donothing=0
|
|
else
|
|
echo "ERROR: function newOTP - Invalid data given... Only one integer from 4 to 16 for number of OTP digits and one string of 2 characters or more for Hash Algorithm can be given..." >&2
|
|
return 13
|
|
fi
|
|
shift
|
|
done
|
|
|
|
if [[ -z "${thesalt}" ]] || [[ "${thesalt}" == "" ]]; then
|
|
local salthash=""
|
|
echo "WARNING: Variable \${thesalt} has not been declared with a value... Assign it a string unique to the service the OTP is being used for to avoid other services getting the same OTP..." >&2
|
|
else
|
|
local salthash="$(genHash "${thesalt}" "${hashsum}")"
|
|
fi
|
|
if [[ -z "${theseed}" ]] || [[ "${theseed}" == "" ]]; then
|
|
local seedhash=""
|
|
echo "WARNING: Variable \${theseed} has not been declared with a value... Assign it a string unique to the user account the OTP is being used for to avoid other users getting the same OTP..." >&2
|
|
else
|
|
local seedhash="$(genHash "${theseed}" "${hashsum}")"
|
|
fi
|
|
|
|
local timehash="$(genHash "$(date -u "+%Y%B%d%H%M%A%U%u")" "${hashsum}")"
|
|
|
|
genOTP "${seedhash}" "${salthash}" "${timehash}" ${digits}
|
|
|
|
return 0
|
|
}
|
|
|
|
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**
|
|
##
|
|
## Examples:
|
|
## 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
|
|
##
|
|
## 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
|
|
##
|
|
## 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
|
|
|
|
local optotps=1
|
|
local optvalids=1
|
|
local optsums=1
|
|
local optquiets=1
|
|
local theotp
|
|
local quiet=false
|
|
local validminutes=30
|
|
local hashsum="md5"
|
|
local digits=0
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
echo "ERROR: function testOTP - No data given... Must at least give one OTP of 4 to 16 digits..." >&2
|
|
return 11
|
|
fi
|
|
|
|
while [ $# -gt 0 ]; do
|
|
if [[ ${optotps} -eq 0 ]] && [[ ${optvalids} -eq 0 ]] && [[ ${optsums} -eq 0 ]] && [[ ${optquiets} -eq 0 ]]; then
|
|
echo "ERROR: function testOTP - Too much data given... Only one OTP of 4 to 16 digits, one integer from 1 to 120 for valid time in minutes, one string of 2 characters or more for Hash Algorithm can be given and optional string \"quiet\" for silent mode relying on exit code 0 for MATCH and 255 for NO MATCH..." >&2
|
|
return 12
|
|
fi
|
|
if [[ "${1}" =~ ^[0-9]+$ ]] && [[ ${#1} -ge 4 ]] && [[ ${#1} -le 16 ]]; then
|
|
if [[ ${optotps} -gt 0 ]]; then
|
|
theotp=${1}
|
|
digits=${#theotp}
|
|
((optotps--))
|
|
else
|
|
echo "ERROR: function testOTP - Too many OTPs given... Only one OTP of 4 to 16 digits can be given..." >&2
|
|
return 43
|
|
fi
|
|
elif [[ "${1}" =~ ^([1-9]|[1-9][0-9]+)$ ]]; then
|
|
if [[ ${optvalids} -gt 0 ]]; then
|
|
if [[ ${1} -gt 120 ]]; then
|
|
echo "ERROR: function testOTP - Minute integer given to high... Integer must be from 1 to 120 for valid time in minutes can be given..." >&2
|
|
return 55
|
|
fi
|
|
validminutes=${1}
|
|
((optvalids--))
|
|
else
|
|
echo "ERROR: function testOTP - Too many minute integers given... Only one integer from 1 to 120 for valid time in minutes can be given..." >&2
|
|
return 53
|
|
fi
|
|
elif [[ "${1,,}" =~ ^(q|quiet)$ ]]; then
|
|
if [[ ${optquiets} -gt 0 ]]; then
|
|
quiet=true
|
|
((optquiets--))
|
|
else
|
|
echo "ERROR: function testOTP - Too many \"quiet\" strings given... Only one optional string \"quiet\" for silent mode can be given relying on exit code 0 for MATCH and 255 for NO MATCH..." >&2
|
|
return 63
|
|
fi
|
|
elif [[ "${1}" =~ ^[0-9a-zA-Z][0-9a-zA-Z]+$ ]]; then
|
|
if [[ ${optsums} -gt 0 ]]; then
|
|
hashsum="${1,,}"
|
|
((optsums--))
|
|
else
|
|
echo "ERROR: function testOTP - Too many hash algorithm strings given... Only one string of 2 characters or more for Hash Algorithm can be given..." >&2
|
|
return 33
|
|
fi
|
|
elif [[ "${1}" == "" ]]; then
|
|
local donothing=0
|
|
else
|
|
echo "ERROR: function testOTP - Invalid data given... Only one OTP of 4 to 16 digits, one integer from 1 to 120 for valid time in minutes, one string of 2 characters or more for Hash Algorithm can be given and optional string \"quiet\" for silent mode relying on exit code 0 for MATCH and 255 for NO MATCH..." >&2
|
|
return 13
|
|
fi
|
|
shift
|
|
done
|
|
|
|
if [[ ${digits} -eq 0 ]]; then
|
|
echo "ERROR: function testOTP - No OTP given... Must give one OTP of 4 to 16 digits..." >&2
|
|
return 41
|
|
fi
|
|
|
|
if [[ -z "${thesalt}" ]] || [[ "${thesalt}" == "" ]]; then
|
|
local salthash=""
|
|
echo "WARNING: Variable \${thesalt} has not been declared with a value... Assign it a string unique to the service the OTP is being used for to avoid other services getting the same OTP..." >&2
|
|
else
|
|
local salthash="$(genHash "${thesalt}" "${hashsum}")"
|
|
fi
|
|
if [[ -z "${theseed}" ]] || [[ "${theseed}" == "" ]]; then
|
|
local seedhash=""
|
|
echo "WARNING: Variable \${theseed} has not been declared with a value... Assign it a string unique to the user account the OTP is being used for to avoid other users getting the same OTP..." >&2
|
|
else
|
|
local seedhash="$(genHash "${theseed}" "${hashsum}")"
|
|
fi
|
|
|
|
local n
|
|
|
|
((validminutes++))
|
|
for ((n=0; n<${validminutes}; n++)); do
|
|
local timehash="$(genHash "$(date -u -d "${n} minutes ago" "+%Y%B%d%H%M%A%U%u")" "${hashsum}")"
|
|
genOTP "${seedhash}" "${salthash}" "${timehash}" ${digits}
|
|
done | grep -q ^${theotp}$
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
if [[ ${quiet} == false ]]; then
|
|
echo "VALID"
|
|
fi
|
|
return 0
|
|
else
|
|
if [[ ${quiet} == false ]]; then
|
|
echo "INVALID"
|
|
fi
|
|
return 255
|
|
fi
|
|
}
|