Sub Class_Globals
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
End Sub
Sub VerifyTOTP(secretKey As String, userEnteredCode As String) As Boolean
Dim currentTimeSlice As Long = Floor(DateTime.Now / 30000) ' 30 seconds time slice
For i = -1 To 1 ' Check previous, current, and next time slices
Dim timeSlice As Long = currentTimeSlice + i
Dim expectedCode As String = GenerateTOTP(secretKey, timeSlice)
If expectedCode = userEnteredCode Then
Return True
End If
Next
Return False
End Sub
Sub GenerateTOTP(secretKey As String, timeSlice As Long) As String
' Dim keyBytes() As Byte = Base32Decode(secretKey) ' Decode Base32 secret to bytes
Dim timeSliceBytes() As Byte = LongToBytes(timeSlice)
Dim hmacBytes() As Byte = hmac_SHA1(timeSliceBytes, secretKey)
Dim offset As Int = Bit.And(hmacBytes(hmacBytes.Length - 1), 0xF)
Dim code As Long = Bit.And(hmacBytes(offset), 0x7F)
code = Bit.Or(Bit.ShiftLeft(code, 8), Bit.And(hmacBytes(offset + 1), 0xFF))
code = Bit.Or(Bit.ShiftLeft(code, 8), Bit.And(hmacBytes(offset + 2), 0xFF))
code = Bit.Or(Bit.ShiftLeft(code, 8), Bit.And(hmacBytes(offset + 3), 0xFF))
code = code Mod 1000000 ' 6-digit code
Return NumberFormat(code, 6, 0)
End Sub
Sub hmac_SHA1(data() As Byte, key As String) As Byte()
Try
Dim m As Mac
Dim k As KeyGenerator
k.Initialize("HMACSHA1")
' Corrected: Convert the key to raw bytes based on its Base32 encoding
Dim keyBytes() As Byte = Base32Decode(key)
k.KeyFromBytes(keyBytes)
m.Initialise("HMACSHA1", k.Key)
m.Update(data)
Dim b() As Byte = m.Sign
Return b
Catch
Log("Error in hmac_SHA1: " & LastException.Message)
Return Null
End Try
End Sub
Sub LongToBytes(value As Long) As Byte()
Dim bytes(8) As Byte ' A long value has 8 bytes
For i = 0 To 7
bytes(7 - i) = Bit.And(Bit.ShiftRight(value, i * 8), 0xFF)
Next
Return bytes
End Sub
Sub Base32Decode(encoded As String) As Byte()
Dim Base32Chars As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
Dim bits As Int = 0
Dim value As Long = 0
Dim buffer As List
buffer.Initialize
For i = 0 To encoded.Length - 1
value = Bit.Or(Bit.ShiftLeft(value, 5), Base32Chars.IndexOf(encoded.CharAt(i)))
bits = bits + 5
If bits >= 8 Then
buffer.Add(Bit.And(Bit.ShiftRight(value, bits - 8), 0xFF))
bits = bits - 8
End If
Next
' Convert the list of bytes to a byte array
Dim byteArray(buffer.Size) As Byte
For i = 0 To buffer.Size - 1
byteArray(i) = buffer.Get(i)
Next
Return byteArray
End Sub