Jump to content

Google Authenticator Implementation


wraithdu
 Share

Recommended Posts

I've had this one rolling around my brain for a while now. And while I can't take credit for much of anything at this point since it's just implementation, here's a framework for Time-based One-Time Password authentication, ie Google Authenticator. I've added links in all the places where I've harvested code. I'm planning on building this into an actual authenticator app, so this is just step one.

As always, thanks to everyone whose code contributed.

_GAuth.au3

#include-once
#include <_HMAC.au3>
#include <Date.au3>

;; http://tools.ietf.org/html/rfc6238
Func _GenerateTOTP($key, $keyIsBase32 = True, $time = Default, $period = 30, $digits = 6)
    Local $DIGITS_POWER[9] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000]
    ; time is some number of seconds
    If $time = Default Then $time = _GetUnixTimeUTC()
    $time = StringFormat("%016X", Floor($time / $period))
    If $keyIsBase32 Then
        $key = _Base32ToHex($key, True) ; return binary
    Else
        $key = StringToBinary($key)
    EndIf
    ; HMAC function expects binary arguments
    Local $hash = _HMAC_SHA1($key, Binary("0x" & $time))
    Local $offset = BitAND(BinaryMid($hash, BinaryLen($hash), 1), 0xf)
    Local $otp = BitOR(BitShift(BitAND(BinaryMid($hash, $offset + 1, 1), 0x7f), -24), _
            BitShift(BitAND(BinaryMid($hash, $offset + 2, 1), 0xff), -16), _
            BitShift(BitAND(BinaryMid($hash, $offset + 3, 1), 0xff), -8), _
            BitAND(BinaryMid($hash, $offset + 4, 1), 0xff) _
            )
    $otp = Mod($otp, $DIGITS_POWER[$digits])
    Return StringFormat("%0" & $digits & "i", $otp)
EndFunc

;; http://www.autoitscript.com/forum/topic/153617-seconds-since-epoch-aka-unix-timestamp/
Func _GetUnixTimeUTC()
    ; returns number of seconds since EPOCH in UTC
    Local $aSysTimeInfo = _Date_Time_GetTimeZoneInformation()
    Local $utcTime = ""
    Local $sDate = _NowCalc()
    If $aSysTimeInfo[0] = 2 Then
        $utcTime = _DateAdd('n', $aSysTimeInfo[1] + $aSysTimeInfo[7], $sDate)
    Else
        $utcTime = _DateAdd('n', $aSysTimeInfo[1], $sDate)
    EndIf
    Return _DateDiff('s', "1970/01/01 00:00:00", $utcTime)
EndFunc

;; http://tomeko.net/online_tools/base32.php?lang=en
Func _Base32ToHex($sInput, $returnBinary = False)
    $sInput = StringRegExpReplace(StringUpper($sInput), "[^A-Z2-7]", "")
    Local $key = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
    Local $buffer = 0, $bitsLeft = 0, $i = 0, $count = 0, $output = "", $val
    While $i < StringLen($sInput)
        $val = StringInStr($key, StringMid($sInput, $i + 1, 1)) - 1 ; StringInStr returns 1 as 1st position
        If $val >=0 And $val < 32 Then
            $buffer = BitOR(BitShift($buffer, -5), $val)
            $bitsLeft += 5
            If $bitsLeft >= 8 Then
                $output &= Chr(BitAND(BitShift($buffer, $bitsLeft - 8), 0xFF))
                $bitsLeft -= 8
            EndIf
        EndIf
        $i += 1
    WEnd
    If $bitsLeft > 0 Then
        $buffer = BitShift($buffer, -5)
        $output &= Chr(BitAND(BitShift($buffer, $bitsLeft - 3), 0xFF))
    EndIf
    If $returnBinary Then
        Return StringToBinary($output)
    Else
        Return $output
    EndIf
EndFunc

