(→See Also) |
Maroonbells (talk | contribs) (Add'l details) |
||
Line 1: | Line 1: | ||
{{mirc title|$hotp Identifier}}'''$hotp''' returns an HOTP (HMAC-based One-Time Password) based on the specified parameters. | {{mirc title|$hotp Identifier}}'''$hotp''' returns an HOTP (HMAC-based One-Time Password) based on the specified parameters. | ||
− | |||
== Synopsis == | == Synopsis == | ||
− | <pre>$hotp(key, count, hash, digits)</pre> | + | <pre>$hotp(key, count [, hash [, digits ]])</pre> |
== Paramters == | == Paramters == | ||
− | * '''key''' - the key is required and can be in a base16 format of either 40, 64 or 128 chars; or in a base32 format of either 16, 24 or 32 chars; or plain text; or it can also be in a Google Authenticator format ie lowercase with spaces. | + | * '''key''' - the key is required and can be in a base16 format of either 40, 64 or 128 chars; or in a base32 format of either 16, 24 or 32 chars; or a base32 format of any multiple of 8 greater than length 8; or plain text; or it can also be in a Google Authenticator format ie lowercase with spaces. |
− | * '''count''' - required, the | + | * '''count''' - required, the 'counter' that should never be used more than once with the same key. This is a 64-bit number with valid range 0 through 2^64-1. Non-numeric are removed from the end, and "+" removed from the beginning. |
− | * '''hash''' - optional, hashing algorithm, default to sha1 | + | * '''hash''' - optional, hashing algorithm, default to sha1. Also allowed: sha256, sha512, sha384, md5 |
− | * '''digits''' - optional, number of digits, default to 6 | + | * '''digits''' - optional, number of digits, default to 6. Valid range 3 through 9. |
== Properties == | == Properties == | ||
None | None | ||
− | == | + | == Details == |
− | + | The /help describes 4 formats for the key, but I can only identify 3 format types. TBD: explain "Google Authenticator format".<br /> | |
+ | |||
+ | 1. If key length is 40/64/128 and is a case-insensitive hexadecimal text string, the key used is the decoded utf8-encoded underlying text characters within that string, excluding 0x00's.<br/> | ||
+ | 2. Else: If key length is 16 or greater and a multiple of 8, and consists of the case-insensitive characters of the Base32 alphabet [A-Z,a-z,2-7], the key used is the decoded binary string that's 5/8ths of the length of the encoded string. (Note that /help states that only base32 lengths 16/24/32 are decoded.)<br /> | ||
+ | 3. Else: Any other string not matching the conditions of #1 or #2 are literal strings used as the key.<br /> | ||
+ | |||
+ | Note that $hotp strips 0x00's and UTF8-encodes underlying 'text' before using the decoded contents as a text key, making it very unlikely a sha256 hash can be used as if it's a 32-byte binary key.<br /> | ||
+ | |||
+ | The '''count''' parameter should be in the range 0 to 2^64-1. Values greater than 2^64-1 return the same password as when 2^64-1 is used. For 64-bit negative numbers, negative N returns the same password as when +2^64 less N is used.<br /> | ||
+ | |||
+ | The OTP in HOTP stands for One Time Password, which is only 'one time' if the application makes sure that the same 'count' value is never used twice. Either the server and the client keep track of the last count used with each key, or each use the current time for a very short interval as defined for $totp(). | ||
+ | |||
+ | == Examples == | ||
+ | <source lang="mIRC"> | ||
+ | //var %a 1234567890 | echo -a $hotp(%a,1,sha512) $hotp($encode(%a,a),1,sha512) | ||
+ | Both return identical passwords because the 2nd usage identifies the key as a valid Base-32 encoded string that's a multiple of 8 greater than 8. | ||
+ | |||
+ | //var %a $str(A,16) | echo -a $hotp($upper(%a),1) $hotp($lower(%a),1) | ||
+ | These return the same value because they are recognized as valid Base32 encoded strings, regardless of upper/lower case. To ensure your key cannot be mistaken for a case-insensitive Base16 or Base32 encoding, you should prevent your key from being a length that's a multiple of 8 or ensure it contains a space or other character not part of base-32 encoding. | ||
+ | |||
+ | //var %a A | var %b $base($asc(%a),10,16,2) | echo -a $hotp($str(%a,20),1,sha256) $hotp($str(%b,20),1,sha256) - %a vs %b | ||
+ | Both return identical passwords because the 2nd usage identifies the key as a valid Base-16 encoded string of length 40,64, or 128. | ||
+ | |||
+ | Both above encoded strings return the same value regardless whether the encoded string contains upper or lower or a mix of upper/lower characters. | ||
+ | //var %a $chr(233) | var %b $base($asc(%a),10,16,2) | echo -a $hotp($str(%a,20),1,sha256) $hotp($str(%b,20),1,sha256) - %a vs %b | ||
+ | This pair also return identical passwords, showing that HOTP UTF8-encodes the underlying decoded hex strings before including them in the key. | ||
+ | |||
+ | //echo -a $hotp(11223344556677889900aabbccddeeff11223344,1) | ||
+ | //echo -a $hotp(112233445566778899aabbccddee00ff11223344,1) | ||
+ | In addition to UTF8-encoding bytes in a hex string of length 40/64/128, $hotp also removes decoded 0x00's from the decoded output. The above '00' can be cut/pasted to any other byte position in the key and the output remains unchanged. | ||
+ | |||
+ | //var %digits 3 | while (%digits isnum 3-9) { echo -a %digits $hotp(password,123,sha1,%digits) | inc %digits } | ||
+ | All passwords are similar, differing only in the number of digits displayed. | ||
+ | |||
+ | //echo -a $hotp(test,123) $hotp(test,123abc456) | ||
+ | Identical results because mIRC removed non-numeric string front the end. | ||
+ | |||
+ | //echo -a $hotp(test,abc) $hotp(test,def) $hotp(test,0) | ||
+ | Identical because non-numeric count parameters are treated as if count is zero. | ||
+ | |||
+ | Even though HOTP supports hash=md5, you should avoid using md5 because HOTP was not designed for hashes shorter than 160 bits, and a few values are returned a high percentage of the time. When the output is 6 digits, each output number should appear approximately once per 1 million random tests. However there are 8 outputs which appear over 60000 times in a million tests: | ||
+ | |||
+ | //var %list 658240 093696 529152 964608 400064 835520 270976 706432 , %i 0 , %x 0 | while (%i < 1000000) { if ($istok(%list,$hotp($rand(1,9999999),$rand(1,9999999),md5,6),32)) inc %x | inc %i } | echo -a 8 passwords appeared %x out of %i times | ||
+ | |||
+ | This is not a weakness in using md5 as a parameter for $hmac, but instead is caused by how the 32-bit 'truncate' value is chosen from within the shorter md5 hash, often at offsets where there are not 8 hex digits available at that position. | ||
+ | |||
+ | alias handshake { | ||
+ | inc %handshake_counter | ||
+ | var %a $hotp(%secret_key,%handshake_counter,sha256,6) | ||
+ | /notice other_nick password is %a for counter %handshake_counter | ||
+ | } | ||
+ | |||
+ | </source> | ||
== Compatibility == | == Compatibility == | ||
{{mIRC compatibility|7.42}} | {{mIRC compatibility|7.42}} | ||
== See Also == | == See Also == | ||
− | {{mIRC|$totp}} | + | {{collist |
− | {{mIRC|$hmac}} | + | |count = 3 |
− | + | |style = width: 60%; display: inherit; | |
− | + | | | |
+ | * {{mIRC|$totp}} | ||
+ | * {{mIRC|$hmac}} | ||
+ | * {{mIRC|$encode}} | ||
+ | * {{mIRC|$decode}} | ||
+ | * {{mIRC|$sha1}} | ||
+ | * {{mIRC|$sha256}} | ||
+ | * {{mIRC|$sha512}} | ||
+ | * {{mIRC|$sha384}} | ||
+ | * {{mIRC|$md5}} | ||
+ | }} |
Revision as of 18:51, 15 May 2018
$hotp returns an HOTP (HMAC-based One-Time Password) based on the specified parameters.
Synopsis
$hotp(key, count [, hash [, digits ]])
Paramters
- key - the key is required and can be in a base16 format of either 40, 64 or 128 chars; or in a base32 format of either 16, 24 or 32 chars; or a base32 format of any multiple of 8 greater than length 8; or plain text; or it can also be in a Google Authenticator format ie lowercase with spaces.
- count - required, the 'counter' that should never be used more than once with the same key. This is a 64-bit number with valid range 0 through 2^64-1. Non-numeric are removed from the end, and "+" removed from the beginning.
- hash - optional, hashing algorithm, default to sha1. Also allowed: sha256, sha512, sha384, md5
- digits - optional, number of digits, default to 6. Valid range 3 through 9.
Properties
None
Details
The /help describes 4 formats for the key, but I can only identify 3 format types. TBD: explain "Google Authenticator format".
1. If key length is 40/64/128 and is a case-insensitive hexadecimal text string, the key used is the decoded utf8-encoded underlying text characters within that string, excluding 0x00's.
2. Else: If key length is 16 or greater and a multiple of 8, and consists of the case-insensitive characters of the Base32 alphabet [A-Z,a-z,2-7], the key used is the decoded binary string that's 5/8ths of the length of the encoded string. (Note that /help states that only base32 lengths 16/24/32 are decoded.)
3. Else: Any other string not matching the conditions of #1 or #2 are literal strings used as the key.
Note that $hotp strips 0x00's and UTF8-encodes underlying 'text' before using the decoded contents as a text key, making it very unlikely a sha256 hash can be used as if it's a 32-byte binary key.
The count parameter should be in the range 0 to 2^64-1. Values greater than 2^64-1 return the same password as when 2^64-1 is used. For 64-bit negative numbers, negative N returns the same password as when +2^64 less N is used.
The OTP in HOTP stands for One Time Password, which is only 'one time' if the application makes sure that the same 'count' value is never used twice. Either the server and the client keep track of the last count used with each key, or each use the current time for a very short interval as defined for $totp().
Examples
//var %a 1234567890 | echo -a $hotp(%a,1,sha512) $hotp($encode(%a,a),1,sha512) Both return identical passwords because the 2nd usage identifies the key as a valid Base-32 encoded string that's a multiple of 8 greater than 8. //var %a $str(A,16) | echo -a $hotp($upper(%a),1) $hotp($lower(%a),1) These return the same value because they are recognized as valid Base32 encoded strings, regardless of upper/lower case. To ensure your key cannot be mistaken for a case-insensitive Base16 or Base32 encoding, you should prevent your key from being a length that's a multiple of 8 or ensure it contains a space or other character not part of base-32 encoding. //var %a A | var %b $base($asc(%a),10,16,2) | echo -a $hotp($str(%a,20),1,sha256) $hotp($str(%b,20),1,sha256) - %a vs %b Both return identical passwords because the 2nd usage identifies the key as a valid Base-16 encoded string of length 40,64, or 128. Both above encoded strings return the same value regardless whether the encoded string contains upper or lower or a mix of upper/lower characters. //var %a $chr(233) | var %b $base($asc(%a),10,16,2) | echo -a $hotp($str(%a,20),1,sha256) $hotp($str(%b,20),1,sha256) - %a vs %b This pair also return identical passwords, showing that HOTP UTF8-encodes the underlying decoded hex strings before including them in the key. //echo -a $hotp(11223344556677889900aabbccddeeff11223344,1) //echo -a $hotp(112233445566778899aabbccddee00ff11223344,1) In addition to UTF8-encoding bytes in a hex string of length 40/64/128, $hotp also removes decoded 0x00's from the decoded output. The above '00' can be cut/pasted to any other byte position in the key and the output remains unchanged. //var %digits 3 | while (%digits isnum 3-9) { echo -a %digits $hotp(password,123,sha1,%digits) | inc %digits } All passwords are similar, differing only in the number of digits displayed. //echo -a $hotp(test,123) $hotp(test,123abc456) Identical results because mIRC removed non-numeric string front the end. //echo -a $hotp(test,abc) $hotp(test,def) $hotp(test,0) Identical because non-numeric count parameters are treated as if count is zero. Even though HOTP supports hash=md5, you should avoid using md5 because HOTP was not designed for hashes shorter than 160 bits, and a few values are returned a high percentage of the time. When the output is 6 digits, each output number should appear approximately once per 1 million random tests. However there are 8 outputs which appear over 60000 times in a million tests: //var %list 658240 093696 529152 964608 400064 835520 270976 706432 , %i 0 , %x 0 | while (%i < 1000000) { if ($istok(%list,$hotp($rand(1,9999999),$rand(1,9999999),md5,6),32)) inc %x | inc %i } | echo -a 8 passwords appeared %x out of %i times This is not a weakness in using md5 as a parameter for $hmac, but instead is caused by how the 32-bit 'truncate' value is chosen from within the shorter md5 hash, often at offsets where there are not 8 hex digits available at that position. alias handshake { inc %handshake_counter var %a $hotp(%secret_key,%handshake_counter,sha256,6) /notice other_nick password is %a for counter %handshake_counter }
Compatibility
Added: mIRC v7.42
Added on: 17 Jul 2015
Note: Unless otherwise stated, this was the date of original functionality.
Further enhancements may have been made in later versions.