diff --git a/.gitignore b/.gitignore
index 3fa1bbc..1299028 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,7 @@ tests/testsuite.dir/
 tests/testsuite.log
 
 tests/utils/utils_test
+tests/kasumi/kasumi_test
 tests/sms/sms_test
 tests/timer/timer_test
 tests/msgfile/msgfile_test
diff --git a/include/osmocom/gsm/kasumi.h b/include/osmocom/gsm/kasumi.h
new file mode 100644
index 0000000..48573b7
--- /dev/null
+++ b/include/osmocom/gsm/kasumi.h
@@ -0,0 +1,34 @@
+/*
+ * KASUMI header
+ *
+ * See kasumi.c for details
+ * The parameters are described in TS 135 202.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*
+ * Single iteration of KASUMI cipher
+*/
+uint64_t _kasumi(uint64_t P, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const 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);
diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am
index 3162a7f..8ccbaec 100644
--- a/src/gsm/Makefile.am
+++ b/src/gsm/Makefile.am
@@ -15,7 +15,7 @@ libosmogsm_la_SOURCES = a5.c rxlev_stat.c tlv_parser.c comp128.c comp128v23.c \
 			gsm_utils.c rsl.c gsm48.c gsm48_ie.c gsm0808.c sysinfo.c \
 			gprs_cipher_core.c gsm0480.c abis_nm.c gsm0502.c \
 			gsm0411_utils.c gsm0411_smc.c gsm0411_smr.c \
-			lapd_core.c lapdm.c \
+			lapd_core.c lapdm.c kasumi.c \
 			auth_core.c auth_comp128v1.c auth_comp128v23.c \
 			auth_milenage.c milenage/aes-encblock.c \
 			milenage/aes-internal.c milenage/aes-internal-enc.c \
diff --git a/src/gsm/kasumi.c b/src/gsm/kasumi.c
new file mode 100644
index 0000000..33e5c78
--- /dev/null
+++ b/src/gsm/kasumi.c
@@ -0,0 +1,190 @@
+/* Kasumi cipher and KGcore functions */
+
+/* (C) 2013 by Max <Max.Suraev@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>
+
+/* See TS 135 202 for constants and full Kasumi spec. */
+inline static uint16_t kasumi_FI(uint16_t I, uint16_t skey)
+{
+	static const 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 const 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;
+}
+
+inline static uint32_t kasumi_FO(uint32_t I, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const 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;
+}
+
+inline static uint32_t kasumi_FL(uint32_t I, const uint16_t *KLi1, const 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, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const 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 };
+
+	/* Work with 16 bit subkeys and create prime subkeys */
+	for (i = 0; i < 8; i++)
+		C[i] ^= osmo_load16be(key + i * 2);
+	/* C[] now stores K-prime[] */
+
+	/* Create round-specific subkeys */
+	for (i = 0; i < 8; i++) {
+		KLi1[i] = rol16(osmo_load16be(key + i * 2), 1);
+		KLi2[i] = C[(i + 2) & 0x7];
+
+		KOi1[i] = rol16(osmo_load16be(key + ((2 * (i + 1)) & 0xE)), 5);
+		KOi2[i] = rol16(osmo_load16be(key + ((2 * (i + 5)) & 0xE)), 8);
+		KOi3[i] = rol16(osmo_load16be(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);
+
+	/* i is a block counter */
+	for (i = 0; i < cl / 64 + 1; i++) {
+		BLK = _kasumi(A ^ i ^ BLK, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
+		osmo_store64be(BLK, co + (i * 8));
+	}
+}
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 9d15d66..3a4a643 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -196,6 +196,10 @@ osmo_a5;
 osmo_a5_1;
 osmo_a5_2;
 
+_kasumi;
+_kasumi_key_expand;
+_kasumi_kgcore;
+
 osmo_auth_alg_name;
 osmo_auth_alg_parse;
 osmo_auth_gen_vec;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c6216d5..ddc13dc 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,7 +4,7 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test		\
                  smscb/smscb_test bits/bitrev_test a5/a5_test		\
                  conv/conv_test auth/milenage_test lapd/lapd_test	\
                  gsm0808/gsm0808_test gsm0408/gsm0408_test		\
-		 gb/bssgp_fc_test gb/gprs_ns_test                       \
+		 gb/bssgp_fc_test gb/gprs_ns_test kasumi/kasumi_test    \
 		 logging/logging_test fr/fr_test	                \
 		 loggingrb/loggingrb_test strrb/strrb_test              \
 		 vty/vty_test comp128/comp128_test utils/utils_test
@@ -19,6 +19,9 @@ utils_utils_test_LDADD = $(top_builddir)/src/libosmocore.la
 a5_a5_test_SOURCES = a5/a5_test.c
 a5_a5_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
 
+kasumi_kasumi_test_SOURCES = kasumi/kasumi_test.c
+kasumi_kasumi_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
+
 comp128_comp128_test_SOURCES = comp128/comp128_test.c
 comp128_comp128_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
 
@@ -102,7 +105,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE)		\
              lapd/lapd_test.ok gsm0408/gsm0408_test.ok			\
              gsm0808/gsm0808_test.ok gb/bssgp_fc_tests.err		\
              gb/bssgp_fc_tests.ok gb/bssgp_fc_tests.sh			\
-             gb/gprs_ns_test.ok						\
+             gb/gprs_ns_test.ok kasumi/kasumi_test.ok			\
              msgfile/msgfile_test.ok msgfile/msgconfig.cfg		\
              logging/logging_test.ok logging/logging_test.err		\
              fr/fr_test.ok loggingrb/logging_test.ok			\
diff --git a/tests/kasumi/kasumi_test.c b/tests/kasumi/kasumi_test.c
new file mode 100644
index 0000000..9101407
--- /dev/null
+++ b/tests/kasumi/kasumi_test.c
@@ -0,0 +1,136 @@
+#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>
+
+/* Test vectors are taken from TS 135 202 */
+
+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);
+	printf(passed ? " OK. " : "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
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 9124f25..7ce2ee8 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -9,6 +9,12 @@ cat $abs_srcdir/a5/a5_test.ok > expout
 AT_CHECK([$abs_top_builddir/tests/a5/a5_test], [0], [expout])
 AT_CLEANUP
 
+AT_SETUP([kasumi])
+AT_KEYWORDS([kasumi])
+cat $abs_srcdir/kasumi/kasumi_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/kasumi/kasumi_test], [0], [expout])
+AT_CLEANUP
+
 AT_SETUP([bits])
 AT_KEYWORDS([bits])
 cat $abs_srcdir/bits/bitrev_test.ok > expout