#cs
Alternate base32 to hex functions
Func _b32toh($input)
    $input = StringRegExpReplace(StringUpper($input), "[^A-Z2-7]", "")
    Local $ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
    Local $bits = "", $hex = "", $val, $i
    For $i = 0 To StringLen($input) - 1
        $val = StringInStr($ch, StringMid($input, $i + 1, 1)) - 1
        $bits &= StringFormat("%05s", _itob($val))
    Next
    $i = 0
    Local $chunk
    While ($i + 4) <= StringLen($bits)
        $chunk = StringMid($bits, $i + 1, 4)
        $hex &= StringFormat("%X", _btoi($chunk))
        $i += 4
    WEnd
    Return $hex
EndFunc

; int to binary (0's and 1's) string
Func _itob($int)
    Local $o = ""
    While $int
        $o = BitAND($int, 1) & $o
        $int = BitShift($int, 1)
    WEnd
    Return $o
EndFunc

; binary (0's and 1's) string to int
Func _btoi($b)
    Local $p = 0, $o = 0
    For $i = StringLen($b) To 1 Step -1
        $o += (2 ^ $p) * Number(StringMid($b, $i, 1))
        $p += 1
    Next
    Return $o
EndFunc
#ce

Func _TOTPTestVectors()
#cs
   Test vectors operate in HOTP mode.

   The test token shared secret uses the ASCII string value
   "12345678901234567890".  With Time Step X = 30, and the Unix epoch as
   the initial value to count time steps, where T0 = 0, the TOTP
   algorithm will display the following values for specified modes and
   timestamps.

  +-------------+--------------+------------------+----------+--------+
  |  Time (sec) |   UTC Time   | Value of T (hex) |   TOTP   |  Mode  |
  +-------------+--------------+------------------+----------+--------+
  |      59     |  1970-01-01  | 0000000000000001 | 94287082 |  SHA1  |
  |             |   00:00:59   |                  |          |        |
  |  1111111109 |  2005-03-18  | 00000000023523EC | 07081804 |  SHA1  |
  |             |   01:58:29   |                  |          |        |
  |  1111111111 |  2005-03-18  | 00000000023523ED | 14050471 |  SHA1  |
  |             |   01:58:31   |                  |          |        |
  |  1234567890 |  2009-02-13  | 000000000273EF07 | 89005924 |  SHA1  |
  |             |   23:31:30   |                  |          |        |
  |  2000000000 |  2033-05-18  | 0000000003F940AA | 69279037 |  SHA1  |
  |             |   03:33:20   |                  |          |        |
  | 20000000000 |  2603-10-11  | 0000000027BC86AA | 65353130 |  SHA1  |
  |             |   11:33:20   |                  |          |        |
  +-------------+--------------+------------------+----------+--------+
#ce
    Local $times[6] = [59, 1111111109, 1111111111, 1234567890, 2000000000, 20000000000]
    For $i = 0 To 5
        ConsoleWrite(StringFormat("%016X", Floor($times[$i] / 30)) & " : " & _
            _GenerateTOTP("12345678901234567890", False, $times[$i], 30, 8) & @CRLF)
    Next
EndFunc

_HMAC.au3

#include-once
#include <Crypt.au3>

;; http://www.autoitscript.com/forum/topic/145556-solved-hmac-sha1/?p=1028830
Func _HMAC_SHA1($key, $message)
    If Not IsBinary($key) Then $key = Binary($key)
    If Not IsBinary($message) Then $message = Binary($message)
    Local $blocksize = 64
    Local $a_opad[$blocksize], $a_ipad[$blocksize]
    Local Const $oconst = 0x5C, $iconst = 0x36
    Local $opad = Binary(''), $ipad = Binary('')
    If BinaryLen($key) > $blocksize Then $key = _Crypt_HashData($key, $CALG_SHA1)
    For $i = 1 To BinaryLen($key)
        $a_ipad[$i-1] = Number(BinaryMid($key, $i, 1))
        $a_opad[$i-1] = Number(BinaryMid($key, $i, 1))
    Next
    For $i = 0 To $blocksize - 1
        $a_opad[$i] = BitXOR($a_opad[$i], $oconst)
        $a_ipad[$i] = BitXOR($a_ipad[$i], $iconst)
    Next
    For $i = 0 To $blocksize - 1
        $ipad &= Binary('0x' & Hex($a_ipad[$i], 2))
        $opad &= Binary('0x' & Hex($a_opad[$i], 2))
    Next
    Return _Crypt_HashData($opad & _Crypt_HashData($ipad & $message, $CALG_SHA1), $CALG_SHA1)
