Maroonbells (talk | contribs) (Add'l details) |
Maroonbells (talk | contribs) (Add'l syntax) |
||
Line 14: | Line 14: | ||
== Details == | == Details == | ||
− | The /help describes 4 formats for the key | + | The /help describes 4 formats for the key. Here is the sequence of parsing:.<br /> |
− | 1. If key length | + | 1. If key is a length 40/64/128 case-insensitive hex string, it is decoded to become a text string where each byte value 128-255 is UTF-8 encoded, and any 0x00's stripped. If the string is entirely 0x00's, the key is $null.<br/> |
− | 2. Else: If key length is 16 or greater and a multiple of 8, and | + | 2. Else: If key length is 16 or greater and a multiple of 8 (except for lengths 40/64/128 containing only 0-9a-f), and if it's a valid case-insensitive Base32 encoded string without spaces or '=' padding, the key is the binary decoded contents whose length is 5/8ths the length of the Base32 string, with no 0x00's stripped and no UTF-8 encoding as if the contents are text.<br /> |
− | + | 3. Else: If the key length is 16/24/32 and contains only spaces or case-insensitive Base-32 characters, the spaces are stripped and the remaining Base-32 characters of arbitrary length are decoded into a binary key.<br /> | |
+ | 4. Else: Any remaining strings not matching the 1st 3 patterns are considered literal text keys, and the input is assumed to already be UTF-8 encoded where necessary.<br /> | ||
− | Note | + | * Note: Google Authenticator format is: Base32 string of length 16/26/32 encoding a key of 80/128/160 bits. String can be upper or lower case chars, and can be divided by spaces into groups of 4 characters. $hotp is not recognizing the 128-bit key because 26 isn't a multiple of 8, unless it's padded with 6 non-consecutive spaces to be length 32. $hotp is not supporting the encoded string divided by spaces into groups unless there are enough spaces to cause the total length including spaces to be a multiple of 8. |
+ | |||
+ | * Note: Because $hotp uses decoded base16 strings after deleting 0x00 bytes and UTF-8 encoding byte values 128-255, keys are replaced by UTF-8 encoded text strings an average of 50% longer, and hex strings with 0x00's in different positions produce matching keys.<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 '''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 /> | ||
Line 48: | Line 51: | ||
//var %digits 3 | while (%digits isnum 3-9) { echo -a %digits $hotp(password,123,sha1,%digits) | inc %digits } | //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. | All passwords are similar, differing only in the number of digits displayed. | ||
+ | |||
+ | //var %a CuRiOsItY KiLlEd ThE CaT | echo -a $hotp($upper(%a),1) $hotp($lower(%a),1) $hotp(%a,1) | ||
+ | Mistakenly decodes as if this is a case-insensitive base32 string | ||
//echo -a $hotp(test,123) $hotp(test,123abc456) | //echo -a $hotp(test,123) $hotp(test,123abc456) |
Revision as of 12:59, 17 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. Here is the sequence of parsing:.
1. If key is a length 40/64/128 case-insensitive hex string, it is decoded to become a text string where each byte value 128-255 is UTF-8 encoded, and any 0x00's stripped. If the string is entirely 0x00's, the key is $null.
2. Else: If key length is 16 or greater and a multiple of 8 (except for lengths 40/64/128 containing only 0-9a-f), and if it's a valid case-insensitive Base32 encoded string without spaces or '=' padding, the key is the binary decoded contents whose length is 5/8ths the length of the Base32 string, with no 0x00's stripped and no UTF-8 encoding as if the contents are text.
3. Else: If the key length is 16/24/32 and contains only spaces or case-insensitive Base-32 characters, the spaces are stripped and the remaining Base-32 characters of arbitrary length are decoded into a binary key.
4. Else: Any remaining strings not matching the 1st 3 patterns are considered literal text keys, and the input is assumed to already be UTF-8 encoded where necessary.
- Note: Google Authenticator format is: Base32 string of length 16/26/32 encoding a key of 80/128/160 bits. String can be upper or lower case chars, and can be divided by spaces into groups of 4 characters. $hotp is not recognizing the 128-bit key because 26 isn't a multiple of 8, unless it's padded with 6 non-consecutive spaces to be length 32. $hotp is not supporting the encoded string divided by spaces into groups unless there are enough spaces to cause the total length including spaces to be a multiple of 8.
- Note: Because $hotp uses decoded base16 strings after deleting 0x00 bytes and UTF-8 encoding byte values 128-255, keys are replaced by UTF-8 encoded text strings an average of 50% longer, and hex strings with 0x00's in different positions produce matching keys.
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. //var %a CuRiOsItY KiLlEd ThE CaT | echo -a $hotp($upper(%a),1) $hotp($lower(%a),1) $hotp(%a,1) Mistakenly decodes as if this is a case-insensitive base32 string //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.