Neels Hofmeyr | 17518fe | 2017-06-20 04:35:06 +0200 | [diff] [blame] | 1 | /*! \file comp128v23.c |
| 2 | * COMP128 version 2 and 3 implementation, common algorithm used for GSM Authentication (A3/A8). |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 3 | * |
Kévin Redon | 7ecb034 | 2018-08-04 17:23:07 +0200 | [diff] [blame] | 4 | * 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 Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 8 | */ |
Neels Hofmeyr | 17518fe | 2017-06-20 04:35:06 +0200 | [diff] [blame] | 9 | /* |
| 10 | * (C) 2013 by Kévin Redon <kevredon@mail.tsaitgaist.info> |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 11 | * |
| 12 | * All Rights Reserved |
| 13 | * |
Harald Welte | e08da97 | 2017-11-13 01:00:26 +0900 | [diff] [blame] | 14 | * SPDX-License-Identifier: GPL-2.0+ |
| 15 | * |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 16 | * 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 | * |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 26 | */ |
| 27 | |
| 28 | #include <stdint.h> |
| 29 | #include <string.h> |
| 30 | |
Harald Welte | 96e2a00 | 2017-06-12 21:44:18 +0200 | [diff] [blame] | 31 | /*! \addtogroup auth |
| 32 | * @{ |
Neels Hofmeyr | 17518fe | 2017-06-20 04:35:06 +0200 | [diff] [blame] | 33 | * \file comp128v23.c */ |
Harald Welte | 96e2a00 | 2017-06-12 21:44:18 +0200 | [diff] [blame] | 34 | |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 35 | static const uint8_t table0[256] = { |
| 36 | 197, 235, 60, 151, 98, 96, 3, 100, 248, 118, 42, 117, 172, 211, 181, 203, 61, |
| 37 | 126, 156, 87, 149, 224, 55, 132, 186, 63, 238, 255, 85, 83, 152, 33, 160, |
| 38 | 184, 210, 219, 159, 11, 180, 194, 130, 212, 147, 5, 215, 92, 27, 46, 113, |
| 39 | 187, 52, 25, 185, 79, 221, 48, 70, 31, 101, 15, 195, 201, 50, 222, 137, |
| 40 | 233, 229, 106, 122, 183, 178, 177, 144, 207, 234, 182, 37, 254, 227, 231, 54, |
| 41 | 209, 133, 65, 202, 69, 237, 220, 189, 146, 120, 68, 21, 125, 38, 30, 2, |
| 42 | 155, 53, 196, 174, 176, 51, 246, 167, 76, 110, 20, 82, 121, 103, 112, 56, |
| 43 | 173, 49, 217, 252, 0, 114, 228, 123, 12, 93, 161, 253, 232, 240, 175, 67, |
| 44 | 128, 22, 158, 89, 18, 77, 109, 190, 17, 62, 4, 153, 163, 59, 145, 138, |
| 45 | 7, 74, 205, 10, 162, 80, 45, 104, 111, 150, 214, 154, 28, 191, 169, 213, |
| 46 | 88, 193, 198, 200, 245, 39, 164, 124, 84, 78, 1, 188, 170, 23, 86, 226, |
| 47 | 141, 32, 6, 131, 127, 199, 40, 135, 16, 57, 71, 91, 225, 168, 242, 206, |
| 48 | 97, 166, 44, 14, 90, 236, 239, 230, 244, 223, 108, 102, 119, 148, 251, 29, |
| 49 | 216, 8, 9, 249, 208, 24, 105, 94, 34, 64, 95, 115, 72, 134, 204, 43, |
| 50 | 247, 243, 218, 47, 58, 73, 107, 241, 179, 116, 66, 36, 143, 81, 250, 139, |
| 51 | 19, 13, 142, 140, 129, 192, 99, 171, 157, 136, 41, 75, 35, 165, 26 |
| 52 | }, table1[256] = { |
| 53 | 170, 42, 95, 141, 109, 30, 71, 89, 26, 147, 231, 205, 239, 212, 124, 129, 216, |
| 54 | 79, 15, 185, 153, 14, 251, 162, 0, 241, 172, 197, 43, 10, 194, 235, 6, |
| 55 | 20, 72, 45, 143, 104, 161, 119, 41, 136, 38, 189, 135, 25, 93, 18, 224, |
| 56 | 171, 252, 195, 63, 19, 58, 165, 23, 55, 133, 254, 214, 144, 220, 178, 156, |
| 57 | 52, 110, 225, 97, 183, 140, 39, 53, 88, 219, 167, 16, 198, 62, 222, 76, |
| 58 | 139, 175, 94, 51, 134, 115, 22, 67, 1, 249, 217, 3, 5, 232, 138, 31, |
| 59 | 56, 116, 163, 70, 128, 234, 132, 229, 184, 244, 13, 34, 73, 233, 154, 179, |
| 60 | 131, 215, 236, 142, 223, 27, 57, 246, 108, 211, 8, 253, 85, 66, 245, 193, |
| 61 | 78, 190, 4, 17, 7, 150, 127, 152, 213, 37, 186, 2, 243, 46, 169, 68, |
| 62 | 101, 60, 174, 208, 158, 176, 69, 238, 191, 90, 83, 166, 125, 77, 59, 21, |
| 63 | 92, 49, 151, 168, 99, 9, 50, 146, 113, 117, 228, 65, 230, 40, 82, 54, |
| 64 | 237, 227, 102, 28, 36, 107, 24, 44, 126, 206, 201, 61, 114, 164, 207, 181, |
| 65 | 29, 91, 64, 221, 255, 48, 155, 192, 111, 180, 210, 182, 247, 203, 148, 209, |
| 66 | 98, 173, 11, 75, 123, 250, 118, 32, 47, 240, 202, 74, 177, 100, 80, 196, |
| 67 | 33, 248, 86, 157, 137, 120, 130, 84, 204, 122, 81, 242, 188, 200, 149, 226, |
| 68 | 218, 160, 187, 106, 35, 87, 105, 96, 145, 199, 159, 12, 121, 103, 112 |
| 69 | }; |
| 70 | |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 71 | |
| 72 | static void |
| 73 | _comp128v23_internal(uint8_t *output, const uint8_t *kxor, const uint8_t *rand) |
| 74 | { |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 75 | uint8_t temp[16]; |
| 76 | uint8_t km_rm[32]; |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 77 | uint8_t i,j,k,z; |
| 78 | |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 79 | memset(temp, 0, sizeof(temp)); |
| 80 | memcpy(km_rm, rand, 16); |
| 81 | memcpy(km_rm + 16, kxor, 16); |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 82 | |
| 83 | for (i=0; i<5; i++) { |
| 84 | for (z=0; z<16; z++) { |
| 85 | temp[z] = table0[table1[km_rm[16+z]]^km_rm[z]]; |
| 86 | } |
| 87 | j=0; |
| 88 | while ((1<<i)>j) { |
| 89 | k = 0; |
| 90 | while ((1<<(4-i))>k) { |
| 91 | km_rm[((2*k+1)<<i)+j] = table0[table1[temp[(k<<i)+j]]^(km_rm[(k<<i)+16+j])]; |
| 92 | km_rm[(k<<(i+1))+j] = temp[(k<<i)+j]; |
| 93 | k++; |
| 94 | } |
| 95 | j++; |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | memset(output,0,16); |
| 100 | |
| 101 | for (i=0; i<16; i++) { |
| 102 | for (j=0; j<8; j++) { |
| 103 | output[i] ^= (((km_rm[(19*(j+8*i)+19)%256/8]>>(3*j+3)%8)&1)<< j); |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
Neels Hofmeyr | 87e4550 | 2017-06-20 00:17:59 +0200 | [diff] [blame] | 108 | /*! Perform COMP128v3 algorithm |
Harald Welte | 96e2a00 | 2017-06-12 21:44:18 +0200 | [diff] [blame] | 109 | * \param[in] ki Secret Key K(i) of subscriber |
| 110 | * \param[in] rand Random Challenge |
| 111 | * \param[out] sres user-supplied buffer for storing computed SRES value |
| 112 | * \param[out] kc user-supplied buffer for storing computed Kc value |
| 113 | * \returns 0 */ |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 114 | int |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 115 | comp128v3(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc) |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 116 | { |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 117 | uint8_t k_mix[16]; |
| 118 | uint8_t rand_mix[16]; |
| 119 | uint8_t katyvasz[16]; |
| 120 | uint8_t output[16]; |
| 121 | uint8_t i; |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 122 | |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 123 | memset(k_mix, 0, sizeof(k_mix)); |
| 124 | memset(rand_mix, 0, sizeof(rand_mix)); |
| 125 | memset(katyvasz, 0, sizeof(katyvasz)); |
| 126 | memset(output, 0, sizeof(output)); |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 127 | |
| 128 | for (i=0; i<8; i++) { |
| 129 | k_mix[i] = ki[15 - i]; |
| 130 | k_mix[15 - i] = ki[i]; |
| 131 | } |
| 132 | |
| 133 | for (i=0; i<8; i++) { |
| 134 | rand_mix[i] = rand[15 - i]; |
| 135 | rand_mix[15 - i] = rand[i]; |
| 136 | } |
| 137 | |
| 138 | for (i=0; i<16; i++) { |
| 139 | katyvasz[i] = k_mix[i]^rand_mix[i]; |
| 140 | } |
| 141 | |
| 142 | for (i=0; i<8; i++) { |
| 143 | _comp128v23_internal(rand_mix,katyvasz,rand_mix); |
| 144 | } |
| 145 | |
| 146 | for (i=0; i<16; i++) { |
| 147 | output[i] = rand_mix[15-i]; |
| 148 | } |
| 149 | |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 150 | memmove(output + 4, output + 8, 8); /* ignore bytes 4..7 */ |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 151 | |
| 152 | /* the algorithm uses 16 bytes until this point, but only 12 bytes are effective |
| 153 | * also 12 bytes coming out from the SIM card */ |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 154 | memcpy(sres, output, 4); |
| 155 | memcpy(kc, output + 4, 8); |
Kevin Redon | be355cd | 2013-11-02 18:11:01 +0100 | [diff] [blame] | 156 | |
| 157 | return 0; |
| 158 | } |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 159 | |
Neels Hofmeyr | 87e4550 | 2017-06-20 00:17:59 +0200 | [diff] [blame] | 160 | /*! Perform COMP128v2 algorithm |
Harald Welte | 96e2a00 | 2017-06-12 21:44:18 +0200 | [diff] [blame] | 161 | * \param[in] ki Secret Key K(i) of subscriber |
| 162 | * \param[in] rand Random Challenge |
| 163 | * \param[out] sres user-supplied buffer for storing computed SRES value |
| 164 | * \param[out] kc user-supplied buffer for storing computed Kc value |
| 165 | * \returns 0 */ |
Max | 4f0abc0 | 2013-12-02 11:30:32 +0100 | [diff] [blame] | 166 | int |
| 167 | comp128v2(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc) |
| 168 | { |
| 169 | int r = comp128v3(ki, rand, sres, kc); |
| 170 | kc[7] = 0; /* 10 last bits of Kc forced to 0 */ |
| 171 | kc[6] &= 0xfc; |
| 172 | return r; |
| 173 | } |
Harald Welte | 96e2a00 | 2017-06-12 21:44:18 +0200 | [diff] [blame] | 174 | |
| 175 | /*! @} */ |