EndFunc

Func _HMAC_MD5($key, $message)
    If Not IsBinary($key) Then $key = Binary($key)
    If Not IsBinary($message) Then $message = Binary($message)
    Local $blocksize = 64
    Local $a_opad[$blocksize], $a_ipad[$blocksize]
    Local Const $oconst = 0x5C, $iconst = 0x36
    Local $opad = Binary(''), $ipad = Binary('')
    If BinaryLen($key) > $blocksize Then $key = _Crypt_HashData($key, $CALG_MD5)
    For $i = 1 To BinaryLen($key)
        $a_ipad[$i-1] = Number(BinaryMid($key, $i, 1))
        $a_opad[$i-1] = Number(BinaryMid($key, $i, 1))
    Next
    For $i = 0 To $blocksize - 1
        $a_opad[$i] = BitXOR($a_opad[$i], $oconst)
        $a_ipad[$i] = BitXOR($a_ipad[$i], $iconst)
    Next
    For $i = 0 To $blocksize - 1
        $ipad &= Binary('0x' & Hex($a_ipad[$i], 2))
        $opad &= Binary('0x' & Hex($a_opad[$i], 2))
    Next
    Return _Crypt_HashData($opad & _Crypt_HashData($ipad & $message, $CALG_MD5), $CALG_MD5)
EndFunc

Example: Use the test vectors function to test HOTP mode, or visit http://gauth.apps.gbraad.nl/ for a live test site. The default account uses "JBSWY3DPEHPK3PXP" as the key ( https://code.google.com/p/google-authenticator/wiki/KeyUriFormat ).

ConsoleWrite(_GenerateTOTP("JBSWY3DPEHPK3PXP") & @CRLF)
Edited by wraithdu
Link to comment
Share on other sites

  • 4 months later...

Nice.

I was just going to write my own, but it's already done and posted.

Thanks. You saved me a bunch of time.

This worked perfectly.

Tested with Android Google Authenticator.

Edited by sheck
Live and Learn, 'cause Knowledge is Super Power.
Link to comment
Share on other sites

  • 4 years later...

嗨〜

我將此UDF用於TOTP,但OTP不正確。

我找不到錯誤,你能幫幫我嗎?謝謝〜

(我在UTC + 8)

 

此代碼生成值<>  http://gauth.apps.gbraad.nl/    value

我也使用谷歌  身份驗證器  <>  http://gauth.apps.gbraad.nl/    值。

昏暗$ OTP = _GenerateTOTP (“JBSWY3DPEHPK3PXP” ,真,默認,306

Translation:

Hi~

I use this UDF for TOTP, but the OTP is incorrect. I can't find the error, can you help me? Thank you~ (I am at UTC + 8)

This code generates a value <> http://gauth.apps.gbraad.nl/ value

I also use the Google Authenticator <> http://gauth.apps.gbraad.nl/ value.

 

Dim $ OTP = _GenerateTOTP ("JBSWY3DPEHPK3PXP", true, default, 30, 6)

 

Edited by Melba23
Added translation
Link to comment
Share on other sites

On 11/6/2018 at 9:24 AM, Lefiya said:

I use this UDF for TOTP, but the OTP is incorrect

I tested the code as shown and it works just fine with "JBSWY3DPEHPK3PXP" and "alice@google.com" on http://gauth.apps.gbraad.nl/

PS: http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/ may have what you need, as it works like the link above.

PS2: UTC is UTC. UTC+8 is YOUR time. Use UTC  =)

