---
include/osmocom/gsm/kasumi.h | 36 ++++++++
src/gsm/kasumi.c | 193 ++++++++++++++++++++++++++++++++++++++++++
tests/kasumi/kasumi_test.c | 128 ++++++++++++++++++++++++++++
tests/kasumi/kasumi_test.ok | 10 +++
4 files changed, 367 insertions(+)
create mode 100644 include/osmocom/gsm/kasumi.h
create mode 100644 src/gsm/kasumi.c
create mode 100644 tests/kasumi/kasumi_test.c
create mode 100644 tests/kasumi/kasumi_test.ok
diff --git a/include/osmocom/gsm/kasumi.h b/include/osmocom/gsm/kasumi.h
new file mode 100644
index 0000000..8479968
--- /dev/null
+++ b/include/osmocom/gsm/kasumi.h
@@ -0,0 +1,36 @@
+/*
+ * KASUMI header
+ *
+ * See kasumi.c for details
+ */
+
+#ifndef __KASUMI_H__
+#define __KASUMI_H__
+
+#include <stdint.h>
+
+/*
+ * Single iteration of KASUMI cipher
+*/
+uint64_t _kasumi(uint64_t P, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t
*KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3);
+
+/*
+ * Implementation of the KGCORE algorithm (used by A5/3, A5/4, GEA3, GEA4 and ECSD)
+ *
+ * CA : uint8_t
+ * cb : uint8_t
+ * cc : uint32_t
+ * cd : uint8_t
+ * ck : uint8_t [8]
+ * co : uint8_t [output, cl-dependent]
+ * cl : uint16_t
+ */
+void _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck,
uint8_t *co, uint16_t cl);
+
+/*! \brief Expand key into set of subkeys
+ * \param[in] key (128 bits) as array of bytes
+ * \param[out] arrays of round-specific subkeys - see TS 135 202 for details
+ */
+void _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t
*KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3);
+
+#endif /* __KASUMI_H__ */
diff --git a/src/gsm/kasumi.c b/src/gsm/kasumi.c
new file mode 100644
index 0000000..816c681
--- /dev/null
+++ b/src/gsm/kasumi.c
@@ -0,0 +1,193 @@
+/* Kasumi cipher and KGcore functions */
+
+/* (C) 2013 by Max <Max.Suraev(a)fairwaves.ru>
+ *
+ * All Rights Reserved
+ *
+ * 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 2 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <osmocom/core/bits.h>
+#include <osmocom/gsm/kasumi.h>
+
+static uint16_t
+_kasumi_FI(uint16_t I, uint16_t skey)
+{
+ static uint16_t S7[] = {
+ 54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18, 123, 33,
+ 55, 113, 39, 114, 21, 67, 65, 12, 47, 73, 46, 27, 25, 111, 124, 81,
+ 53, 9, 121, 79, 52, 60, 58, 48, 101, 127, 40, 120, 104, 70, 71, 43,
+ 20, 122, 72, 61, 23, 109, 13, 100, 77, 1, 16, 7, 82, 10, 105, 98,
+ 117, 116, 76, 11, 89, 106, 0,125,118, 99, 86, 69, 30, 57, 126, 87,
+ 112, 51, 17, 5, 95, 14, 90, 84, 91, 8, 35,103, 32, 97, 28, 66,
+ 102, 31, 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29, 115, 44,
+ 64, 107, 108, 24, 110, 83, 36, 78, 42, 19, 15, 41, 88, 119, 59, 3
+ };
+ static uint16_t S9[] = {
+ 167, 239, 161, 379, 391, 334, 9, 338, 38, 226, 48, 358, 452, 385, 90, 397,
+ 183, 253, 147, 331, 415, 340, 51, 362, 306, 500, 262, 82, 216, 159, 356, 177,
+ 175, 241, 489, 37, 206, 17, 0, 333, 44, 254, 378, 58, 143, 220, 81, 400,
+ 95, 3, 315, 245, 54, 235, 218, 405, 472, 264, 172, 494, 371, 290, 399, 76,
+ 165, 197, 395, 121, 257, 480, 423, 212, 240, 28, 462, 176, 406, 507, 288, 223,
+ 501, 407, 249, 265, 89, 186, 221, 428,164, 74, 440, 196, 458, 421, 350, 163,
+ 232, 158, 134, 354, 13, 250, 491, 142,191, 69, 193, 425, 152, 227, 366, 135,
+ 344, 300, 276, 242, 437, 320, 113, 278, 11, 243, 87, 317, 36, 93, 496, 27,
+ 487, 446, 482, 41, 68, 156, 457, 131, 326, 403, 339, 20, 39, 115, 442, 124,
+ 475, 384, 508, 53, 112, 170, 479, 151, 126, 169, 73, 268, 279, 321, 168, 364,
+ 363, 292, 46, 499, 393, 327, 324, 24, 456, 267, 157, 460, 488, 426, 309, 229,
+ 439, 506, 208, 271, 349, 401, 434, 236, 16, 209, 359, 52, 56, 120, 199, 277,
+ 465, 416, 252, 287, 246, 6, 83, 305, 420, 345, 153,502, 65, 61, 244, 282,
+ 173, 222, 418, 67, 386, 368, 261, 101, 476, 291, 195,430, 49, 79, 166, 330,
+ 280, 383, 373, 128, 382, 408, 155, 495, 367, 388, 274, 107, 459, 417, 62, 454,
+ 132, 225, 203, 316, 234, 14, 301, 91, 503, 286, 424, 211, 347, 307, 140, 374,
+ 35, 103, 125, 427, 19, 214, 453, 146, 498, 314, 444, 230, 256, 329, 198, 285,
+ 50, 116, 78, 410, 10, 205, 510, 171, 231, 45, 139, 467, 29, 86, 505, 32,
+ 72, 26, 342, 150, 313, 490, 431, 238, 411, 325, 149, 473, 40, 119, 174, 355,
+ 185, 233, 389, 71, 448, 273, 372, 55, 110, 178, 322, 12, 469, 392, 369, 190,
+ 1, 109, 375, 137, 181, 88, 75, 308, 260, 484, 98, 272, 370, 275, 412, 111,
+ 336, 318, 4, 504, 492, 259, 304, 77, 337, 435, 21, 357, 303, 332, 483, 18,
+ 47, 85, 25, 497, 474, 289, 100, 269, 296, 478, 270, 106, 31, 104, 433, 84,
+ 414, 486, 394, 96, 99, 154, 511, 148, 413, 361, 409, 255, 162, 215, 302, 201,
+ 266, 351, 343, 144, 441, 365, 108, 298, 251, 34, 182, 509, 138, 210, 335, 133,
+ 311, 352, 328, 141, 396, 346, 123, 319, 450, 281, 429, 228, 443, 481, 92, 404,
+ 485, 422, 248, 297, 23, 213, 130, 466, 22, 217, 283, 70, 294, 360, 419, 127,
+ 312, 377, 7, 468, 194, 2, 117, 295, 463, 258, 224, 447, 247, 187, 80, 398,
+ 284, 353, 105, 390, 299, 471, 470, 184, 57, 200, 348, 63, 204, 188, 33, 451,
+ 97, 30, 310, 219, 94, 160, 129, 493, 64, 179, 263, 102, 189, 207, 114, 402,
+ 438, 477, 387, 122, 192, 42, 381, 5, 145, 118, 180, 449, 293, 323, 136, 380,
+ 43, 66, 60, 455, 341, 445, 202, 432, 8, 237, 15, 376, 436, 464, 59, 461
+ };
+ uint16_t L, R;
+
+ /* Split 16 bit input into two unequal halves: 9 and 7 bits, same for subkey */
+ L = I >> 7; /* take 9 bits */
+ R = I & 0x7F; /* take 7 bits */
+
+ L = S9[L] ^ R;
+ R = S7[R] ^ (L & 0x7F);
+
+ L ^= (skey & 0x1FF);
+ R ^= (skey >> 9);
+
+ L = S9[L] ^ R;
+ R = S7[R] ^ (L & 0x7F);
+
+ return (R << 9) + L;
+}
+
+static uint32_t
+_kasumi_FO(uint32_t I, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1,
uint16_t *KIi2, uint16_t *KIi3, unsigned i)
+{
+ uint16_t L = I >> 16, R = I; /* Split 32 bit input into Left and Right parts
*/
+
+ L ^= KOi1[i];
+ L = _kasumi_FI(L, KIi1[i]);
+ L ^= R;
+
+ R ^= KOi2[i];
+ R = _kasumi_FI(R, KIi2[i]);
+ R ^= L;
+
+ L ^= KOi3[i];
+ L = _kasumi_FI(L, KIi3[i]);
+ L ^= R;
+
+ return (((uint32_t)R) << 16) + L;
+}
+
+static uint32_t
+_kasumi_FL(uint32_t I, uint16_t *KLi1, uint16_t *KLi2, unsigned i)
+{
+ uint16_t L = I >> 16, R = I, tmp; /* Split 32 bit input into Left and Right
parts */
+
+ tmp = L & KLi1[i];
+ R ^= rol16(tmp, 1);
+
+ tmp = R | KLi2[i];
+ L ^= rol16(tmp, 1);
+
+ return (((uint32_t)L) << 16) + R;
+}
+
+uint64_t
+_kasumi(uint64_t P, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2,
uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3)
+{
+ uint32_t i, L = P >> 32, R = P; /* Split 64 bit input into Left and Right parts
*/
+
+ for (i = 0; i < 8; i++)
+ {
+ R ^= _kasumi_FO(_kasumi_FL(L, KLi1, KLi2, i), KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i); /*
odd round */
+ i++;
+ L ^= _kasumi_FL(_kasumi_FO(R, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i), KLi1, KLi2, i); /*
even round */
+ }
+ return (((uint64_t)L) << 32) + R; /* Concatenate Left and Right 32 bits into 64
bit ciphertext */
+}
+
+/*! \brief Expand key into set of subkeys
+ * \param[in] key (128 bits) as array of bytes
+ * \param[out] arrays of round-specific subkeys - see TS 135 202 for details
+ */
+void
+_kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1,
uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3)
+{
+ uint16_t i, C[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, 0xFEDC, 0xBA98, 0x7654, 0x3210
};
+
+ for (i = 0; i < 8; i++) /* Work with 16 bit subkeys and create prime subkeys */
+ {
+ C[i] ^= osmo_get2bytes(key + i * 2);
+ }
+ /* C[] now stores K-prime[] */
+ for (i = 0; i < 8; i++) /* Create round-specific subkeys */
+ {
+ KLi1[i] = rol16(osmo_get2bytes(key + i * 2), 1);
+ KLi2[i] = C[(i + 2) & 0x7];
+
+ KOi1[i] = rol16(osmo_get2bytes(key + ((2 * (i + 1)) & 0xE)), 5);
+ KOi2[i] = rol16(osmo_get2bytes(key + ((2 * (i + 5)) & 0xE)), 8);
+ KOi3[i] = rol16(osmo_get2bytes(key + ((2 * (i + 6)) & 0xE)), 13);
+
+ KIi1[i] = C[(i + 4) & 0x7];
+ KIi2[i] = C[(i + 3) & 0x7];
+ KIi3[i] = C[(i + 7) & 0x7];
+ }
+}
+
+void
+_kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck,
uint8_t *co, uint16_t cl)
+{
+ uint16_t KLi1[8], KLi2[8], KOi1[8], KOi2[8], KOi3[8], KIi1[8], KIi2[8], KIi3[8], i;
+ uint64_t A = ((uint64_t)cc) << 32, BLK = 0, _ca = ((uint64_t)CA << 16) ;
+ A |= _ca;
+ _ca = (uint64_t)((cb << 3) | (cd << 2)) << 24;
+ A |= _ca;
+ /* Register loading complete: see TR 55.919 8.2 and TS 55.216 3.2 */
+
+ uint8_t ck_km[16];
+ for (i = 0; i < 16; i++) ck_km[i] = ck[i] ^ 0x55; /* Modified key established */
+
+ /* preliminary round with modified key */
+ _kasumi_key_expand(ck_km, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
+ A = _kasumi(A, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
+
+ /* Run Kasumi in OFB to obtain enough data for gamma. */
+ _kasumi_key_expand(ck, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
+ for (i = 0; i < cl / 64 + 1; i++) /* i is a block counter */
+ {
+ BLK = _kasumi(A ^ i ^ BLK, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
+ osmo_64pack2pbit(BLK, co + (i * 8));
+ }
+}
diff --git a/tests/kasumi/kasumi_test.c b/tests/kasumi/kasumi_test.c
new file mode 100644
index 0000000..5504905
--- /dev/null
+++ b/tests/kasumi/kasumi_test.c
@@ -0,0 +1,128 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/kasumi.h> // for testing internal A5/3 functions
+
+
+inline int _compare_mem(uint8_t * x, uint8_t * y, size_t len) {
+ if (0 != memcmp(x, y, len)) {
+ printf ("X: %s\t", osmo_hexdump_nospc(x, len));
+ printf ("Y: %s\n", osmo_hexdump_nospc(y, len));
+ return 0;
+ }
+ return 1;
+}
+
+inline static void test_expansion(uint8_t * test_key, uint16_t * _KLi1, uint16_t * _KLi2,
uint16_t * _KOi1, uint16_t * _KOi2, uint16_t * _KOi3, uint16_t * _KIi1, uint16_t * _KIi2,
uint16_t * _KIi3, uint16_t * _KLi1_r, uint16_t * _KLi2_r, uint16_t * _KOi1_r, uint16_t *
_KOi2_r, uint16_t * _KOi3_r, uint16_t * _KIi1_r, uint16_t * _KIi2_r, uint16_t * _KIi3_r)
+{
+ _kasumi_key_expand(test_key, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2,
_KIi3);
+ int passed = 1;
+ passed = _compare_mem((uint8_t *)_KLi1, (uint8_t *)_KLi1_r, 16);
+ passed = _compare_mem((uint8_t *)_KLi2, (uint8_t *)_KLi2_r, 16);
+ passed = _compare_mem((uint8_t *)_KOi1, (uint8_t *)_KOi1_r, 16);
+ passed = _compare_mem((uint8_t *)_KOi2, (uint8_t *)_KOi2_r, 16);
+ passed = _compare_mem((uint8_t *)_KOi3, (uint8_t *)_KOi3_r, 16);
+ passed = _compare_mem((uint8_t *)_KIi1, (uint8_t *)_KIi1_r, 16);
+ passed = _compare_mem((uint8_t *)_KIi2, (uint8_t *)_KIi2_r, 16);
+ passed = _compare_mem((uint8_t *)_KIi3, (uint8_t *)_KIi3_r, 16);
+ if (passed) printf(" OK. "); else printf("FAILED!");
+}
+
+int main(int argc, char **argv)
+{
+ uint16_t _KLi1[8], _KLi2[8], _KOi1[8], _KOi2[8], _KOi3[8], _KIi1[8], _KIi2[8],
_KIi3[8], _KLi1_r[8], _KLi2_r[8], _KOi1_r[8], _KOi2_r[8], _KOi3_r[8], _KIi1_r[8],
_KIi2_r[8], _KIi3_r[8];
+
+ printf("testing KASUMI key expansion and encryption (ETSI TS 135
203):\n");
+ printf("KASUMI Test Set 1...");
+
+uint8_t _test_key1[] = {0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49,
0x10, 0x48, 0x81, 0xFF, 0x48};
+_KLi1_r[0] = 0x57AC; _KLi1_r[1] = 0x8B3E; _KLi1_r[2] = 0x058B; _KLi1_r[3] = 0x6601;
_KLi1_r[4] = 0x2A59; _KLi1_r[5] = 0x9220; _KLi1_r[6] = 0x9102; _KLi1_r[7] = 0xFE91;
+_KLi2_r[0] = 0x0B6E; _KLi2_r[1] = 0x7EEF; _KLi2_r[2] = 0x6BF0; _KLi2_r[3] = 0xF388;
_KLi2_r[4] = 0x3ED5; _KLi2_r[5] = 0xCD58; _KLi2_r[6] = 0x2AF5; _KLi2_r[7] = 0x00F8;
+_KOi1_r[0] = 0xB3E8; _KOi1_r[1] = 0x58B0; _KOi1_r[2] = 0x6016; _KOi1_r[3] = 0xA592;
_KOi1_r[4] = 0x2209; _KOi1_r[5] = 0x1029; _KOi1_r[6] = 0xE91F; _KOi1_r[7] = 0x7AC5;
+_KOi2_r[0] = 0x1049; _KOi2_r[1] = 0x8148; _KOi2_r[2] = 0x48FF; _KOi2_r[3] = 0xD62B;
_KOi2_r[4] = 0x9F45; _KOi2_r[5] = 0xC582; _KOi2_r[6] = 0x00B3; _KOi2_r[7] = 0x2C95;
+_KOi3_r[0] = 0x2910; _KOi3_r[1] = 0x1FE9; _KOi3_r[2] = 0xC57A; _KOi3_r[3] = 0xE8B3;
_KOi3_r[4] = 0xB058; _KOi3_r[5] = 0x1660; _KOi3_r[6] = 0x92A5; _KOi3_r[7] = 0x0922;
+_KIi1_r[0] = 0x6BF0; _KIi1_r[1] = 0xF388; _KIi1_r[2] = 0x3ED5; _KIi1_r[3] = 0xCD58;
_KIi1_r[4] = 0x2AF5; _KIi1_r[5] = 0x00F8; _KIi1_r[6] = 0x0B6E; _KIi1_r[7] = 0x7EEF;
+_KIi2_r[0] = 0x7EEF; _KIi2_r[1] = 0x6BF0; _KIi2_r[2] = 0xF388; _KIi2_r[3] = 0x3ED5;
_KIi2_r[4] = 0xCD58; _KIi2_r[5] = 0x2AF5; _KIi2_r[6] = 0x00F8; _KIi2_r[7] = 0x0B6E;
+_KIi3_r[0] = 0xCD58; _KIi3_r[1] = 0x2AF5; _KIi3_r[2] = 0x00F8; _KIi3_r[3] = 0x0B6E;
_KIi3_r[4] = 0x7EEF; _KIi3_r[5] = 0x6BF0; _KIi3_r[6] = 0xF388; _KIi3_r[7] = 0x3ED5;
+test_expansion(_test_key1, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3,
_KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r);
+
+if (0xDF1F9B251C0BF45F == _kasumi(0xEA024714AD5C4D84, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3,
_KIi1, _KIi2, _KIi3))
+ printf("OK."); else printf("FAILED!");
+
+printf("\nKASUMI Test Set 2...");
+
+uint8_t _test_key2[] = {0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, 0x1F, 0x3D, 0xE8,
0xA6, 0xDC, 0x66, 0xB1, 0xF3};
+_KLi1_r[0] = 0x19C7; _KLi1_r[1] = 0x7C58; _KLi1_r[2] = 0x8781; _KLi1_r[3] = 0x6BF9;
_KLi1_r[4] = 0x3E7A; _KLi1_r[5] = 0xD14D; _KLi1_r[6] = 0xB8CD; _KLi1_r[7] = 0x63E7;
+_KLi2_r[0] = 0x4A6B; _KLi2_r[1] = 0x7813; _KLi2_r[2] = 0xE1E1; _KLi2_r[3] = 0x523E;
_KLi2_r[4] = 0xAA32; _KLi2_r[5] = 0x83E3; _KLi2_r[6] = 0x8DC0; _KLi2_r[7] = 0x7B4B;
+_KOi1_r[0] = 0xC587; _KOi1_r[1] = 0x7818; _KOi1_r[2] = 0xBF96; _KOi1_r[3] = 0xE7A3;
_KOi1_r[4] = 0x14DD; _KOi1_r[5] = 0x8CDB; _KOi1_r[6] = 0x3E76; _KOi1_r[7] = 0x9C71;
+_KOi2_r[0] = 0xA6E8; _KOi2_r[1] = 0x66DC; _KOi2_r[2] = 0xF3B1; _KOi2_r[3] = 0xE38C;
_KOi2_r[4] = 0x2C3E; _KOi2_r[5] = 0xC0C3; _KOi2_r[6] = 0xFCB5; _KOi2_r[7] = 0x3D1F;
+_KOi3_r[0] = 0xDB8C; _KOi3_r[1] = 0x763E; _KOi3_r[2] = 0x719C; _KOi3_r[3] = 0x87C5;
_KOi3_r[4] = 0x1878; _KOi3_r[5] = 0x96BF; _KOi3_r[6] = 0xA3E7; _KOi3_r[7] = 0xDD14;
+_KIi1_r[0] = 0xE1E1; _KIi1_r[1] = 0x523E; _KIi1_r[2] = 0xAA32; _KIi1_r[3] = 0x83E3;
_KIi1_r[4] = 0x8DC0; _KIi1_r[5] = 0x7B4B; _KIi1_r[6] = 0x4A6B; _KIi1_r[7] = 0x7813;
+_KIi2_r[0] = 0x7813; _KIi2_r[1] = 0xE1E1; _KIi2_r[2] = 0x523E; _KIi2_r[3] = 0xAA32;
_KIi2_r[4] = 0x83E3; _KIi2_r[5] = 0x8DC0; _KIi2_r[6] = 0x7B4B; _KIi2_r[7] = 0x4A6B;
+_KIi3_r[0] = 0x83E3; _KIi3_r[1] = 0x8DC0; _KIi3_r[2] = 0x7B4B; _KIi3_r[3] = 0x4A6B;
_KIi3_r[4] = 0x7813; _KIi3_r[5] = 0xE1E1; _KIi3_r[6] = 0x523E; _KIi3_r[7] = 0xAA32;
+test_expansion(_test_key2, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3,
_KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r);
+
+if (0xDE551988CEB2F9B7 == _kasumi(0xD3C5D592327FB11C, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3,
_KIi1, _KIi2, _KIi3))
+ printf("OK."); else printf("FAILED!");
+
+printf("\nKASUMI Test Set 3...");
+
+uint8_t _test_key3[] = {0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1, 0xA8, 0xFF, 0x86,
0x67, 0xB1, 0x71, 0x40, 0x13};
+_KLi1_r[0] = 0x806A; _KLi1_r[1] = 0x8CD1; _KLi1_r[2] = 0x15F0; _KLi1_r[3] = 0x8DA3;
_KLi1_r[4] = 0x51FF; _KLi1_r[5] = 0x0CCF; _KLi1_r[6] = 0x62E3; _KLi1_r[7] = 0x8026;
+_KLi2_r[0] = 0x8353; _KLi2_r[1] = 0x0B3E; _KLi2_r[2] = 0x5623; _KLi2_r[3] = 0x3CFF;
_KLi2_r[4] = 0xC725; _KLi2_r[5] = 0x7203; _KLi2_r[6] = 0x4116; _KLi2_r[7] = 0x830F;
+_KOi1_r[0] = 0xCD18; _KOi1_r[1] = 0x5F01; _KOi1_r[2] = 0xDA38; _KOi1_r[3] = 0x1FF5;
_KOi1_r[4] = 0xCCF0; _KOi1_r[5] = 0x2E36; _KOi1_r[6] = 0x0268; _KOi1_r[7] = 0x06A8;
+_KOi2_r[0] = 0x6786; _KOi2_r[1] = 0x71B1; _KOi2_r[2] = 0x1340; _KOi2_r[3] = 0x3540;
_KOi2_r[4] = 0x68C6; _KOi2_r[5] = 0xF80A; _KOi2_r[6] = 0xD1C6; _KOi2_r[7] = 0xFFA8;
+_KOi3_r[0] = 0x362E; _KOi3_r[1] = 0x6802; _KOi3_r[2] = 0xA806; _KOi3_r[3] = 0x18CD;
_KOi3_r[4] = 0x015F; _KOi3_r[5] = 0x38DA; _KOi3_r[6] = 0xF51F; _KOi3_r[7] = 0xF0CC;
+_KIi1_r[0] = 0x5623; _KIi1_r[1] = 0x3CFF; _KIi1_r[2] = 0xC725; _KIi1_r[3] = 0x7203;
_KIi1_r[4] = 0x4116; _KIi1_r[5] = 0x830F; _KIi1_r[6] = 0x8353; _KIi1_r[7] = 0x0B3E;
+_KIi2_r[0] = 0x0B3E; _KIi2_r[1] = 0x5623; _KIi2_r[2] = 0x3CFF; _KIi2_r[3] = 0xC725;
_KIi2_r[4] = 0x7203; _KIi2_r[5] = 0x4116; _KIi2_r[6] = 0x830F; _KIi2_r[7] = 0x8353;
+_KIi3_r[0] = 0x7203; _KIi3_r[1] = 0x4116; _KIi3_r[2] = 0x830F; _KIi3_r[3] = 0x8353;
_KIi3_r[4] = 0x0B3E; _KIi3_r[5] = 0x5623; _KIi3_r[6] = 0x3CFF; _KIi3_r[7] = 0xC725;
+test_expansion(_test_key3, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3,
_KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r);
+
+if (0x4592B0E78690F71B == _kasumi(0x62A540981BA6F9B7, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3,
_KIi1, _KIi2, _KIi3))
+ printf("OK."); else printf("FAILED!");
+
+printf("\nKASUMI Test Set 4...");
+uint8_t _test_key4[] = {0x3A, 0x3B, 0x39, 0xB5, 0xC3, 0xF2, 0x37, 0x6D, 0x69, 0xF7, 0xD5,
0x46, 0xE5, 0xF8, 0x5D, 0x43};
+uint64_t I4 = 0xCA49C1C75771AB0B, i;
+_kasumi_key_expand(_test_key4, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3);
+
+for (i = 0; i < 50; i++)
+ I4 = _kasumi(I4, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3);
+
+if (0x738BAD4C4A690802 == I4) printf(" OK.\n"); else
printf("FAILED!");
+
+
+uint8_t gamma[32];
+
+uint8_t _Key1[] = {0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xBC, 0x00, 0x2B, 0xD6, 0x45,
0x9F, 0x82, 0xC5, 0xBC, 0x00},
+_gamma1[] = {0x88, 0x9E, 0xEA, 0xAF, 0x9E, 0xD1, 0xBA, 0x1A, 0xBB, 0xD8, 0x43, 0x62,
0x32, 0xE4, 0x57, 0x28, 0xD0, 0x1A, 0xA8, 0x91, 0x33, 0xDA, 0x73, 0xC1, 0x1E, 0xAB, 0x68,
0xB7, 0xD8, 0x9B, 0xC8, 0x41};
+_kasumi_kgcore(0xF, 0, 0x0024F20F, 0, _Key1, gamma, 228);
+printf ("KGCORE Test Set 1: %d\n", _compare_mem(gamma, _gamma1, 32));
+
+uint8_t _Key2[] = {0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48, 0x95, 0x2C, 0x49,
0x10, 0x48, 0x81, 0xFF, 0x48},
+_gamma2[] = {0xFB, 0x4D, 0x5F, 0xBC, 0xEE, 0x13, 0xA3, 0x33, 0x89, 0x28, 0x56, 0x86,
0xE9, 0xA5, 0xC9, 0x42, 0x40, 0xDE, 0x38, 0x15, 0x01, 0x15, 0xF1, 0x5F, 0x8D, 0x9D, 0x98,
0xB9, 0x1A, 0x94, 0xB2, 0x96};
+_kasumi_kgcore(0xF, 0, 0x00061272, 0, _Key2, gamma, 228);
+printf ("KGCORE Test Set 2: %d\n", _compare_mem(gamma, _gamma2, 32));
+
+uint8_t _Key3[] = {0xEF, 0xA8, 0xB2, 0x22, 0x9E, 0x72, 0x0C, 0x2A, 0xEF, 0xA8, 0xB2,
0x22, 0x9E, 0x72, 0x0C, 0x2A},
+_gamma3[] = {0x0E, 0x40, 0x15, 0x75, 0x5A, 0x33, 0x64, 0x69, 0xC3, 0xDD, 0x86, 0x80,
0xE3, 0x03, 0x5B, 0xC4, 0x19, 0xA7, 0x8A, 0xD3, 0x86, 0x2C, 0x10, 0x90, 0xC6, 0x8A, 0x39,
0x1F, 0xE8, 0xA6, 0xAD, 0xEB};
+_kasumi_kgcore(0xF, 0, 0x0033FD3F, 0, _Key3, gamma, 228);
+printf ("KGCORE Test Set 3: %d\n", _compare_mem(gamma, _gamma3, 32));
+
+uint8_t _Key4[] = {0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D, 0x51, 0x20, 0x4E, 0xA5, 0x5A,
0xCB, 0x1D, 0x64, 0x4C, 0x0D},
+_gamma4[] = {0xE0, 0x95, 0x30, 0x6A, 0xD5, 0x08, 0x6E, 0x2E, 0xAC, 0x7F, 0x31, 0x07,
0xDE, 0x4F, 0xA2, 0x2D, 0xC1, 0xDF, 0xC9, 0x7D, 0x5B, 0xC5, 0x66, 0x1D, 0xD6, 0x09, 0x6F,
0x47, 0x6A, 0xED, 0xC6, 0x4B};
+_kasumi_kgcore(0xF, 0, 0x00156B26, 0, _Key4, gamma, 228);
+printf ("KGCORE Test Set 4: %d\n", _compare_mem(gamma, _gamma4, 32));
+
+uint8_t _Key5[] = {0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, 0x40, 0x35, 0xC6,
0x68, 0x0A, 0xF8, 0xC6, 0xD1},
+_gamma5[] = {0xDC, 0xE6, 0x43, 0x62, 0xAB, 0x5F, 0x89, 0xC1, 0x1E, 0xF0, 0xB3, 0x05,
0x16, 0x65, 0x70, 0xF4, 0x88, 0x9D, 0x55, 0x11, 0xE9, 0xE3, 0x57, 0x5D, 0x06, 0x2B, 0x5C,
0xED, 0x60, 0x39, 0x50, 0x6A};
+_kasumi_kgcore(0xF, 0, 0x000A59B4, 0, _Key5, gamma, 228);
+printf ("KGCORE Test Set 5: %d\n", _compare_mem(gamma, _gamma5, 32));
+
+ return 0;
+}
diff --git a/tests/kasumi/kasumi_test.ok b/tests/kasumi/kasumi_test.ok
new file mode 100644
index 0000000..2c2af4c
--- /dev/null
+++ b/tests/kasumi/kasumi_test.ok
@@ -0,0 +1,10 @@
+testing KASUMI key expansion and encryption (ETSI TS 135 203):
+KASUMI Test Set 1... OK. OK.
+KASUMI Test Set 2... OK. OK.
+KASUMI Test Set 3... OK. OK.
+KASUMI Test Set 4... OK.
+KGCORE Test Set 1: 1
+KGCORE Test Set 2: 1
+KGCORE Test Set 3: 1
+KGCORE Test Set 4: 1
+KGCORE Test Set 5: 1
--
1.7.10.4
--------------060001040407040305040404
Content-Type: text/x-patch;
name="0003-Add-GEA3-and-GEA4-ciphers.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="0003-Add-GEA3-and-GEA4-ciphers.patch"
=46rom da6079e295966d9de1bba344f926c8c9eb2af33f Mon Sep 17 00:00:00 2001
From: Max <Max.Suraev(a)fairwaves.ru>
Date: Sun, 7 Apr 2013 14:56:02 +0200
Subject: [PATCH 3/5] Add GEA3 and GEA4 ciphers.
---
include/osmocom/crypt/gprs_cipher.h | 1 +
include/osmocom/gsm/gea.h | 28 +++++
src/gsm/gea.c | 45 +++++++
src/gsm/gprs_gea.c | 39 ++++++
tests/gea/gea_test | 228 +++++++++++++++++++++++++++++=
++++++
tests/gea/gea_test.c | 54 +++++++++
tests/gea/gea_test.ok | 11 ++
7 files changed, 406 insertions(+)
create mode 100644 include/osmocom/gsm/gea.h
create mode 100644 src/gsm/gea.c
create mode 100644 src/gsm/gprs_gea.c
create mode 100755 tests/gea/gea_test
create mode 100644 tests/gea/gea_test.c
create mode 100644 tests/gea/gea_test.ok
diff --git a/include/osmocom/crypt/gprs_cipher.h b/include/osmocom/crypt/=
gprs_cipher.h
index 3051071..f6ca01a 100644
--- a/include/osmocom/crypt/gprs_cipher.h
+++ b/include/osmocom/crypt/gprs_cipher.h
@@ -10,6 +10,7 @@ enum gprs_ciph_algo {
GPRS_ALGO_GEA1,
GPRS_ALGO_GEA2,
GPRS_ALGO_GEA3,
+ GPRS_ALGO_GEA4,
_GPRS_ALGO_NUM
};
=20
diff --git a/include/osmocom/gsm/gea.h b/include/osmocom/gsm/gea.h
new file mode 100644
index 0000000..9ea7231
--- /dev/null
+++ b/include/osmocom/gsm/gea.h
@@ -0,0 +1,28 @@
+/*
+ * GEA3 header
+ *
+ * See gea.c for details
+ */
+
+#ifndef __GEA_H__
+#define __GEA_H__
+
+#include <stdint.h>
+
+#include <osmocom/crypt/gprs_cipher.h>
+
+/*
+ * Performs the GEA3 algorithm (used in GPRS)
+ * out : uint8_t []
+ * len : uint16_t
+ * kc : uint64_t
+ * iv : uint32_t
+ * direct: 0 or 1
+ */
+
+int osmo_gea3(uint8_t *out, uint16_t len, uint64_t kc, uint32_t iv, enum=
gprs_cipher_direction direct);
+
+int osmo_gea4(uint8_t *out, uint16_t len, uint8_t * kc, uint32_t iv, enu=
m gprs_cipher_direction direct);
+
+#endif /* __GEA_H__ */
+
diff --git a/src/gsm/gea.c b/src/gsm/gea.c
new file mode 100644
index 0000000..ac879a8
--- /dev/null
+++ b/src/gsm/gea.c
@@ -0,0 +1,45 @@
+/*
+ * gea.c
+ *
+ * Full reimplementation of GEA3
+ *
+ * Copyright (C) 2013 Max <Max.Suraev(a)fairwaves.ru>
+ *
+ * All Rights Reserved
+ *
+ * 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 2 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 alo=
ng
+ * with this program; if not, write to the Free Software Foundation, Inc=
=2E,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <stdint.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/crypt/gprs_cipher.h>
+#include <osmocom/gsm/kasumi.h>
+
+
+int osmo_gea4(uint8_t *out, uint16_t len, uint8_t * kc, uint32_t iv, enu=
m gprs_cipher_direction direction) {
+ _kasumi_kgcore(0xFF, 0, iv, direction, kc, out, len * 8);
+
+ return 0;
+}
+
+int osmo_gea3(uint8_t *out, uint16_t len, uint64_t kc, uint32_t iv, enum=
gprs_cipher_direction direction) {
+ uint8_t ck[16];
+ osmo_64pack2pbit(kc, ck);
+ osmo_64pack2pbit(kc, ck + 8);
+
+// _kasumi_kgcore(0xFF, 0, iv, direction, ck, out, len * 8);
+
+ return osmo_gea4(out, len, ck, iv, direction);
+}
diff --git a/src/gsm/gprs_gea.c b/src/gsm/gprs_gea.c
new file mode 100644
index 0000000..3e0fddd
--- /dev/null
+++ b/src/gsm/gprs_gea.c
@@ -0,0 +1,39 @@
+/*
+ * gprs_gea.c
+ *
+ * GEA3 plugin
+ *
+ * Copyright (C) 2013 Max <Max.Suraev(a)fairwaves.ru>
+ *
+ * All Rights Reserved
+ *
+ * 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 2 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 alo=
ng
+ * with this program; if not, write to the Free Software Foundation, Inc=
=2E,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <stdint.h>
+
+#include <osmocom/crypt/gprs_cipher.h>
+#include <osmocom/gsm/gea.h>
+
+static struct gprs_cipher_impl gea3_impl =3D {
+ .algo =3D GPRS_ALGO_GEA3,
+ .name =3D "GEA3 (libosmogsm built-in)",
+ .priority =3D 1000,
+ .run =3D &osmo_gea3,
+};
+
+static void __attribute__((constructor)) osmo_crypt_a5_init(void)
+{
+ gprs_cipher_register(&gea3_impl);
+}
diff --git a/tests/gea/gea_test b/tests/gea/gea_test
new file mode 100755
index 0000000..aa1fb66
--- /dev/null
+++ b/tests/gea/gea_test
@@ -0,0 +1,228 @@
+#! /bin/bash
+
+# gea/gea_test - temporary wrapper script for .libs/gea_test
+# Generated by libtool (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu2
+#
+# The gea/gea_test program cannot be directly executed until all the lib=
tool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst=3D's/\([`"$\\]\)/\\\1/g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null
2>&1; then
+ emulate sh
+ NULLCMD=3D:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'=3D'"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=3Dxpg4; export BIN_SH # for Tru64
+DUALCASE=3D1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=3D"(cd /home/god/source/libosmocore/tests; { test -z \"\$=
{LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=3D; export L=
IBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_=
PATH || { COMPILER_PATH=3D; export COMPILER_PATH; }; }; { test -z \"\${GC=
C_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=3D; ex=
port GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD=
_RUN_PATH || { LD_RUN_PATH=3D; export LD_RUN_PATH; }; }; { test -z \"\${L=
D_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=3D; e=
xport LD_LIBRARY_PATH; }; }; PATH=3D/home/god/bin:/sbin:/usr/local/sbin:/=
usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games; =
export PATH; gcc -Wall -I../include -g -O2 -o \$progdir/\$file gea_test.o=
../src/.libs/libosmocore.so ../src/gsm/.libs/libosmogsm.so -Wl,-rpath -=
Wl,/home/god/source/libosmocore/src/.libs -Wl,-rpath -Wl,/home/god/source=
/libosmocore/src/gsm/.libs)"
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" =3D "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version=3D'2.4.2'
+ notinst_deplibs=3D' ../src/libosmocore.la ../src/gsm/libosmogsm.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set=
=2E
+ if test "$libtool_execute_magic" !=3D "%%%MAGIC variable%%%"; then
+ file=3D"$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO=3D"printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../libtool value, followed by no.
+lt_option_debug=3D
+func_parse_lt_options ()
+{
+ lt_script_arg0=3D$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=3D1 ;;
+ --lt-dump-script)
+ lt_dump_D=3D`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e
=
's%/[^/]*$%%'`
+ test "X$lt_dump_D" =3D "X$lt_script_arg0" &&
lt_dump_D=3D.
+ lt_dump_F=3D`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e
=
's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "gea_test:gea/gea_test:${LINENO}: libtool wrapper (GNU libtool)=
2.4.2 Debian-2.4.2-1ubuntu2" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=3D1;
+ for lt_arg
+ do
+ $ECHO "gea_test:gea/gea_test:${LINENO}: newargv[$lt_dump_args_N]: $l=
t_arg"
+ lt_dump_args_N=3D`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "gea_test:gea/gea_test:${LINENO}: newargv[0]: $progdir/$pr=
ogram" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=3D`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
+ test "x$thisdir" =3D "x$file" && thisdir=3D.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=3D`ls -ld "$file" | /bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=3D`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" !=3D "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir=3D"$destdir" ;;
+ *) thisdir=3D"$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=3D`$ECHO "$file" | /bin/sed 's%^.*/%%'`
+ file=3D`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=3Dno
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" =3D "yes"; then
+ # special case for '.'
+ if test "$thisdir" =3D "."; then
+ thisdir=3D`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=3D`$ECHO "$thisdir" | /bin/sed 's%[\\/][^\\/]*=
$%%'` ;;
+ .libs ) thisdir=3D. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=3D`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir=3D"$absdir"
+
+ program=3Dlt-'gea_test'
+ progdir=3D"$thisdir/.libs"
+
+ if test ! -f "$progdir/$program" ||
+ { file=3D`ls -1dt "$progdir/$program" "$progdir/../$program"
2>/dev=
/null | /bin/sed 1q`; \
+ test "X$file" !=3D "X$progdir/$program"; }; then
+
+ file=3D"$$-$program"
+
+ if test ! -d "$progdir"; then
+ mkdir "$progdir"
+ else
+ rm -f "$progdir/$file"
+ fi
+
+ # relink executable if necessary
+ if test -n "$relink_command"; then
+ if relink_command_output=3D`eval $relink_command 2>&1`; then :
+ else
+ printf %s\n "$relink_command_output" >&2
+ rm -f "$progdir/$file"
+ exit 1
+ fi
+ fi
+
+ mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null ||
+ { rm -f "$progdir/$program";
+ mv -f "$progdir/$file" "$progdir/$program"; }
+ rm -f "$progdir/$file"
+ fi
+
+ if test -f "$progdir/$program"; then
+ if test "$libtool_execute_magic" !=3D "%%%MAGIC variable%%%";
then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/tests/gea/gea_test.c b/tests/gea/gea_test.c
new file mode 100644
index 0000000..70a4d2a
--- /dev/null
+++ b/tests/gea/gea_test.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/crypt/gprs_cipher.h>
+#include <osmocom/gsm/gea.h>
+
+void print_check(char * res, uint8_t * out, uint16_t len) {
+ uint8_t buf[len];
+ osmo_hexparse(res, buf, len);
+ if (0 !=3D memcmp(buf, out, len)) {
+ printf("FAIL:\n");
+ printf("OUT: %s\n", osmo_hexdump_nospc(out, len));
+ printf("EXP: %s\n", osmo_hexdump_nospc(buf, len));
+ }
+ else printf("OK\n");
+}
+
+void test_gea3(uint64_t kc, uint32_t iv, int dir, uint16_t len, char * r=
es) {
+ printf("%d: %d -> 0x%X ", len, dir, iv);
+ uint8_t out[len];
+ osmo_gea3(out, len, kc, iv, dir);
+ print_check(res, out, len);
+}
+
+void test_gea4(char * kc, uint32_t iv, int dir, uint16_t len, char * res=
) {
+ printf("%d: %d -> 0x%X ", len, dir, iv);
+ uint8_t out[len], ck[256];
+ osmo_hexparse(kc, ck, len);
+ osmo_gea4(out, len, ck, iv, dir);
+ print_check(res, out, len);
+}
+
+int main(int argc, char **argv)
+{
+ printf("GEA3 support: %d\n", gprs_cipher_supported(GPRS_ALGO_GEA3));=
+ printf("GEA4 support: %d\n", gprs_cipher_supported(GPRS_ALGO_GEA4));=
+// test vectors according to 3GPP TS 55.217 and TS 55.218
+test_gea3(0x2BD6459F82C5BC00, 0x8E9421A3, 0, 59, "5F359709DE950D0105B17B=
6C90194280F880B48DCCDC2AFEED415DBEF4354EEBB21D073CCBBFB2D706BD7AFFD371FC9=
6E3970D143DCB2624054826");
+test_gea3(0x952C49104881FF48, 0x5064DB71, 0, 59, "FDC03D738C8E14FF0320E5=
9AAF75760799E9DA78DD8F888471C4AEAAC1849633A26CD84F459D265B83D7D9B9A0B1E54=
F4D75E331640DF19E0DB0E0");
+test_gea3(0xEFA8B2229E720C2A, 0x4BDBD5E5, 1, 59, "4718A2ADFC90590949DDAD=
AB406EC3B925F1AF1214673909DAAB96BB4C18B1374BB1E99445A81CC856E47C6E49E9DBB=
9873D0831B2175CA1E109BA");
+test_gea3(0x3451F23A43BD2C87, 0x893FE14F, 0, 59, "B46B1E284E3F8B63B86D9D=
F0915CFCEDDF2F061895BF9F82BF2593AE4847E94A4626C393CF8941CE15EA7812690D841=
5B88C5730FE1F5D410E16A2");
+test_gea3(0xCAA2639BE82435CF, 0x8FE17885, 1, 59, "9FEFAF155A26CF35603E72=
7CDAA87BA067FD84FF98A50B7FF0EC8E95A0FB70E79CB93DEE2B7E9AB59D050E126240157=
1F349C68229DDF0DECC4E85");
+test_gea3(0x1ACA8B448B767B39, 0x4F7BC3B5, 0, 59, "514F6C3A3B5A55CA190092=
F7BB6E80EF3EDB738FCDCE2FF90BB387DDE75BBC32A04A67B898A3DFB8198FFFC37D437CF=
69E7F9C13B51A868720E750");
+test_gea4("D3C5D592327FB11C4035C6680AF8C6D1", 0x0A3A59B4, 0, 51, "6E217C=
E41EBEFB5EC8094C15974290065E42BABC9AE35654A53085CE68DFA4426A2FF0AD4AF3341=
006A3F84B7613ACB4FBDC34");
+test_gea4("3D43C388C9581E337FF1F97EB5C1F85E", 0x48571AB9, 0, 59, "FC7314=
EF00A63ED0116F236C5D25C54EEC56A5B71F9F18B4D7941F84E422ACBDE5EEA9A20467900=
2D14F312F3DEE2A1AC917C3FBDC3696143C0F5D");
+test_gea4("A4496A64DF4F399F3B4506814A3E07A1", 0xEB04ADE2, 1, 59, "2AEB59=
70FB06B718027D048488AAF24FB3B74EA4A6B1242FF85B108FF816A303C72757D9AAD862B=
835D1D287DBC141D0A28D79D87BB137CD1198CD");
+
+ return 0;
+}
diff --git a/tests/gea/gea_test.ok b/tests/gea/gea_test.ok
new file mode 100644
index 0000000..15abd38
--- /dev/null
+++ b/tests/gea/gea_test.ok
@@ -0,0 +1,11 @@
+GEA3 support: 0
+GEA4 support: 0
+59: 0 -> 0x8E9421A3 OK
+59: 0 -> 0x5064DB71 OK
+59: 1 -> 0x4BDBD5E5 OK
+59: 0 -> 0x893FE14F OK
+59: 1 -> 0x8FE17885 OK
+59: 0 -> 0x4F7BC3B5 OK
+51: 0 -> 0xA3A59B4 OK
+59: 0 -> 0x48571AB9 OK
+59: 1 -> 0xEB04ADE2 OK
--=20
1.7.10.4
--------------060001040407040305040404
Content-Type: text/x-patch;
name="0004-Add-A5-3-and-A5-4-ciphers.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="0004-Add-A5-3-and-A5-4-ciphers.patch"