blob: 550f6a4997a67d33e63298a8e81e50d66957a3cb [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file comp128v23.c
2 * COMP128 version 2 and 3 implementation, common algorithm used for GSM Authentication (A3/A8).
Kevin Redonbe355cd2013-11-02 18:11:01 +01003 *
Kévin Redon7ecb0342018-08-04 17:23:07 +02004 * This code is a C conversion of the original code by Tamas Jos <info@skelsec.com> from:
5 * - original (out of service): http://www.hackingprojects.net/
6 * - original (archive): https://web.archive.org/web/20130730113347/http://www.hackingprojects.net/
7 * - new site: https://github.com/skelsec/COMP128
Kevin Redonbe355cd2013-11-02 18:11:01 +01008 */
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02009/*
10 * (C) 2013 by Kévin Redon <kevredon@mail.tsaitgaist.info>
Kevin Redonbe355cd2013-11-02 18:11:01 +010011 *
12 * All Rights Reserved
13 *
Harald Weltee08da972017-11-13 01:00:26 +090014 * SPDX-License-Identifier: GPL-2.0+
15 *
Kevin Redonbe355cd2013-11-02 18:11:01 +010016 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 *
30 */
31
32#include <stdint.h>
33#include <string.h>
34
Harald Welte96e2a002017-06-12 21:44:18 +020035/*! \addtogroup auth
36 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020037 * \file comp128v23.c */
Harald Welte96e2a002017-06-12 21:44:18 +020038
Kevin Redonbe355cd2013-11-02 18:11:01 +010039static const uint8_t table0[256] = {
40 197, 235, 60, 151, 98, 96, 3, 100, 248, 118, 42, 117, 172, 211, 181, 203, 61,
41 126, 156, 87, 149, 224, 55, 132, 186, 63, 238, 255, 85, 83, 152, 33, 160,
42 184, 210, 219, 159, 11, 180, 194, 130, 212, 147, 5, 215, 92, 27, 46, 113,
43 187, 52, 25, 185, 79, 221, 48, 70, 31, 101, 15, 195, 201, 50, 222, 137,
44 233, 229, 106, 122, 183, 178, 177, 144, 207, 234, 182, 37, 254, 227, 231, 54,
45 209, 133, 65, 202, 69, 237, 220, 189, 146, 120, 68, 21, 125, 38, 30, 2,
46 155, 53, 196, 174, 176, 51, 246, 167, 76, 110, 20, 82, 121, 103, 112, 56,
47 173, 49, 217, 252, 0, 114, 228, 123, 12, 93, 161, 253, 232, 240, 175, 67,
48 128, 22, 158, 89, 18, 77, 109, 190, 17, 62, 4, 153, 163, 59, 145, 138,
49 7, 74, 205, 10, 162, 80, 45, 104, 111, 150, 214, 154, 28, 191, 169, 213,
50 88, 193, 198, 200, 245, 39, 164, 124, 84, 78, 1, 188, 170, 23, 86, 226,
51 141, 32, 6, 131, 127, 199, 40, 135, 16, 57, 71, 91, 225, 168, 242, 206,
52 97, 166, 44, 14, 90, 236, 239, 230, 244, 223, 108, 102, 119, 148, 251, 29,
53 216, 8, 9, 249, 208, 24, 105, 94, 34, 64, 95, 115, 72, 134, 204, 43,
54 247, 243, 218, 47, 58, 73, 107, 241, 179, 116, 66, 36, 143, 81, 250, 139,
55 19, 13, 142, 140, 129, 192, 99, 171, 157, 136, 41, 75, 35, 165, 26
56}, table1[256] = {
57 170, 42, 95, 141, 109, 30, 71, 89, 26, 147, 231, 205, 239, 212, 124, 129, 216,
58 79, 15, 185, 153, 14, 251, 162, 0, 241, 172, 197, 43, 10, 194, 235, 6,
59 20, 72, 45, 143, 104, 161, 119, 41, 136, 38, 189, 135, 25, 93, 18, 224,
60 171, 252, 195, 63, 19, 58, 165, 23, 55, 133, 254, 214, 144, 220, 178, 156,
61 52, 110, 225, 97, 183, 140, 39, 53, 88, 219, 167, 16, 198, 62, 222, 76,
62 139, 175, 94, 51, 134, 115, 22, 67, 1, 249, 217, 3, 5, 232, 138, 31,
63 56, 116, 163, 70, 128, 234, 132, 229, 184, 244, 13, 34, 73, 233, 154, 179,
64 131, 215, 236, 142, 223, 27, 57, 246, 108, 211, 8, 253, 85, 66, 245, 193,
65 78, 190, 4, 17, 7, 150, 127, 152, 213, 37, 186, 2, 243, 46, 169, 68,
66 101, 60, 174, 208, 158, 176, 69, 238, 191, 90, 83, 166, 125, 77, 59, 21,
67 92, 49, 151, 168, 99, 9, 50, 146, 113, 117, 228, 65, 230, 40, 82, 54,
68 237, 227, 102, 28, 36, 107, 24, 44, 126, 206, 201, 61, 114, 164, 207, 181,
69 29, 91, 64, 221, 255, 48, 155, 192, 111, 180, 210, 182, 247, 203, 148, 209,
70 98, 173, 11, 75, 123, 250, 118, 32, 47, 240, 202, 74, 177, 100, 80, 196,
71 33, 248, 86, 157, 137, 120, 130, 84, 204, 122, 81, 242, 188, 200, 149, 226,
72 218, 160, 187, 106, 35, 87, 105, 96, 145, 199, 159, 12, 121, 103, 112
73};
74
Kevin Redonbe355cd2013-11-02 18:11:01 +010075
76static void
77_comp128v23_internal(uint8_t *output, const uint8_t *kxor, const uint8_t *rand)
78{
Max4f0abc02013-12-02 11:30:32 +010079 uint8_t temp[16];
80 uint8_t km_rm[32];
Kevin Redonbe355cd2013-11-02 18:11:01 +010081 uint8_t i,j,k,z;
82
Max4f0abc02013-12-02 11:30:32 +010083 memset(temp, 0, sizeof(temp));
84 memcpy(km_rm, rand, 16);
85 memcpy(km_rm + 16, kxor, 16);
Kevin Redonbe355cd2013-11-02 18:11:01 +010086
87 for (i=0; i<5; i++) {
88 for (z=0; z<16; z++) {
89 temp[z] = table0[table1[km_rm[16+z]]^km_rm[z]];
90 }
91 j=0;
92 while ((1<<i)>j) {
93 k = 0;
94 while ((1<<(4-i))>k) {
95 km_rm[((2*k+1)<<i)+j] = table0[table1[temp[(k<<i)+j]]^(km_rm[(k<<i)+16+j])];
96 km_rm[(k<<(i+1))+j] = temp[(k<<i)+j];
97 k++;
98 }
99 j++;
100 }
101 }
102
103 memset(output,0,16);
104
105 for (i=0; i<16; i++) {
106 for (j=0; j<8; j++) {
107 output[i] ^= (((km_rm[(19*(j+8*i)+19)%256/8]>>(3*j+3)%8)&1)<< j);
108 }
109 }
110}
111
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200112/*! Perform COMP128v3 algorithm
Harald Welte96e2a002017-06-12 21:44:18 +0200113 * \param[in] ki Secret Key K(i) of subscriber
114 * \param[in] rand Random Challenge
115 * \param[out] sres user-supplied buffer for storing computed SRES value
116 * \param[out] kc user-supplied buffer for storing computed Kc value
117 * \returns 0 */
Kevin Redonbe355cd2013-11-02 18:11:01 +0100118int
Max4f0abc02013-12-02 11:30:32 +0100119comp128v3(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc)
Kevin Redonbe355cd2013-11-02 18:11:01 +0100120{
Max4f0abc02013-12-02 11:30:32 +0100121 uint8_t k_mix[16];
122 uint8_t rand_mix[16];
123 uint8_t katyvasz[16];
124 uint8_t output[16];
125 uint8_t i;
Kevin Redonbe355cd2013-11-02 18:11:01 +0100126
Max4f0abc02013-12-02 11:30:32 +0100127 memset(k_mix, 0, sizeof(k_mix));
128 memset(rand_mix, 0, sizeof(rand_mix));
129 memset(katyvasz, 0, sizeof(katyvasz));
130 memset(output, 0, sizeof(output));
Kevin Redonbe355cd2013-11-02 18:11:01 +0100131
132 for (i=0; i<8; i++) {
133 k_mix[i] = ki[15 - i];
134 k_mix[15 - i] = ki[i];
135 }
136
137 for (i=0; i<8; i++) {
138 rand_mix[i] = rand[15 - i];
139 rand_mix[15 - i] = rand[i];
140 }
141
142 for (i=0; i<16; i++) {
143 katyvasz[i] = k_mix[i]^rand_mix[i];
144 }
145
146 for (i=0; i<8; i++) {
147 _comp128v23_internal(rand_mix,katyvasz,rand_mix);
148 }
149
150 for (i=0; i<16; i++) {
151 output[i] = rand_mix[15-i];
152 }
153
Max4f0abc02013-12-02 11:30:32 +0100154 memmove(output + 4, output + 8, 8); /* ignore bytes 4..7 */
Kevin Redonbe355cd2013-11-02 18:11:01 +0100155
156 /* the algorithm uses 16 bytes until this point, but only 12 bytes are effective
157 * also 12 bytes coming out from the SIM card */
Max4f0abc02013-12-02 11:30:32 +0100158 memcpy(sres, output, 4);
159 memcpy(kc, output + 4, 8);
Kevin Redonbe355cd2013-11-02 18:11:01 +0100160
161 return 0;
162}
Max4f0abc02013-12-02 11:30:32 +0100163
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200164/*! Perform COMP128v2 algorithm
Harald Welte96e2a002017-06-12 21:44:18 +0200165 * \param[in] ki Secret Key K(i) of subscriber
166 * \param[in] rand Random Challenge
167 * \param[out] sres user-supplied buffer for storing computed SRES value
168 * \param[out] kc user-supplied buffer for storing computed Kc value
169 * \returns 0 */
Max4f0abc02013-12-02 11:30:32 +0100170int
171comp128v2(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc)
172{
173 int r = comp128v3(ki, rand, sres, kc);
174 kc[7] = 0; /* 10 last bits of Kc forced to 0 */
175 kc[6] &= 0xfc;
176 return r;
177}
Harald Welte96e2a002017-06-12 21:44:18 +0200178
179/*! @} */