Edited by argumentum
more info

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

On 2018/11/9 at 12:59 AM, argumentum said:

我測試了所顯示的代碼,它與http://gauth.apps.gbraad.nl/上的“JBSWY3DPEHPK3PXP”和“ alice@google.com ”  一樣正常工作

PS:http:  //blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/  可能有你需要的東西,因為它像上面的鏈接一樣工作。

PS2:UTC是UTC。UTC + 8是你的時間使用UTC =)

Thank you for your heip ^^

but i understand about how to use...

Can you heip me again? thx~

And   why use   >>  ConsoleWrite(_GenerateTOTP("JBSWY3DPEHPK3PXP") & @CRLF)   ==   8

What mean about 8?

 

The site OTP <> code OTP... 

Video: 

 

 

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GuiListBox.au3>
#include <GuiComboBox.au3>
#include <GuiListView.au3>
#include <Array.au3>
#include <Misc.au3>
#include <Process.au3>
#include <GUIConstants.au3>
#include <EditConstants.au3>
#Include <GuiEdit.au3>
#include <APIConstants.au3>
#include <GDIPlus.au3>
#include <Memory.au3>
#include <WinAPIEx.au3>
#include <MsgBoxConstants.au3>
#include <Access.au3>
#include <Thread.au3>
#include <GuiIPAddress.au3>
#include <Crypt.au3>
#include <Excel.au3>
#include <GuiMenu.au3>
#include <_HMAC.au3>
#include <_GAuth.au3>
#include <math.au3>
#include <Clipboard.au3>


Dim $a, $n


Opt("GUIOnEventMode", 1)
$Form1 = GUICreate('GAuth', 500, 500, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "GUI_EVENT_CLOSE")
$Edit1 = GUICtrlCreateEdit('',20,20,460,410)
GUICtrlCreateButton('Grt OTP',200,450,100,30,$BS_DEFPUSHBUTTON)
GUICtrlSetOnEvent(-1, "_RUN")

GUISetState(@SW_SHOW)
_SetWindowPos($Form1,-1,-1,-1,-1,$HWND_TOPMOST,$SWP_NOMOVE+$SWP_NOSIZE);;TOP


While 1
        Sleep(100)
WEnd


Func GUI_EVENT_CLOSE()
    Exit
EndFunc


