/* * KeeLoq implementation for Atmel AVR * Copyright (C) 2005 Jiri Pittner * * This program is 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, either version 3 of the License, or * (at your option) any later version. This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef _keeloq_c #define _keeloq_c #include "keeloq.h" ///////////////////////////////////////////////////////////////////////////// //keeloq routines static uint8_t NLF[4]={0x2e,0x74,0x5c,0x3a}; void decrypt(register uint32_t *code, uint64_t *key) { #ifdef AVR_SOURCE //assembler implementation asm volatile ( //preload code and key into registers "ld r12,Y" "\n\t" "ldd r13,Y+1" "\n\t" "ldd r14,Y+2" "\n\t" "ldd r15,Y+3" "\n\t" "ld r16,Z" "\n\t" "ldd r17,Z+1" "\n\t" "ldd r18,Z+2" "\n\t" "ldd r19,Z+3" "\n\t" "ldd r20,Z+4" "\n\t" "ldd r21,Z+5" "\n\t" "ldd r22,Z+6" "\n\t" "ldd r23,Z+7" "\n\t" //load loop counter "ldi r24,lo8(528)" "\n\t" "ldi r25,hi8(528)" "\n\t" "LoopD:" "\n\t" //prepare NLFind "eor r11,r11" "\n\t" "bst r15,1" "\n\t" "bld r11,0" "\n\t" "bst r15,6" "\n\t" "bld r11,1" "\n\t" //pick up proper byte from NLF "eor r10,r10" "\n\t" "mov r30,r26" "\n\t" "mov r31,r27" "\n\t" "add r30,r11" "\n\t" "adc r31,r10" "\n\t" "ld r9,Z" "\n\t" //is now byte of NLF //prepare NLFshift "bst r12,0" "\n\t" "bld r10,0" "\n\t" "bst r13,0" "\n\t" "bld r10,1" "\n\t" "bst r14,3" "\n\t" "bld r10,2" "\n\t" //pick up proper bit from r9 "tst r10" "\n\t" "Lab1D:" "\n\t" "breq Lab2D" "\n\t" "lsr r9" "\n\t" "dec r10" "\n\t" "rjmp Lab1D" "\n\t" "Lab2D:" "\n\t" //do all the eors "bst r17,7" "\n\t" "bld r10,0" "\n\t" "eor r9,r10" "\n\t" "bst r15,7" "\n\t" "bld r10,0" "\n\t" "eor r9,r10" "\n\t" "bst r13,7" "\n\t" "bld r10,0" "\n\t" "eor r9,r10" "\n\t" //shift code "rol r12" "\n\t" "rol r13" "\n\t" "rol r14" "\n\t" "rol r15" "\n\t" //put the resulting bit back to code "bst r9,0" "\n\t" "bld r12,0" "\n\t" //rotate key "bst r23,7" "\n\t" "rol r16" "\n\t" "rol r17" "\n\t" "rol r18" "\n\t" "rol r19" "\n\t" "rol r20" "\n\t" "rol r21" "\n\t" "rol r22" "\n\t" "rol r23" "\n\t" "bld r16,0" "\n\t" //Loop end "sbiw r24,1" "\n\t" "brne LoopD" "\n\t" //store code back in memory "st Y+,r12" "\n\t" "st Y+,r13" "\n\t" "st Y+,r14" "\n\t" "st Y+,r15" "\n\t" : //no outputs via register : "x" (NLF), "y" (code) , "z" (key) : "r12", "r13", "r14", "r15", //code "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", //key "r24", "r25", //iteration variable "r9", "r10", "r11", //eortmp, nlfshift, nlfind "cc" ); #else uint16_t i; uint64_t keybak; keybak=*key; for(i=0; i<528; ++i) { uint8_t nlfshift,nlfind,tmp,r; nlfshift = *code&1; if(*code&256) nlfshift |=2; if(*code&0x080000) nlfshift |= 4; nlfind = (*code&0x2000000) ?1:0; if(*code&0x40000000) nlfind |= 2; r= (NLF[nlfind]>>nlfshift) & 1; if(*key&0x8000) r^=1; if(*code & 0x80000000) r^=1; if(*code & 0x8000) r^=1; tmp=*key>>63; *key<<=1; *key|=tmp; //rotate key *code <<=1; *code|=r; //shift code } *key=keybak; #endif } void encrypt(register uint32_t *code, uint64_t *key) { #ifdef AVR_SOURCE //assembler implementation asm volatile ( //preload code and key into registers "ld r12,Y" "\n\t" "ldd r13,Y+1" "\n\t" "ldd r14,Y+2" "\n\t" "ldd r15,Y+3" "\n\t" "ld r16,Z" "\n\t" "ldd r17,Z+1" "\n\t" "ldd r18,Z+2" "\n\t" "ldd r19,Z+3" "\n\t" "ldd r20,Z+4" "\n\t" "ldd r21,Z+5" "\n\t" "ldd r22,Z+6" "\n\t" "ldd r23,Z+7" "\n\t" //rotate key like in decrypt 16 times -> 2 bytes shift "mov r9,r22" "\n\t" "mov r22,r20" "\n\t" "mov r20,r18" "\n\t" "mov r18,r16" "\n\t" "mov r16,r9" "\n\t" "mov r9,r23" "\n\t" "mov r23,r21" "\n\t" "mov r21,r19" "\n\t" "mov r19,r17" "\n\t" "mov r17,r9" "\n\t" //load loop counter "ldi r24,lo8(528)" "\n\t" "ldi r25,hi8(528)" "\n\t" "LoopE:" "\n\t" //prepare NLFind "eor r11,r11" "\n\t" "bst r15,2" "\n\t" "bld r11,0" "\n\t" "bst r15,7" "\n\t" "bld r11,1" "\n\t" //pick up proper byte from NLF "eor r10,r10" "\n\t" "mov r30,r26" "\n\t" "mov r31,r27" "\n\t" "add r30,r11" "\n\t" "adc r31,r10" "\n\t" "ld r9,Z" "\n\t" //is now byte of NLF //prepare NLFshift "bst r12,1" "\n\t" "bld r10,0" "\n\t" "bst r13,1" "\n\t" "bld r10,1" "\n\t" "bst r14,4" "\n\t" "bld r10,2" "\n\t" //pick up proper bit from r9 "tst r10" "\n\t" "Lab1E:" "\n\t" "breq Lab2E" "\n\t" "lsr r9" "\n\t" "dec r10" "\n\t" "rjmp Lab1E" "\n\t" "Lab2E:" "\n\t" //do all the eors "bst r18,0" "\n\t" "bld r10,0" "\n\t" "eor r9,r10" "\n\t" "bst r12,0" "\n\t" "bld r10,0" "\n\t" "eor r9,r10" "\n\t" "bst r14,0" "\n\t" "bld r10,0" "\n\t" "eor r9,r10" "\n\t" //shift code "ror r15" "\n\t" "ror r14" "\n\t" "ror r13" "\n\t" "ror r12" "\n\t" //put the resulting bit back to code "bst r9,0" "\n\t" "bld r15,7" "\n\t" //rotate key "bst r16,0" "\n\t" "ror r23" "\n\t" "ror r22" "\n\t" "ror r21" "\n\t" "ror r20" "\n\t" "ror r19" "\n\t" "ror r18" "\n\t" "ror r17" "\n\t" "ror r16" "\n\t" "bld r23,7" "\n\t" //Loop end "sbiw r24,1" "\n\t" "brne LoopE" "\n\t" //store code back in memory "st Y+,r12" "\n\t" "st Y+,r13" "\n\t" "st Y+,r14" "\n\t" "st Y+,r15" "\n\t" : //no outputs via register : "x" (NLF), "y" (code) , "z" (key) : "r12", "r13", "r14", "r15", //code "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", //key "r24", "r25", //iteration variable "r9", "r10", "r11", //eortmp, nlfshift, nlfind "cc" ); #else uint16_t i; uint64_t keybak; keybak=*key; for(i=0;i<16;++i) {uint8_t tmp; tmp=*key>>63; *key<<=1; *key|=tmp; } for(i=0; i<528; ++i) { uint8_t nlfshift,nlfind,tmp,r; nlfshift = *code&2?1:0; if(*code&512) nlfshift |=2; if(*code&0x100000) nlfshift |= 4; nlfind = (*code&0x4000000) ?1:0; if(*code&0x80000000) nlfind |= 2; r= (NLF[nlfind]>>nlfshift)&1; if(*key&0x10000) r^=1; if(*code & 1) r^=1; if(*code & 0x10000) r^=1; tmp=*key&1; *key>>=1; *key|= ((uint64_t)tmp)<<63; //rotate key *code >>=1; *code|= ((uint32_t)r)<<31; //shift code } *key=keybak; #endif } #endif