From the Archives: TI-85 Password Protection

When I was in high school, the TI-85 was the shit. It was a great calculator, and someone had figured out how to install a loader that would allow you to run arbitrary native programs using some fancy hacking and installing programs into the “Custom” menu. The loader was called “ZShell.”

The TI-85 had an available serial port connector that let you transfer files to and from your computer and backup your calculator. ZShell was distributed as a backup file that once installed you could copy over individual programs in string variables.

Development was done using a Z80 cross assembler and some basic libraries and ROM calls that were distributed by the ZShell authors.

The first real program that I wrote and distributed was a password protection program called PWPROT. From the PWPROT readme file:

+-----------+
| Overview: |
+-----------+

    This program allows the user to implement a password protection scheme
for the Texas Instrument TI-85 graphing calculator.  The password can be
up to 8 characters long, uppercase alphabet only.

+--------+
| Usage: |
+--------+

    To run the program press the custom menu key.  This should show Zshell as
Custom Menu number 1.  Select it with the f1 key.  From the menu choose
pwprot.  The program will prompt the user for a menu of changing passwords,
shutting down, or quit.
    To change passwords select option 2, by hitting the 2 button.
The calculator will prompt you for the password, enter it bytyping it on
the calculator keys.  When you have completed the password hit enter.  The
calculator will then print the password you have entered and ask if it is
correct or not.  If it is correct select 1, and the calculatorwill display
password changed.  If you have have not entered the password correctly
choose option 2, and the calculator will display "Password Not Changed"
and return to the main menu.
    To shut down and use the password protection feature choose option
1 from the main menu.  The calculator will promptly turn itself off.  When
the on key is pressed pwprot will prompt you to enter a password if it is
correct the calculator will return to normal operating mode.  If it is
incorrect, the calculator will turn itself off again.

Below is the source code to PWPROT, my password protection program.

;+--------------------------------------------
;| Password Protection For TI-85, Via Zshell
;| Chris Bowron / Digital Dreamland 1996
;| ai150@detroit.freenet.org
;|
;|  "When Privacy Is Outlawed, Only Outlaws
;|             Will Have Privacy"
;|
;|  "Living is easy with eyes closed,
;|    Misunderstanding all you see"
;|                     John Lennon
;|
;|  "Anyone who says they can see through
;|        women is missing alot"
;|                     Groucho Marx
;+--------------------------------------------
;|Don't laugh, this is my first 'real' program
;+--------------------------------------------
;| Last Modification Jan 24, 1996 Circa 9:30 PM
;+----------------------------------------------
;| To Do List:
;|    Change Password From Program (e.g. Choose Shutdown or Change PW) - Done
;|    Distribute (String & Source) - In Progress
;|    Fathom How The Hell It Actually Works - Slowly, but Surely
;|    Self Encrypting????  - Pipe Dream 🙂
;|    Makes Wads Of Cash - Working on It
;|

#INCLUDE "TI-85.H"

#define RECALC     ld   hl,ZS_BITS  \ set  0,(hl)
#define WARPOUT    ld   hl,ZS_BITS  \ set  1,(hl)

TEXT_X =  $800D
TEXT_Y =  $800C

.org 0
.db "¿¿Â PW Protect v1.24",0

;+------
;| Start Here Buddy,
;+------

ProgStart:

    ROM_CALL(ClearLCD)
	ld  a,0
    ld  (text_x),a
    ld  (text_y),a
    ld  hl, (PROGRAM_ADDR)
    ld  de, MenuStr
    add hl, de
	ROM_CALL(D_ZT_STR)

    CALL_(WaitKey)

    cp K_EXIT
    jr z, OutOfHere

    cp K_3
    jr z, Menu3

    cp K_1
	jr z, Menu1

    cp K_2
	jr z, Menu2

    jr ProgStart

Menu1:
	CALL_(ShutDown)
    jr OutOfHere

Menu2:
    CALL_(ChangePassword)
	jr ProgStart

