mirror of
https://github.com/adulau/ootp.git
synced 2024-11-21 09:37:11 +00:00
846 lines
21 KiB
QBasic
846 lines
21 KiB
QBasic
'
|
|
' Copyright (c) 2005,2006 Mark Fullmer
|
|
' Copyright (c) 2009 Mark Fullmer and the Ohio State University
|
|
' All rights reserved.
|
|
'
|
|
' Redistribution and use in source and binary forms, with or without
|
|
' modification, are permitted provided that the following conditions
|
|
' are met:
|
|
' 1. Redistributions of source code must retain the above copyright
|
|
' notice, this list of conditions and the following disclaimer.
|
|
' 2. Redistributions in binary form must reproduce the above copyright
|
|
' notice, this list of conditions and the following disclaimer in the
|
|
' documentation and/or other materials provided with the distribution.
|
|
'
|
|
' THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
' ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
' ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
' FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
' DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
' OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
' HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
' LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
' OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
' SUCH DAMAGE.
|
|
'
|
|
' $Id: HOTPC.BAS 148 2011-03-31 00:46:42Z maf $
|
|
'
|
|
#include "sha-1.def"
|
|
#include "preader.def"
|
|
#include "AlgID.DEF"
|
|
#include "Commands.def"
|
|
#include "hotp.def"
|
|
|
|
' Disable filesystem
|
|
#files 0
|
|
|
|
Option Explicit
|
|
|
|
' number of keys/hosts - max 254. 255 is reserved. Index is 8 bits.
|
|
Const HOTPNum = 50
|
|
|
|
' HOTPCodeVersion notes:
|
|
' Rev 1 - first production version - feb 2006
|
|
' Rev 2 - disable AdminMode on first usage - safety net
|
|
' if left on by mistake.
|
|
' Rev 3 - Count32 Commands
|
|
' - conditional compile Commands
|
|
' - Get/Set/Test naming standardize
|
|
' Rev 4 - release of Rev3
|
|
' Rev 5 - renumber Commands, readerKey, getCapabilities
|
|
' - ClearALL, checkReaderKey
|
|
' Rev 6 - release Rev5
|
|
' Rev 7 - dynamic truncate, decimal HOTP, readerKeyFailCount
|
|
' reset in ClearAll, HOTPCommon, move stack vars
|
|
' to global, reorg balance reader code
|
|
' naming consistency, default 50 systems
|
|
' Rev 8 - release Rev7
|
|
' Rev 9 - CheckPIN for GetHOTP*, myReaderKey
|
|
|
|
' 20 byte scratch area addressable as 5 32bit vars
|
|
public str20 as String*20
|
|
public tmpb1 as Long at str20
|
|
public tmpb2 as Long at str20+4
|
|
public tmpb3 as Long at str20+8
|
|
public tmpb4 as Long at str20+12
|
|
public tmpb5 as Long at str20+16
|
|
|
|
' 32 bit HOTPCount stored 64 bits. Top 32 bits always 0
|
|
public Count64 as String*8
|
|
public Count64low as Long at Count64+4
|
|
|
|
' Truncated 4 or 5 byte HOTP
|
|
public HOTPTruncated as String*5
|
|
|
|
' HOTPTruncated aliases for 31 bit decimal formats
|
|
public u32 as Long at HOTPTruncated
|
|
public u32b0 as Byte at u32
|
|
public u32b1 as Byte at u32+1
|
|
public u32b2 as Byte at u32+2
|
|
public u32b3 as Byte at u32+3
|
|
|
|
' HOTP Format
|
|
public HOTPfmt as Byte
|
|
|
|
' Code version
|
|
Const HOTPCodeVersion = 9
|
|
|
|
' Capabilities (conditionally compiled in functions)
|
|
eeprom Capabilities as Long = CAPSETHOST + CAPGETHOST + CAPGETHOSTNAME + _
|
|
CAPGETHOTP + CAPSETADMINMODE + _
|
|
CAPSETBALANCECARDINDEX + CAPSETPIN + _
|
|
CAPTESTPIN + CAPGETVERSION + _
|
|
CAPSETADMINKEY + CAPSETHOST32 + _
|
|
CAPGETHOST32 + CAPGETHOTPCOUNT32 + _
|
|
CAPGETHOTPHOST + CAPGETHOTPHOSTCOUNT32 + _
|
|
CAPPRDISPLAY + CAPCLEARALL + CAPSETREADERKEY
|
|
|
|
' Default PIN
|
|
Const DefaultPIN = "28165"
|
|
|
|
' Default Admin Key
|
|
eeprom AdminKey as String*20 = "00000000000000000000"
|
|
|
|
' HOTPK and its derivatives
|
|
' default Key "00000000000000000000"
|
|
' KeyI is Key XOR input pad (0x36)
|
|
' IPAD44 is 0x36 repeated 44 times
|
|
' KeyO is Key XOR output pad (0x5c)
|
|
' OPAD44 is 0x5c repeated 44 times.
|
|
|
|
' Note that only the I and O versions of the keys
|
|
' are stored -- which is all that's needed.
|
|
' An alternative implementation could choose to store
|
|
' the key and compute the I and O versions at run time
|
|
' this would use less EEPROM space at the cost of more
|
|
' CPU cycles (and less battery life) to compute a HOTP
|
|
|
|
eeprom HOTPKeyI(HOTPNum) as String*20 = &H06,&H06,&H06,&H06,&H06,&H06,&H06, _
|
|
&H06,&H06,&H06,&H06,&H06,&H06,&H06, _
|
|
&H06,&H06,&H06,&H06,&H06,&H06
|
|
|
|
|
|
eeprom HOTPKeyO(HOTPNum) as String*20 = &H6C,&H6C,&H6C,&H6C,&H6C,&H6C,&H6C, _
|
|
&H6C,&H6C,&H6C,&H6C,&H6C,&H6C,&H6C, _
|
|
&H6C,&H6C,&H6C,&H6C,&H6C,&H6C
|
|
|
|
' system hostname
|
|
eeprom HOTPHost(HOTPNum) as String*12
|
|
|
|
' system count
|
|
eeprom HOTPCount32(HOTPNum) as Long
|
|
|
|
|
|
' Input pad
|
|
eeprom IPAD44 as String*44 = &H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _
|
|
&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _
|
|
&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _
|
|
&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _
|
|
&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36
|
|
|
|
|
|
' Output pad
|
|
eeprom OPAD44 as String*44 = &H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _
|
|
&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _
|
|
&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _
|
|
&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _
|
|
&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C
|
|
|
|
' Temporary message digest (inner)
|
|
eeprom eestr20 as String*20
|
|
|
|
' PIN - used to deter unauthorized use
|
|
eeprom PIN as String*5 = DefaultPIN
|
|
|
|
' Reader Key. Weak authentication for reader
|
|
eeprom ReaderKey as String*5 = "00000"
|
|
|
|
' The balance card can only use one of the host definitions.
|
|
eeprom BalanceCardIndex = 255 ' Disabled
|
|
|
|
' if AdminMode is not set some Commands require a valid PIN to work.
|
|
eeprom AdminMode as Byte = 1
|
|
|
|
' Keep track of PIN failures
|
|
eeprom PINFailCount as Byte = 0
|
|
eeprom ReaderKeyFailCount as Byte = 0
|
|
Const MaxPINFail = 10
|
|
Const MaxReaderKeyFail = 2
|
|
|
|
declare Sub Truncate(Idx as Byte)
|
|
|
|
declare Sub HOTPCommon(ReadOnly Idx as Byte, ReadOnly Count as Long, _
|
|
ReadOnly myPIN as String*5, ReadOnly myReaderKey as String*5)
|
|
|
|
declare Function CheckReaderKey(ReadOnly Idx as Byte, _
|
|
ReadOnly myReaderKey as String*5) as Byte
|
|
|
|
declare Function CheckPIN(ReadOnly myPIN as String*5) as Byte
|
|
|
|
declare Function CheckAdmin() as Byte
|
|
|
|
declare Function CheckIndex(Idx as Byte) as Byte
|
|
|
|
|
|
' Common HOTP generation code
|
|
Sub HOTPCommon(ReadOnly Idx as Byte, ReadOnly Count32 as Long, _
|
|
ReadOnly myPIN as String*5, ReadOnly myReaderKey as String*5)
|
|
|
|
' disable admin mode on first use.
|
|
if (AdminMode = 1) then
|
|
AdminMode = 0
|
|
end if
|
|
|
|
' don't allow operations with default pin
|
|
if myPIN = DefaultPIN then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
' check PIN
|
|
if CheckPIN(myPIN) <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
' Check reader access
|
|
if CheckReaderKey(Idx, myReaderKey) <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
if CheckIndex(Idx) <> 0 then
|
|
SW1SW2 = swDataNotFound
|
|
Exit
|
|
end if
|
|
|
|
' when Count32 == 0, use stored count
|
|
if Count32 <> 0 then
|
|
Count64low = Count32
|
|
else
|
|
Count64low = HOTPCount32(Idx)
|
|
end if
|
|
|
|
Call ShaStart()
|
|
Call ShaAppend(HOTPKeyI(Idx))
|
|
Call ShaAppend(IPAD44)
|
|
Call ShaAppend(Count64)
|
|
str20 = ShaEnd()
|
|
|
|
Call ShaStart()
|
|
Call ShaAppend(HOTPKeyO(Idx))
|
|
Call ShaAppend(OPAD44)
|
|
Call ShaAppend(str20)
|
|
str20 = ShaEnd()
|
|
|
|
Disable OverflowCheck
|
|
HOTPCount32(Idx) = Count64low + 1
|
|
Enable OverflowCheck
|
|
|
|
' Set HOTPTruncated
|
|
Call Truncate(Idx)
|
|
|
|
End Sub ' HOTPCommon
|
|
|
|
' Convert 160 bit String to 4 or 5 Bytes and format for reader
|
|
Sub Truncate(Idx as Byte)
|
|
private offset as Byte
|
|
|
|
HOTPfmt = 0
|
|
|
|
if (asc(HOTPHost(Idx)(12)) AND &H80) then
|
|
HOTPfmt = 1
|
|
end if
|
|
|
|
if (asc(HOTPHost(Idx)(11)) AND &H80) then
|
|
HOTPfmt = HOTPfmt or 2
|
|
end if
|
|
|
|
if (asc(HOTPHost(Idx)(10)) AND &H80) then
|
|
HOTPfmt = HOTPfmt or 4
|
|
end if
|
|
|
|
' future?
|
|
' if (asc(HOTPHost(Idx)(9)) AND &H80) then
|
|
' HOTPfmt = HOTPfmt or 8
|
|
' end if
|
|
|
|
' not suport on ZC3.9 card
|
|
' HOTPfmt = (asc(HOTPHost(Idx)(12)) AND &H80) SHRL 7
|
|
' HOTPfmt = fmt OR ((asc(HOTPHost(Idx)(11)) AND &H80) SHRL 6)
|
|
' HOTPfmt = fmt OR ((asc(HOTPHost(Idx)(10)) AND &H80) SHRL 5)
|
|
' HOTPfmt = fmt OR ((asc(HOTPHost(Idx)(9)) AND &H80) SHRL 4)
|
|
|
|
if (HOTPfmt = FMTHEX40) or (HOTPfmt = 0) then
|
|
HOTPTruncated = Left$(str20,5)
|
|
Exit Sub
|
|
end if
|
|
|
|
offset = asc(str20(20)) and &H0F
|
|
|
|
if (HOTPfmt = FMTDHEX40) then
|
|
HOTPTruncated = Mid$(str20,offset+1,5)
|
|
Exit Sub
|
|
end if
|
|
|
|
' u32b0..3 are bytes of u32 alias for HOTPtruncated
|
|
u32b0 = asc(str20(offset+1)) and &H7F
|
|
u32b1 = asc(str20(offset+2))
|
|
u32b2 = asc(str20(offset+3))
|
|
u32b3 = asc(str20(offset+4))
|
|
|
|
if (HOTPfmt = FMTDEC316) then
|
|
u32 = u32 mod 1000000
|
|
elseif (HOTPfmt = FMTDEC317) then
|
|
u32 = u32 mod 10000000
|
|
elseif (HOTPfmt = FMTDEC318) then
|
|
u32 = u32 mod 100000000
|
|
elseif (HOTPfmt = FMTDEC319) then
|
|
u32 = u32 mod 1000000000
|
|
' FMTDEC3110 does not require mod
|
|
end if
|
|
|
|
End Sub ' Truncate
|
|
|
|
Function CheckPIN(ReadOnly myPIN as String*5) as Byte
|
|
|
|
if AdminMode = 1 then
|
|
CheckPIN = 0 ' success
|
|
else
|
|
if PINFailCount >= MaxPINFail then
|
|
CheckPIN = 2 ' fail
|
|
else
|
|
if myPIN <> PIN then
|
|
CheckPIN = 1 ' fail
|
|
PINFailCount = PINFailCount + 1
|
|
else
|
|
CheckPIN = 0 ' Success
|
|
PINFailCount = 0
|
|
end if
|
|
end if
|
|
end if
|
|
|
|
End Function ' CheckPIN
|
|
|
|
Function CheckReaderKey(ReadOnly Idx as Byte, _
|
|
ReadOnly myReaderKey as String*5) as Byte
|
|
|
|
if (Asc(HOTPHost(Idx)(2)) AND &H80) then
|
|
if (ReaderKeyFailCount >= MAXReaderKeyFail) then
|
|
PINFailCount = MaxPINFail ' Lock card
|
|
CheckReaderKey = 1 ' fail
|
|
else
|
|
if myReaderKey <> ReaderKey then
|
|
CheckReaderKey = 1 ' Fail
|
|
ReaderKeyFailCount = ReaderKeyFailCount + 1
|
|
else
|
|
CheckReaderKey = 0 ' Success
|
|
ReaderKeyFailCount = 0 ' reset on good key
|
|
end if
|
|
end if
|
|
else
|
|
CheckReaderKey = 0 'Success
|
|
end if
|
|
|
|
End Function ' CheckReaderKey
|
|
|
|
Function CheckAdmin() as Byte
|
|
|
|
if AdminMode <> 1 then
|
|
CheckAdmin = 1 ' fail
|
|
else
|
|
CheckAdmin = 0 ' success
|
|
end if
|
|
|
|
End Function ' CheckAdmin
|
|
|
|
Function CheckIndex(Idx as Byte) as Byte
|
|
|
|
if Idx > HOTPNum then
|
|
CheckIndex = 1
|
|
else
|
|
CheckIndex = 0
|
|
end if
|
|
|
|
End Function ' CheckIndex
|
|
|
|
#ifdef ENABLECSETHOST
|
|
Command &H80 &H40 SetHost(Idx as Byte, Count as Integer, _
|
|
HostName as String*12, HOTPKey as String*20)
|
|
|
|
if CheckAdmin() <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
if CheckIndex(Idx) <> 0 then
|
|
SW1SW2 = swDataNotFound
|
|
Exit
|
|
End if
|
|
|
|
' store K
|
|
' HOTPKey(n) = K
|
|
|
|
' store K XOR IPAD
|
|
str20 = HOTPKey
|
|
tmpb1 = tmpb1 xor &H36363636
|
|
tmpb2 = tmpb2 xor &H36363636
|
|
tmpb3 = tmpb3 xor &H36363636
|
|
tmpb4 = tmpb4 xor &H36363636
|
|
tmpb5 = tmpb5 xor &H36363636
|
|
HOTPKeyI(Idx) = str20
|
|
|
|
' store K XOR OPAD
|
|
str20 = HOTPKey
|
|
tmpb1 = tmpb1 xor &H5C5C5C5C
|
|
tmpb2 = tmpb2 xor &H5C5C5C5C
|
|
tmpb3 = tmpb3 xor &H5C5C5C5C
|
|
tmpb4 = tmpb4 xor &H5C5C5C5C
|
|
tmpb5 = tmpb5 xor &H5C5C5C5C
|
|
HOTPKeyO(Idx) = str20
|
|
|
|
HOTPCount32(Idx) = Count
|
|
HOTPHost(Idx) = HostName
|
|
|
|
End Command ' SetHost
|
|
#endif 'ENABLECSETHOST
|
|
|
|
#ifdef ENABLECGETHOST
|
|
Command &H80 &H42 GetHost(Idx as Byte, Count as Integer, _
|
|
HostName as String*12, HOTPKey as String*20)
|
|
|
|
if CheckAdmin() <> 0 then
|
|
sw1sw2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
if CheckIndex(Idx) <> 0 then
|
|
sw1sw2 = swDataNotFound
|
|
Exit
|
|
end if
|
|
|
|
Count = HOTPCount32(Idx)
|
|
HostName = HOTPHost(Idx)
|
|
|
|
' load K XOR IPAD
|
|
' could also do this with OPAD...
|
|
str20 = HOTPKeyI(Idx)
|
|
tmpb1 = tmpb1 xor &H36363636
|
|
tmpb2 = tmpb2 xor &H36363636
|
|
tmpb3 = tmpb3 xor &H36363636
|
|
tmpb4 = tmpb4 xor &H36363636
|
|
tmpb5 = tmpb5 xor &H36363636
|
|
|
|
HOTPKey = str20
|
|
|
|
End Command ' GetHost
|
|
#endif 'ENABLECGETHOST
|
|
|
|
#ifdef ENABLECGETHOSTNAME
|
|
Command &H80 &H44 GetHostName(Idx as Byte, myPIN as String*5,_
|
|
HostName as String*12)
|
|
|
|
if CheckPIN(myPIN) <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
if CheckIndex(Idx) <> 0 then
|
|
SW1SW2 = swDataNotFound
|
|
Exit
|
|
end if
|
|
|
|
HostName = HOTPHost(Idx)
|
|
|
|
End Command ' GetHostName
|
|
#endif 'ENABLECGETHOSTNAME
|
|
|
|
#ifdef ENABLECGETHOTP
|
|
Command &H80 &H46 GetHOTP(Idx as Byte, myPIN as String*5, HOTP as String*5)
|
|
|
|
Call HOTPCommon(Idx, 0, myPIN, HOTP)
|
|
HOTP = HOTPTruncated
|
|
|
|
End Command ' GetHOTP
|
|
#endif 'ENABLECGETHOTP
|
|
|
|
#ifdef ENABLECSETADMINMODE
|
|
Command &H80 &H48 SetAdminMode(Mode as Byte, K as String*20)
|
|
|
|
if K <> AdminKey then
|
|
SW1SW2 = swAccessDenied
|
|
else
|
|
AdminMode = Mode
|
|
end if
|
|
|
|
if AdminMode = 1 then
|
|
ReaderKeyFailCount = 0 ' reset
|
|
PINFailCount = 0 ' reset
|
|
end if
|
|
|
|
End Command ' SetAdminMode
|
|
#endif 'ENABLECSETADMINMODE
|
|
|
|
#ifdef ENABLECSETBALANCECARDINDEX
|
|
Command &H80 &H4A SetBalanceCardIndex(Idx as Byte)
|
|
|
|
if CheckAdmin() <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
else
|
|
BalanceCardIndex = Idx
|
|
end if
|
|
|
|
End Command ' SetBalanceCardIndex
|
|
#endif 'ENABLECSETBALANCECARDINDEX
|
|
|
|
#ifdef ENABLECSETPIN
|
|
Command &H80 &H4C SetPIN(myPIN as String*5, newPIN as String*5)
|
|
|
|
if CheckPIN(myPIN) <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
else
|
|
PIN = newPIN
|
|
end if
|
|
|
|
End Command ' SetPIN
|
|
#endif 'ENABLECSETPIN
|
|
|
|
#ifdef ENABLECTESTPIN
|
|
Command &H80 &H4E TestPIN(myPIN as String*5)
|
|
private t as Byte
|
|
|
|
t = CheckPIN(myPIN)
|
|
|
|
if t <> 0 then
|
|
if t = 2 then
|
|
SW1SW2 = swBadAuthenticate ' too many tries
|
|
else
|
|
SW1SW2 = swAccessDenied
|
|
end if
|
|
end if
|
|
|
|
End Command ' TestPIN
|
|
#endif 'ENABLECTESTPIN
|
|
|
|
#ifdef ENABLECGETVERSION
|
|
Command &H80 &H50 GetVersion(V as Byte)
|
|
|
|
V = HOTPCodeVersion
|
|
|
|
End Command ' GetVersion
|
|
#endif 'ENABLECGETVERSION
|
|
|
|
#ifdef ENABLECSETADMINKEY
|
|
Command &H80 &H52 SetAdminKey(K as String*20)
|
|
|
|
if CheckAdmin() <> 0 then
|
|
sw1sw2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
AdminKey = K
|
|
|
|
End Command ' SetAdminKey
|
|
#endif 'ENABLECSETADMINKEY
|
|
|
|
#ifdef ENABLECSETHOST32
|
|
Command &H80 &H54 SetHost32(Idx as Byte, Count32 as Long,_
|
|
HostName as String*12, HOTPKey as String*20)
|
|
|
|
if CheckAdmin() <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
if CheckIndex(Idx) <> 0 then
|
|
SW1SW2 = swDataNotFound
|
|
Exit
|
|
End if
|
|
|
|
HOTPCount32(Idx) = Count32
|
|
HOTPHost(Idx) = HostName
|
|
|
|
' store K
|
|
' HOTPKey(n) = K
|
|
|
|
' store K XOR IPAD
|
|
str20 = HOTPKey
|
|
tmpb1 = tmpb1 xor &H36363636
|
|
tmpb2 = tmpb2 xor &H36363636
|
|
tmpb3 = tmpb3 xor &H36363636
|
|
tmpb4 = tmpb4 xor &H36363636
|
|
tmpb5 = tmpb5 xor &H36363636
|
|
HOTPKeyI(Idx) = str20
|
|
|
|
' store K XOR OPAD
|
|
str20 = HOTPKey
|
|
tmpb1 = tmpb1 xor &H5C5C5C5C
|
|
tmpb2 = tmpb2 xor &H5C5C5C5C
|
|
tmpb3 = tmpb3 xor &H5C5C5C5C
|
|
tmpb4 = tmpb4 xor &H5C5C5C5C
|
|
tmpb5 = tmpb5 xor &H5C5C5C5C
|
|
HOTPKeyO(Idx) = str20
|
|
|
|
End Command ' SetHost32
|
|
#endif 'ENABLECSETHOST32
|
|
|
|
#ifdef ENABLECGETHOST32
|
|
Command &H80 &H56 GetHost32(Idx as Byte, Count32 as Long,_
|
|
HostName as String*12, HOTPKey as String*20)
|
|
|
|
if CheckAdmin() <> 0 then
|
|
sw1sw2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
if CheckIndex(Idx) <> 0 then
|
|
sw1sw2 = swDataNotFound
|
|
Exit
|
|
end if
|
|
|
|
Count32 = HOTPCount32(Idx)
|
|
HostName = HOTPHost(Idx)
|
|
|
|
' load K XOR IPAD
|
|
' could also do this with OPAD...
|
|
str20 = HOTPKeyI(Idx)
|
|
tmpb1 = tmpb1 xor &H36363636
|
|
tmpb2 = tmpb2 xor &H36363636
|
|
tmpb3 = tmpb3 xor &H36363636
|
|
tmpb4 = tmpb4 xor &H36363636
|
|
tmpb5 = tmpb5 xor &H36363636
|
|
|
|
HOTPKey = str20
|
|
|
|
End Command ' GetHost32
|
|
#endif 'ENABLECGETHOST32
|
|
|
|
#ifdef ENABLECGETHOTPCOUNT32
|
|
Command &H80 &H58 GetHOTPCount32(Idx as Byte, myPIN as String*5,_
|
|
Count32 as Long, HOTP as String*5)
|
|
|
|
Call HOTPCommon(Idx, Count32, myPIN, HOTP)
|
|
HOTP = HOTPTruncated
|
|
|
|
End Command ' GetHOTPCount32
|
|
#endif 'ENABE_GETHOTPCOUNT32
|
|
|
|
#ifdef ENABLECGETHOTPHOST
|
|
Command &H80 &H5A GetHOTPHost(Idx as Byte, myPIN as String*5,_
|
|
HOTP as String*5, HostName as String*12)
|
|
|
|
Call HOTPCommon(Idx, 0, myPIN, HOTP)
|
|
HOTP = HOTPTruncated
|
|
HostName = HOTPHost(Idx)
|
|
|
|
End Command ' GetHOTPHost
|
|
#endif 'ENABLECGETHOTPHOST
|
|
|
|
#ifdef ENABLECGETHOTPHOSTCOUNT32
|
|
Command &H80 &H5C GetHOTPHostCount32(Idx as Byte, myPIN as String*5,_
|
|
Count32 as Long, HOTP as String*5, HostName as String*12)
|
|
|
|
Call HOTPCommon(Idx, Count32, myPIN, HOTP)
|
|
HOTP = HOTPTruncated
|
|
HostName = HOTPHost(Idx)
|
|
|
|
End Command ' GetHOTPHostCount32
|
|
#endif 'ENABLECGETHOTPHOSTCOUNT32
|
|
|
|
#ifdef ENABLECCLEARALL
|
|
Command &H80 &H5E ClearAll()
|
|
private i,j as Integer
|
|
|
|
if CheckAdmin() <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
end if
|
|
|
|
for i = 0 to HOTPNum
|
|
|
|
HOTPKeyI(i) = Chr$(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
|
HOTPKeyO(i) = Chr$(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
|
HOTPCount32(i) = 0
|
|
HOTPHost(i) = Chr$(0,0,0,0,0,0,0,0,0,0,0,0)
|
|
next i
|
|
|
|
BalanceCardIndex = 255
|
|
|
|
PINFailCount = 0
|
|
|
|
ReaderKeyFailCount = 0
|
|
|
|
AdminMode = 1
|
|
|
|
AdminKey = "00000000000000000000"
|
|
|
|
PIN = DefaultPIN
|
|
|
|
End Command ' ClearAll
|
|
#endif 'ENABLECCLEARALL
|
|
|
|
#ifdef ENABLESETReaderKey
|
|
Command &H80 &H60 SetReaderKey(myReaderKey as String*5)
|
|
|
|
if CheckAdmin() <> 0 then
|
|
SW1SW2 = swAccessDenied
|
|
Exit
|
|
else
|
|
ReaderKey = myReaderKey
|
|
end if
|
|
|
|
End Command ' SetReaderKey
|
|
#endif 'ENABLECSETReaderKey
|
|
|
|
Command &H80 &H90 GetCapabilities(C as Long)
|
|
|
|
C = Capabilities
|
|
|
|
End Command ' GetCapabilities
|
|
|
|
'
|
|
' The balance reader doesn't wait Long for a reponse so the HMAC must be
|
|
' computed in steps
|
|
'
|
|
|
|
#ifdef ENABLECPRDISPLAY
|
|
Command &HC8 &H00 PRDisplay(RecordNumber as Byte, DataFormat as Byte, _
|
|
DigitCount as Byte,DecimalPoint as Byte, _
|
|
Delay as Byte, MoreData as Byte, _
|
|
Data as String)
|
|
|
|
select case RecordNumber
|
|
|
|
case 0
|
|
DataFormat = PRAlpha
|
|
DigitCount = 0
|
|
DecimalPoint = 0
|
|
Delay = 1
|
|
MoreData = PRMoreData
|
|
|
|
' disable admin mode on first use.
|
|
if (AdminMode = 1) then
|
|
AdminMode = 0
|
|
end if
|
|
|
|
if BalanceCardIndex = 255 then
|
|
data = "Not Enabled"
|
|
dataFormat = PRAlpha
|
|
Exit Command
|
|
end if
|
|
|
|
Count64low = HOTPCount32(BalanceCardIndex)
|
|
|
|
' Display VER8-count
|
|
data = "VER8-" + hex$(Count64low)
|
|
|
|
' start inner hash of HMAC SHA-160(K XOR ipad,text)
|
|
Call ShaStart()
|
|
Call ShaAppend(HOTPKeyI(BalanceCardIndex))
|
|
|
|
case 1
|
|
DataFormat = PRAlpha
|
|
DigitCount = 0
|
|
DecimalPoint = 6
|
|
Delay = 1
|
|
MoreData = PRMoreData
|
|
data = "HOTP"
|
|
|
|
Count64low = HOTPcount32(BalanceCardIndex)
|
|
|
|
' inner hash still working
|
|
Call ShaAppend(IPAD44)
|
|
Call ShaAppend(Count64)
|
|
|
|
case 2
|
|
DataFormat = PRAlpha
|
|
DigitCount = 0
|
|
DecimalPoint = 5
|
|
Delay = 1
|
|
MoreData = PRMoreData
|
|
Data = "HOTP"
|
|
|
|
' done with inner hash. Store temp result in eestr20 while
|
|
' balance reader resets
|
|
eestr20 = ShaEnd()
|
|
|
|
case 3
|
|
DataFormat = PRAlpha
|
|
DigitCount = 0
|
|
DecimalPoint = 4
|
|
Delay = 1
|
|
MoreData = PRMoreData
|
|
Data = "HOTP"
|
|
|
|
' start outer hash H(K XOR opad, inner)
|
|
Call ShaStart()
|
|
Call ShaAppend(HOTPKeyO(BalanceCardIndex))
|
|
|
|
case 4
|
|
DataFormat = PRAlpha
|
|
DigitCount = 0
|
|
DecimalPoint = 3
|
|
Delay = 1
|
|
MoreData = PRMoreData
|
|
data = "HOTP"
|
|
|
|
' outer still working.
|
|
Call ShaAppend(OPAD44)
|
|
|
|
case 5
|
|
DataFormat = PRAlpha
|
|
DigitCount = 0
|
|
DecimalPoint = 2
|
|
Delay = 1
|
|
MoreData = PRMoreData
|
|
data = "HOTP"
|
|
|
|
' outer still working...
|
|
Call ShaAppend(eestr20)
|
|
|
|
' Increment Count just before displaying result.
|
|
|
|
Disable OverflowCheck
|
|
HOTPCount32(BalanceCardIndex) = HOTPCount32(BalanceCardIndex) + 1
|
|
Enable OverflowCheck
|
|
|
|
case 6
|
|
DataFormat = PRAlpha
|
|
DigitCount = 0
|
|
DecimalPoint = 1
|
|
Delay = 1
|
|
MoreData = PRMoreData
|
|
data = "HOTP"
|
|
|
|
' finish with outer
|
|
eestr20 = ShaEnd()
|
|
|
|
case 7
|
|
Delay = 10000 / PRDelayUnits ' display 10 seconds
|
|
DecimalPoint = 0
|
|
MoreData = PRNoMoreData
|
|
str20 = eestr20
|
|
' sets HOTPfmt, HOTPTruncated
|
|
Call Truncate(BalanceCardIndex)
|
|
|
|
if (HOTPfmt = 0) or (HOTPfmt = FMTHEX40) or (HOTPfmt = FMTDHEX40) then
|
|
DataFormat = PRHex
|
|
DigitCount = 10
|
|
' data must be 8 Bytes Long. 3 high order Bytes ignored by reader
|
|
data = "000" + HOTPTruncated
|
|
else
|
|
DataFormat = PRNum
|
|
DigitCount = 10
|
|
' data must be 4 Bytes Long.
|
|
data = Left$(HOTPTruncated,4)
|
|
end if
|
|
|
|
case else
|
|
' should not happen
|
|
SW1SW2=swDataNotFound
|
|
end select
|
|
|
|
End Command ' PRDisplay
|
|
|
|
#endif ' ENABLECPRDISPLAY
|