Func _RUN()
        Dim $unixTime = _GetUnixTimeUTC()
        Dim $time =  @YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC   
        Dim $easy0 = ConsoleWrite(_GenerateTOTP("JBSWY3DPEHPK3PXP") & @CRLF)
        Dim $easy1 = _GenerateTOTP("JBSWY3DPEHPK3PXP", True, Default, 30, 6)
        Dim $counter = Int($unixTime) / 30
        Dim $T = Floor($counter)
        Dim $key = _HMAC_SHA1('JBSWY3DPEHPK3PXP',$T)
        Dim $Offset = StringRight($key,1)

        If StringRegExp($Offset,'[a-fA-F]',0) = 1 Then
                If $Offset = 'A' Then $Offset = '10'
                If $Offset = 'B' Then $Offset = '11'
                If $Offset = 'C' Then $Offset = '12'
                If $Offset = 'D' Then $Offset = '13'
                If $Offset = 'E' Then $Offset = '14'
                If $Offset = 'F' Then $Offset = '15'
        EndIf
        $m = StringSplit($key,'x')
        $Sbits = StringMid($m[2],$Offset,8) ;;---hex

        $Sbits2 = StringMid ($Sbits,5,2) & StringMid ($Sbits,3,6)

        ;;---hex to dec
        Dim $s = 7
        Dim $tenVal = Null, $num = Null, $num2 = Null
        For $i = 0 to 7
                $num = StringMid ($Sbits2,$i+1,1)
                If StringRegExp($num,'[a-fA-F]',0) = 1 Then
                        If $num = 'A' Then $num = '10'
                        If $num = 'B' Then $num = '11'
                        If $num = 'C' Then $num = '12'
                        If $num = 'D' Then $num = '13'
                        If $num = 'E' Then $num = '14'
                        If $num = 'F' Then $num = '15'
                EndIf
                $num2 = $num * 16 ^ $s
                $s -= 1
                $tenVal += $num2 ;;dec
        Next


        $Digit = 6 ;;6 digits key
        $OTP = Mod($tenVal,10^$Digit)-1

        ;;---Number of digits: 6
        If StringLen($OTP) < 6 Then
                $a = 6 - StringLen($OTP)
                If $a = 6 Then $OTP = '000000' & Mod($tenVal,10^6)
                If $a = 5 Then $OTP = '00000' & Mod($tenVal,10^6)
                If $a = 4 Then $OTP = '0000' & Mod($tenVal,10^6)
                If $a = 3 Then $OTP = '000' & Mod($tenVal,10^6)
                If $a = 2 Then $OTP = '00' & Mod($tenVal,10^6)
                If $a = 1 Then $OTP = '0' & Mod($tenVal,10^6)
        EndIf

        GUICtrlSetData($Edit1, 'Basic' & @CRLF & '===================' & @CRLF & '$unixTime: ' & $unixTime & @CRLF & 'unix to time: ' & _DateAdd('s',$unixTime,"1970/01/01 00:00:00") & @CRLF & '$time: ' & $time & @CRLF & @CRLF & 'wraithdu code' & @CRLF & '===================' & @CRLF & 'ConsoleWrite(_GenerateTOTP("JBSWY3DPEHPK3PXP") & @CRLF):' & $easy0 & @CRLF & '_GenerateTOTP:' & $easy1 & @CRLF & @CRLF & 'my code' & @CRLF & '===================' & @CRLF & '$counter: ' & $counter & @CRLF & '$T: ' & $T & @CRLF & '$key: ' & $key & @CRLF & '$Sbits: ' & $Sbits & @CRLF & '$tenVal: ' & $tenVal & @CRLF & '$OTP: ' & $OTP)

EndFunc


Func _SetWindowPos($hWnd,$x,$y,$cX,$cY,$hWndInsertAfter = -1,$wFlags = 1)
    DllCall("user32.dll","long","SetWindowPos","long",$hWnd,"long",$hWndInsertAfter,"long",$x,"long",$y,"long",$cX,"long",$cY,"long",$wFlags)
EndFunc;==>_SetWindowPos

 

Edited by Lefiya
Link to comment
Share on other sites

5 hours ago, Lefiya said:

And   why use   >>  ConsoleWrite(_GenerateTOTP("JBSWY3DPEHPK3PXP") & @CRLF)   ==   8

The " == 8", I do not see anywhere AND would be useless. The StringLen($OfGenertatedTOTP) would be 6 anyway ( as declared in the example).
As long as the 2 devices ( the server side and client side ) have the same time ( UTC time ), the original code shows to perform as advertised.

PS: The " == 8" is because you added the "@CRLF" in your implementation and ConsoleWrite reports to have written 6 ( $OfGenertatedTOTP ) + 2 ( @CRLF ). 
The rest I can not understand, as I am not a programmer. Just a kind soul to copy and paste to see if it works, or not.    =/
I can no longer help. And since you are attempting a new implementation, kindly use the help and support forum, referencing this topic.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

7 minutes ago, argumentum said:

“== 8”,我什麼都看不到,也沒用。無論如何,StringLen($ OfGenertatedTOTP)將為6(如示例中所聲明的)。
只要2個設備(服務器端和客戶端)具有相同的時間(UTC時間),原始代碼就會顯示為廣告執行。

PS:“== 8”是因為您在實現中添加了“@CRLF”,而ConsoleWrite報告中寫入了6($ OfGenertatedTOTP)+ 2(@CRLF)。 
其餘我無法理解,因為我不是程序員。只是一個善良的複制和粘貼靈魂,看看它是否有效。= /
我再也無法幫助了。由於您正在嘗試新的實施,請使用幫助和支持論壇,引用此主題。

