--- .gitignore | 3 +- include/Makefile.am | 7 ++ include/osmocom/core/bitXXgen.h.tpl | 101 +++++++++++++++++ include/osmocom/core/bits.h | 5 + include/osmocom/core/msgb.h | 23 ++-- tests/bits/bitrev_test.c | 218 +++++++++++++++++++++++++++++++++++- tests/bits/bitrev_test.ok | 31 +++++ 7 files changed, 376 insertions(+), 12 deletions(-) create mode 100644 include/osmocom/core/bitXXgen.h.tpl
diff --git a/.gitignore b/.gitignore index 71b27f2..3fa1bbc 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ tests/testsuite tests/testsuite.dir/ tests/testsuite.log
+tests/utils/utils_test tests/sms/sms_test tests/timer/timer_test tests/msgfile/msgfile_test @@ -89,7 +90,7 @@ doc/html.tar
src/crc*gen.c include/osmocom/core/crc*gen.h - +include/osmocom/core/bit*gen.h
# vi files *.sw? diff --git a/include/Makefile.am b/include/Makefile.am index b035906..48ca7ea 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,9 @@ nobase_include_HEADERS = \ osmocom/codec/codec.h \ osmocom/core/application.h \ osmocom/core/backtrace.h \ + osmocom/core/bit16gen.h \ + osmocom/core/bit32gen.h \ + osmocom/core/bit64gen.h \ osmocom/core/bits.h \ osmocom/core/bitvec.h \ osmocom/core/conv.h \ @@ -107,6 +110,10 @@ endif
noinst_HEADERS = osmocom/core/timer_compat.h
+osmocom/core/bit%gen.h: osmocom/core/bitXXgen.h.tpl + $(AM_V_GEN)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)sed -e's/XX/$*/g' $< > $@ + osmocom/core/crc%gen.h: osmocom/core/crcXXgen.h.tpl $(AM_V_GEN)$(MKDIR_P) $(dir $@) $(AM_V_GEN)sed -e's/XX/$*/g' $< > $@ diff --git a/include/osmocom/core/bitXXgen.h.tpl b/include/osmocom/core/bitXXgen.h.tpl new file mode 100644 index 0000000..69ab492 --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,101 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max max.suraev@fairwaves.co + * + * 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. + */ + +/*! \brief load unaligned n-byte integer (little-endian encoding) into uintXX_t + * \param[in] p Buffer where integer is stored + * \param[in] n Number of bytes stored in p + * \returns XX bit unsigned integer + */ +static inline uintXX_t osmo_loadXXle_ext(const void *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + const uint8_t *q = (uint8_t *)p; + for(i = 0; i < n; r |= ((uintXX_t)q[i] << (8 * i)), i++); + return r; +} + +/*! \brief load unaligned n-byte integer (big-endian encoding) into uintXX_t + * \param[in] p Buffer where integer is stored + * \param[in] n Number of bytes stored in p + * \returns XX bit unsigned integer + */ +static inline uintXX_t osmo_loadXXbe_ext(const void *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + const uint8_t *q = (uint8_t *)p; + for(i = 0; i < n; r |= ((uintXX_t)q[i] << (XX - 8* (1 + i))), i++); + return r; +} + + +/*! \brief store unaligned n-byte integer (little-endian encoding) into uintXX_t + * \param[in] x unsigned XX bit integer + * \param[out] p Buffer to store integer + * \param[in] n Number of bytes to store + */ +static inline void osmo_storeXXle_ext(uintXX_t x, uint8_t *p, uint8_t n) +{ + uint8_t i; + for(i = 0; i < n; p[i] = (x >> i * 8) & 0xFF, i++); +} + +/*! \brief store unaligned n-byte integer (big-endian encoding) into uintXX_t + * \param[in] x unsigned XX bit integer + * \param[out] p Buffer to store integer + * \param[in] n Number of bytes to store + */ +static inline void osmo_storeXXbe_ext(uintXX_t x, uint8_t *p, uint8_t n) +{ + uint8_t i; + for(i = 0; i < n; p[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++); +} + + +/* Convenience function for most-used cases */ + + +/*! \brief load unaligned XX-bit integer (little-endian encoding) */ +static inline uintXX_t osmo_loadXXle(const void *p) +{ + return osmo_loadXXle_ext(p, XX / 8); +} + +/*! \brief load unaligned XX-bit integer (big-endian encoding) */ +static inline uintXX_t osmo_loadXXbe(const void *p) +{ + return osmo_loadXXbe_ext(p, XX / 8); +} + + +/*! \brief store unaligned XX-bit integer (little-endian encoding) */ +static inline void osmo_storeXXle(uintXX_t x, void *p) +{ + return osmo_storeXXle_ext(x, p, XX / 8); +} + +/*! \brief store unaligned XX-bit integer (big-endian encoding) */ +static inline void osmo_storeXXbe(uintXX_t x, void *p) +{ + return osmo_storeXXbe_ext(x, p, XX / 8); +} diff --git a/include/osmocom/core/bits.h b/include/osmocom/core/bits.h index 4c68532..5c9c7a6 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,6 +2,11 @@ #define _OSMO_BITS_H
#include <stdint.h> +#include <stddef.h> + +#include <osmocom/core/bit16gen.h> +#include <osmocom/core/bit32gen.h> +#include <osmocom/core/bit64gen.h>
/*! \defgroup bits soft, unpacked and packed bits * @{ diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 33e8081..44a4c1e 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -23,6 +23,7 @@ #include <stdint.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/utils.h> +#include <osmocom/core/bits.h>
/*! \defgroup msgb Message buffers * @{ @@ -205,8 +206,7 @@ static inline void msgb_put_u8(struct msgb *msgb, uint8_t word) static inline void msgb_put_u16(struct msgb *msgb, uint16_t word) { uint8_t *space = msgb_put(msgb, 2); - space[0] = word >> 8 & 0xFF; - space[1] = word & 0xFF; + osmo_store16be(word, space); }
/*! \brief append a uint32 value to the end of the message @@ -216,10 +216,7 @@ static inline void msgb_put_u16(struct msgb *msgb, uint16_t word) static inline void msgb_put_u32(struct msgb *msgb, uint32_t word) { uint8_t *space = msgb_put(msgb, 4); - space[0] = word >> 24 & 0xFF; - space[1] = word >> 16 & 0xFF; - space[2] = word >> 8 & 0xFF; - space[3] = word & 0xFF; + osmo_store32be(word, space); }
/*! \brief remove data from end of message @@ -236,6 +233,7 @@ static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) msgb->len -= len; return tmp; } + /*! \brief remove uint8 from end of message * \param[in] msgb message buffer * \returns 8bit value taken from end of msgb @@ -245,6 +243,7 @@ static inline uint8_t msgb_get_u8(struct msgb *msgb) uint8_t *space = msgb_get(msgb, 1); return space[0]; } + /*! \brief remove uint16 from end of message * \param[in] msgb message buffer * \returns 16bit value taken from end of msgb @@ -252,8 +251,9 @@ static inline uint8_t msgb_get_u8(struct msgb *msgb) static inline uint16_t msgb_get_u16(struct msgb *msgb) { uint8_t *space = msgb_get(msgb, 2); - return space[0] << 8 | space[1]; + return osmo_load16be(space); } + /*! \brief remove uint32 from end of message * \param[in] msgb message buffer * \returns 32bit value taken from end of msgb @@ -261,7 +261,7 @@ static inline uint16_t msgb_get_u16(struct msgb *msgb) static inline uint32_t msgb_get_u32(struct msgb *msgb) { uint8_t *space = msgb_get(msgb, 4); - return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3]; + return osmo_load32be(space); }
/*! \brief prepend (push) some data to start of message @@ -285,6 +285,7 @@ static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) msgb->len += len; return msgb->data; } + /*! \brief remove (pull) a header from the front of the message buffer * \param[in] msgb message buffer * \param[in] len number of octets to be pulled @@ -324,6 +325,7 @@ static inline uint8_t msgb_pull_u8(struct msgb *msgb) uint8_t *space = msgb_pull(msgb, 1) - 1; return space[0]; } + /*! \brief remove uint16 from front of message * \param[in] msgb message buffer * \returns 16bit value taken from end of msgb @@ -331,8 +333,9 @@ static inline uint8_t msgb_pull_u8(struct msgb *msgb) static inline uint16_t msgb_pull_u16(struct msgb *msgb) { uint8_t *space = msgb_pull(msgb, 2) - 2; - return space[0] << 8 | space[1]; + return osmo_load16be(space); } + /*! \brief remove uint32 from front of message * \param[in] msgb message buffer * \returns 32bit value taken from end of msgb @@ -340,7 +343,7 @@ static inline uint16_t msgb_pull_u16(struct msgb *msgb) static inline uint32_t msgb_pull_u32(struct msgb *msgb) { uint8_t *space = msgb_pull(msgb, 4) - 4; - return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3]; + return osmo_load32be(space); }
/*! \brief Increase headroom of empty msgb, reducing the tailroom diff --git a/tests/bits/bitrev_test.c b/tests/bits/bitrev_test.c index 5eca990..e963656 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,20 +1,192 @@ - +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> +#include <time.h> +#include <stdbool.h>
#include <osmocom/core/utils.h> #include <osmocom/core/bits.h>
static const uint8_t input[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; static const uint8_t exp_out[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; +static char s[18]; + +enum END {LE, BE}; + +const char * end2str(enum END e) { + if (e == LE) return "LE"; + return "BE"; +} + + +/* convenience wrappers */ + +inline uint64_t load64(enum END e, const uint8_t *buf, unsigned nbytes) { + return (e == BE) ? osmo_load64be_ext(buf, nbytes) : osmo_load64le_ext(buf, nbytes); +} + +inline uint32_t load32(enum END e, const uint8_t *buf, unsigned nbytes) { + return (e == BE) ? osmo_load32be_ext(buf, nbytes) : osmo_load32le_ext(buf, nbytes); +} + +inline uint16_t load16(enum END e, const uint8_t *buf) { + return (e == BE) ? osmo_load16be(buf) : osmo_load16le(buf); +} + +inline void store64(enum END e, uint64_t t, uint8_t *buf, unsigned nbytes) { + (e == BE) ? osmo_store64be_ext(t, buf, nbytes) : osmo_store64le_ext(t, buf, nbytes); +} + +inline void store32(enum END e, uint64_t t, uint8_t *buf, unsigned nbytes) { + (e == BE) ? osmo_store32be_ext(t, buf, nbytes) : osmo_store32le_ext(t, buf, nbytes); +} + +inline void store16(enum END e, uint64_t t, uint8_t *buf) { + (e == BE) ? osmo_store16be(t, buf) : osmo_store16le(t, buf); +} + + +/* helper functions */ + +inline bool printcheck(bool chk, unsigned nbytes, enum END e, bool b) +{ + if (!chk) { + printf("%u %s FAILED", nbytes * 8, end2str(e)); + return true; + } + printf("%u %s OK", nbytes * 8, end2str(e)); + return b; +} + +inline bool dumpcheck(const char *dump, const char *s, unsigned nbytes, bool chk, enum END e, bool b) +{ + bool x = printcheck(chk, nbytes, e, b); + if (!dump) return x; + + int m = memcmp(s, dump, nbytes); + if (0 == m) { + printf(", storage OK"); + return x; + } + printf(", [%d]", m); + + return true; +} + + +/* printcheckXX(): load/store 'test' and check against 'expected' value, compare to 'dump' buffer if given and print if necessary */ + +inline void printcheck64(enum END e, unsigned nbytes, uint64_t test, uint64_t expected, const char *dump, bool print) +{ + uint8_t buf[nbytes]; + + store64(e, test, buf, nbytes); + + char *s = osmo_hexdump_nospc(buf, nbytes); + uint64_t result = load64(e, buf, nbytes); + + print = dumpcheck(dump, s, nbytes, result == expected, e, print); + + if (print) + printf(": buffer %s known buffer %s loaded %.16" PRIx64 " expected %.16" PRIx64, s, dump, result, expected); + printf("\n"); +} + +inline void printcheck32(enum END e, unsigned nbytes, uint32_t test, uint32_t expected, const char *dump, bool print) +{ + uint8_t buf[nbytes]; + + store32(e, test, buf, nbytes); + + char *s = osmo_hexdump_nospc(buf, nbytes); + uint32_t result = load32(e, buf, nbytes); + + print = dumpcheck(dump, s, nbytes, result == expected, e, print); + + if (print) + printf(": buffer %s known buffer %s loaded %.8" PRIx32 " expected %.8" PRIx32, s, dump, result, expected); + printf("\n"); +} + +inline void printcheck16(enum END e, uint32_t test, uint32_t expected, const char *dump, bool print) +{ + uint8_t buf[2]; + + store16(e, test, buf); + + char *s = osmo_hexdump_nospc(buf, 2); + uint16_t result = load16(e, buf); + + print = dumpcheck(dump, s, 2, result == expected, e, print); + + if (print) + printf(": buffer %s known buffer %s loaded %.4" PRIx16 " expected %.4" PRIx16, s, dump, result, expected); + printf("\n"); +} + + +/* compute expected value - zero excessive bytes */ + +inline uint64_t exp64(enum END e, unsigned nbytes, uint64_t value) { + uint8_t adj = 64 - nbytes * 8; + uint64_t v = value << adj; + return (e == LE) ? v >> adj : v; +} + +inline uint32_t exp32(enum END e, unsigned nbytes, uint32_t value) { + uint8_t adj = 32 - nbytes * 8; + uint32_t v = value << adj; + return (e == LE) ? v >> adj : v; +} + + +/* run actual tests - if 'test' is 0 than generate random test value internally */ + +inline void check64(uint64_t test, uint64_t expected, unsigned nbytes, enum END e) +{ + bool print = true; + if (0 == test && 0 == expected) { + test = ((uint64_t)rand() << 32) + rand(); + expected = exp64(e, nbytes, test); + print = false; + } + snprintf(s, 17, "%.16" PRIx64, expected); + printcheck64(e, nbytes, test, expected, (BE == e) ? s : NULL, print); +} + +inline void check32(uint32_t test, uint32_t expected, unsigned nbytes, enum END e) +{ + bool print = true; + if (0 == test && 0 == expected) { + test = rand(); + expected = exp32(e, nbytes, test); + print = false; + } + snprintf(s, 17, "%.8" PRIx32, expected); + printcheck32(e, nbytes, test, expected, (BE == e) ? s : NULL, print); +} + +inline void check16(uint16_t test, enum END e) +{ + bool print = true; + if (0 == test) { + test = (uint16_t)rand(); + print = false; + } + snprintf(s, 17, "%.4" PRIx16, test); + printcheck16(e, test, test, (BE == e) ? s : NULL, print); +} +
int main(int argc, char **argv) { uint8_t out[ARRAY_SIZE(input)]; unsigned int offs;
+ srand(time(NULL)); + for (offs = 0; offs < sizeof(out); offs++) { uint8_t *start = out + offs; uint8_t len = sizeof(out) - offs; @@ -32,5 +204,49 @@ int main(int argc, char **argv) printf("\n"); }
+ printf("checking byte packing...\n"); + + printf("running static tests...\n"); + + check64(0xDEADBEEFF00DCAFE, 0xDEADBEEFF00DCAFE, 8, BE); + check64(0xDEADBEEFF00DCAFE, 0xADBEEFF00DCAFE00, 7, BE); + check64(0xDEADBEEFF00DCAFE, 0xBEEFF00DCAFE0000, 6, BE); + check64(0xDEADBEEFF00DCAFE, 0xEFF00DCAFE000000, 5, BE); + + check64(0xDEADBEEFF00DCAFE, 0xDEADBEEFF00DCAFE, 8, LE); + check64(0xDEADBEEFF00DCAFE, 0x00ADBEEFF00DCAFE, 7, LE); + check64(0xDEADBEEFF00DCAFE, 0x0000BEEFF00DCAFE, 6, LE); + check64(0xDEADBEEFF00DCAFE, 0x000000EFF00DCAFE, 5, LE); + + check32(0xBABEFACE, 0xBABEFACE, 4, BE); + check32(0xBABEFACE, 0xBEFACE00, 3, BE); + + check32(0xBABEFACE, 0xBABEFACE, 4, LE); + check32(0xBABEFACE, 0x00BEFACE, 3, LE); + + check16(0xB00B, BE); + check16(0xB00B, LE); + + printf("running random tests...\n"); + + check64(0, 0, 8, BE); + check64(0, 0, 7, BE); + check64(0, 0, 6, BE); + check64(0, 0, 5, BE); + + check64(0, 0, 8, LE); + check64(0, 0, 7, LE); + check64(0, 0, 6, LE); + check64(0, 0, 5, LE); + + check32(0, 0, 4, BE); + check32(0, 0, 3, BE); + + check32(0, 0, 4, LE); + check32(0, 0, 3, LE); + + check16(0, BE); + check16(0, LE); + return 0; } diff --git a/tests/bits/bitrev_test.ok b/tests/bits/bitrev_test.ok index 47f402f..90cb295 100644 --- a/tests/bits/bitrev_test.ok +++ b/tests/bits/bitrev_test.ok @@ -22,3 +22,34 @@ REVERSED: 02 01 INORDER: 80 REVERSED: 01
+checking byte packing... +running static tests... +64 BE OK, storage OK: buffer deadbeeff00dcafe known buffer deadbeeff00dcafe loaded deadbeeff00dcafe expected deadbeeff00dcafe +56 BE OK, storage OK: buffer adbeeff00dcafe known buffer adbeeff00dcafe00 loaded adbeeff00dcafe00 expected adbeeff00dcafe00 +48 BE OK, storage OK: buffer beeff00dcafe known buffer beeff00dcafe0000 loaded beeff00dcafe0000 expected beeff00dcafe0000 +40 BE OK, storage OK: buffer eff00dcafe known buffer eff00dcafe000000 loaded eff00dcafe000000 expected eff00dcafe000000 +64 LE OK: buffer feca0df0efbeadde known buffer (null) loaded deadbeeff00dcafe expected deadbeeff00dcafe +56 LE OK: buffer feca0df0efbead known buffer (null) loaded 00adbeeff00dcafe expected 00adbeeff00dcafe +48 LE OK: buffer feca0df0efbe known buffer (null) loaded 0000beeff00dcafe expected 0000beeff00dcafe +40 LE OK: buffer feca0df0ef known buffer (null) loaded 000000eff00dcafe expected 000000eff00dcafe +32 BE OK, storage OK: buffer babeface known buffer babeface loaded babeface expected babeface +24 BE OK, storage OK: buffer beface known buffer beface00 loaded beface00 expected beface00 +32 LE OK: buffer cefabeba known buffer (null) loaded babeface expected babeface +24 LE OK: buffer cefabe known buffer (null) loaded 00beface expected 00beface +16 BE OK, storage OK: buffer b00b known buffer b00b loaded b00b expected b00b +16 LE OK: buffer 0bb0 known buffer (null) loaded b00b expected b00b +running random tests... +64 BE OK, storage OK +56 BE OK, storage OK +48 BE OK, storage OK +40 BE OK, storage OK +64 LE OK +56 LE OK +48 LE OK +40 LE OK +32 BE OK, storage OK +24 BE OK, storage OK +32 LE OK +24 LE OK +16 BE OK, storage OK +16 LE OK
--- include/osmocom/core/bits.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/include/osmocom/core/bits.h b/include/osmocom/core/bits.h index 5c9c7a6..c2c4863 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -78,6 +78,16 @@ uint32_t osmo_revbytebits_8(uint8_t x); /* \brief reverse the bits of each byte in a given buffer */ void osmo_revbytebits_buf(uint8_t *buf, int len);
+/*! \brief left circular shift + * \param[in] in The 16 bit unsigned integer to be rotated + * \param[in] shift Number of bits to shift \a in to, [0;16] bits + * \returns shifted value + */ +static inline uint16_t osmo_rol16(uint16_t in, unsigned shift) +{ + return (in << shift) | (in >> (16 - shift)); +} + /*! @} */
#endif /* _OSMO_BITS_H */
--- .gitignore | 1 + include/osmocom/gsm/kasumi.h | 41 ++++++++++ src/gsm/Makefile.am | 2 +- src/gsm/kasumi.c | 190 +++++++++++++++++++++++++++++++++++++++++++ src/gsm/libosmogsm.map | 4 + tests/Makefile.am | 7 +- tests/kasumi/kasumi_test.c | 136 +++++++++++++++++++++++++++++++ tests/kasumi/kasumi_test.ok | 10 +++ tests/testsuite.at | 6 ++ 9 files changed, 394 insertions(+), 3 deletions(-) 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/.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..6acc959 --- /dev/null +++ b/include/osmocom/gsm/kasumi.h @@ -0,0 +1,41 @@ +/* + * KASUMI header + * + * See kasumi.c for details + * The parameters are described in TS 135 202. + */ + +#pragma once + +#include <stdint.h> + +/*! \brief Single iteration of KASUMI cipher + * \param[in] P Block, 64 bits to be processed in this round + * \param[in] KLi1 Expanded subkeys + * \param[in] KLi2 Expanded subkeys + * \param[in] KOi1 Expanded subkeys + * \param[in] KOi2 Expanded subkeys + * \param[in] KOi3 Expanded subkeys + * \param[in] KIi1 Expanded subkeys + * \param[in] KIi2 Expanded subkeys + * \param[in] KIi3 Expanded subkeys + * \returns processed block of 64 bits + */ +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); + +/*! \brief Implementation of the KGCORE algorithm (used by A5/3, A5/4, GEA3, GEA4 and ECSD) + * \param[in] CA + * \param[in] cb + * \param[in] cc + * \param[in] cd + * \param[in] ck 8-bytes long key + * \param[out] co cl-dependent + * \param[in] cl + */ +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 46698cd..94729c9 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..c56f3ed --- /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 ^= osmo_rol16(tmp, 1); + + tmp = R | KLi2[i]; + L ^= osmo_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] = osmo_rol16(osmo_load16be(key + i * 2), 1); + KLi2[i] = C[(i + 2) & 0x7]; + + KOi1[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 1)) & 0xE)), 5); + KOi2[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 5)) & 0xE)), 8); + KOi3[i] = osmo_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 cab4fc4..5f0d877 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -198,6 +198,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
Hi Max,
+#pragma once
All the other files use the classic #ifdef #define, so either replace all before that, or stick to the current way of doing it.
+#include <stdint.h>
+/*! \brief Single iteration of KASUMI cipher
- \param[in] P Block, 64 bits to be processed in this round
- \param[in] KLi1 Expanded subkeys
- \param[in] KLi2 Expanded subkeys
- \param[in] KOi1 Expanded subkeys
- \param[in] KOi2 Expanded subkeys
- \param[in] KOi3 Expanded subkeys
- \param[in] KIi1 Expanded subkeys
- \param[in] KIi2 Expanded subkeys
- \param[in] KIi3 Expanded subkeys
- \returns processed block of 64 bits
- */
We usually put the documentation only in the .c file and not the header. (except for stuff that's only in the header obviously).
If it's picked up by doxygen all the same then I don't have big objections against putting it in the header (to be checked though) if you insist, but then be consistent ... you have some of the doc duplicated for some of the methods
+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);
Either the methods are meant to be part of the public API and then they should carry the osmo prefix. Or they're meant to be internal, then the symbol should not be exported in the map file and the header should not be installed.
+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;
+}
Not of much importance here I admit (and not a blocker), but for future reference, make sure all that can be static is marked static. 'inline' doesn't make it static so you'll end up with both the function being inlined at every use in the file and a symbol _compare_mem that can be called from other .o (and obviously won't be and so the linker will strip it but still it's a good habit to take).
Cheers,
Sylvain
15.06.2014 22:49, Sylvain Munaut пишет:
Hi Max,
+#pragma once
All the other files use the classic #ifdef #define, so either replace all before that, or stick to the current way of doing it.
What do you mean by "all before that"?
Either the methods are meant to be part of the public API and then they should carry the osmo prefix. Or they're meant to be internal, then the symbol should not be exported in the map file and the header should not be installed.
I think I've asked it already but I don't recall an answer: I do not want to make it a part of public API (hence - no osmo_ prefix) but I still need to call it explicitly in test/ - how can I do that without adding it to map file?
Hi,
What do you mean by "all before that"?
Like change all libosmocore headers to use #pragma once.
We pretty much only target gcc/llvm AFAIK so that shouldn't be a problem.
Any one see an objection to that ?
I think I've asked it already but I don't recall an answer: I do not want to make it a part of public API (hence - no osmo_ prefix) but I still need to call it explicitly in test/ - how can I do that without adding it to map file?
I think the header should be in noinst_HEADER then (don't remember the exact name).
As for the testing, linking the test statically should do right ? I didn't test but since this only changes the presence of the symbol in the dynamic symbol table, linking to the static lib should work.
Cheers,
Sylvain
16.06.2014 00:33, Sylvain Munaut пишет:
I think the header should be in noinst_HEADER then (don't remember the exact name).
noinst_HEADERS it is, thanks.
As for the testing, linking the test statically should do right ? I didn't test but since this only changes the presence of the symbol in the dynamic symbol table, linking to the static lib should work.
Where should I pass -static to gcc linker? Is there some statically-linked test available as an example?
Hi,
As for the testing, linking the test statically should do right ? I didn't test but since this only changes the presence of the symbol in the dynamic symbol table, linking to the static lib should work.
Where should I pass -static to gcc linker? Is there some statically-linked test available as an example?
testname_LDFLAGS = -static
I fixed it up myself and pushed the 3 patches.
Cheers,
Sylvain
On Sun, Jun 15, 2014 at 10:49:45PM +0200, Sylvain Munaut wrote:
Hi,
+#pragma once
All the other files use the classic #ifdef #define, so either replace all before that, or stick to the current way of doing it.
do we really want to be that strong? I think all future header files should use "#pragma once".
+#pragma once
All the other files use the classic #ifdef #define, so either replace all before that, or stick to the current way of doing it.
do we really want to be that strong? I think all future header files should use "#pragma once".
I like consistency :p
Especially since such a change won't really lead to conflict since it only change a couple lines at the beginning/end of each file and it's also pretty easy to do with a script. (I did it in like 10 min).
Cheers,
Sylvain
16.06.2014 10:19, Sylvain Munaut пишет:
Especially since such a change won't really lead to conflict since it only change a couple lines at the beginning/end of each file and it's also pretty easy to do with a script. (I did it in like 10 min).
Good. Can you commit this?
Especially since such a change won't really lead to conflict since it only change a couple lines at the beginning/end of each file and it's also pretty easy to do with a script. (I did it in like 10 min).
Good. Can you commit this?
Holger, can I get a ack on this ?
Cheers,
Sylvain
On Mon, Jun 16, 2014 at 01:55:03PM +0200, Sylvain Munaut wrote:
Especially since such a change won't really lead to conflict since it only change a couple lines at the beginning/end of each file and it's also pretty easy to do with a script. (I did it in like 10 min).
Good. Can you commit this?
Holger, can I get a ack on this ?
sure. it looked fine.
This series of patches adds Kasumi encryption algorithm and necessary groundwork for it. It differs from previous version only in improved documentation (based on previous comments).
All the tests are included and pass just fine. Once this is merged I plan to send patches implementing A5/4, GEA4 etc which relies on Kasumi.
Please review and comment. Max.
baseband-devel@lists.osmocom.org