]> git.cryptolib.org Git - avr-crypto-lib.git/blob - a51/A5_1.c
a8bbf3da8513566dcd947064a229362c4082b481
[avr-crypto-lib.git] / a51 / A5_1.c
1 /* A5_1.c */
2 /*
3     This file is part of the AVR-Crypto-Lib.
4     Copyright (C) 2008  Daniel Otte (daniel.otte@rub.de)
5
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /* 
20  * File:        A5_1.c
21  * Author:      Daniel Otte
22  * email:       daniel.otte@rub.de
23  * Date:        2006-06-24
24  * License:     GPLv3 or later
25  * Description: Implementation of the A5/1 stream cipher algorithm, as used in GSM.
26  * ! Warning, this is weak crypto !
27  * 
28  */
29  
30 #include <stdint.h>
31 #include <string.h>
32 #include "A5_1.h"
33 #include <avr/pgmspace.h>
34
35 uint8_t a5_1_clock_core(a5_1_ctx_t *c, uint8_t clockoverride);
36
37
38 /*
39  * length is length of key in bits!
40  */
41
42 void a5_1_init(a5_1_ctx_t *c, void *key, uint8_t keylength_b, void *iv, uint8_t ivlength_b){
43         uint8_t i,t;
44         memset(c->r1, 0, 3);
45         memset(c->r2, 0, 3);
46         memset(c->r3, 0, 3);
47         for(i=0; i<keylength_b; ++i){
48                 t=((uint8_t*)key)[i/8];
49                 t=1&(t>>i);
50                 c->r1[0] ^= t;
51                 c->r2[0] ^= t;
52                 c->r3[0] ^= t;
53                 a5_1_clock_core(c, 0x7);
54         }
55         for(i=0; i<ivlength_b; ++i){
56                 t=((uint8_t*)iv)[i/8];
57                 t=1&(t>>i);
58                 c->r1[0] ^= t;
59                 c->r2[0] ^= t;
60                 c->r3[0] ^= t;
61                 a5_1_clock_core(c, 0x7);
62         }
63         for(i=0; i<100; ++i)
64                 a5_1_clock_core(c,0);
65 }
66
67 static
68 void shiftreg(uint8_t *d){
69         uint8_t c, c2;
70         c=d[0]>>7;
71         d[0] <<= 1;
72         c2=d[1]>>7;
73         d[1] = (d[1]<<1) | c;
74         d[2] = (d[2]<<1) | c2;
75
76
77 const uint8_t parity3_lut[] PROGMEM = {0, 1, 1, 0,
78                                              1, 0, 0, 1};       
79 const uint8_t clock_lut[] PROGMEM =  {0x7, 0x6, 0x5, 0x3,
80                                             0x3, 0x5, 0x6, 0x7}; 
81                                             
82 uint8_t a5_1_clock_core(a5_1_ctx_t *c, uint8_t clockoverride){
83         uint8_t ret,clk,fb;
84         ret = (0x04&c->r1[2]) | (0x20&c->r2[2]) | (0x40&c->r3[2]);
85         ret = ret^(ret>>6);
86         ret &= 0x7;
87         ret = pgm_read_byte(parity3_lut+ret);
88         clk = (0x08&c->r1[1]) | (0x10&c->r2[1]) | (0x20&c->r3[1]);
89         clk >>= 3;
90         clk = pgm_read_byte(clock_lut+clk);
91         clk |= clockoverride;
92         
93         if(clk&1){
94                 fb = c->r1[2] ^ (1&((c->r1[1])>>5));
95                 fb &= 0x7;
96                 fb = pgm_read_byte(parity3_lut+fb);
97                 shiftreg(c->r1);
98                 c->r1[0] |= fb;
99                 c->r1[2] &= 0x07;
100         }
101         clk>>=1;
102         if(clk&1){
103                 fb = c->r2[2]>>4 ;
104                 fb &= 0x7;
105                 fb = pgm_read_byte(parity3_lut+fb);
106                 shiftreg(c->r2);
107                 c->r2[0] |= fb;
108                 c->r2[2] &= 0x3F;
109         
110         }
111         clk>>=1;
112         if(clk&1){
113                 fb = (c->r3[2]>>4) ^ (1&((c->r3[0])>>7));
114                 fb &= 0x7;
115                 fb = pgm_read_byte(parity3_lut+fb);
116                 shiftreg(c->r3);
117                 c->r3[0] |= fb;
118                 c->r3[2] &= 0x7F;
119         }
120         return ret;
121 }
122
123 uint8_t a5_1_clock(a5_1_ctx_t *c){
124         return a5_1_clock_core(c, 0);
125 }
126
127
128 uint8_t a5_1_gen(a5_1_ctx_t *c){
129         uint8_t ret=0;
130         ret = a5_1_clock(c);
131         ret <<= 1;
132         ret = a5_1_clock(c);
133         ret <<= 1;
134         ret = a5_1_clock(c);
135         ret <<= 1;
136         ret = a5_1_clock(c);
137         ret <<= 1;
138         ret = a5_1_clock(c);
139         ret <<= 1;
140         ret = a5_1_clock(c);
141         ret <<= 1;
142         ret = a5_1_clock(c);
143         ret <<= 1;
144         ret = a5_1_clock(c);
145         return ret;
146 }
147
148
149
150