thank you~ for everything^^

i think maybe demo site server time and i different... 

Can i  inquire you about Your location?(UTC+?)

i want to try it~

thank you very much~

Link to comment
Share on other sites

  • Moderators

@Lefiya in the future please just hit reply rather than quoting everything everyone says. We know what we said, we were there when we said it :)

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

34 minutes ago, Lefiya said:

Can i  inquire you about Your location?(UTC+?)

Mine is "-5" but read about UTC and you will see that is not important if I'm in "-5" and you are in "+8", as we are plus or minus of the reference. 

PS: 

ConsoleWrite('GetMyTimeUTC() = "' & GetMyTimeUTC() & '"' & @CRLF)
Func GetMyTimeUTC()
    Local $tTime = _Date_Time_EncodeFileTime(@MON, @MDAY, @YEAR, @HOUR, @MIN, @SEC)
    Local $tLocal = _Date_Time_LocalFileTimeToFileTime($tTime)
    Return _Date_Time_FileTimeToStr($tLocal, 1)
EndFunc   ;==>GetMyTimeUTC

PS2: https://www.autoitscript.com/forum/topic/182902-autoit-real-time-server-with-inet/?do=findComment&comment=1313452

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

  • 4 years later...

Thanks for sharing the UDF and I apologize in advance for posting in such an old topic, but I believe I found a bug. The OTP generation isn't working properly on my client's computer and I narrowed it down the function to convert base32 to hex, which is the part acting faulty on my client's computer, I haven't dug deeper so I have no idea what's going wrong.

However the bug that I want to report here is that the given alternative function seems to be omitting the final hex digit for some reason... Here's my code for testing:

For $iKey = 0 To 100
    ConsoleWrite('Input: ' & $iKey & @CRLF)
    ConsoleWrite('_Base32ToHex: ' & _Base32ToHex(String($iKey), True) & @CRLF)
    ConsoleWrite('_b32toh: ' & '0x' & _b32toh(String($iKey)) & @CRLF)
Next

And the output:

