[PATCH 2/5] Add KASUMI implementation.

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/baseband-devel@lists.osmocom.org/.

Max Max.Suraev at fairwaves.ru
Sun Apr 7 12:54:41 UTC 2013


---
 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 at 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 at 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 at 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 at 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"



More information about the baseband-devel mailing list