Search code examples
assemblydosx86-16google-authenticatortotp

Implementing TOTP 8086 Assembly (TASM)


I'm trying to implement TOTP on 8086 assembly. The procedures that return unix time/30 and HMAC-SHA1 are working perfectly(checked). I'm using the key "0000000000" which is equal to 0x30303030303030303030(GAYDAMBQGAYDAMBQ in base32) and I'm getting different results than the Google Authenticator app. This is my code:

proc GoogleAuthenticator
    call EpochTimeDiv30 ;get epoch time in seconds/30 in dx:ax
    xchg dh, dl ;we need it to be big endian in the memory
    xchg ah, al
;---------------------HMAC-SHA1 preparation------------------
    mov [word HmacMsg], dx 
    mov [word HmacMsg+2], ax ;msg is epoch time
    mov [HmacMsgLen], 4 ;msg length is 4bytes
    mov [HKeyLen], 10 ;key length is 10bytes
    lea bx, [HmacMsg]
    mov [HmacMsgOffset], bx ;put the offset of the msg
    call HMAC_SHA1 ;Key is already in Key var
;Now the result is in msgHash (result is big-endian)

    mov al, [msgHash+19] ;last byte of hashed msg
    and al, 0Fh ;we need only the last nibble
    xor ah, ah
    mov si, ax
    mov dx, [word msgHash+si] ;get offset, offset+1
    mov ax, [word msgHash+si+2] ;get offfset+2, offset+3
    xchg dh, dl ;back to big endian
    xchg ah, al ;back to big endian

    and dh, 7Fh ;removing the most significant bit(MSB)

    Mod32 0Fh, 4240h ;dx:ax modulo 1,000,000
    ret
endp GoogleAuthenticator    

EDIT: The algorithm I'm trying to implement:

  function GoogleAuthenticatorCode(string secret)
      key := 5B5E7MMX344QRHYO
      message := floor(current Unix time / 30)
      hash := HMAC-SHA1(key, message)
      offset := last nibble of hash
      truncatedHash := hash[offset..offset+3]  //4 bytes starting at the offset
      Set the first bit of truncatedHash to zero  //remove the most significant bit
      code := truncatedHash mod 1000000
      pad code with 0 from the left until length of code is 6
      return code

Solution

  • I've found the problem. The messsage should be 8 bytes long. This is the working code:

    proc GoogleAuthenticator
        call EpochTimeDiv30 ;get epoch time in seconds/30 in dx:ax
        xchg dh, dl ;we need it to be big endian in the memory
        xchg ah, al
    ;---------------------HMAC-SHA1 preparation------------------
        mov [word HmacMsg], 0
        mov [word HmacMsg+2], 0
        mov [word HmacMsg+4], dx 
        mov [word HmacMsg+6], ax ;msg is epoch time
        mov [HmacMsgLen], 8 ;msg length is 4bytes
        mov [HKeyLen], 10 ;key length is 10bytes
        lea bx, [HmacMsg]
        mov [HmacMsgOffset], bx ;put the offset of the msg
        call HMAC_SHA1 ;Key is already in Key var
    ;Now the result is in msgHash (result is big-endian)
    
        mov al, [msgHash+19] ;last byte of hashed msg
        and al, 0Fh ;we need only the last nibble
        xor ah, ah
        mov si, ax
        mov dx, [word msgHash+si] ;get offset, offset+1
        mov ax, [word msgHash+si+2] ;get offfset+2, offset+3
        xchg dh, dl ;back to big endian
        xchg ah, al ;back to big endian
    
        and dh, 7Fh ;removing the most significant bit(MSB)
    
        Mod32 0Fh, 4240h ;dx:ax modulo 1,000,000
        ret
    endp GoogleAuthenticator