-
Notifications
You must be signed in to change notification settings - Fork 3
/
totp.xa
528 lines (445 loc) · 8.84 KB
/
totp.xa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
/* main loop for TOTP-C64 generator. requires setup from BASIC interface.
uses time.xa and sha1.xa as dependencies.
(c)2022 cameron kaiser. all rights reserved. BSD license.
http://oldvcr.blogspot.com/
*/
.word $4000
* = $4000
totpsa = *
/* initialize keys for HMAC and sprite display */
jmp initkeys
/* grab time from CMD device and start TOTP loop */
jmp totpcmd
/* grab manually provided time and start TOTP loop */
jmp totpman
; 64 byte key padded with zeroes
; at least 192 bytes required
key = 12288
; where to deposit sprites (watch for VIC char ROM images)
sprites = 8192
; forward define
sha1_zp0 = $57
initkeys
; create ipad and opad from key
ipad = key + 64
opad = key + 128
ldx #63
klup lda key,x
tay
eor #92
sta opad,x
tya
eor #54
sta ipad,x
dex
bpl klup
; set up sprites
; padlock sprite
ldx #62
klups lda sprdat,x
sta sprites,x
dex
bpl klups
; number sprites - clear first
ldx #160
lda #0
klupsc dex
sta sprites+64,x
sta sprites+64+160,x
sta sprites+64+320,x
sta sprites+64+480,x
cpx #0
bne klupsc ; can't use bpl
; next, copy from char ROM and stretch
sei
lda $01
and #251
sta $01 ; char ROM on
tospr = sha1_zp0
lda #$40
sta sha1_zp0
lda #$20
sta sha1_zp0+1
ldx #0 ; index into character set
ldy #0 ; index into current sprite
klupsp lda $d180,x ; the 0 glyph
sta (tospr),y ; stretch
iny
iny
iny
sta (tospr),y ; strrreeeettttcccchhhhh
iny
iny
iny
inx
cpy #48 ; six bytes per glyph row, eight rows in a glyph
bne klupsp
lda tospr
clc
adc #64
sta tospr
lda tospr+1
adc #0
sta tospr+1
ldy #0 ; advance to next sprite, reset index
cpx #80 ; ten character shapes copied
bne klupsp ; no, keep going
; setup complete
lda $01
ora #4
sta $01
cli
rts
totpcmd:
ldx #15
jsr cmuxtm
jmp totp
totpman:
jsr mauxtm
; fall thru
totp:
; flush keyboard buffer
lda #0
sta 198
; configure CIA #1 TOD clock for timekeeping
lda 56335
and #127 ; don't set the alarm
sta 56335
; set 50Hz or 60Hz timing using Silver Dream's method
; test with the TOD on CIA #2
; https://codebase64.org/doku.php?id=base:efficient_tod_initialisation
sei
lda #0
sta $dd08
nplup cmp $dd08
beq nplup
lda #255
sta $dd04
sta $dd05
lda #17
sta $dd0e
lda $dd08
nplup0 cmp $dd08
beq nplup0
lda $dd05
cli
cmp #$51
bcs t60hz ; 60Hz on TOD pin
lda 56334 ; 50Hz, turn on bit 7 for CIA #1
ora #128
sta 56334
jmp tcnvm
t60hz lda 56334 ; 60Hz, turn off bit 7 for CIA #1
and #127
sta 56334
; draw progress bar, first in base colour from utime LSB
tcnvm lda utime+7
sec
sbc #1 ; need the PAST colour
and #7
tax
inx ; no black
ldy #29
dpb0 txa
sta 55296+605,y
lda #160
sta 1024+605,y
dey
bpl dpb0
; predict next colour
lda utime+7
and #7
clc
adc #1
sta ccol
; if remainder seconds, overpaint partially, unless there are none
ldx utimem
stx totpb
stx totpb+2 ; save for destructive BCD conversion below
beq sclock
dpb1 dex
sta 55296+605,x
bne dpb1
; convert remainder seconds to BCD, from Andrew Jacobs' routine
sei
sed
lda #0
sta totpb ; use as workspace
sta totpb+1
ldx #8
tcnvbt asl totpb+2 ; don't clobber utimem, we use it for the prog bar
lda totpb
adc totpb
sta totpb
lda totpb+1
adc totpb+1
sta totpb+1
dex
bne tcnvbt
cld
cli
; start TOD clock as interval timer with that many seconds on
sclock lda #0
sta $dc0b
sta $dc0a
lda totpb ; guaranteed < 100
sta $dc09
lda #0
sta $dc08 ; click!
; and loop until exited
cycle
/* TOTP proceeds in four 512-byte chunks */
/* chunk 1: key padded to 64 bytes ^ 0x36. this is our ipad. */
ldx #63
tlup0 lda ipad,x
sta sha1_bytes,x
dex
bpl tlup0
jsr sha1_reset
jsr sha1_chunk
/* chunk 2: time counter || 0x80 || 53 nulls || 0x02 || 0x40 */
; clear it first, we're lazy
ldx #61
lda #0
tlup1 sta sha1_bytes,x
dex
cpx #7
bne tlup1
tlup1b lda utime,x
sta sha1_bytes,x
dex
bpl tlup1b
; load remainder
lda #128
sta sha1_bytes+8
lda #2
sta sha1_bytes+62
lda #64
sta sha1_bytes+63
; do NOT reset -- this is the same hash
jsr sha1_chunk
; stash hash for chunk 4
ldx #19
tlup2 lda sha1_h0,x
sta stash,x
dex
bpl tlup2
/* chunk 3: key padded to 64 bytes ^ 0x5c. this is our opad. */
ldx #63
tlup3 lda opad,x
sta sha1_bytes,x
dex
bpl tlup3
jsr sha1_reset
jsr sha1_chunk
/* chunk 4: hash from chunk 2 || 0x80 || 41 nulls || 0x02 || 0xa0 */
ldx #61
lda #0
tlup4 sta sha1_bytes,x
dex
cpx #19
bne tlup4
tlup5 lda stash,x
sta sha1_bytes,x
dex
bpl tlup5
lda #128
sta sha1_bytes+20
lda #2
sta sha1_bytes+62
lda #160
sta sha1_bytes+63
; do NOT reset -- this is the same hash
jsr sha1_chunk
/* compute 6 digit TOTP result */
/* offset within h0 || h1 || h2 || h3 || h4 is h4[3] & 0xf
take 32 bits, masking off the high bit (big-endian) for 31 bits */
ldy #3
lda sha1_h4,y
and #$0f
tay
lda sha1_h0,y
and #127
sta totpb
lda sha1_h0+1,y
sta totpb+1
lda sha1_h0+2,y
sta totpb+2
lda sha1_h0+3,y
sta totpb+3
/* the decimal version limit is 2**31, which is 10 digits.
we'll use the zp area, which is 10 bytes long */
ldx #10
lda #0
dex
sta sha1_zp0,x
bne *-3
/* totp code is last 6 digits */
#if(0)
/* long way: repeatedly subtract to compute decimal version */
#define DIGIT4(d,r,s,t,l,ll,lll) l=*: \
lda totpb:cmp #r:bcc lll:bne ll: \
lda totpb+1:cmp #s:bcc lll:bne ll: \
lda totpb+2:cmp #t:bcc lll:bne ll: \
ll=*: inc d: sec:\
lda totpb+2:sbc #t:sta totpb+2: \
lda totpb+1:sbc #s:sta totpb+1: \
lda totpb:sbc #r:sta totpb:jmp l: \
lll=*
/* no fourth byte because it's zero for these */
DIGIT4(sha1_zp0+0,$3b,$9a,$ca,bil,lio,ns) /* 1 000 000 000 */
DIGIT4(sha1_zp0+1,$05,$f5,$e1,hun,dre,dm) /* 100 000 000 */
#define DIGIT3(d,r,s,t,l,ll,lll) l=*: \
lda totpb:bne ll: \
lda totpb+1:cmp #r:bcc lll:bne ll: \
lda totpb+2:cmp #s:bcc lll:bne ll: \
lda totpb+3:cmp #t:bcc lll:bne ll: \
ll=*: inc d: sec:\
lda totpb+3:sbc #t:sta totpb+3: \
lda totpb+2:sbc #s:sta totpb+2: \
lda totpb+1:sbc #r:sta totpb+1: \
lda totpb:sbc #0:sta totpb:jmp l: \
lll=*
DIGIT3(sha1_zp0+2,$98,$96,$80,ten,mil,li) /* 10 000 000 */
DIGIT3(sha1_zp0+3,$0f,$42,$40,mll,ion,ss) /* 1 000 000 */
DIGIT3(sha1_zp0+4,$01,$86,$a0,hnd,red,th) /* 100 000 */
#define DIGIT2(d,s,t,l,ll,lll) l=*: \
lda totpb+1:bne ll: \
lda totpb+2:cmp #s:bcc lll:bne ll: \
lda totpb+3:cmp #t:bcc lll:bne ll: \
ll=*: inc d: sec:\
lda totpb+3:sbc #t:sta totpb+3: \
lda totpb+2:sbc #s:sta totpb+2: \
lda totpb+1:sbc #0:sta totpb+1:jmp l: \
lll=*
DIGIT2(sha1_zp0+5,$27,$10,tnt,hou,sd) /* 10 000 */
DIGIT2(sha1_zp0+6,$03,$e8,tho,usa,nd) /* 1 000 */
#define DIGIT1(d,t,l,ll,lll) l=*: \
lda totpb+2:bne ll: \
lda totpb+3:cmp #t:bcc lll:bne ll: \
ll=*: inc d: sec:\
lda totpb+3:sbc #t:sta totpb+3: \
lda totpb+2:sbc #0:sta totpb+2:jmp l: \
lll=*
DIGIT1(sha1_zp0+7,100,thr,eem,re) /* 100 */
DIGIT1(sha1_zp0+8, 10,tog,oan,dw) /* 10 */
; remainder is left in totpb+3
lda totpb+3
sta sha1_zp0+9
#else
/* short way: convert it to BCD
after Andrew Jacobs' routine, expanded to 32 bits
http://www.6502.org/source/integers/hex2dec-more.htm */
sei ; need this to avoid crashing the C64
sed
ldx #32
; BIG ENDIAN!
cnvbit asl totpb+3 ; shift out bit
rol totpb+2
rol totpb+1
rol totpb+0
; load into least significant bytes so that we can expand
; BIG ENDIAN!
#define LAZAD(w) lda sha1_zp0+w:adc sha1_zp0+w:sta sha1_zp0+w
LAZAD(9)
LAZAD(8)
LAZAD(7)
LAZAD(6)
LAZAD(5)
dex
bne cnvbit
cld
cli
; break up the last three bytes into six digits
#define BREKUP(w,x,y) \
lda sha1_zp0+w: \
tax:lsr:lsr:lsr:lsr: \
sta sha1_zp0+x: \
txa:and #$0f: \
sta sha1_zp0+y
BREKUP(7,4,5)
BREKUP(8,6,7)
BREKUP(9,8,9)
#endif
dundec
#if(0)
lda #13
jsr $ffd2
ldy #4
printlu lda sha1_zp0,y
clc
adc #48
jsr $ffd2
iny
cpy #10
bne printlu
lda #13
jsr $ffd2
#else
; set up sprites
ldy #4
sprlu lda sha1_zp0,y
clc
adc #129
sta 2036,y
iny
cpy #10
bne sprlu
lda #191
sta 53269
#endif
; watch clock until next 30 second interval, advancing prog bar
ldx $dc09
watchc cpx $dc09
bne checkw
lda 631
cmp #133
beq exit
bne watchc
checkw ldy utimem
lda ccol
sta 55296+605,y
inc utimem
ldx $dc09
cpx #$30
bcc watchc
; increment utime
lda #1
clc
adc utime+7
sta utime+7
lda utime+6:adc #0:sta utime+6
lda utime+5:adc #0:sta utime+5
lda utime+4:adc #0:sta utime+4
lda utime+3:adc #0:sta utime+3
lda utime+2:adc #0:sta utime+2
lda utime+1:adc #0:sta utime+1
lda utime:adc #0:sta utime
; do again
lda utime+7
and #7
clc
adc #1
sta ccol ; next colour
lda #0
sta utimem ; no more remainder
sta $dc0b
sta $dc0a
sta $dc09
sta $dc08 ; reset TOD timer entirely
jmp cycle
; F1 pressed
exit lda #0
sta 53269 ; die sprites
lda #0
sta 198 ; die keyboard buffer
lda #147
jmp $ffd2 ; die screen, die everything
totpb .byt 0,0,0,0
stash .dsb 20,0
ccol .byt 0
#include "sha1.xa"
#include "time.xa"
sprdat
#include "spr.gen"