Menu3:

OutOfHere:

	CALL_(DispCorrect)
	CALL_(WaitKey)

	RECALC               ;Recalculate CheckSum
   	WARPOUT

	ret

;+-----
;| Change Password
;+-----
ChangePassword:

	ROM_CALL(ClearLCD)

    ld 	hl, (PROGRAM_ADDR)
    ld 	de, CurrentStr
    add hl, de
    ld  a,0
    ld  (text_x),a
    ld  a,4
    ld  (text_y),a
	ROM_CALL(D_ZT_STR)

    CALL_(GetPassword)
    CALL_(CheckPW)
    cp 0
    jr nz, WrongPW

    ROM_CALL(ClearLCD)

    ld 	hl, (PROGRAM_ADDR)
    ld 	de, NewStr
    add hl, de
    ld  a,0
    ld  (text_x),a
    ld  a,4
    ld  (text_y),a
    ROM_CALL(D_ZT_STR)

    CALL_(GetPassword)

    ROM_CALL(ClearLCD)

    ld a,0
    ld (text_x),a
    ld (text_y),a

    ld hl, (PROGRAM_ADDR)
    ld de, DummyStr
    add hl, de

    ROM_CALL(D_ZT_STR)

    ld a,0
    ld (text_x),a
    ld a,1
    ld (text_y),a

    ld hl, (PROGRAM_ADDR)
    ld de, YesNoStr
    add hl, de

    ROM_CALL(D_ZT_STR)

PWCKeyLoop:

	CALL_(WaitKey)

    cp K_1
    jr z, ChangeIt

    cp K_2
    jr z, DontDoIt

    cp K_EXIT
    jr z, DontDoIt

    jr PWCKeyLoop

ChangeIt:

	CALL_(DummyStr2PWStr)
    jr CPWExit

DontDoIt:

	ld 	hl, (PROGRAM_ADDR)
    ld 	de, NoChangeStr
    add hl, de
	ROM_CALL(D_ZT_STR)
	CALL_(WaitKey)
    jr  CPWExit

WrongPW:

	CALL_(DispWrong)
   	CALL_(WaitKey)

CPWExit:

    ret
;+----
;| Copy Password From DummyStr to PWStr
;+----
DummyStr2PWStr:
	ld  hl, (PROGRAM_ADDR)
    ld  de, DummyStr
    add hl, de				; HL Points To DummyStr
    ex  de, hl				; DE Points To DummyStr

    ld  hl, (PROGRAM_ADDR)
    ld  bc, PWStr
    add hl, bc				; HL Points To PWStr

    ld b, 8					; 8 Chars For PW
CILoop:

	ld a, (de)
    ld (hl), a				; PWStr[8-b] = DummyStr[8-b]

    inc hl
    inc de

	djnz CILoop

	ld 	hl, (PROGRAM_ADDR)
    ld 	de, ChangeStr
    add hl, de
	ROM_CALL(D_ZT_STR)
    CALL_(WaitKey)

	ret

;+-----
;| Shut Down Calculator, Prompting For PW When Turned ON
;+-----
ShutDown:

   ROM_CALL(ClearLCD)
   CALL_(DispInfo)

MajorLoop:

   CALL_(PowerDown)

   CALL_(GetPassWord)

   CALL_(CheckPW)

   cp 0
   jr z, CorrectPW

WrongStinkingPW:

   CALL_(DispWrong)
   CALL_(WaitKey)
   ROM_CALL(ClearLCD)
   CALL_(DispInfo)

   jr MajorLoop

CorrectPW:

ReturnCalc:

   ret

;+------
;| Display Program Info
;+------
DispInfo:

   ld  a, 0
   ld  (text_x),a
   ld  (text_y),a
   ld  de, InfoStr
   ld  hl, (PROGRAM_ADDR)
   add hl, de
   ROM_CALL(D_ZT_STR)
   ret