Input: 0
_Base32ToHex: 
_b32toh: 0x
Input: 1
_Base32ToHex: 
_b32toh: 0x
Input: 2
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 3
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 4
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 5
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 6
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 7
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 8
_Base32ToHex: 
_b32toh: 0x
Input: 9
_Base32ToHex: 
_b32toh: 0x
Input: 10
_Base32ToHex: 
_b32toh: 0x
Input: 11
_Base32ToHex: 
_b32toh: 0x
Input: 12
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 13
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 14
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 15
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 16
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 17
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 18
_Base32ToHex: 
_b32toh: 0x
Input: 19
_Base32ToHex: 
_b32toh: 0x
Input: 20
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 21
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 22
_Base32ToHex: 0xD680
_b32toh: 0xD6
Input: 23
_Base32ToHex: 0xD6C0
_b32toh: 0xD6
Input: 24
_Base32ToHex: 0xD700
_b32toh: 0xD7
Input: 25
_Base32ToHex: 0xD740
_b32toh: 0xD7
Input: 26
_Base32ToHex: 0xD780
_b32toh: 0xD7
Input: 27
_Base32ToHex: 0xD7C0
_b32toh: 0xD7
Input: 28
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 29
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 30
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 31
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 32
_Base32ToHex: 0xDE80
_b32toh: 0xDE
Input: 33
_Base32ToHex: 0xDEC0
_b32toh: 0xDE
Input: 34
_Base32ToHex: 0xDF00
_b32toh: 0xDF
Input: 35
_Base32ToHex: 0xDF40
_b32toh: 0xDF
Input: 36
_Base32ToHex: 0xDF80
_b32toh: 0xDF
Input: 37
_Base32ToHex: 0xDFC0
_b32toh: 0xDF
Input: 38
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 39
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 40
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 41
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 42
_Base32ToHex: 0xE680
_b32toh: 0xE6
Input: 43
_Base32ToHex: 0xE6C0
_b32toh: 0xE6
Input: 44
_Base32ToHex: 0xE700
_b32toh: 0xE7
Input: 45
_Base32ToHex: 0xE740
_b32toh: 0xE7
Input: 46
_Base32ToHex: 0xE780
_b32toh: 0xE7
Input: 47
_Base32ToHex: 0xE7C0
_b32toh: 0xE7
Input: 48
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 49
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 50
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 51
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 52
_Base32ToHex: 0xEE80
_b32toh: 0xEE
Input: 53
_Base32ToHex: 0xEEC0
_b32toh: 0xEE
Input: 54
_Base32ToHex: 0xEF00
_b32toh: 0xEF
Input: 55
_Base32ToHex: 0xEF40
_b32toh: 0xEF
Input: 56
_Base32ToHex: 0xEF80
_b32toh: 0xEF
Input: 57
_Base32ToHex: 0xEFC0
_b32toh: 0xEF
Input: 58
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 59
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 60
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 61
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 62
_Base32ToHex: 0xF680
_b32toh: 0xF6
Input: 63
_Base32ToHex: 0xF6C0
_b32toh: 0xF6
Input: 64
_Base32ToHex: 0xF700
_b32toh: 0xF7
Input: 65
_Base32ToHex: 0xF740
_b32toh: 0xF7
Input: 66
_Base32ToHex: 0xF780
_b32toh: 0xF7
Input: 67
_Base32ToHex: 0xF7C0
_b32toh: 0xF7
Input: 68
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 69
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 70
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 71
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 72
_Base32ToHex: 0xFE80
_b32toh: 0xFE
Input: 73
_Base32ToHex: 0xFEC0
_b32toh: 0xFE
Input: 74
_Base32ToHex: 0xFF00
_b32toh: 0xFF
Input: 75
_Base32ToHex: 0xFF40
_b32toh: 0xFF
Input: 76
_Base32ToHex: 0xFF80
_b32toh: 0xFF
Input: 77
_Base32ToHex: 0xFFC0
_b32toh: 0xFF
Input: 78
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 79
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 80
_Base32ToHex: 
_b32toh: 0x
Input: 81
_Base32ToHex: 
_b32toh: 0x
Input: 82
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 83
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 84
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 85
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 86
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 87
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 88
_Base32ToHex: 
_b32toh: 0x
Input: 89
_Base32ToHex: 
_b32toh: 0x
Input: 90
_Base32ToHex: 
_b32toh: 0x
Input: 91
_Base32ToHex: 
_b32toh: 0x
Input: 92
_Base32ToHex: 0xD0
_b32toh: 0xD
Input: 93
_Base32ToHex: 0xD8
_b32toh: 0xD
Input: 94
_Base32ToHex: 0xE0
_b32toh: 0xE
Input: 95
_Base32ToHex: 0xE8
_b32toh: 0xE
Input: 96
_Base32ToHex: 0xF0
_b32toh: 0xF
Input: 97
_Base32ToHex: 0xF8
_b32toh: 0xF
Input: 98
_Base32ToHex: 
_b32toh: 0x
Input: 99
_Base32ToHex: 
_b32toh: 0x
Input: 100
_Base32ToHex: 
_b32toh: 0x

As you can see, _b32toh always omits the final digit in the result when you compare it to _Base32ToHex :wacko:

Anybody know why this is the case? I'm too tired to debug it myself... I'll post here if I find a solution before others.

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Link to comment
Share on other sites

  • 6 months later...

Strangely I was unable to get the correct OTP code to be generated until I uncommented the _b32toh() code and replaced

$key = _Base32ToHex($key, True)

 with

$key = Binary('0x'&_b32toh($key))

 in GenerateTOTP().

EDIT: The problem appears to be that but _b32toh("JBSWY3DPEHPK3PXP") = 0x48656C6C6F21DEADBEEF, but _Base32ToHex("JBSWY3DPEHPK3PXP") = 0x48656C6C6F21DEADBE8145. I do not know why...

Edited by garbb
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...