]> git.cryptolib.org Git - avr-crypto-lib.git/blob - a51/A5_1.c
fixing E-Mail-Address & Copyright
[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) 2006-2015 Daniel Otte (bg@nerilex.org)
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:       bg@nerilex.org
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  * length is length of key in bits!
39  */
40
41 void a5_1_init(a5_1_ctx_t *c, void *key, uint8_t keylength_b, void *iv,
42         uint8_t ivlength_b)
43 {
44     uint8_t i, t;
45     memset(c->r1, 0, 3);
46     memset(c->r2, 0, 3);
47     memset(c->r3, 0, 3);
48     for (i = 0; i < keylength_b; ++i) {
49         t = ((uint8_t*) key)[i / 8];
50         t = 1 & (t >> i);
51         c->r1[0] ^= t;
52         c->r2[0] ^= t;
53         c->r3[0] ^= t;
54         a5_1_clock_core(c, 0x7);
55     }
56     for (i = 0; i < ivlength_b; ++i) {
57         t = ((uint8_t*) iv)[i / 8];
58         t = 1 & (t >> i);
59         c->r1[0] ^= t;
60         c->r2[0] ^= t;
61         c->r3[0] ^= t;
62         a5_1_clock_core(c, 0x7);
63     }
64     for (i = 0; i < 100; ++i)
65         a5_1_clock_core(c, 0);
66 }
67
68 static
69 void shiftreg(uint8_t *d)
70 {
71     uint8_t c, c2;
72     c = d[0] >> 7;
73     d[0] <<= 1;
74     c2 = d[1] >> 7;
75     d[1] = (d[1] << 1) | c;
76     d[2] = (d[2] << 1) | c2;
77 }
78
79 const uint8_t parity3_lut[] PROGMEM = { 0, 1, 1, 0,
80         1, 0, 0, 1 };
81 const uint8_t clock_lut[] PROGMEM = { 0x7, 0x6, 0x5, 0x3,
82         0x3, 0x5, 0x6, 0x7 };
83
84 uint8_t a5_1_clock_core(a5_1_ctx_t *c, uint8_t clockoverride)
85 {
86     uint8_t ret, clk, fb;
87     ret = (0x04 & c->r1[2]) | (0x20 & c->r2[2]) | (0x40 & c->r3[2]);
88     ret = ret ^ (ret >> 6);
89     ret &= 0x7;
90     ret = pgm_read_byte(parity3_lut + ret);
91     clk = (0x08 & c->r1[1]) | (0x10 & c->r2[1]) | (0x20 & c->r3[1]);
92     clk >>= 3;
93     clk = pgm_read_byte(clock_lut + clk);
94     clk |= clockoverride;
95
96     if (clk & 1) {
97         fb = c->r1[2] ^ (1 & ((c->r1[1]) >> 5));
98         fb &= 0x7;
99         fb = pgm_read_byte(parity3_lut + fb);
100         shiftreg(c->r1);
101         c->r1[0] |= fb;
102         c->r1[2] &= 0x07;
103     }
104     clk >>= 1;
105     if (clk & 1) {
106         fb = c->r2[2] >> 4;
107         fb &= 0x7;
108         fb = pgm_read_byte(parity3_lut + fb);
109         shiftreg(c->r2);
110         c->r2[0] |= fb;
111         c->r2[2] &= 0x3F;
112
113     }
114     clk >>= 1;
115     if (clk & 1) {
116         fb = (c->r3[2] >> 4) ^ (1 & ((c->r3[0]) >> 7));
117         fb &= 0x7;
118         fb = pgm_read_byte(parity3_lut + fb);
119         shiftreg(c->r3);
120         c->r3[0] |= fb;
121         c->r3[2] &= 0x7F;
122     }
123     return ret;
124 }
125
126 uint8_t a5_1_clock(a5_1_ctx_t *c)
127 {
128     return a5_1_clock_core(c, 0);
129 }
130
131 uint8_t a5_1_gen(a5_1_ctx_t *c)
132 {
133     uint8_t ret = 0;
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     ret <<= 1;
146     ret = a5_1_clock(c);
147     ret <<= 1;
148     ret = a5_1_clock(c);
149     return ret;
150 }
151