;+------
;| Display Incorrect PW Info
;+------
DispWrong:

   ROM_CALL(ClearLCD)

   ld  a, 0
   ld  (text_x),a
   ld  (text_y),a
   ld  de, WrongPWStr
   ld  hl, (PROGRAM_ADDR)
   add hl, de
   ROM_CALL(D_ZT_STR)
   ret

;+------
;| Display Correct PW Info
;+------
DispCorrect:

   ROM_CALL(ClearLCD)

   ld  a, 0
   ld  (text_x),a
   ld  (text_y),a
   ld  de, CorrectPWStr
   ld  hl, (PROGRAM_ADDR)
   add hl, de
   ROM_CALL(D_ZT_STR)

   ret

;+------
;| Wait Until Keypressed (A = Scan code)
;+------
WaitKey:

   call get_key
   cp K_NOKEY
   jr z, WaitKey
   ret

;+------
;| Wait Till Key Pressed Or LCD Is On / Currently Unused
;+------
;WaitOn:
;
;    in a, (3)
;
;    bit 1, a			; Is LCD On?
;    jr nz, ExitWO
;
;    bit 0, a
;    jr  nz, ExitWO		; Has On Been Pressed?
;
;    bit 3, a
;    jr  z, ExitWO	    ; Is On Pressed NOW...
;
;	call GET_KEY
;    cp 0
;    jr z, WaitOn
;
;ExitWO:
;
;	ret
;
;+------
;| Shut Down Calculator
;+------
PowerDown:

    DI

   	ld a, 00000001b
	OUT  ($03),A
		 ;76543210
    ld a, 00000000
    	 ;   ||||
         ;	 ||++---Low Resistance
		 ;	 ++---- 10 Byte Buffer
    out (4),a

	EX	AF,AF'		; 4B59
	EXX			; 4B5A

    ;ld a, $40		; Doesn't work correctly
    ;out (6),a

	EI
	HALT

TurnOn:

   	;DI

    ld 	a,  $16			; Normal Buffer Mode
    out (4),a

   	ld  a, $41
   	out (6),a

	ld a, 00001011b      ;LCD On
   	out (3),a

   	;EI

   	ret
;+------
;| Get Password From Calculator
;+------
GetPassWord:

   ld  a, 0
   ld  (text_x),a
   ld  a, 5
   ld  (text_y),a
   ld  hl, (PROGRAM_ADDR)
   ld  de, PromptStr
   add hl,de

   ROM_CALL(D_ZT_STR)           ; print prompt

   CALL_(GetString)             ; DummyStr = Entered Password

   ret

;+------
;| Get String Into DummyStr
;+------
GetString:
   ld   hl,(PROGRAM_ADDR)
   ld   de, DummyStr
   add  hl, de          ; HL Points To DummyStr

   push hl              ; start of DummyStr

   ld   b, 8            ; Zero Out DummyStr

FillLoop:
   inc hl
   ld  a,0
   ld  (hl), a
   djnz FillLoop

   pop hl

GSLoop:

   push hl

   ld a, 'Ú'
   ROM_CALL(TX_CHARPUT)
   ld hl, (TEXT_X)
   dec hl
   ld (TEXT_X), hl
   pop hl

   CALL_(GetLetter)
   cp 0
   jr z, HopOut

   cp K_EXIT
   jr z, HopOut

   ld (hl),a

   inc b
   inc hl

   ld a, b      ; Check If 8 Chars entered
   cp 8
   jr nz, GSLoop

HopOut:

   ld  a, 0
   ld  (hl),a   ;  Set to Null

   ret

;+----
;| Check if DummyStr=PWStr
;+----
CheckPW:
   ld   hl, (PROGRAM_ADDR)
   ld   de, DummyStr
   add hl, de
   ex  de, hl           ; DE Points To DummyStr

   ld  hl, (PROGRAM_ADDR)
   ld  bc, PWStr
   add hl, bc           ; HL Points To PWStr

