hier de secanix assem. voor de liefhebbers.
; Version 44.2G
; 2000, November 26
; Supports:
; autoupdate
; remote update
; superencription
; LED flashing on CAM comms
; LED set on keys/subscription date update
;------------------------------------------------------------------------------------
;
; PIC 16F84/16C84
; _______ _______
; | \/ |
; LED GREEN__RA2 --+ 1 << >> 18 +-- RA1__YELLOW LED
; | |
; LED GREEN2__RA3 --+ 2 >> 17 +-- RA0__RED LED
; | |
; not used__rtcc --+ 3 << 16 +-- OSC1/CLKIN__from CAM (CLOCK)
; | |
; from CAM__MCLR --+ 4 >> 15 +-- OSC2/CLKOUT__not used
; | |
; from CAM__Vss --+ 5 >> << 14 +-- Vdd__from CAM
; | |
; not used__RB0 --+ 6 <> 13 +-- RB7__from /to CAM (data)
; | |
; not used__RB1 --+ 7 << 12 +-- RB6__from CAM (CLOCK)
; | |
; not used__RB2 --+ 8 >> 11 +-- RB5__SCLK to EEprom
; | |
; not used__RB3 --+ 9 <> 10 +-- RB4__SDAta from / to EEprom
; | |
; +----------------+
;
; ">>" and "<<" indicate connected pins.
;
;------------------------------------------------------------------------------------
;
; 24C16/24LC16
; _______ _______
; | \/ |
; Gnd__A0 --+ 1 << 8 +-- VCC (2.5-5.5 24LCXX / 4.75-5.25 24CXX)
; | |
; Gnd__A1 --+ 2 << 7 +-- Write Protection__Gnd
; | |
; Gnd__A2 --+ 3 << 6 +-- SCLK__Serial Clock (max 400 Khz)
; | |
; GND --+ 4 >> <> 5 +-- SDA__Serial Data input/Output
; | |
; +----------------+
;
; Signal Condition
; SCLK ___|---|___|---|___|---|___|---|___|---|___|---|___|---|___|---|__
; SDA ====>-<=====>-<=====>-<=====>-<=====>-<=====>-<=====>-<=====>-<===
;
; Data Transfer
; S = Start Bit
; 1 = hight level logic
; 0 = low level logic
; B = Block Address
; C = Address
; D = Data
; X = dont care
; R = 1Read 0Write
; A = ACK (0 level)
; N = NO ACK (1 level)
; P = Stop Bit
;
; ---Control byte---- ---Address byte-- ---Data byte-----
; | | | | | |
; 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2
; 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
; | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
; Byte Write S 1 0 1 0 B B B R A B B B B B B B B A D D D D D D D D A P
;
; ---Control byte---- ---Address byte-- ---Data byte----- ---Data byte-----
; | | | | | | | |
; 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 ---- n n n
; 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ---- 1 2 3
; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ---- | | |
; Page Write S 1 0 1 0 B B B R A B B B B B B B B A D D D D D D D D A D D D D D D D D A D D D ---- D A P
; 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 15
;
; ---Control byte---- ---Data byte-----
; | | | |
; 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2
; 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
; | | | | | | | | | | | | | | | | | | | |
; Byte Read S 1 0 1 0 B B B R A D D D D D D D D N P
;
; ---Control byte---- ---Address byte-- ---Control byte---- ---Data byte-----
; | | | | | | | |
; 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3
; 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
; Byte Read Add S 1 0 1 0 B B B R A B B B B B B B B A S 1 0 1 0 B B B R A D D D D D D D D N P
;
; ---Control byte---- ---Data byte----- ---Data byte----- ---Data byte-----
; | | | | | | | |
; 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 ---- n n n
; 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 ---- 1 2 3
; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ---- | | |
; Seque. Read S 1 0 1 0 B B B R A D D D D D D D D A D D D D D D D D A D D D D D D D D A ---- D N P
; 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 X
;
;------------------------------------------------------------------------------------
LIST P=16F84, F=INHX8M
include "P16F84.inc"
errorlevel 1,-224,-302
;******************************************************
constant LED=1 ; <===
;******************************************************
constant T_SERIAL = 0x1A ; 0x1B for Kenwood
constant T_SEND_START = 0x32
constant T_SEND_STOP = 0x4F
constant T_RECEIV_START = 0x2A
constant T_RECEIV_STOP = 0x28
; LED policy:
; Green is turned on by start of comms from/to CAM, and it is turned off by end of comms from/to CAM
; Yellow is turned on by Ins 1a and 5a, and it is turned off by Ins 3c
; Red is turned on by key and subscription updates
; Green2 is not used by now
; Yellow, Red and Green2 are turned off by entering PIN menu or by entering 0000 as PIN
IF LED
constant LED_RED = 0 ; Red LED (RA0)
constant LED_YELLOW = 1 ; Yellow LED (RA1)
constant LED_GREEN = 2 ; Green LED (RA2)
constant LED_GREEN2 = 3 ; Green2 LED (RA3)
ENDIF
;******************************************************
ORG 0x0000
CALL Std_pause ; Returns W=0
; The following is obsolete, but more compact
TRIS PORTA ; Define PORT as all output
IF LED ;
MOVWF PORTA ; Init LED ports (RA0,1,2,3)
BSF PORTA,LED_GREEN2 ;\
BSF PORTA,LED_RED ; LED check
BSF PORTA,LED_YELLOW ; start
ENDIF ;/
ADDLW 0x7F ; Load OPTION register with 0x7f (PORT B pull-ups enabled)
OPTION
; Code above should be written instead as
; BSF STATUS,RP0 ; Select bank 1
; MOVWF TRISA ; Define PORT A as all output
; IF LED ;\
; MOVWF PORTA ; Init LED ports (RA0,1)
; ENDIF ;/
; BCF OPTION_REG, NOT_RBPU ;PORT B pull-ups enabled, OPTION_REG is set to 0XFF on all resets
; BCF STATUS,RP0 ; Select bank 0
; Read the ATR bytes stored in the pic eeprom in reverse order, starting from position 0x0E down to
; position 0x01, 14 bytes total
MOVLW 0x0E ; ATR end address
MOVWF 0x10 ; Internal eeprom pointer
ATR_loop MOVF 0x10,W ;\
CALL Rd_eeprom ;
CALL Send ; ATR
DECFSZ 0x10,f ;
GOTO ATR_loop ;/
IF LED ;\
MOVWF PORTA ; \
BCF PORTA,LED_GREEN2 ; LED check
BCF PORTA,LED_RED ; stop
BCF PORTA,LED_YELLOW ; /
ENDIF ;/
; Send status bytes 9000, end of response with no error, or 900D when an error is simulated
; If bit 3 of PCLATH has value 1 then a 901D is sent, else 9000 is sent
; Status bytes 901D are sent on reception of a C1 40 command which does not contain keys
; since this reduces the message traffic between cam and card
TX9000 MOVLW 0x90
TX00_1D CALL Send
MOVLW 0x00 ; 9000
BTFSC PCLATH,0x03 ; (use of bits 3:4 of PCLATH is discouraged)
MOVLW 0x1D ; 901D
CALL Send
CLRF PCLATH ; Reset PCLATH
; Wait for and receive the first byte of the command (C1)
; THIS CALLS THE MAIN LOOP
CALL Receive ; Get class byte (SECA: C1), discard it
; Read the remaining 4 bytes from the command header and put
; them into RAM starting from RAM position 0x0C,
; that is
; 0x0C: Instruction byte
; 0x0D: P1
; 0x0E: P2
; 0x0F: Length
MOVLW 0x0C ; Initialize pointer
MOVWF FSR ; to RAM
Com_loop CALL Receive ; Read 1 byte
MOVWF INDF ; store it into RAM
MOVWF 0x10 ; store it into 0x10 also
INCF FSR,f ; Increment pointer to next RAM location
BTFSS FSR,0x04 ; is 0x1F pointed?
GOTO Com_loop ; no, repeat
; yes, the last stored value was in RAM location 0x0F
; The instruction to be processed is in RAM position 0x0C, while the list of valid
; instructions is stored in a table in the internal EEPROM starting from position 0x0E
; it contains 0x0E commands in this version
MOVLW 0x0E ; We have 0x0E instructions
MOVWF 0x11 ; instructions counter
Comm_scan MOVF 0x11,W
ADDLW 0x0E ; Offset wrt internal EEPROM
CALL Rd_eeprom ; Read an instruction
XORWF 0x0C,W
BTFSC STATUS,Z ; if this is the received instruction
GOTO Send_ack ; then jump to process it
DECFSZ 0x11,f ;\ else decrement the instructions counter
GOTO Comm_scan ;/ and look down in the instruction table
MOVLW 0x6D ; If the received instruction is not found, return 6D00
GOTO TX00_1D
Send_ack MOVF 0x0C,W ;\ ACK (echo of instruction byte in 0x0C)
CALL Send ;/
MOVF 0x11,W ; 0x11 contains the instruction index in the EEPROM table
; The following has been modified to be position independent
; ADDLW 0x2B ; (2B was the MOVVWF address, substitute to 2B the correct MOVWF address)
ADDLW Tab_instr ; Add the instruction index to the Tab_instr label address
; In the following a table is contained which corresponds to the instructions table
; stored in the internal EEPROM, i.e. in the same order
; The program counter is then set to the same offset in this table as the received instruction
; in the instruction table
Tab_instr MOVWF PCL ; Jump to the GOTO which actually processes the command
GOTO Instr_0A ; Operating system version
GOTO Instr_0E ; Serial number
GOTO Instr_16 ; Number of providers
GOTO Instr_12 ; Provider ID (ident)
GOTO Instr_34 ; Data request specification
GOTO Instr_32 ; Data request
GOTO Instr_22 ; Key update ?
GOTO Instr_30 ; PIN protected transaction
GOTO Instr_21 ; External EEPROM read ?
GOTO Instr_3A ; ECM decoding control word
GOTO Instr_3C ; ECM coding control word
GOTO Instr_40 ; EMM subscription management
GOTO Instr_1A ; Key index selection
GOTO Instr_5A ; CipherText selection
; Not supported yet:
; 3E key request
; 68 CSD attack (seems it probes ID 13,14,15)
;=======================================================================
; C1 INSTRUCTION PROCESSING
;=======================================================================
;*************************************************
; function : 5A C1 CLASS instruction *
; CipherText selection *
;*************************************************
; The (P2+1) values for instr. 5a are stored in a table in the internal EEPROM
; starting at offset 0x30 (this table is indexed by the P1 value)
; The number of bytes to be returned is contained in the register file 0x10
; (copy of 0x0F, command length parameter)
Instr_5A
IF LED ;\
BSF PORTA,LED_YELLOW ; Yellow LED on
ENDIF ;/
INCF 0x0E,f ; Increment P2 by one
MOVF 0x0D,W ; Load P1 value (0-15) in W
ADDLW 0x30 ; Add table start address to W
CALL Rd_eeprom ; Read the value indexed by P1 from the table
ANDWF 0x0E,W ;\ If ((P2+1) and (value read from 5a answer table))=0
BTFSS STATUS, Z ; then 9000 will be returned as status bytes at end of response
BSF PCLATH,0x03 ;/ else 901D
MOVLW 0xFF ;\ Transmit as many 0xFF as stored in file register 0x10
GOTO send_w_fill ;/ followed by the status bytes
;*************************************************
; function : 0E C1 CLASS instruction *
; request smartcard serial number *
; command : C1 0E 00 00 08 *
; answer : 0E 00 03 00 00 00 CA 13 66 90 00 *
; i.e. region is 03, UA is 00 00 00 CA 13 66 *
; It corresponds to serial number 013.243.238 *
;*************************************************
; Instr. 0E: send the byte sequence stored from offset 0x00 in the external EEPROM
; The number of bytes to be sent was stored in file register 0x0F (it should be
Instr_0E MOVLW 0x00 ; Offset in the external EEPROM
COMM_EEPR CALL EEPROM_send ; Transmit data from external EEPROM
GOTO TX9000 ; Transmit status bytes
;*************************************************
; function : 0A C1 CLASS instruction *
;*************************************************
; Instr. 0A: send the byte sequence stored from offset 0x1BB to offset 0x1FF in the external EEPROM
Instr_0A INCF PCLATH,f ; Offset in the external EEPROM, high byte, page 1 (i.e. set PCLATH to 1)
MOVLW 0xBB ; Offset in the external EEPROM, low byte
GOTO COMM_EEPR ; Transmit answer
;*************************************************
; function : 1A C1 CLASS instruction *
;*************************************************
; Instr. 1A: send the byte sequence stored from offset 0x1A6 to offset 0x1BA in the external EEPROM
Instr_1A
IF LED ;\
BSF PORTA,LED_YELLOW ; Yellow LED on
ENDIF ;/
INCF PCLATH,f ; Offset in the external EEPROM, high byte, page 1 (i.e. set PCLATH to 1)
MOVLW 0xA6 ; Offset in the external EEPROM, low byte
GOTO COMM_EEPR ; Transmit answer
;*************************************************
; function : 16 C1 CLASS instruction *
; ENTITIES SUPPORTED *
;*************************************************
; Instr. 16: send the byte sequence stored from offset 0x08 in the external EEPROM
Instr_16 MOVLW 0x08 ; Offset in the external EEPROM
GOTO COMM_EEPR ; Transmit answer
;*************************************************
; function : 12 C1 CLASS instruction *
; this instruction requests an ID CAM *
; command : C1 12 aa 00 18 *
; aa is the ID provider *
; answer : 12 ii ii bb bb bb bb bb bb bb bb bb *
; bb bb bb bb bb bb bb 00 xx xx xx zz *
; zz 90 00 *
; ii ii : provider channel *
; bb..bb : provider name *
; xx..xx : smartcard address (PPUA) * *
; zz zz : termination date ( 7 bits year since *
; 1990 + 4 bits month + 5 bits day ) *
;*************************************************
; Instr. 12: file register 0x0D contains P1, i.e. the provider ID
; W is initialized by -8 (0xF8) and each loop iteration increments W by 0x18 which is the
; length of the ID CAM for each provider. Since the loop starts by incrementing W, the first provider
; data (P1=0) are stored from offset 0x18-0x08=0x10 in the external EEPROM. Moreover a check is provided
; to increment PCLATH when the external EEPROM offset 0x100 has to be reached. Than at the end of the loop
; PCLATH contains the high byte for the external EEPROM address to be read and W the low byte
Instr_12 MOVLW 0xF8 ; Initialize offset in the external EEPROM to -8
INCF 0x0D,f ; P1 + 1 loop iterations, since 1st provider corresponds to P1=0
instr_12_loop
ADDLW 0x18 ; ID CAM length
BTFSC STATUS,Z ;\ If 0x100 has been reached
INCF PCLATH,f ;/ then increment PCLATH (i.e. set PCLATH to 1)
DECFSZ 0x0D,f ;\ Loop until the provider specified by P1 is reached
GOTO instr_12_loop ;/
GOTO COMM_EEPR ; Transmit answer
;*************************************************
; function : 3C C1 CLASS instruction *
; ENTITLEMENT CONTROL MESSAGE *
;*************************************************
; command :
; C1
; 3C ; command
; 04 ; 4-th provider on the card
; 0C ; key 0C
; 27 ; 27H bytes long
; answer:
; 3C ; ACK
; 71 00 ; unknown
; 00 10 ; provider
; 07 D0 ; year
; 00 08 ; month
; 27 ; separator
; 15 0C ; complete data
; 13 21 ; boundle
; [D1] ; marker
; EF 44 F8 57 15 A0 A0 A6 ; control word 1
; D0 11 1C 81 87 6E 24 8E ; control word 2
; 82 ; separator
; 23 C0 DF FB 10 19 62 DB ; signature
; 90 00 ; status bytes
;
; This instruction sends encrypted control words to be decrypted
; First GET_CW_loop is called. That routine receives the remaining part of the command,
; reads the 16 bytes key from the external EEPROM according to P1 and P2, and in case of
; superencription it implements the first decription
Instr_3C
IF LED ;\
BCF PORTA,LED_YELLOW ; Yellow LED off
ENDIF ;/
CALL GET_CW_loop ;
; The routine swap_eedat swaps an 8-bytes block with another
; W has to contain the st block starting position and EEADR the offset of the 1st block wrt the 2nd
; In 0x14 GET_CW_loop has stored the first free position following the command just received
; Swap the block starting 0x11 bytes before the last byte with the one starting at 0x0C
MOVF 0x14,W ;\
SUBLW 0x1D ; 1st block offset wrt 2nd block (0x1D is used as offset since it is 0x11+0x0C)
MOVWF EEADR ;/
MOVLW 0x0C ; First block start
CALL swap_eedat ; Swap blocks
; Load into 2nd encrypted word position
CALL swap_2C_38 ; Swap bytes 0x0C-0x13 with 0x38-0x3F
; Swap the block starting 0x19 bytes before the last byte with the one starting at 0x0C
MOVF 0x14,W ;\
SUBLW 0x25 ; 1st block offset wrt 2nd block (0x25 is used as offset since it is 0x19+0x0C)
MOVWF EEADR ;/
MOVLW 0x0C ; First block start
CALL swap_eedat ; Swap blocks
; Load into 1st encrypted word position
CALL swap_24_30 ; Swap bytes 0x0C-0x13 with 0x30-0x37
; Decrypt the two control words
CALL Decrypt ; Decrypt 1st word
CALL swap_F8_30 ; Swap 1st and 2nd word (0x30-0x37 with 0x38-0x3F)
CALL Decrypt ; Decrypt 2nd word
CALL swap_F8_30 ; Swap words again
GOTO TX9000 ; That's all, transmit status bytes
;-----------------------------------------------------------------------
GET_CW_loop MOVLW 0x31 ;\
SUBWF 0x10,W ; If the command contains at most 0x31 bytes (in 0x10 was a copy of the length parameter)
BTFSS STATUS,C ;/
GOTO store18 ; then start storing it from RAM position 0x18
MOVLW 0x08 ;\
SUBWF 0x10,f ; else decrease length by 8
MOVWF 0x0F ; and receive and discard 8 bytes
CALL Rec_skip ;/
GOTO GET_CW_loop ; Repeat until at most 0x31 bytes are left to receive
store18 MOVLW 0x18 ;\ Store the remaining part of the command
MOVWF FSR ;/ starting from RAM position 0x18 (at most 0x31 bytes)
store18_loop
CALL Receive ; Receive 1 byte
MOVWF INDF ; store it
INCF FSR,f ; Increment pointer
DECFSZ 0x10,f ;\ until the number of bytes contained in 0x10 is received
GOTO store18_loop ;/
MOVF FSR,W ;\ Save in 0x14 the pointer to the next free position
MOVWF 0x14 ;/ following the command just received
CALL kaddress ; Compute the external EEPROM address for the key to be used
; Since the maximum stored portion of a command starting from offset 0x18 is 0x31 bytes,
; then keys loaded starting from offset 0x40 can overwrite at most the last 9 bytes of the
; stored command (bytes 0x40-0x48), but they are not needed since they contain nano 0x82 (1 byte)
; followed by the signature (8 bytes)
; So 0x40 is the lowest safe RAM position for loading keys
MOVLW 0x40 ;\ Load keys into RAM starting from offset 0x40
MOVWF FSR ;/
CALL Get_key_10 ; Read 8 bytes key from external EEPROM
MOVLW 0x40 ;\ If a secundary key is used
BTFSC 0x0D,03 ; then read it from external EEPROM 0x40 bytes forward
ADDWF 0x10,f ;/ that is from the next provider
CALL Get_key_10 ; Either read secundary key or re-read the same key as above
BTFSS PCLATH,04 ;\ If no superencription
GOTO cw_return ;/ then return, else decrypt the entire command stored from 0x18
MOVLW 0x18 ;\ Swap 0x30-0x37 with 0x18-0x1F
CALL swap_xx_30 ;/
CALL Decrypt ; Decrypt
MOVLW 0x18 ;\ Swap 0x30-0x37 with 0x18-0x1F
CALL swap_xx_30 ;/
MOVLW 0x10 ;\ Swap 0x30-0x37 with 0x20-0x27
CALL swap_xx_30 ;/
CALL Decrypt ; Decrypt
MOVLW 0x10 ;\ Swap 0x30-0x37 with 0x20-0x27
CALL swap_xx_30 ;/
MOVLW 0x08 ;\ Swap 0x30-0x37 with 0x28-0x2F
CALL swap_xx_30 ;/
CALL Decrypt ; Decrypt
MOVLW 0x08 ;\ Swap 0x30-0x37 with 0x28-0x2F
CALL swap_xx_30 ;/
CALL swap_F8_30_encr; Swap 0x30-0x37 with 0x38-0x3F and decrypt
swap_F8_30_encr
CALL swap_F8_30 ; Once again
CALL Decrypt
cw_return RETURN
; Swap the block 0x30-0x37 with 0x38-0x3f
swap_F8_30 MOVLW 0xF8 ; Load -8 into W
; Swap the block 0x30-0x37 with the 8 bytes block starting at 0x30 minus W
swap_xx_30 MOVWF EEADR ; 1st 8-bytes block offset wrt 2-nd block should be loaded into EEADR
MOVLW 0x30 ; 1st 8-bytes block starting address should be loaded into W
CALL swap_eedat ; Swap the 8 bytes block starting at W with the 8 bytes block starting at W minus EEADR
RETURN
; SECA decription routine
; 0x0F points to the key element which is being processed (0x00..0x0F)
; 0c0D is the "C" constant
Decrypt CLRF 0x0F
MOVLW 0x02 ;\ Set PCLATH to 2
MOVWF PCLATH ;/ since SECA table 1 starts at offset 0x200
CLRF 0x0D
; Key preparation
keyprep_loop
CALL kbprep ; Set K
=K XOR T1[K[i-1] XOR K[i+1] XOR C] (i is the value in 0x0F)
INCF 0x0F,f ; i=i+1
MOVF 0x0F,W ;\
ANDLW 0x03 ; Every 4 loop iterations the constant "C" is incremented
BTFSC STATUS,Z ;
INCF 0x0D,f ;/
BTFSS 0x0F,0x06 ;\ 64 iterations
GOTO keyprep_loop ;/
; Step 1: XOR key bytes with data bytes. Also set initial lookups for Step 2
MOVLW 0x0F ;\ Constant "C" is initially set to the value 0x0F
MOVWF 0x0D ;/
MOVLW 0x0C ;\ i=13 (13th key element)
MOVWF 0x0F ;/ so the index in 0..15 (0x00...0xFF) is 12 (0x0C)
keydata_loop
CALL kbget_0f ; Read K and store it into W
XORWF 0x34,W ; W=d[4] XOR K
CALL Get_tab1
MOVWF 0x10 ; [0x10]=T1[d[4] XOR K]
CALL kbget_0f_p1 ; Read K[i+1] and store it into W
XORWF 0x35,W ; W=d[5] XOR K[i+1]
CALL Get_tab1
MOVWF 0x11 ; [0x11]=T1[d[5] XOR K[i+1]]
CALL kbget_0f_p1 ; Read K[i+2] and store it into W
XORWF 0x36,W ; W=d[6] XOR K[i+2]
CALL Get_tab1
MOVWF 0x12 ; [0x12]=T1[d[6] XOR K[i+2]]
CALL kbget_0f_p1 ; Read K[i+3] and store it into W
XORWF 0x37,W ; W=d[7] XOR K[i+3]
CALL Get_tab1
MOVWF 0x13 ; [0x13]=T1[d[7] XOR K[i+3]]
; Step 2: core function. The step (T1 table lookup) has been performed in the previous step
; The new values for d[4]..d[7] are stored in 0x10..0x13
; At the end of Step 1 W contains d[7]
INCF PCLATH,f ; PCLATH=3, block address of T2 in the external EEPROM is 3 (offset 0x300)
XORWF 0x10,f ; d[4]=d[4] XOR d[7]
SWAPF 0x13,W ; Swap nibbles in d[7]
ADDWF 0x12,W ; W=~d[7]+d[6]
CALL Get_tab2 ; W=T2[W]
MOVWF 0x12 ; d[6]=T2[~d[7]+d[6]]
XORWF 0x13,f ; d[7]=d[7] XOR d[6]
SWAPF 0x12,W ; Swap nibbles in d[6]
ADDWF 0x11,W ; W=~d[6]+d[5]
CALL Get_tab2 ; W=T2[W]
MOVWF 0x11 ; d[5]=T2[~d[6]+d[5]]
XORWF 0x12,f ; d[6]=d[6] XOR d[5]
SWAPF 0x11,W ; Swap nibbles in d[5]
ADDWF 0x10,W ; W=~d[5]+d[4]
CALL Get_tab2 ; W=T2[W]
MOVWF 0x10 ; d[4]=T2[~d[5]+d[4]]
DECF PCLATH,f ; PCLATH=2, SECA table 1 starts at offset 0x200
XORWF 0x11,f ; d[5]=d[5] XOR d[4]
SWAPF 0x10,W ; Swap nibbles in d[4]
ADDWF 0x13,W ; W=~d[4]+d[7]
CALL Get_tab1
MOVWF 0x13 ; d[7]=T1[~d[4]+d[7]]
XORWF 0x10,f ; d[4]=d[4] XOR d[7]
SWAPF 0x13,W ; Swap nibbles in d[7]
ADDWF 0x12,W ; W=~d[7]+d[6]
CALL Get_tab1
MOVWF 0x12 ; d[6]=T1[~d[7]+d[6]]
XORWF 0x13,f ; d[7]=d[7] XOR d[6]
SWAPF 0x12,W ; Swap nibbles in d[6]
ADDWF 0x11,W ; W=~d[6]+d[5]
CALL Get_tab1
MOVWF 0x11 ; d[5]=T1[~d[6]+d[5]]
XORWF 0x12,f ; d[6]=d[6] XOR d[5]
MOVF 0x10,W ;\ d[5]=d[5] XOR d[4]
XORWF 0x11,f ;/
;Step 3: get data values for the next iteration
INCF PCLATH,f ; PCLATH=3, block address of T2 in the external EEPROM is 3 (offset 0x300)
MOVF 0x11,W ;\
CALL Get_tab2 ; d[0]=d[0] XOR T2[d[5]]
XORWF 0x30,f ;/
MOVF 0x13,W ;\
CALL Get_tab2 ; d[1]=d[1] XOR T2[d[7]]
XORWF 0x31,f ;/
MOVF 0x10,W ;\
CALL Get_tab2 ; d[2]=d[2] XOR T2[d[4]]
XORWF 0x32,f ;/
MOVF 0x12,W ;\
CALL Get_tab2 ; d[3]=d[3] XOR T2[d[6]]
XORWF 0x33,f ;/
DECF PCLATH,f ; PCLATH=2, SECA table 1 starts at offset 0x200
; At the end there is no swap of d[0]..d[3] with d[4]..d[7].
; It is performed in Step 3.b below, which is reached in case another iteration is needed
; Step 4: prepare keys for the next iteration
CALL kbprep ; K[i+3]=K[i+3] XOR T1[K[i+4] XOR K[i-2]]
CALL kbprep_im1 ; K[i+2]=K[i+2] XOR T1[K[i+3] XOR K[i-1]]
CALL kbprep_im1 ; K[i+1]=K[i+1] XOR T1[K[i+2] XOR K]
CALL kbprep_im1 ; K=K XOR T1[K[i+1] XOR K[i-1]]
MOVF 0x0D,f ;\ If C=0 then return
BTFSC STATUS,Z ;/
RETURN ; Decription has been performed, return
; Step 3.b: Another iteration is needed, swap nibbles and decrement C
MOVLW 0x04 ;\ p_swap_nibble offset=4
MOVWF EEADR ;/
MOVLW 0x34 ; p_swap_nibble address=0x34
CALL p_swap_nibble ; Swap d[0]..d[3] with d[4]..d[7]
DECF 0x0D,f ; C=C-1
MOVLW 0xFC ;\ i=i-4
ADDWF 0x0F,f ;/
MOVLW 0x0C ;\
BTFSC 0x0F,07 ; If i <0 set i again to 12 (0x0C)
MOVWF 0x0F ;/
GOTO keydata_loop ; Iterate again
; Perform the operation K=K XOR T1[K[i-1] XOR K[i+1] XOR C]
; 0x0F contains the "i" value and 0x0D contains the "C" value
kbprep_im1 DECF 0x0F,f ; Entry point for the same function, but with i -> i-1
kbprep INCF 0x0F,W ;\ Load K[i+1] into W
CALL kbget_w ;/
MOVWF 0x0C ; save it also into 0x0C
DECF 0x0F ,W ;\ Load K[i-1] into W
CALL kbget_w ;/
XORWF 0x0C,f ;K[i-1] XOR K[i+1]
CALL kbget_0f ; Read K, the result is not used, but now FSR points to K
MOVF 0x0C,W ;\ XOR with "C"
XORWF 0x0D,W ;/
CALL Get_tab1 ; Get T1[....]
XORWF INDF,f ; and at last K=K XOR ...
RETURN
; Routines to read the key byte at a given offset from the key start address 0x40
; the offset is wrapped to lie in 0x00...0x0F
; The key byte is returned in W
kbget_0f_p1 INCF 0x0F,f ; The key byte offset minus 1 is contained in 0x0F
kbget_0f MOVF 0x0F,W ; The key byte offset is contained in 0x0F
kbget_w ; The key byte offset is contained in W
ANDLW 0x0F ; Wrap W to lie in 0x00...0x0F
MOVWF FSR ; Set pointer to the byte offset
BSF FSR,0x06 ; Key is stored starting from 0x40
MOVF INDF,W ; Read the key byte value and store it into W
RETURN
;-----------------------------------------------------------------------
; Computes the external EEPROM address of the key to be used (from P1 in 0x0D)
; Returns in 0x10 the key offset (word address) and in PCLATH the page (block address)
; PCLATH bit 4 is set to indicate superencription
kaddress CLRF 0x10 ;\
RRF 0x0D,f ; Move bits 1,0 of P1 (provider number) to bits 7,6 in file register 0x10
RRF 0x10,f ; This is the same as a left shift by 6 bits (each provider uses 64 bytes (2^6))
RRF 0x0D,W ; Moroever put into W(3:0) bits 5-2 of the provider number
RRF 0x10,f ;/
ANDLW 0x03 ; Set W to bits 3-2 of provider number
MOVWF PCLATH ; which identify the page (one external EEPROM (256 bytes) contains 4 providers (4 prov*8 keys*8 bytes/key)
BSF PCLATH,0x02 ; Keys start at block address 4 in the external EEPROM (offset 0x400)
BTFSC 0x0E,07 ;\ If there is superencription
BSF PCLATH,0x04 ;/ then set bit 4 in PCLATH
MOVLW 0x07 ;\ Reduce key number P2 to lie in (0..7)
ANDWF 0x0E,f ;/
kaddr_loop MOVLW 0x08 ; Each key uses 8 bytes
DECF 0x0E,f ; Decrement key number
BTFSC 0x0E,07 ; Loop until 0x0E < 0 (exit from the loop is with 0x0E = -1 (0xff))
RETURN ; Here 0x10 contains the proper word addres for the key
ADDWF 0x10,f ; Increment word address by 8
GOTO kaddr_loop ; as many times as the key number minus one
;-----------------------------------------------------------------------
; Read a key from the external EEPROM starting from the offset specified in file register 0x10
; The key is stored in RAM starting from where the indirect register points
Get_key_10 MOVF 0x10,W
; As above, but the offset comes from W
Get_key CALL i2c_wr ; Send address to be read to external EEPROM
MOVLW 0x08 ; 8 bytes are to be read
MOVWF 0x11 ; 0x11 is the loop counter
Get_key_loop
CALL i2c_rd ; Read byte from external EEPROM
MOVWF INDF ; Write to RAM
INCF FSR,f ; Increment RAM pointer
DECFSZ 0x11,f ;\ Loop until the entire key is read
GOTO Get_key_loop ;/
RETURN
;-----------------------------------------------------------------------
; Routine which performs the swap of 2 blocks of eight bytes each
; W contains the starting address of the first block and EEADR contains the offset
; of the first block wrt the second
; A positive offset means the first block is after the second and a negative offset
; means the second block is after the first
swap_eedat ; Swap two 8-bytes blocks
CALL p_swap_nibble
GOTO swap_nibble
p_swap_nibble
MOVWF FSR ; Set pointer to the first block start address
swap_nibble ; Swap two 4-bytes blocks
CALL swap_byte
CALL swap_byte
CALL swap_byte
; Swap 1 byte of the first block with 1 byte of the second block
; The byte in the first block is poited by FSR, 1st block offset wrt 2nd block is into EEADR
swap_byte MOVF INDF,W ;\ Save 1st block byte pointed by FSR into EEDATA
MOVWF EEDATA ;/
MOVF EEADR,W ;\ Offset FSR by the block offset so it points to the 2nd byte
SUBWF FSR,f ;/
MOVF EEDATA,W ; Load 1st block byte into W
XORWF INDF,f ; Xor the two bytes and save in place of the 2nd block byte
MOVF INDF,W ; and also into W
XORWF EEDATA,f ; Xor again with the 1st block byte, so the 2nd block byte is now into EEDATA
MOVF EEDATA,W ; and also into W
XORWF INDF,f ; Xor again, so now the 1st block byte is in place of the 2nd block byte
MOVF EEADR,W ;\ Now point to the 1st block byte
ADDWF FSR,f ;/
MOVF EEDATA,W ;\ Put the 2nd block byte in place of the 1st block byte
MOVWF INDF ;/
INCF FSR,f ; Move FSR one place forward in the 1st block
RETURN
;-----------------------------------------------------------------------
;*************************************************
; function : 32 C1 CLASS instruction *
; either startup or *
; extra and general infos (package bitmap) *
;*************************************************
Instr_32 INCF PCLATH,f ; External EEPROM page 1 \ The startup answer is stored in
MOVLW 0x99 ; Address 0x99 / external EEPROM address 0x199
BTFSS 0x40,00 ; If the last received byte was not 0x01 (from C1 34)
GOTO pbmap ; then jump to extra and general infos (package bitmap)
GOTO COMM_EEPR ; else transmit data from external EEPROM (startup) starting from 0x199
;-----------------------------------------------------------------------
; Write a byte sequence to external EEPROM
; The byte sequence is stored starting from RAM address 0x38, and its length is stored in 0x0F
; The external EEPROM internal address pointer should have been set previously
; by a control byte, word address write sequence
wr_i2c_string
MOVLW 0x37 ;\ Load pointer (one location lower since the loop starts by incrementing the address)
MOVWF FSR ;/ to RAM
wr_i2c_str_loop
INCF FSR,f ;\ Read next byte
MOVF INDF,W ;/
CALL i2cw_byte ; Send to EEPROM
DECFSZ 0x0F,f ;\ Loop until all bytes are sent
GOTO wr_i2c_str_loop;/
GOTO i2c_stop ; Stop transfer to EEPROM
;-----------------------------------------------------------------------
Rec_skip_r SUBWF 0x0F,f ; Receive and discard the number of bytes stored at RAM location 0x0F minus the number of bytes stored in W
Rec_skip CALL Receive ; Receive and discard the number of bytes stored at RAM location 0x0F
DECFSZ 0x0F,f
GOTO Rec_skip
RETURN
;=======================================================================
; RB7 I/O procedures
;=======================================================================
; Send the data byte contained in W to RB7
Send
IF LED ;\
BSF PORTA,LED_GREEN; Green LED on
ENDIF ;/
MOVWF 0x16 ; Store the data byte into 0x16
MOVLW T_SEND_START ;\ Pause
CALL Pause ;/
MOVLW 0x7F ;\ Define PORT B I/O RB7=output, all others=input
TRIS PORTB ;/
CLRF 0x17 ; Clear 0x17, used for parity
BCF PORTB,07 ; Send start bit
MOVLW 0x08 ;\ Length = 8, load counter
MOVWF 0x14 ;/
send_loop CALL Std_pause ; Wait
RRF 0x16,f ;\ Load bit to be transmitted in bit 7 of W
RRF 0x16,W ;/
ANDLW 0x80 ; Clear bits 6:0 of W
XORWF 0x17,f ; Update parity
XORWF PORTB,W ; Read PORT B data into W xoring bit 7 (RB7) \ merge bit 7 of W
XORWF PORTB,f ; Write W to PORT B xoring bit 7 again / into PORT B
DECFSZ 0x14,f ;\ Cycle
GOTO send_loop ;/
CALL Std_pause ; Wait
MOVF 0x17,W ;\
XORWF PORTB,W ; Send parity
XORWF PORTB,f ;/
CALL Std_pause ; Wait
MOVLW 0xFF ;\ Define PORT B I/O = all input
TRIS PORTB ;/
IF LED
BCF PORTA,LED_GREEN; Green LED off
ENDIF
MOVLW T_SEND_STOP ;\ Pause
GOTO Pause ;/
;-----------------------------------------------------------------------
; Wait for input on RB7, receive one byte of data from RB7 and return it through W
Receive BTFSC PORTB,07 ;\ Read PORT B, loop while 1 on RB7
GOTO Receive ;/ THIS IS THE MAIN LOOP
IF LED ;\
BSF PORTA,LED_GREEN; Green LED on
ENDIF ;/
MOVLW T_RECEIV_START ;\ 0 (start bit) has been seen on RB7: pause
CALL Pause ;/
MOVLW 0x09 ; Length = 9 (1 byte data + 1 bit parity)
MOVWF 0x14 ; Counter
Receive_loop
BCF STATUS,C ; Clear carry flag
BTFSC PORTB,07 ; Read PORT B
BSF STATUS,C ; 1 on RB7, set carry flag
RRF 0x16,f ; 0 on RB7, rotate right
CALL Std_pause
DECFSZ 0x14,f ; Decrement counter
GOTO Receive_loop ; Repeat
RLF 0x16,f ; Done, rotate left to skip parity bit
MOVLW T_RECEIV_STOP ;\ Pause
CALL Pause ;/
MOVF 0x16,W ; Return received byte in W
IF LED ;\
BCF PORTA,LED_GREEN; Green LED off
ENDIF ;/
RETURN
;-----------------------------------------------------------------------
Std_pause MOVLW T_SERIAL ; Standard pause for reading/writing via serial protocol
Pause MOVWF 0x15 ; Pause for the time stored in W
Pause_loop DECFSZ 0x15,f ;\ Loop until pause expires
GOTO Pause_loop ;/
RETLW 0x00 ; Return always 0
;=======================================================================
; External EEPROM R/W procedures
;=======================================================================
; ACK polling, tries to write a control byte until ACK
I2C_busy CALL i2c_start
BCF STATUS,C ; Clear carry flag, R/W bit = 0 (write)
CALL i2cw_conbyte ; Write control byte, returns ACK into carry
BTFSC STATUS,C ; Skip if not busy
GOTO I2C_busy ; Loop while busy
RETURN
;-----------------------------------------------------------------------
; Read a byte from the PIC EEPROM
; The address is read from W and the read value is returned in W
Rd_eeprom MOVWF EEADR ; Load address
BSF STATUS,RP0 ; Select page 1 (80H - FFH)
BSF EECON1,0x00
BCF STATUS,RP0 ; Select page 0 (00H - 7FH)
MOVF EEDATA,W ; Return value
RETURN
;-----------------------------------------------------------------------
; Send a byte sequence from the external EEPROM to the serial line
; The block select bits (high address) comes from PCLATH and the word address (low byte) comes from W
; 0x0F contains the number of bytes to be sent
EEPROM_send CALL i2c_wr ; Send address
eepr_send_loop
DECF 0x0F,f ; Decrement counter
BTFSC 0x0F,07 ;\ If all bytes have been read then return
RETURN ;/
CALL i2c_rd ; Read byte
CALL Send ; Send to serial line
GOTO eepr_send_loop
; Returns in W the external EEPROM byte with block address givan by PCLATH(2:0) and
; word address given by W.
; In case PCLATH(2:0) is 3, it returns in W the SECA algorythm table 2 value
; corresponding to the value contained in W (since T2 is in external EEPROM page 3)
Get_tab2 MOVWF EEADR ; Save W into EEADR
CALL i2c_start
BCF STATUS,C ; Clear carry flag, next i2c access is for writing
CALL i2cw_conbyte ; Send control byte to i2c
MOVF EEADR,W ; Reload W from EEADR
CALL i2cw_byte ; Send word address to i2c
;-----------------------------------------------------------------------
; Read the external EEPROM byte specified by W and PCLATH
; The external EEPROM internal address pointer should have been set previously
; by a control byte, word address write sequence
; The value is returned in W
i2c_rd CALL i2c_start
BSF STATUS,C ; Set carry flag, next i2c access is for reading
CALL i2cw_conbyte ; Send again control byte to i2c
CALL i2cr_byte ; Read byte from i2c into EEDATA
CALL i2c_stop
MOVF EEDATA,W ; Return read byte in W
RETURN
;-----------------------------------------------------------------------
; Writes a complete address (control byte + word address) to the external EEPROM
; block address is in PCLATH(2:0) and word address is in W
i2c_wr MOVWF EEADR ; Save word address
CALL I2C_busy ; Loop writing cotrol byte until ACK
MOVF EEADR,W ; Recover word address
GOTO i2cw_byte ; Write it
; Write a data byte to external EEPROM
; The external EEPROM internal address pointer should have been set previously
; by a control byte, word address write sequence
wr_last CALL i2cw_byte
GOTO i2c_stop
;-----------------------------------------------------------------------
; Build control byte into W from block address into PCLATH(2:0) and R/W bit into carry flag
i2cw_conbyte
RLF PCLATH,W ; Load block select bits from PCLATH and R/W bit from carry into W
ANDLW 0x0F ; Clear space for control code bits
IORLW 0xA0 ; Load control code bits 1010 into W, control byte in W is complete
; Send a byte stored in W to external EEPROM
i2cw_byte MOVWF EEDATA ; Store W into EEDATA
MOVLW 0xCF ;\ Define PORT B I/O RB4,RB5=output, all others=input
TRIS PORTB ;/
CALL i2cw_nibble ;\ Write byte contained in EEDATA
CALL i2cw_nibble ;/
GOTO i2cr_bit ; Read ACK
; Send a nibble from EEDATA to external EEPROM
i2cw_nibble
CALL i2cw_nibble_2 ; 1st bit
CALL i2cw_nibble_2 ; 2nd bit
CALL i2cw_nibble_2 ; 3rd bit, 4th bit below
; Send an EEDATA bit to external EEPROM
i2cw_nibble_2
RLF EEDATA,f ; Put bit to be sent into carry
GOTO i2cw_bit_x ; Send
; Read a byte from external EEPROM into EEDATA
i2cr_byte MOVLW 0xDF ;\ Define PORT B I/O RB5=output, all others=input
TRIS PORTB ;/
CALL i2cr_nibble ;\ Read byte
CALL i2cr_nibble ;/
BSF STATUS,C ; Set carry flag
GOTO i2cw_bit ; NACK, stop
; Read a nibble form external EEPROM int EEDATA
i2cr_nibble CALL i2cr_nibble_2 ; 1st bit
CALL i2cr_nibble_2 ; 2nd bit
CALL i2cr_nibble_2 ; 3rd bit, 4th bit below
; Read a bit from external EEPROM into EEDATA
i2cr_nibble_2
CALL i2cr_bit_x ; Read bot into carry
RLF EEDATA,f ; Store into EEDATA
RETURN
;-----------------------------------------------------------------------
; Init data transfer from/to external EEPROM
i2c_start BSF PORTB,0x04
MOVLW 0xCF ;\ Define PORT B I/O RB4,RB5=output, all others=input
TRIS PORTB ;/
BSF PORTB,0x05 ; Clock high
NOP
BCF PORTB,0x04 ; Data start
GOTO clock_low
;-----------------------------------------------------------------------
; Stop data transfer from/to external EEPROM
i2c_stop BCF PORTB,04 ; Data start
MOVLW 0xCF ;\ Define PORT B I/O RB4,RB5=output, all others=input
TRIS PORTB ;/
NOP
BSF PORTB,05 ; Clock high
NOP
BSF PORTB,04 ; Data stop
nclock_low NOP
clock_low BCF PORTB,05 ; Clock low
RETURN
i2cw_bit MOVLW 0xCF ;\ Define PORT B I/O RB4,RB5=output, all others=input
TRIS PORTB ;/
; Actual bit write to RB4 (external EEPROM)
; Bit to be written is from carry
i2cw_bit_x
BTFSS STATUS,C ; Skip if carry set
BCF PORTB,04
BTFSC STATUS,C ; skip if no carry
BSF PORTB,04
BSF PORTB,05 ; Clock high
GOTO nclock_low
;-----------------------------------------------------------------------
i2cr_bit MOVLW 0xDF ;\ Define PORT B I/O RB5=output, all others=input
TRIS PORTB ;/
; actual bit read from RB4 (external EEPROM)
; bit is read into carry
i2cr_bit_x BSF PORTB,05 ; Clock high
NOP
BSF STATUS,C ; Set carry flag
BTFSS PORTB,04
BCF STATUS,C ; Clear carry flag
GOTO clock_low
;=======================================================================
; SECA Table 1
;=======================================================================
; Returns in W the SECA algorythm table 1 value corresponding to the value contained in W
; Before calling this routine PCLATH should have the value 2, since the table starts at offset 0x200
Get_tab1 MOVWF PCL ; Absolute addressing
ORG 0x200
dt 0x2A,0xE1,0x0B,0x13,0x3E,0x6E,0x32,0x48
dt 0xD3,0x31,0x08,0x8C,0x8F,0x95,0xBD,0xD0
dt 0xE4,0x6D,0x50,0x81,0x20,0x30,0xBB,0x75
dt 0xF5,0xD4,0x7C,0x87,0x2C,0x4E,0xE8,0xF4
dt 0xBE,0x24,0x9E,0x4D,0x80,0x37,0xD2,0x5F
dt 0xDB,0x04,0x7A,0x3F,0x14,0x72,0x67,0x2D
dt 0xCD,0x15,0xA6,0x4C,0x2E,0x3B,0x0C,0x41
dt 0x62,0xFA,0xEE,0x83,0x1E,0xA2,0x01,0x0E
dt 0x7F,0x59,0xC9,0xB9,0xC4,0x9D,0x9B,0x1B
dt 0x9C,0xCA,0xAF,0x3C,0x73,0x1A,0x65,0xB1
dt 0x76,0x84,0x39,0x98,0xE9,0x53,0x94,0xBA
dt 0x1D,0x29,0xCF,0xB4,0x0D,0x05,0x7D,0xD1
dt 0xD7,0x0A,0xA0,0x5C,0x91,0x71,0x92,0x88
dt 0xAB,0x93,0x11,0x8A,0xD6,0x5A,0x77,0xB5
dt 0xC3,0x19,0xC1,0xC7,0x8E,0xF9,0xEC,0x35
dt 0x4B,0xCC,0xD9,0x4A,0x18,0x23,0x9F,0x52
dt 0xDD,0xE3,0xAD,0x7B,0x47,0x97,0x60,0x10
dt 0x43,0xEF,0x07,0xA5,0x49,0xC6,0xB3,0x55
dt 0x28,0x51,0x5D,0x64,0x66,0xFC,0x44,0x42
dt 0xBC,0x26,0x09,0x74,0x6F,0xF7,0x6B,0x4F
dt 0x2F,0xF0,0xEA,0xB8,0xAE,0xF3,0x63,0x6A
dt 0x56,0xB2,0x02,0xD8,0x34,0xA4,0x00,0xE6
dt 0x58,0xEB,0xA3,0x82,0x85,0x45,0xE0,0x89
dt 0x7E,0xFD,0xF2,0x3A,0x36,0x57,0xFF,0x06
dt 0x69,0x54,0x79,0x9A,0xB6,0x6C,0xDC,0x8B
dt 0xA7,0x1F,0x90,0x03,0x17,0x1C,0xED,0xD5
dt 0xAA,0x5E,0xFE,0xDA,0x78,0xB0,0xBF,0x12
dt 0xA8,0x22,0x21,0x3D,0xC2,0xC0,0xB7,0xA9
dt 0xE7,0x33,0xFB,0xF1,0x70,0xE5,0x17,0x96
dt 0xF8,0x8D,0x46,0xA1,0x86,0xE2,0x40,0x38
dt 0xF6,0x68,0x25,0x16,0xAC,0x61,0x27,0xCB
dt 0x5B,0xC8,0x2B,0x0F,0x99,0xDE,0xCE,0xC5
;-----------------------------------------------------------------------
;*************************************************
; function : 3A C1 CLASS instruction *
; request for the control word *
; command : C1 3A 00 00 10 *
; answer : 3A 10 10 55 E6 55 54 05 80 04 14 40 *
; 8F 40 41 11 23 90 00 *
;*************************************************
; This instruction asks for the decrypted control words previously issued by an instruction C1 3C
; The decrypted values were stored starting from RAM address 0x30
; Here a loop reads the values through the indirect register and sends them
Instr_3A MOVLW 0x30 ;\ Point to RAM address 0x30
MOVWF FSR ;/
instr_3A_loop
MOVF INDF,W ; Read value
CALL Send ; send it
INCF FSR,f ; Next value
DECFSZ 0x0F,f ;\ Loop for the lenght stored in 0x0F
GOTO instr_3A_loop ;/
GOTO TX9000 ; Send status bytes
;*************************************************
; function : 34 C1 CLASS instruction *
; request for the control word *
;*************************************************
Instr_34 CALL Rec_skip ; Discard the received bytes
MOVWF 0x40 ; Save the last received byte in 0x40 (0x01:startup, 0x00
ackage bitmap)
GOTO TX9000 ; Transmit OK
;*************************************************
; function : 30 C1 CLASS instruction *
; PIN CONTROLLED OPERATIONS *
;*************************************************
Instr_30 MOVLW 0x02
CALL Rec_skip_r ; Receive and discard everithing but the last 2 bytes (PIN), returns with 0x0F=0
CALL Receive ; Receive the first PIN byte
IORWF 0x0F,f ; Save it into 0x0F
ANDLW 0x0F ;\ Low nibble into 0x0C
MOVWF 0x0C ;/
CALL Receive ; Receive the second PIN byte
MOVWF 0x0D ; Save it into 0x0D
IORWF 0x0F,f ; IOR with the first PIN byte
MOVF 0x0E,f ;\
BTFSS STATUS,Z ; If P2 is not 0 then transmit status bytes
GOTO TX9000 ;/
INCF PCLATH,f ;\ PCLATH=1 \ Point to 0x190 in the external EEPROM
MOVLW 0x90 ;/ W=0x90 /
; Initialization
MOVF 0x0F,f ;\ If (1st PIN byte) IOR (2nd PIN byte) = 0
BTFSC STATUS,Z ;/ (i.e. if both bytes are 0)
GOTO wr190 ; then write 0x91 to external EEPROM position 0x190 and transmit status bytes
; Load next external EEPROM offset to be written (points to the next byte of the key to be written)
CALL Get_tab2 ; else read external EEPROM position 0x190 into W
MOVWF 0x0F ; and into 0x0F too
; Apparently, the byte at offset 0x190 in the external EEPROM (here just loaded into 0x0F)
; contains the offset in page 1 of the next new key byte to be written in 0x191-0x198 (in the external EEPROM).
; Since the new key starts at 0x191, offset 0x190 initially contain 0x91.
; Moreover, if bit 6 of the byte at offset 0x190 is 1, then the high nibble at that offset has
; already been written, so it is re-read, combined with the low nibble of the 1st PIN byte,
; and then rewritten at the following location, writing the 2nd PIN byte in its place
;
; A call with PIN 0000 is needed to initialize external EEPROM offsewt 0x190 to 0x91.
; After that, the key update strategy is 3 nibbles per call, as follows:
;
; 1st call: xx = PIN 2, x=PIN 1 low
; 2nd call: yy = PIN 2, y=PIN 1 low
; 3rd call: zz = PIN 2, z=PIN 1 low
; 4th call: pp = PIN 2, p=PIN 1 low
; 5th call: qq = PIN 2, q=PIN 1 low
; 6th call: rr = PIN 2, r=PIN 1 low
; This is the image of the external EEPROM 0x190-0x198:
; before 1st call: 0x91 00 00 00 00 00 00 00 00
; after 1st call: 0xD2 xx x- -- -- -- -- -- --, since 0x92 XOR 0x40 = 0xD2
; after 2nd call: 0x94 xx yy xy -- -- -- -- --
; after 3rd call: 0xD5 xx yy xy zz z- -- -- --, since 0x95 XOR 0x40 = 0xD5
; after 4th call: 0x97 xx yy xy zz pp zp -- --
; after 5th call: 0xD8 xx yy xy zz pp zp qq q-, since 0x95 XOR 0x40 = 0xD8
; On the 6th call the key is written as
; xx yy xy zz pp zp qq qr
; to the external EEPROM at block address rr(2:0)
; and word address rr(7:3)
;
; PIN 0000 is also used to reset yellow and green LEDs on subscription date update
; and key update respectively
BTFSS 0x0F,0x06 ; If bit 6 in W was 0
GOTO wr19x ; then goto wr19x (no spare nibble from the previous call)
BTFSC 0x0F,0x03 ;\ If all the 8 key bytes have been received
GOTO Remote_kupdate ;/ then update EEPROM key
XORLW 0x40 ; else flip bit 6 in W (set it to 0)
CALL Get_tab2 ; and read external EEPROM byte with word address W and block address 1
; i.e., read previous spare nibble
; Combine previous and current spare nibbles
IORWF 0x0C,f ;\ IOR W (from external EEPROM) and the low nibble of the first PIN byte
SWAPF 0x0C,f ;/ and swap nibbles in the result (in 0x0C)
MOVF 0x0F,W ; Set W to the byte read from external EEPROM position 0x190
XORLW 0x40 ; and flip bit 6 of W (set it to 0)
INCF 0x0F,f ; Increment key bytes pointer
wr19x CALL i2c_wr ; set pointer to external EEPROM as specified by W
MOVF 0x0D,W ;\ Write 2nd PIN byte
CALL i2cw_byte ;/
SWAPF 0x0C,W ;\ Write 1st PIN byte low nibble as high nibble on calls 1,3,5
CALL wr_last ;/ or combined with previous 1st PIN byte low nibble on calls 2,4
; CALL i2c_delay
MOVLW 0x40 ;\ Move key bytes pointer to W and flip bit 6
XORWF 0x0F,W ;/
; Write W+1 to external EEPROM position 0x190
wr190 MOVWF 0x0F ;\ Save W+1 into 0x0F
INCF 0x0F,f ;/ (increment key bytes pointer)
MOVLW 0x90 ;\ Set external EEPROM pointer to 0x190
CALL i2c_wr ;/
MOVF 0x0F,W ;\ Write there W+1
CALL wr_last ;/
; CALL i2c_delay
IF LED ;\
BCF PORTA,LED_YELLOW ; Yellow LED is set off
BCF PORTA,LED_RED ; Red LED is set off
BCF PORTA,LED_GREEN2 ; Green2 LED is set off
ENDIF ;/
GOTO TX9000 ; Transmit status bytes
;-----------------------------------------------------------------------
; Actualize a key stored in EEPROM from the key stored into RAM via remote
Remote_kupdate
MOVLW 0x38 ;\ Set pointer to RAM address 0x38
MOVWF FSR ;/
MOVLW 0x91 ;\ Read key starting from external EEPROM offset 0x191
CALL Get_key ;/ (since PCLATH has been set to 1) and store it into RAM from position 0x38
MOVF 0x0C,W ;\ IOR the last byte of the key with the low nibble of the last PIN byte 1 received
IORWF 0x3F,f ;/
CLRF PCLATH ; reset PCLATH to 0
MOVF 0x0D,W ;\
ANDLW 0x07 ; Set external EEPROM block address to bits (2:0) of the last PIN byte 2 received
ADDWF PCLATH,f ;/
MOVF 0x0D,W ;\ Set external EEPROM word address to bits (7:3) of the last PIN byte 2 received
ANDLW 0xF8 ;/
CALL i2c_wr ; Set external EEPROM pointer
MOVLW 0x08 ;\
MOVWF 0x0F ; Write the 8 bytes key from RAM offset 0x38 to external EEPROM
CALL wr_i2c_string ;/
IF LED ;\
BSF PORTA,LED_RED ; Red LED is set and left on if key updated
ENDIF ;/
GOTO TX9000 ; transmit 9000
;**************************************************
; function : C1 40 CLASS instruction *
; ENTITLEMENT MANAGEMENT MESSAGE *
;**************************************************
; c14003814e
;
; 4b c8 7c 75 ab 0b 84 84 96 f1 d3 f7 ee 94 96 c0
; b1 51 cc 39 a7 b6 08 c4 a1 50 39 0d 00 b0 df 73
; e9 d6 6c c3 d5 ec 8e d6 0f 7b 1f 9b 74 48 f7 7b
; cc 97 d8 60 da 91 e9 c3 d7 03 8b b1 a0 7f de 50
; 5c 56 2f 8b b2 c9 e3 39
; da 86 dd a7 34 d1
; 90 00
; decoder
; f0 5b 08 02 04 45 02 08 ce b4 01 42 04 50 aa 76
; b7 10 01 42 13 0e 2b 11 a4 50 48 60 32 2c 10 11
; 12 22 15 1f
; 21 ;nano data
; 15 5f ;data
; 90 5d ;nano primary key | key d
; d9 5f e0 f4 66 94 29 ab
; 90 5c ;nano primary key | key c
; 15 3f bb df 11 bb e5 30
; 90 5e ;nano primary key | key e
; 68 19 ba 23 4b c4 1b 07
;
; 82 ;\ signature
; 27 c9 da 86 dd a7 34 d1 ;/
;
; Subscription 31/10/2000
; primary key 0d
; primary key 0c
; primary key 0e
; index=01
; key=42 22 7b 71 20 34 93 ef
; index=0c
; key=d9 cb b8 5c 57 af 2d 53
; index=0d
; key=61 24 8c d4 1a 39 2a ad
; index=0e
; key=5a 1d b3 dd 48 22 12 31
Instr_40
MOVF 0x0D,W ; Save P1 into W
MOVWF 0x17 ; and into file register 0x17
BSF PCLATH,0x03 ; Set PCLATH(3) to 1 (next call to TX9000 will transmit 901D)
MOVLW 0x34 ;\
SUBWF 0x0F,W ; If length is less than 0x34 bytes
BTFSS STATUS,C ; then jump to process instruction 34 (i.e., discard received data and transmit status bytes)
GOTO Instr_34 ;/
CALL GET_CW_loop ; else receive the remaining part of the command (only the last 0x31 bytes are retained),
; read the 16 bytes key from the external EEPROM according to P1 and P2,
; and in case of superencription implement the first decription
BSF PCLATH,0x03 ; Set PCLATH(3) to 1 (next call to TX9000 will transmit 901D)
MOVF 0x17,W ; Recover P1 from file register 0x17
ANDLW 0x0F ;\
BTFSC STATUS,Z ; If P1 is 0 (SECA) transmit 901D