; ; Copyright © B. Gérard, 2012. ; e-mail: . ; ; This program is a free software: you can redistribute it ; and/or modify it under the terms of the GNU General Public ; License as published by the Free Software Foundation. ; ; It is distributed without any warranty of correctness nor ; fintess for any particular purpose. See the GNU General ; Public License for more details. ; ; . ; ; Description: hash function. ; Version 1.0 - June 2012. ; ; ; ---------------------------------------------------- ; | User interface: | ; |----------------------------------------------------| ; |(1) Data to hash must be in SRAM with the first byte| ; | at the location pointed by SRAM_DATA. The data | ; | has to be udated before each update or final | ; | call and the number of bytes needed in SRAM by | ; | each update call is equal to DATA_NUM_BYTE | ; | | ; | If final routine is called, r24 must contain | ; | the number of bytes of data passed to the | ; | function. | ; |----------------------------------------------------| ; |(2) Call init, update or final routine | ; |----------------------------------------------------| ; |(3) After each call, the intermediate (or final) | ; | hash function state is at location pointed by | ; | SRAM_STATE. Lenght of hash intermediate states | ; | is given by STATE_NUM_BYTE constant. | ; | Lenght of final hash value is given by | ; | HASH_NUM_BYTE. | ; ---------------------------------------------------- ; ; Constants ; .EQU DATA_NUM_BYTE = 32 ;Number of bytes that will be processed by the update function .EQU STATE_NUM_BYTE = 32 + 2 ;Memory needed for hash function intermediate state (in bytes) .EQU ADD_MEM_NUM_BYTE = 96 ;Optional additional memory for internal computation (in bytes) .EQU HASH_NUM_BYTE = 32 ;Size of output hash (in bytes) .DSEG SRAM_DATA: .BYTE DATA_NUM_BYTE SRAM_STATE: .BYTE STATE_NUM_BYTE SRAM_ADD_MEM : .BYTE ADD_MEM_NUM_BYTE .CSEG ; ; Registers declarations ;; RIJNDAEL regs ; Key registers .def K0 = R0 .def K1 = R1 .def K2 = R2 .def K3 = R3 ; State registers .def S0 = R4 .def S1 = R5 .def S2 = R6 .def S3 = R7 ; Temp registers .def T0 = R8 .def T1 = R9 .def T2 = R10 .def T3 = R11 .def T4 = R12 ; For message length .def LL = R13 .def LH = R14 ; Address backups .def SL = R16 ; "source" address for RoundCore .def SH = R17 .def DL = R18 ; "dest" address for RoundCore .def DH = R19 ; Rcon register .def Rcon = R20 ; Field polynomial .def Rpol = R21 ; Temp register .def I = R22 .def J = R23 ; Column index .def Col = R24 ; Round variable .def Rcount = R25 ; Initialisation ; Init the IV to all-zero value init: ldi XH, high(SRAM_STATE) ldi XL, low(SRAM_STATE) ldi I, 34 ; 32 for IV and 2 for message length ldi J, $00 init_loop: st X+, J; dec I brne init_loop ret ; Update Hash ; Set the key to the all-zero value ; Encrypts the bloc using DM mode ; Encrypts the chaining value using DM mode ; XORs both values ; Encrypts the XORed value ; Finally sets the IV to the XOR between the last result and the cencrypted bloc update: ; Copy bloc and set key to zero rcall loadloopvariables ldi J, $00 update_bloc_loop: std Z+32, J ld S0, Y+ st Z+, S0 dec I brne update_bloc_loop ; F1 rcall encrypt ; XOR result of encryption to DATA rcall loadloopvariables f1_xor_loop: ld S0, Z+ ld S1, Y eor S0, S1 st Y+, S0; dec I brne f1_xor_loop ; Store IV in SRAM_ADD_MEM rcall loadloopvariables ldi J, $11 store_loop: std Z+32, J ld S0, X+ st Z+, S0 dec I brne store_loop ; F2 rcall encrypt rcall loadloopvariables ldi J, $22 f2_xor_loop: std Z+32, J ld S0, Z ld S1, X ld S2, Y+ eor S0, S1 eor S0, S2 st X+, S0 st Z+, S0 dec I brne f2_xor_loop ; F3 rcall encrypt rcall loadloopvariables f3_xor_loop: ld S0, Z+ ld S1, Y+ ld S2, X eor S0, S1 eor S0, S2 st X+, S0 dec I brne f3_xor_loop ; Now increment the length of the message ld ZH, X+ ld ZL, X adiw Z, 32 st X, ZL st -X, ZH ret loadloopvariables: ldi XH, high(SRAM_STATE) ldi XL, low(SRAM_STATE) ldi YH, high(SRAM_DATA) ldi YL, low(SRAM_DATA) ldi ZH, high(SRAM_ADD_MEM) ldi ZL, low(SRAM_ADD_MEM) ldi I, 32 ret ; Final ; Update message length then check if enough Bytes to store ; message length. If no padd with zeros, update and start with ; new block (r24=0). ; r24 contains the number of bytes passed to the final function. final: ; Padding ldi XH, high(SRAM_STATE+32) ldi XL, low(SRAM_STATE+32) ld LH, X+ ld LL, X add LL, r24 ; LL + r24 < 0X10 -> no carries ; L contains the message length ;if r24 <= 24 then only one bloc cpi r24, 25 brcs SingleBloc ldi I, 32 sub I, r24 ; Pad with zeros and process the bloc ldi XH, high(SRAM_DATA) ldi XL, low(SRAM_DATA) add XL, r24 ldi J, $00 padding_loop1: st X+, J dec I brne padding_loop1 rcall update cbr r24, $FF SingleBloc: ldi XH, high(SRAM_DATA) ldi XL, low(SRAM_DATA) add XL, r24 ldi I, 30 sub I, r24 ldi J, $00 padding_loop2: st X+, J dec I brne padding_loop2 st X+, LH st X+, LL rcall update ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; RIJNDAEL 256 ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .CSEG .EQU SRAM_PTEXT = SRAM_ADD_MEM .EQU SRAM_KEY = SRAM_PTEXT + 32 .EQU SRAM_ADD_STATE = SRAM_KEY + 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ENCRYPTION ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; encrypt: ldi ZH, high(sbox_table<<1) ; Init round constant ldi Rcon, 1 ; Init field polynomial ldi Rpol, $1B ; Init Round counter ldi Rcount, 14; ; Jump to round core rjmp RoundCore FullRound: ; Updating Rcon lsl Rcon brcc RoundCore eor Rcon, Rpol ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; MIXADDSUBSHIFT ; ; (mixcolumns, add round key, ; ; bytesub and shiftrow, ; ; integrated in one function) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RoundCore: ; Select RAM locations depending on round parity bst Rcount,0 brts odd_round ldi SH, high(SRAM_PTEXT) ; for even rounds, copy from PTEXT to ADDMEM ldi SL, low(SRAM_PTEXT) ldi DH, high(SRAM_ADD_STATE-32) ldi DL, low(SRAM_ADD_STATE-32) rjmp even_round odd_round: ldi DH, high(SRAM_PTEXT-32) ; for even rounds, copy from ADDMEM to PTEXT ldi DL, low(SRAM_PTEXT-32) ldi SH, high(SRAM_ADD_STATE) ldi SL, low(SRAM_ADD_STATE) even_round: ; Load last key-state column in registers Kx for key schedule ; apply S-boxes, rotate and xor round constant ldi YH, high(SRAM_KEY) ldi YL, low(SRAM_KEY) ldd ZL, Y+31 lpm K2, Z ldd ZL, Y+30 lpm K1, Z ldd ZL, Y+29 lpm K0, Z ldd ZL, Y+28 lpm K3, Z eor K0, Rcon ; Initialization before looping over columns ldi XH, high(SRAM_KEY) ldi XL, low(SRAM_KEY) ldi I, 4 ldi Col, 0 roundcore_loop: ; Get the 4-byte column from the source movw Y, SH:SL ld S0, Y+ ld S1, Y+ ld S2, Y+ ld S3, Y+ movw SH:SL,Y ; Save the address of the following source column ;Skip first MixColumn to start with AddRoundKey cpi Rcount, 14 breq AddSubUp MixColumn: ; Mixing the column (S0 S1 S2 S3) mov T0, S0 eor T0, S1 mov T1, S1 eor T1, S2 mov T2, S2 eor T2, S3 mov T3, S0 eor T3, S3 mov T4, T0 eor T4, T2 ; xtime lsl T0 brcc nocarry0 eor T0, Rpol nocarry0: lsl T1 brcc nocarry1 eor T1, Rpol nocarry1: lsl T2 brcc nocarry2 eor T2, Rpol nocarry2: lsl T3 brcc nocarry3 eor T3, Rpol nocarry3: eor S0, T4 eor S0, T0 eor S1, T4 eor S1, T1 eor S2, T4 eor S2, T2 eor S3, T4 eor S3, T3 ; Column mixed AddSubUp: ; Now apply AddRoundKey + ByteSub + UpdateRoundKey ld ZL, X ; load key byte eor K0, ZL ; XOR key byte to previous key byte for updating key eor ZL, S0 ; XOR state byte to the key byte lpm S0, Z ; apply S-box to this value st X+, K0 ; update round-key byte ld ZL, X eor K1, ZL eor ZL, S1 lpm S1, Z st X+, K1 ld ZL, X eor K2, ZL eor ZL, S2 lpm S2, Z st X+, K2 ld ZL, X eor K3, ZL eor ZL, S3 lpm S3, Z st X+, K3 ; Store values according to ShiftRows in the destination movw Y, DH:DL ; place Y to the destination std Y+32, S0 mov J, Col dec J brmi wrap1 std Y+29,S1 subi J,2 brmi wrap2 std Y+22,S2 dec J brmi wrap3 std Y+19,S3 rjmp nowrap wrap1: std Y+61,S1 wrap2: std Y+54,S2 wrap3: std Y+51,S3 nowrap: adiw Y, 4 ; Y now points to the next destination column movw DH:DL, Y ; Save new destination ; Increment the Col variable inc Col ; Decrement loop variable dec I breq SpecialUpdateKey rjmp roundcore_loop SpecialUpdateKey: bst Col, 2; if 8th column then ends the round brtc end_loop ;else here we go for 4 more rounds ldi I,4 ; Since next column is the fifth, pass previous key-state column through S-boxes ; for key updating mov ZL, K0 lpm K0, Z mov ZL, K1 lpm K1, Z mov ZL, K2 lpm K2, Z mov ZL, K3 lpm K3, Z rjmp roundcore_loop end_loop: ; Decrement round counter dec Rcount breq FinalAddRoundKey ; branch to final key addition rjmp FullRound ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FINAL ADD ROUND KEY ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FinalAddRoundKey: ldi XH, high(SRAM_PTEXT) ldi XL, low(SRAM_PTEXT) ldi YH, high(SRAM_KEY) ldi YL, low(SRAM_KEY) ldi I, 32 finaladdroundkey_loop: ld S0, X ld K0, Y+ eor S0, K0 st X+, S0 dec I brne finaladdroundkey_loop ret; .org $400 sbox_table: .db $63,$7c,$77,$7b,$f2,$6b,$6f,$c5,$30,$01,$67,$2b,$fe,$d7,$ab,$76 .db $ca,$82,$c9,$7d,$fa,$59,$47,$f0,$ad,$d4,$a2,$af,$9c,$a4,$72,$c0 .db $b7,$fd,$93,$26,$36,$3f,$f7,$cc,$34,$a5,$e5,$f1,$71,$d8,$31,$15 .db $04,$c7,$23,$c3,$18,$96,$05,$9a,$07,$12,$80,$e2,$eb,$27,$b2,$75 .db $09,$83,$2c,$1a,$1b,$6e,$5a,$a0,$52,$3b,$d6,$b3,$29,$e3,$2f,$84 .db $53,$d1,$00,$ed,$20,$fc,$b1,$5b,$6a,$cb,$be,$39,$4a,$4c,$58,$cf .db $d0,$ef,$aa,$fb,$43,$4d,$33,$85,$45,$f9,$02,$7f,$50,$3c,$9f,$a8 .db $51,$a3,$40,$8f,$92,$9d,$38,$f5,$bc,$b6,$da,$21,$10,$ff,$f3,$d2 .db $cd,$0c,$13,$ec,$5f,$97,$44,$17,$c4,$a7,$7e,$3d,$64,$5d,$19,$73 .db $60,$81,$4f,$dc,$22,$2a,$90,$88,$46,$ee,$b8,$14,$de,$5e,$0b,$db .db $e0,$32,$3a,$0a,$49,$06,$24,$5c,$c2,$d3,$ac,$62,$91,$95,$e4,$79 .db $e7,$c8,$37,$6d,$8d,$d5,$4e,$a9,$6c,$56,$f4,$ea,$65,$7a,$ae,$08 .db $ba,$78,$25,$2e,$1c,$a6,$b4,$c6,$e8,$dd,$74,$1f,$4b,$bd,$8b,$8a .db $70,$3e,$b5,$66,$48,$03,$f6,$0e,$61,$35,$57,$b9,$86,$c1,$1d,$9e .db $e1,$f8,$98,$11,$69,$d9,$8e,$94,$9b,$1e,$87,$e9,$ce,$55,$28,$df .db $8c,$a1,$89,$0d,$bf,$e6,$42,$68,$41,$99,$2d,$0f,$b0,$54,$bb,$16