CheckLoop:

   ld a, (hl)           ; HL to PWStr
   ld b, a              ; DE to DummyStr
   ex de, hl            ;  Switch

   ld a,(hl)            ; HL to DummyStr
   ex de, hl            ; DE Points to PWStr

   cp b
   jr nz, NotEqual

Equal:                  ; DE[n] = HL[n]

   inc de               ; increase pointers
   inc hl

   cp 0                 ; If Zero Return 0
   jr nz, CheckLoop     ; A = 0
                        ; EOS
   ld b,0
   jr BaBoom

NotEqual:

   ld b, 1              ; If Not = Then Return 1

BaBoom:

   ld a,b               ; ret b as acc
   ret

;+-------
;| Get One Letter & Translate
;| This routine and LetterTable from Magnus Hagander's Texanoid Game
;+-------
GetLetter:
   push hl
   push bc
   ld   hl,(PROGRAM_ADDR)
   ld   de,LetterTable-1 ;Point to one before, since we always inc once
   add  hl,de                   ;HL now points right

ConvertLoop:
   push hl
   CALL Get_Key                 ;ACC holds key
   pop  hl

   cp   K_EXIT                  ;temp
   jr   z, Shazam

   cp   0
   jr   z,ConvertLoop

   push hl                      ;save away...
   ld   b,a
   ld   c,0

ConversionLoop:
   inc  hl
   djnz ConversionLoop          ;After this, we have the correct offset...
   ld   a,(HL)
   pop  hl
   cp   255
   jr   z,ConvertLoop           ;Invalid key

   ROM_CALL(TX_CHARPUT)         ;Show the char

Shazam:

   pop  bc
   pop  hl

   ret                          ;Value is in acc

;+-------
;|  Stuff That's Useful
;+-------
InfoStr:
       ;123456789012345678901 ;
   .db "  Password  Protect  "
   .db "  Digital Dreamland  "
   .db " hristopher  owron "
   .db 0                       ; End String

MenuStr:
   	   ;123456789012345678901
   .db " ¿¿Â Password Protect"
   .db "      Ver 1.24       "
   .db "1. Shut Down         "
   .db "2. Change Password   "
   .db "3. Quit              "
   .db 0

NewStr:
   .db "New ",0
CurrentStr:
   .db "Current ",0
PromptStr:
   .db "Password:",0

PWStr: ;1234567
   .db 'B','O','O',0,0,0,0,0,0        ; Allow for 8 chars + Null Byte

DummyStr:
   .db 0,0,0,0,0,0,0,0,0        ; Temp Work Space

YesNoStr:
	   ;123456789012345678901
   .db "Is This Correct?    "
   .db "1. Yes               "
   .db "2. No                "
   .db 0

ChangeStr:
   .db "Password Changed",0

NoChangeStr:
   .db "Password Not Changed",0

WrongPWStr:
   .db "Incorrect PW!",0

CorrectPWStr:
       ;123456789012345678901
   .db " Thank You For Using " ;1
   .db "    DDL Products     " ;2
   .db "    ¿¿Â MCMXCVI      " ;3
   .db "                     " ;4
   .db "  [Share And Enjoy]  " ;5
   .db "ai150@               " ;6
   .db "detroit.freenet.org  " ;7
   .db 0

LetterTable:                                ; For converting keys into letters
   .db 255,255,255,255
   .db 255,255,255,255
   .db 000,'X','T','O'
   .db 'J','E',255,255
   .db ' ','W','S','N'
   .db 'I','D',255,255
   .db 'Z','V','R','M'
   .db 'H','C',255,255
   .db 'Y','U','Q','L'
   .db 'G','B',255,255
   .db 255,255,'P','K'
   .db 'F','A',255,255
   .db 255,255,255,255
   .db 255,255,255,255

.end

One thought on “From the Archives: TI-85 Password Protection

Leave a Reply

Your email address will not be published. Required fields are marked *