From Max.Suraev at fairwaves.ru Fri Mar 7 16:41:21 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Fri, 07 Mar 2014 17:41:21 +0100 Subject: [PATCH] RFC - change GPRS cipher API In-Reply-To: <52BE02E0.2040801@fairwaves.ru> References: <52961EF6.4060107@fairwaves.ru> <20131201133501.GL3133@nataraja.gnumonks.org> <52BDFFED.6080602@fairwaves.ru> <52BE02E0.2040801@fairwaves.ru> Message-ID: <5319F6B1.7070005@fairwaves.ru> While I'm at it I'd like to request feedback for this old patch as well. -- best regards, Max, http://fairwaves.ru From holger at freyther.de Thu Mar 6 09:17:04 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 6 Mar 2014 10:17:04 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <52F29A81.4070907@fairwaves.ru> References: <52BF3C52.40207@fairwaves.ru> <20140112184654.GT23594@nataraja> <52D52B37.5040300@fairwaves.ru> <20140131112609.GA18567@xiaoyu.lan> <52EBAEE8.2020104@fairwaves.ru> <20140205090021.GA29789@xiaoyu.lan> <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> Message-ID: <20140306091704.GA26569@xiaoyu.lan> On Wed, Feb 05, 2014 at 09:09:37PM +0100, ? wrote: > +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ > +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++); > +/* > + > + uint8_t i, adj = 8 * (8 - n); > + uintXX_t y = (x << adj) >> adj; > + for(i = 0; i < n; p[i] = (y >> i * 8) & 0xFF, i++); > +*/ left over comments or is that expanded in another way? > +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ > +static inline void osmo_storeXXbe_ext(uintXX_t x, uint8_t *p, uint8_t n) > +{ > +/* > + uint8_t i, adj = 8 * (8 - n); > + uintXX_t y = (x << adj) >> adj; > + for(i = 0; i < n; p[i] = (y >> ((n - 1 - i) * 8)) & 0xFF, i++); > +*/ left over? > +/* > + Less trivial LE/BE functions are autogenerated > + see included bitXXgen.h files > +*/ What makes them more trivial? > diff --git a/tests/bits/bitrev_test.c b/tests/bits/bitrev_test.c > index 5eca990..6cf340e 100644 > --- a/tests/bits/bitrev_test.c > +++ b/tests/bits/bitrev_test.c > +char s[18], *p; make static? > + > +void check_ls_64(uint8_t bytes) static too > +{ > + uint8_t T[bytes], D = (8 - bytes), A = 8 * D, C = 2 * D; > + uint64_t _test = ((uint64_t)rand() << 32) + rand(), a_test = (_test << A) >> A; that looks a bit crazy? What is your goal? Can you simplify it? > + if (0 != memcmp(s + C, p, bytes)) { > + printf("%s\t%s\t%u BE store FAILED!\n", s + C, p, bytes * 8); > + } else printf("%u BE store OK\n", bytes * 8); coding style. :) > + if (0 != memcmp(s, p, 2)) { > + printf ("%s\t", s); > + printf ("%s\t", p); > + printf("16 BE FAILED on %" PRIx16 "\n"); > + } else printf("16 BE store OK\n"); coding style. :) > From ab98c898fa54e441fdb0b08145bad074c09f2cf1 Mon Sep 17 00:00:00 2001 > From: Max > Date: Wed, 5 Feb 2014 20:10:38 +0100 > Subject: [PATCH 2/2] Add Kasumi cipher implementation > + osmocom/core/bit32gen.h \ > + osmocom/core/bit64gen.h \ that is is in the wrong patch? > +osmocom/core/bit%gen.h: osmocom/core/bitXXgen.h.tpl > + $(AM_V_GEN)$(MKDIR_P) $(dir $@) > + $(AM_V_GEN)sed -e's/XX/$*/g' $< > $@ > + that is in the wrong patch too? > +#ifndef __KASUMI_H__ > +#define __KASUMI_H__ _/__ are reserved for the system. I started to use "#pragma once" > +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); can you mark some of the parameters as const? > +static uint16_t > +_kasumi_FI(uint16_t I, uint16_t skey) coding style. :) > + static uint16_t S7[] = { Mark these arrays as const too. GCC is clever enough to figure out it is static. > + static uint16_t S9[] = { Same here. > + L ^= (skey & 0x1FF); > + R ^= (skey >> 9); Extra spaces? > + > + L = S9[L] ^ R; > + R = S7[R] ^ (L & 0x7F); Extra spaces? > +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) coding style. :) > +static uint32_t > +_kasumi_FL(uint32_t I, uint16_t *KLi1, uint16_t *KLi2, unsigned i) coding style. :) > +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) coding style. :) > +/*! \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) commented again? make const? > + for (i = 0; i < 8; i++) /* Work with 16 bit subkeys and create prime subkeys */ > + { > + C[i] ^= osmo_load16be(key + i * 2); > + } coding style. :) > + /* C[] now stores K-prime[] */ > + for (i = 0; i < 8; i++) /* Create round-specific subkeys */ > + { coding style. :) > +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) coding style. :) > +inline int _compare_mem(uint8_t * x, uint8_t * y, size_t len) { > + if (0 != memcmp(x, y, len)) { static coding style (tabs vs. space) From Max.Suraev at fairwaves.ru Thu Mar 6 10:52:10 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Thu, 06 Mar 2014 11:52:10 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <20140306091704.GA26569@xiaoyu.lan> References: <52BF3C52.40207@fairwaves.ru> <20140112184654.GT23594@nataraja> <52D52B37.5040300@fairwaves.ru> <20140131112609.GA18567@xiaoyu.lan> <52EBAEE8.2020104@fairwaves.ru> <20140205090021.GA29789@xiaoyu.lan> <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> <20140306091704.GA26569@xiaoyu.lan> Message-ID: <5318535A.3050208@fairwaves.ru> Thanks for comments - all either fixed or comments added to clarify. Max. From max.suraev at fairwaves.co Thu Mar 6 10:19:35 2014 From: max.suraev at fairwaves.co (Max) Date: Thu, 6 Mar 2014 11:19:35 +0100 Subject: [PATCH 1/2] Add generic LE/BE load store uint type convertors Message-ID: --- .gitignore | 3 +- include/Makefile.am | 6 ++ include/osmocom/core/bitXXgen.h.tpl | 86 +++++++++++++++++++++++++++++ include/osmocom/core/bits.h | 45 ++++++++++++++- include/osmocom/core/msgb.h | 23 ++++---- tests/bits/bitrev_test.c | 107 ++++++++++++++++++++++++++++++++++-- tests/bits/bitrev_test.ok | 22 ++++++++ 7 files changed, 276 insertions(+), 16 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..18011ff 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,8 @@ nobase_include_HEADERS = \ osmocom/codec/codec.h \ osmocom/core/application.h \ osmocom/core/backtrace.h \ + osmocom/core/bit32gen.h \ + osmocom/core/bit64gen.h \ osmocom/core/bits.h \ osmocom/core/bitvec.h \ osmocom/core/conv.h \ @@ -107,6 +109,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..1deffb9 --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,86 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max + * + * 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. + */ + + +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXle_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (8 * i)), i++); + return r; +} + +/* Load unaligned n-byte integer (big-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXbe_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (XX - 8* (1 + i))), i++); + return r; +} + + +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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++); +} + +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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 */ + + +/* Load unaligned XX-bit integer (little-endian encoding) */ +static inline uintXX_t osmo_loadXXle(const uint8_t *p) +{ + return osmo_loadXXle_ext(p, XX / 8); +} + +/* Load unaligned XX-bit integer (big-endian encoding) */ +static inline uintXX_t osmo_loadXXbe(const uint8_t *p) +{ + return osmo_loadXXbe_ext(p, XX / 8); +} + + +/* Store unaligned XX-bit integer (little-endian encoding) */ +static inline void osmo_storeXXle(uintXX_t x, uint8_t *p) +{ + return osmo_storeXXle_ext(x, p, XX / 8); +} + +/* Store unaligned XX-bit integer (big-endian encoding) */ +static inline void osmo_storeXXbe(uintXX_t x, uint8_t *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..09d163d 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,7 +2,9 @@ #define _OSMO_BITS_H #include - +#include +#include +#include /*! \defgroup bits soft, unpacked and packed bits * @{ */ @@ -15,6 +17,37 @@ typedef int8_t sbit_t; /*!< \brief soft bit (-127...127) */ typedef uint8_t ubit_t; /*!< \brief unpacked bit (0 or 1) */ typedef uint8_t pbit_t; /*!< \brief packed bis (8 bits in a byte) */ +/* Load unaligned 16-bit integer (little-endian encoding) */ +static inline uint16_t osmo_load16le(const uint8_t *p) +{ + return p[0] | (p[1] << 8); +} + +/* Load unaligned 16-bit integer (big-endian encoding) */ +static inline uint16_t osmo_load16be(const uint8_t *p) +{ + return (p[0] << 8) | p[1]; +} + +/* Store unaligned 16-bit integer (little-endian encoding) */ +static inline void osmo_store16le(uint16_t a, uint8_t *p) +{ + p[0] = a & 0xFF; + p[1] = (a >> 8) & 0xFF; +} + +/* Store unaligned 16-bit integer (big-endian encoding) */ +static inline void osmo_store16be(uint16_t a, uint8_t *p) +{ + p[0] = (a >> 8) & 0xFF; + p[1] = a & 0xFF; +} + +/* + Less trivial LE/BE functions (24 bits and above) are autogenerated + see included bitXXgen.h files +*/ + /* NOTE on the endianess of pbit_t: Bits in a pbit_t are ordered MSB first, i.e. 0x80 is the first bit. @@ -73,6 +106,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 reverse the order of the bytes in a given buffer */ +void osmo_revbytes_buf(uint8_t *buf, size_t len); + +/* \brief left circular shift */ +static inline uint16_t rol16(uint16_t in, unsigned shift) +{ + return (in << shift) | (in >> (16 - shift)); +} + + /*! @} */ #endif /* _OSMO_BITS_H */ diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index fe2733b..72fdc24 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -23,6 +23,7 @@ #include #include #include +#include /*! \defgroup msgb Message buffers * @{ @@ -204,8 +205,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 @@ -215,10 +215,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 @@ -235,6 +232,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 @@ -244,6 +242,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 @@ -251,8 +250,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 @@ -260,7 +260,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 @@ -284,6 +284,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 @@ -308,6 +309,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 @@ -315,8 +317,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 @@ -324,7 +327,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..9d5882c 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,8 +1,9 @@ - +#include #include #include #include #include +#include #include #include @@ -10,12 +11,75 @@ 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], *p; + +static void check_ls_64(uint8_t bytes) +{ + /* calculate various adjustment constants (number of bits, bytes, octets etc.) + based on number of bytes in type we actually test */ + uint8_t T[bytes], D = (8 - bytes), A = 8 * D, C = 2 * D; + /* zero exceeding bytes to avoid polluting test results */ + uint64_t _test = ((uint64_t)rand() << 32) + rand(), a_test = (_test << A) >> A; + + osmo_store64be_ext(_test, T, bytes); + snprintf(s, 17, "%.16" PRIx64, a_test); + p = osmo_hexdump_nospc(T, bytes); + if (0 != memcmp(s + C, p, bytes)) + printf("%s\t%s\t%u BE store FAILED!\n", s + C, p, bytes * 8); + else + printf("%u BE store OK\n", bytes * 8); + + osmo_store64le_ext(_test, T, bytes); + if (osmo_load64le_ext(T, bytes) == a_test) + printf("%u LE OK\n", bytes * 8); + else + printf("%u LE FAILED on %s- loaded %.16" PRIx64 " instead of %.16" PRIx64 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load64le_ext(T, bytes), a_test); + + osmo_store64be_ext(_test, T, bytes); + if (osmo_load64be_ext(T, bytes) == (a_test << A)) + printf("%u BE OK\n", bytes * 8); + else + printf("%u BE FAILED on %s- loaded %.16" PRIx64 " instead of %.16" PRIx64 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load64be_ext(T, bytes), (a_test << A)); +} + +static void check_ls_32(uint8_t bytes) +{ + /* calculate various adjustment constants (number of bits, bytes, octets etc.) + based on number of bytes in type we actually test */ + uint8_t T[bytes], D = (4 - bytes), A = 8 * D, C = 2 * D; + /* zero exceeding bytes to avoid polluting test results */ + uint32_t _test = rand(), a_test = (_test << A) >> A; + + osmo_store32be_ext(_test, T, bytes); + snprintf(s, 17, "%.8" PRIx32, a_test); + p = osmo_hexdump_nospc(T, bytes); + if (0 != memcmp(s + C, p, bytes)) + printf("%s\t%s\t%u BE store FAILED on %" PRIx32 "\n", s + C, p, bytes * 8, _test); + else + printf("%u BE store OK\n", bytes * 8); + + osmo_store32le_ext(_test, T, bytes); + if (osmo_load32le_ext(T, bytes) == a_test) + printf("%u LE OK\n", bytes * 8); + else + printf("%u LE FAILED on %s- loaded %.8" PRIx32 " instead of %.8" PRIx32 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load32le_ext(T, bytes), a_test); + + osmo_store32be_ext(_test, T, bytes); + if (osmo_load32be_ext(T, bytes) == (a_test << A)) + printf("%u BE OK\n", bytes * 8); + else + printf("%u BE FAILED on %s- loaded %.8" PRIx32 " instead of %.8" PRIx32 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load32be_ext(T, bytes), (a_test << A)); +} + int main(int argc, char **argv) { - uint8_t out[ARRAY_SIZE(input)]; + uint8_t out[ARRAY_SIZE(input)], test[8]; unsigned int offs; - for (offs = 0; offs < sizeof(out); offs++) { + srand(time(NULL)); + + for (offs = 0; offs < sizeof(out); offs++) + { uint8_t *start = out + offs; uint8_t len = sizeof(out) - offs; @@ -24,7 +88,8 @@ int main(int argc, char **argv) printf("INORDER: %s\n", osmo_hexdump(start, len)); osmo_revbytebits_buf(start, len); printf("REVERSED: %s\n", osmo_hexdump(start, len)); - if (memcmp(start, exp_out + offs, len)) { + if (memcmp(start, exp_out + offs, len)) + { printf("EXPECTED: %s\n", osmo_hexdump(exp_out+offs, len)); fprintf(stderr, "REVERSED != EXPECTED!\n"); exit(1); @@ -32,5 +97,39 @@ int main(int argc, char **argv) printf("\n"); } + printf("checking byte packing...\n"); + + check_ls_64(8); + check_ls_64(7); + check_ls_64(6); + check_ls_64(5); + check_ls_32(4); + check_ls_32(3); + + uint16_t _test16 = (uint16_t)rand(); + osmo_store16be(_test16, test); + + snprintf(s, 17, "%.4" PRIx16, _test16); + p = osmo_hexdump_nospc(test, 2); + if (0 != memcmp(s, p, 2)) + { + printf ("%s\t", s); + printf ("%s\t", p); + printf("16 BE FAILED on %" PRIx16 "\n"); + } else + printf("16 BE store OK\n"); + + osmo_store16le(_test16, test); + if (osmo_load16le(test) == _test16) + printf("16 LE OK\n"); + else + printf("16 LE FAILED: %s, %.4" PRIx16 ", %.4" PRIx16 "\n", osmo_hexdump(test, 2), osmo_load16le(test), _test16); + + osmo_store16be(_test16, test); + if (osmo_load16be(test) == _test16) + printf("16 BE OK\n"); + else + printf("16 BE FAILED: %s, %.4" PRIx16 ", %.4" PRIx16 "\n", osmo_hexdump(test, 2), osmo_load16be(test), _test16); + return 0; } diff --git a/tests/bits/bitrev_test.ok b/tests/bits/bitrev_test.ok index 47f402f..0cbc4db 100644 --- a/tests/bits/bitrev_test.ok +++ b/tests/bits/bitrev_test.ok @@ -22,3 +22,25 @@ REVERSED: 02 01 INORDER: 80 REVERSED: 01 +checking byte packing... +64 BE store OK +64 LE OK +64 BE OK +56 BE store OK +56 LE OK +56 BE OK +48 BE store OK +48 LE OK +48 BE OK +40 BE store OK +40 LE OK +40 BE OK +32 BE store OK +32 LE OK +32 BE OK +24 BE store OK +24 LE OK +24 BE OK +16 BE store OK +16 LE OK +16 BE OK -- 1.8.3.2 --------------020709010205080901010203 Content-Type: text/x-patch; name="0002-Add-Kasumi-cipher-implementation.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-Add-Kasumi-cipher-implementation.patch" From max.suraev at fairwaves.co Thu Mar 6 10:49:07 2014 From: max.suraev at fairwaves.co (Max) Date: Thu, 6 Mar 2014 11:49:07 +0100 Subject: [PATCH 2/2] Add Kasumi cipher implementation Message-ID: --- .gitignore | 1 + include/osmocom/gsm/kasumi.h | 33 ++++++++ src/gsm/Makefile.am | 2 +- src/gsm/kasumi.c | 190 +++++++++++++++++++++++++++++++++++++++++++ src/gsm/libosmogsm.map | 4 + tests/Makefile.am | 7 +- tests/kasumi/kasumi_test.c | 130 +++++++++++++++++++++++++++++ tests/kasumi/kasumi_test.ok | 10 +++ tests/testsuite.at | 6 ++ 9 files changed, 380 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..d0d07c7 --- /dev/null +++ b/include/osmocom/gsm/kasumi.h @@ -0,0 +1,33 @@ +/* + * KASUMI header + * + * See kasumi.c for details + */ + +#pragma once + +#include + +/* + * 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..dfecb4e --- /dev/null +++ b/src/gsm/kasumi.c @@ -0,0 +1,190 @@ +/* Kasumi cipher and KGcore functions */ + +/* (C) 2013 by Max + * + * 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 +#include +#include + +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); + 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_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..d8b3c70 --- /dev/null +++ b/tests/kasumi/kasumi_test.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + + +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 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 -- 1.8.3.2 --------------020709010205080901010203-- From holger at freyther.de Thu Mar 6 11:28:25 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 6 Mar 2014 12:28:25 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <5318535A.3050208@fairwaves.ru> References: <52D52B37.5040300@fairwaves.ru> <20140131112609.GA18567@xiaoyu.lan> <52EBAEE8.2020104@fairwaves.ru> <20140205090021.GA29789@xiaoyu.lan> <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> <20140306091704.GA26569@xiaoyu.lan> <5318535A.3050208@fairwaves.ru> Message-ID: <20140306112825.GD23770@xiaoyu.lan> On Thu, Mar 06, 2014 at 11:52:10AM +0100, ? wrote: > Thanks for comments - all either fixed or comments added to clarify. let me have another look. On general comment. The amount of parameters you pass to the method are a lot. Would you be able to be woken up in the middle of the day/night (whatever is less comfortable) and would you know the parameters? Did you consider passing them as a struct? > +static void check_ls_64(uint8_t bytes) > +{ > + /* calculate various adjustment constants (number of bits, bytes, octets etc.) > + based on number of bytes in type we actually test */ I was more thinking about what exactly do you want to test? Encode/Decode being compatible with each other? Corner cases? This is very difficult to understand code and I don't see your intend. I wonder/guess that there is a more simple approach to it. > int main(int argc, char **argv) > { > - uint8_t out[ARRAY_SIZE(input)]; > + uint8_t out[ARRAY_SIZE(input)], test[8]; > unsigned int offs; > > - for (offs = 0; offs < sizeof(out); offs++) { > + srand(time(NULL)); > + > + for (offs = 0; offs < sizeof(out); offs++) > + { coding style. :) > - if (memcmp(start, exp_out + offs, len)) { > + if (memcmp(start, exp_out + offs, len)) > + { coding style. :) > + if (0 != memcmp(s, p, 2)) > + { coding style. :) > +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); sorry. I didn't see that the first time. _NAME is reversed by the system. > +inline static uint16_t _kasumi_FI(uint16_t I, uint16_t skey) _kasumi is reserved for gcc/glibc. :) > + static const uint16_t S7[] = { > + }; > + static const uint16_t S9[] = { > + }; these tables were copied from the spec? > +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) > +inline static uint32_t _kasumi_FL(uint32_t I, const uint16_t *KLi1, const uint16_t *KLi2, unsigned i) again reserved symbol. :) > +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++) > + { coding style. :) > +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) > +{ > + for (i = 0; i < 8; i++) > + { coding style. :) (and reserved symbol) > + _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 */ > + { coding style. :) time is up. probably more coding style and symbol issues. :) From Max.Suraev at fairwaves.ru Thu Mar 6 12:13:35 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Thu, 06 Mar 2014 13:13:35 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <20140306112825.GD23770@xiaoyu.lan> References: <52D52B37.5040300@fairwaves.ru> <20140131112609.GA18567@xiaoyu.lan> <52EBAEE8.2020104@fairwaves.ru> <20140205090021.GA29789@xiaoyu.lan> <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> <20140306091704.GA26569@xiaoyu.lan> <5318535A.3050208@fairwaves.ru> <20140306112825.GD23770@xiaoyu.lan> Message-ID: <5318666F.3040809@fairwaves.ru> 06.03.2014 12:28, Holger Hans Peter Freyther ?????: > On Thu, Mar 06, 2014 at 11:52:10AM +0100, ? wrote: >> Thanks for comments - all either fixed or comments added to clarify. > > let me have another look. On general comment. The amount of parameters > you pass to the method are a lot. Would you be able to be woken up in > the middle of the day/night (whatever is less comfortable) and would > you know the parameters? Did you consider passing them as a struct? That's why I referenced corresponding standard in the comment. I do not see how adding struct will help with remembering parameter names at night - I think it will increase code complexity and decrease readability. Besides those are parameters to internal-only functions - you are not supposed to work with this code without reading corresponding standard beforehand. > >> +static void check_ls_64(uint8_t bytes) >> +{ >> + /* calculate various adjustment constants (number of bits, bytes, octets etc.) >> + based on number of bytes in type we actually test */ > > > I was more thinking about what exactly do you want to test? Encode/Decode > being compatible with each other? Corner cases? This is very difficult to > understand code and I don't see your intend. I wonder/guess that there is > a more simple approach to it. I'll add more comments to clarify - in general, I do not see better approach for serialize/deserialize kind of functions than trying to read/write and compare the results. > > coding style. :) > Would you mind to be more specific? I know that it's linux-kernel style but it would greatly help if you spend 3 more seconds to add few words to clarify what exactly you're unhappy about - for example in this particular case I've been confused by the undescriptive comments from previous email. > >> +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); > > sorry. I didn't see that the first time. _NAME is reversed by the system. > Is there some general way to mark function as internal-use only? For example the only reason I'm exposing _kasumi* is to be able to use them in test/kasumi_test code. >> +inline static uint16_t _kasumi_FI(uint16_t I, uint16_t skey) > > _kasumi is reserved for gcc/glibc. :) > >> + static const uint16_t S7[] = { >> + }; >> + static const uint16_t S9[] = { >> + }; > > these tables were copied from the spec? Yes, sure. The test vectors in kasumi_test were taken from the spec as well. -- best regards, Max, http://fairwaves.ru From holger at freyther.de Thu Mar 6 14:55:40 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 6 Mar 2014 15:55:40 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <5318666F.3040809@fairwaves.ru> References: <52EBAEE8.2020104@fairwaves.ru> <20140205090021.GA29789@xiaoyu.lan> <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> <20140306091704.GA26569@xiaoyu.lan> <5318535A.3050208@fairwaves.ru> <20140306112825.GD23770@xiaoyu.lan> <5318666F.3040809@fairwaves.ru> Message-ID: <20140306145540.GI23770@xiaoyu.lan> On Thu, Mar 06, 2014 at 01:13:35PM +0100, ? wrote: > That's why I referenced corresponding standard in the comment. I do not see how > adding struct will help with remembering parameter names at night - I think it will > increase code complexity and decrease readability. Besides those are parameters to > internal-only functions - you are not supposed to work with this code without reading > corresponding standard beforehand. Maybe you don't remember but you wil get the order right. Why do you want/ need to export the methods then? :) > > I was more thinking about what exactly do you want to test? Encode/Decode > > being compatible with each other? Corner cases? This is very difficult to > > understand code and I don't see your intend. I wonder/guess that there is > > a more simple approach to it. > > I'll add more comments to clarify - in general, I do not see better approach for > serialize/deserialize kind of functions than trying to read/write and compare the > results. Max, what do you want to test? > Would you mind to be more specific? I know that it's linux-kernel style but it would > greatly help if you spend 3 more seconds to add few words to clarify what exactly > you're unhappy about - for example in this particular case I've been confused by the > undescriptive comments from previous email. if (foo) { and not if (foo)\n{ > Is there some general way to mark function as internal-use only? For example the only > reason I'm exposing _kasumi* is to be able to use them in test/kasumi_test code. ANSI C. E.g. in C99 Chapter 7.1.3 Reserved identifiers: "All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use." Okay _kasumi is actually fine, __kasumi would not, _KASUMI would be neither. My take is that it is best to avoid anything close to reserved symbols. :) > > > > these tables were copied from the spec? > > Yes, sure. The test vectors in kasumi_test were taken from the spec as well. do you want to add another reference? From Max.Suraev at fairwaves.ru Thu Mar 6 17:27:38 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Thu, 06 Mar 2014 18:27:38 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <20140306145540.GI23770@xiaoyu.lan> References: <52EBAEE8.2020104@fairwaves.ru> <20140205090021.GA29789@xiaoyu.lan> <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> <20140306091704.GA26569@xiaoyu.lan> <5318535A.3050208@fairwaves.ru> <20140306112825.GD23770@xiaoyu.lan> <5318666F.3040809@fairwaves.ru> <20140306145540.GI23770@xiaoyu.lan> Message-ID: <5318B00A.9080002@fairwaves.ru> 06.03.2014 15:55, Holger Hans Peter Freyther ?????: > Maybe you don't remember but you wil get the order right. Why do you want/ > need to export the methods then? :) So I can use them in tests/kasumi. >> I'll add more comments to clarify - in general, I do not see better approach for >> serialize/deserialize kind of functions than trying to read/write and compare the >> results. > > Max, what do you want to test? > Commented. -- best regards, Max, http://fairwaves.ru From max.suraev at fairwaves.co Thu Mar 6 17:07:13 2014 From: max.suraev at fairwaves.co (Max) Date: Thu, 6 Mar 2014 18:07:13 +0100 Subject: [PATCH 1/2] Add generic LE/BE load store uint type convertors Message-ID: --- .gitignore | 3 +- include/Makefile.am | 6 ++ include/osmocom/core/bitXXgen.h.tpl | 86 ++++++++++++++++++++++++++++ include/osmocom/core/bits.h | 45 ++++++++++++++- include/osmocom/core/msgb.h | 23 ++++---- tests/bits/bitrev_test.c | 109 +++++++++++++++++++++++++++++++++++- tests/bits/bitrev_test.ok | 22 ++++++++ 7 files changed, 280 insertions(+), 14 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..18011ff 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,8 @@ nobase_include_HEADERS = \ osmocom/codec/codec.h \ osmocom/core/application.h \ osmocom/core/backtrace.h \ + osmocom/core/bit32gen.h \ + osmocom/core/bit64gen.h \ osmocom/core/bits.h \ osmocom/core/bitvec.h \ osmocom/core/conv.h \ @@ -107,6 +109,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..1deffb9 --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,86 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max + * + * 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. + */ + + +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXle_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (8 * i)), i++); + return r; +} + +/* Load unaligned n-byte integer (big-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXbe_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (XX - 8* (1 + i))), i++); + return r; +} + + +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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++); +} + +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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 */ + + +/* Load unaligned XX-bit integer (little-endian encoding) */ +static inline uintXX_t osmo_loadXXle(const uint8_t *p) +{ + return osmo_loadXXle_ext(p, XX / 8); +} + +/* Load unaligned XX-bit integer (big-endian encoding) */ +static inline uintXX_t osmo_loadXXbe(const uint8_t *p) +{ + return osmo_loadXXbe_ext(p, XX / 8); +} + + +/* Store unaligned XX-bit integer (little-endian encoding) */ +static inline void osmo_storeXXle(uintXX_t x, uint8_t *p) +{ + return osmo_storeXXle_ext(x, p, XX / 8); +} + +/* Store unaligned XX-bit integer (big-endian encoding) */ +static inline void osmo_storeXXbe(uintXX_t x, uint8_t *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..09d163d 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,7 +2,9 @@ #define _OSMO_BITS_H #include - +#include +#include +#include /*! \defgroup bits soft, unpacked and packed bits * @{ */ @@ -15,6 +17,37 @@ typedef int8_t sbit_t; /*!< \brief soft bit (-127...127) */ typedef uint8_t ubit_t; /*!< \brief unpacked bit (0 or 1) */ typedef uint8_t pbit_t; /*!< \brief packed bis (8 bits in a byte) */ +/* Load unaligned 16-bit integer (little-endian encoding) */ +static inline uint16_t osmo_load16le(const uint8_t *p) +{ + return p[0] | (p[1] << 8); +} + +/* Load unaligned 16-bit integer (big-endian encoding) */ +static inline uint16_t osmo_load16be(const uint8_t *p) +{ + return (p[0] << 8) | p[1]; +} + +/* Store unaligned 16-bit integer (little-endian encoding) */ +static inline void osmo_store16le(uint16_t a, uint8_t *p) +{ + p[0] = a & 0xFF; + p[1] = (a >> 8) & 0xFF; +} + +/* Store unaligned 16-bit integer (big-endian encoding) */ +static inline void osmo_store16be(uint16_t a, uint8_t *p) +{ + p[0] = (a >> 8) & 0xFF; + p[1] = a & 0xFF; +} + +/* + Less trivial LE/BE functions (24 bits and above) are autogenerated + see included bitXXgen.h files +*/ + /* NOTE on the endianess of pbit_t: Bits in a pbit_t are ordered MSB first, i.e. 0x80 is the first bit. @@ -73,6 +106,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 reverse the order of the bytes in a given buffer */ +void osmo_revbytes_buf(uint8_t *buf, size_t len); + +/* \brief left circular shift */ +static inline uint16_t rol16(uint16_t in, unsigned shift) +{ + return (in << shift) | (in >> (16 - shift)); +} + + /*! @} */ #endif /* _OSMO_BITS_H */ diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index fe2733b..72fdc24 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -23,6 +23,7 @@ #include #include #include +#include /*! \defgroup msgb Message buffers * @{ @@ -204,8 +205,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 @@ -215,10 +215,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 @@ -235,6 +232,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 @@ -244,6 +242,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 @@ -251,8 +250,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 @@ -260,7 +260,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 @@ -284,6 +284,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 @@ -308,6 +309,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 @@ -315,8 +317,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 @@ -324,7 +327,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..fbf4b22 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,8 +1,9 @@ - +#include #include #include #include #include +#include #include #include @@ -10,11 +11,79 @@ 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], *p; + +static void check_ls_64(uint8_t bytes) +{ + /* calculate various adjustment constants (number of bits, bytes, octets etc.) + based on number of bytes in type we actually test */ + uint8_t T[bytes], D = (8 - bytes), A = 8 * D, C = 2 * D; + /* zero exceeding bytes to avoid polluting test results */ + uint64_t _test = ((uint64_t)rand() << 32) + rand(), a_test = (_test << A) >> A; + + /* TEST 1: store and compare the result with snprintf serialization (big-endian) */ + osmo_store64be_ext(_test, T, bytes); + snprintf(s, 17, "%.16" PRIx64, a_test); + p = osmo_hexdump_nospc(T, bytes); + if (0 != memcmp(s + C, p, bytes)) + printf("%s\t%s\t%u BE store FAILED!\n", s + C, p, bytes * 8); + else + printf("%u BE store OK\n", bytes * 8); + + /* TEST 2: verify that store/load cycle does not change value (little-endian) */ + osmo_store64le_ext(_test, T, bytes); + if (osmo_load64le_ext(T, bytes) == a_test) + printf("%u LE OK\n", bytes * 8); + else + printf("%u LE FAILED on %s- loaded %.16" PRIx64 " instead of %.16" PRIx64 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load64le_ext(T, bytes), a_test); + + /* TEST 3: verify that store/load cycle does not change value (big-endian) */ + osmo_store64be_ext(_test, T, bytes); + if (osmo_load64be_ext(T, bytes) == (a_test << A)) + printf("%u BE OK\n", bytes * 8); + else + printf("%u BE FAILED on %s- loaded %.16" PRIx64 " instead of %.16" PRIx64 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load64be_ext(T, bytes), (a_test << A)); +} + +static void check_ls_32(uint8_t bytes) +{ + /* calculate various adjustment constants (number of bits, bytes, octets etc.) + based on number of bytes in type we actually test */ + uint8_t T[bytes], D = (4 - bytes), A = 8 * D, C = 2 * D; + /* zero exceeding bytes to avoid polluting test results */ + uint32_t _test = rand(), a_test = (_test << A) >> A; + + /* TEST 1: store and compare the result with snprintf serialization (big-endian) */ + osmo_store32be_ext(_test, T, bytes); + snprintf(s, 17, "%.8" PRIx32, a_test); + p = osmo_hexdump_nospc(T, bytes); + if (0 != memcmp(s + C, p, bytes)) + printf("%s\t%s\t%u BE store FAILED on %" PRIx32 "\n", s + C, p, bytes * 8, _test); + else + printf("%u BE store OK\n", bytes * 8); + + /* TEST 2: verify that store/load cycle does not change value (little-endian) */ + osmo_store32le_ext(_test, T, bytes); + if (osmo_load32le_ext(T, bytes) == a_test) + printf("%u LE OK\n", bytes * 8); + else + printf("%u LE FAILED on %s- loaded %.8" PRIx32 " instead of %.8" PRIx32 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load32le_ext(T, bytes), a_test); + + /* TEST 3: verify that store/load cycle does not change value (big-endian) */ + osmo_store32be_ext(_test, T, bytes); + if (osmo_load32be_ext(T, bytes) == (a_test << A)) + printf("%u BE OK\n", bytes * 8); + else + printf("%u BE FAILED on %s- loaded %.8" PRIx32 " instead of %.8" PRIx32 "\n", bytes * 8, osmo_hexdump(T, bytes), osmo_load32be_ext(T, bytes), (a_test << A)); +} + int main(int argc, char **argv) { - uint8_t out[ARRAY_SIZE(input)]; + uint8_t out[ARRAY_SIZE(input)], test[8]; 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 +101,41 @@ int main(int argc, char **argv) printf("\n"); } + printf("checking byte packing...\n"); + + check_ls_64(8); + check_ls_64(7); + check_ls_64(6); + check_ls_64(5); + check_ls_32(4); + check_ls_32(3); + + uint16_t _test16 = (uint16_t)rand(); + osmo_store16be(_test16, test); + + /* TEST 1: store and compare the result with snprintf serialization (big-endian) */ + snprintf(s, 17, "%.4" PRIx16, _test16); + p = osmo_hexdump_nospc(test, 2); + if (0 != memcmp(s, p, 2)) { + printf ("%s\t", s); + printf ("%s\t", p); + printf("16 BE FAILED on %" PRIx16 "\n"); + } else + printf("16 BE store OK\n"); + + /* TEST 2: verify that store/load cycle does not change value (little-endian) */ + osmo_store16le(_test16, test); + if (osmo_load16le(test) == _test16) + printf("16 LE OK\n"); + else + printf("16 LE FAILED: %s, %.4" PRIx16 ", %.4" PRIx16 "\n", osmo_hexdump(test, 2), osmo_load16le(test), _test16); + + /* TEST 3: verify that store/load cycle does not change value (big-endian) */ + osmo_store16be(_test16, test); + if (osmo_load16be(test) == _test16) + printf("16 BE OK\n"); + else + printf("16 BE FAILED: %s, %.4" PRIx16 ", %.4" PRIx16 "\n", osmo_hexdump(test, 2), osmo_load16be(test), _test16); + return 0; } diff --git a/tests/bits/bitrev_test.ok b/tests/bits/bitrev_test.ok index 47f402f..0cbc4db 100644 --- a/tests/bits/bitrev_test.ok +++ b/tests/bits/bitrev_test.ok @@ -22,3 +22,25 @@ REVERSED: 02 01 INORDER: 80 REVERSED: 01 +checking byte packing... +64 BE store OK +64 LE OK +64 BE OK +56 BE store OK +56 LE OK +56 BE OK +48 BE store OK +48 LE OK +48 BE OK +40 BE store OK +40 LE OK +40 BE OK +32 BE store OK +32 LE OK +32 BE OK +24 BE store OK +24 LE OK +24 BE OK +16 BE store OK +16 LE OK +16 BE OK -- 1.8.3.2 --------------030704070502020202070204 Content-Type: text/x-patch; name="0002-Add-Kasumi-cipher-implementation.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-Add-Kasumi-cipher-implementation.patch" From max.suraev at fairwaves.co Thu Mar 6 17:24:51 2014 From: max.suraev at fairwaves.co (Max) Date: Thu, 6 Mar 2014 18:24:51 +0100 Subject: [PATCH 2/2] Add Kasumi cipher implementation Message-ID: --- .gitignore | 1 + include/osmocom/gsm/kasumi.h | 34 ++++++++ src/gsm/Makefile.am | 2 +- src/gsm/kasumi.c | 191 +++++++++++++++++++++++++++++++++++++++++++ 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, 388 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..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 + +/* + * 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..c2dfa6f --- /dev/null +++ b/src/gsm/kasumi.c @@ -0,0 +1,191 @@ +/* Kasumi cipher and KGcore functions */ + +/* (C) 2013 by Max + * + * 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 +#include +#include + +/* 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); + 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_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 +#include +#include +#include +#include + +#include +#include +#include + +/* 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 -- 1.8.3.2 --------------030704070502020202070204-- From holger at freyther.de Fri Mar 7 07:44:31 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Fri, 7 Mar 2014 08:44:31 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <5318B00A.9080002@fairwaves.ru> References: <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> <20140306091704.GA26569@xiaoyu.lan> <5318535A.3050208@fairwaves.ru> <20140306112825.GD23770@xiaoyu.lan> <5318666F.3040809@fairwaves.ru> <20140306145540.GI23770@xiaoyu.lan> <5318B00A.9080002@fairwaves.ru> Message-ID: <20140307074431.GC30569@xiaoyu.lan> On Thu, Mar 06, 2014 at 06:27:38PM +0100, ? wrote: Dear Max, > >> I'll add more comments to clarify - in general, I do not see better approach for > >> serialize/deserialize kind of functions than trying to read/write and compare the > >> results. > > > > Max, what do you want to test? > > > > Commented. That was not the point. I tried to ask you what you intend to test. E.g. if you take a look at Jacob's range encoding tests in OpenBSC. There is a simple list of fixes values that are tested and then some random numbers. Now I find your testcase very hard to comprehend. This is why I want to understand the goal first and then propose a more simple/straight forward approach. But now I did propose something. ;) You are still having for (...) but we have for (...) { { sorry about that. But we still have some time until Sunday. :) From Max.Suraev at fairwaves.ru Fri Mar 7 10:34:37 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Fri, 07 Mar 2014 11:34:37 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <20140307074431.GC30569@xiaoyu.lan> References: <52F2404A.5090802@fairwaves.ru> <52F28D50.6090707@fairwaves.ru> <20140205195506.GO22661@xiaoyu.lan> <52F29A81.4070907@fairwaves.ru> <20140306091704.GA26569@xiaoyu.lan> <5318535A.3050208@fairwaves.ru> <20140306112825.GD23770@xiaoyu.lan> <5318666F.3040809@fairwaves.ru> <20140306145540.GI23770@xiaoyu.lan> <5318B00A.9080002@fairwaves.ru> <20140307074431.GC30569@xiaoyu.lan> Message-ID: <5319A0BD.2080903@fairwaves.ru> 07.03.2014 08:44, Holger Hans Peter Freyther ?????: > That was not the point. I tried to ask you what you intend to test. E.g. > if you take a look at Jacob's range encoding tests in OpenBSC. There is a > simple list of fixes values that are tested and then some random numbers. > > Now I find your testcase very hard to comprehend. This is why I want to > understand the goal first and then propose a more simple/straight forward > approach. But now I did propose something. ;) > I don't get what exactly you want? Right now I generate random data and serialize/deserialize it: test 1 verifies that data is serialized properly, tests 2 and 3 verify that serialize-deserialize cycle does not change the data. You want to test some specific constants instead? Please, feel free add your favorite numbers in there :) If it's unclear how to do that - let me know and I'll update documentation. -- best regards, Max, http://fairwaves.ru From Max.Suraev at fairwaves.ru Mon Mar 10 18:23:56 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Mon, 10 Mar 2014 19:23:56 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <52BF344B.1020001@fairwaves.ru> References: <52BF344B.1020001@fairwaves.ru> Message-ID: <531E033C.90809@fairwaves.ru> Attached is latest version - completely revamped test code plus some style improvements. When shall we expect patchwork to take over ML? :) -- best regards, Max, http://fairwaves.ru From max.suraev at fairwaves.co Mon Mar 10 18:13:58 2014 From: max.suraev at fairwaves.co (Max) Date: Mon, 10 Mar 2014 19:13:58 +0100 Subject: [PATCH 1/2] Add generic LE/BE load store uint type convertors Message-ID: --- .gitignore | 3 +- include/Makefile.am | 6 + include/osmocom/core/bitXXgen.h.tpl | 86 ++++++++++++++ include/osmocom/core/bits.h | 45 +++++++- include/osmocom/core/msgb.h | 23 ++-- tests/bits/bitrev_test.c | 218 +++++++++++++++++++++++++++++++++++- tests/bits/bitrev_test.ok | 31 +++++ 7 files changed, 399 insertions(+), 13 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..18011ff 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,8 @@ nobase_include_HEADERS = \ osmocom/codec/codec.h \ osmocom/core/application.h \ osmocom/core/backtrace.h \ + osmocom/core/bit32gen.h \ + osmocom/core/bit64gen.h \ osmocom/core/bits.h \ osmocom/core/bitvec.h \ osmocom/core/conv.h \ @@ -107,6 +109,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..1deffb9 --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,86 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max + * + * 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. + */ + + +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXle_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (8 * i)), i++); + return r; +} + +/* Load unaligned n-byte integer (big-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXbe_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (XX - 8* (1 + i))), i++); + return r; +} + + +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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++); +} + +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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 */ + + +/* Load unaligned XX-bit integer (little-endian encoding) */ +static inline uintXX_t osmo_loadXXle(const uint8_t *p) +{ + return osmo_loadXXle_ext(p, XX / 8); +} + +/* Load unaligned XX-bit integer (big-endian encoding) */ +static inline uintXX_t osmo_loadXXbe(const uint8_t *p) +{ + return osmo_loadXXbe_ext(p, XX / 8); +} + + +/* Store unaligned XX-bit integer (little-endian encoding) */ +static inline void osmo_storeXXle(uintXX_t x, uint8_t *p) +{ + return osmo_storeXXle_ext(x, p, XX / 8); +} + +/* Store unaligned XX-bit integer (big-endian encoding) */ +static inline void osmo_storeXXbe(uintXX_t x, uint8_t *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..09d163d 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,7 +2,9 @@ #define _OSMO_BITS_H #include - +#include +#include +#include /*! \defgroup bits soft, unpacked and packed bits * @{ */ @@ -15,6 +17,37 @@ typedef int8_t sbit_t; /*!< \brief soft bit (-127...127) */ typedef uint8_t ubit_t; /*!< \brief unpacked bit (0 or 1) */ typedef uint8_t pbit_t; /*!< \brief packed bis (8 bits in a byte) */ +/* Load unaligned 16-bit integer (little-endian encoding) */ +static inline uint16_t osmo_load16le(const uint8_t *p) +{ + return p[0] | (p[1] << 8); +} + +/* Load unaligned 16-bit integer (big-endian encoding) */ +static inline uint16_t osmo_load16be(const uint8_t *p) +{ + return (p[0] << 8) | p[1]; +} + +/* Store unaligned 16-bit integer (little-endian encoding) */ +static inline void osmo_store16le(uint16_t a, uint8_t *p) +{ + p[0] = a & 0xFF; + p[1] = (a >> 8) & 0xFF; +} + +/* Store unaligned 16-bit integer (big-endian encoding) */ +static inline void osmo_store16be(uint16_t a, uint8_t *p) +{ + p[0] = (a >> 8) & 0xFF; + p[1] = a & 0xFF; +} + +/* + Less trivial LE/BE functions (24 bits and above) are autogenerated + see included bitXXgen.h files +*/ + /* NOTE on the endianess of pbit_t: Bits in a pbit_t are ordered MSB first, i.e. 0x80 is the first bit. @@ -73,6 +106,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 reverse the order of the bytes in a given buffer */ +void osmo_revbytes_buf(uint8_t *buf, size_t len); + +/* \brief left circular shift */ +static inline uint16_t rol16(uint16_t in, unsigned shift) +{ + return (in << shift) | (in >> (16 - shift)); +} + + /*! @} */ #endif /* _OSMO_BITS_H */ diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index fe2733b..72fdc24 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -23,6 +23,7 @@ #include #include #include +#include /*! \defgroup msgb Message buffers * @{ @@ -204,8 +205,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 @@ -215,10 +215,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 @@ -235,6 +232,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 @@ -244,6 +242,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 @@ -251,8 +250,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 @@ -260,7 +260,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 @@ -284,6 +284,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 @@ -308,6 +309,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 @@ -315,8 +317,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 @@ -324,7 +327,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..fc5a811 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,20 +1,192 @@ - +#include #include #include #include #include +#include +#include #include #include 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 -- 1.8.3.2 --------------070304090402030003020005 Content-Type: text/x-patch; name="0002-Add-Kasumi-cipher-implementation.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-Add-Kasumi-cipher-implementation.patch" From max.suraev at fairwaves.co Mon Mar 10 18:18:57 2014 From: max.suraev at fairwaves.co (Max) Date: Mon, 10 Mar 2014 19:18:57 +0100 Subject: [PATCH 2/2] Add Kasumi cipher implementation Message-ID: --- .gitignore | 1 + include/osmocom/gsm/kasumi.h | 34 ++++++++ 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, 387 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..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 + +/* + * 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 + * + * 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 +#include +#include + +/* 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 +#include +#include +#include +#include + +#include +#include +#include + +/* 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 -- 1.8.3.2 --------------070304090402030003020005-- From bajtelo at o2.pl Mon Mar 3 12:42:40 2014 From: bajtelo at o2.pl (=?UTF-8?Q?Sebastian_Komorowski?=) Date: Mon, 03 Mar 2014 13:42:40 +0100 Subject: =?UTF-8?Q?Make_phone_calls_using_IMSI?= Message-ID: Hello, I'm new with Osmocom. I have a question. Can I make phone calls using IMSI instead traditional phone number? Is Osmocom have function to do this? If not - is it somehow possible to call somebody using IMSI? Thank you for the answer. Regards Sebastian From holger at freyther.de Mon Mar 3 12:57:39 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 3 Mar 2014 13:57:39 +0100 Subject: Make phone calls using IMSI In-Reply-To: References: Message-ID: <20140303125739.GC22350@xiaoyu.lan> On Mon, Mar 03, 2014 at 01:42:40PM +0100, Sebastian Komorowski wrote: Hi, > If not - is it somehow possible to call somebody using IMSI? I don't think so. The argument of sendRoutingInfo on SS7/MAP only contains the "msisdn". So I don't think it works in the normal gsm network. From Max.Suraev at fairwaves.ru Mon Mar 3 13:41:20 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Mon, 03 Mar 2014 14:41:20 +0100 Subject: Make phone calls using IMSI In-Reply-To: References: Message-ID: <53148680.2080005@fairwaves.ru> Call-by-IMSI got to be supported by BTS, which is not normally the case, however OpenBTS fork from Fairwaves have testcall function which does just that. In general - mobile-terminated call can "by IMSI" because for mobile phone there's no difference in how it was reached exactly_ as long as BTS exposes that functionlity. For mobile originated calls I think it can be implemented on BTS side if you simply use IMSI as a phone number in authentication db/sip backend of OpenBTS. -- best regards, Max, http://fairwaves.ru From bajtelo at o2.pl Mon Mar 3 14:28:56 2014 From: bajtelo at o2.pl (=?UTF-8?Q?Sebastian_Komorowski?=) Date: Mon, 03 Mar 2014 15:28:56 +0100 Subject: =?UTF-8?Q?Re:_Make_phone_calls_using_IMSI?= In-Reply-To: <53148680.2080005@fairwaves.ru> References: <53148680.2080005@fairwaves.ru> Message-ID: <1dbb5b19.395e4159.531491a8.883b1@o2.pl> I have USRP with OpenBTS. I can now make phone calls from phone to phone i this two MS is connected to my BTS. Can you explain more precisely how to make phone calls using IMSI and OpenBTS? Secondly - how i can input (enter) IMSI to mobile phone to make phone calls successfully. Software in phones supports functions like this? Regards Sebastian Dnia 3 marca 2014 14:41 ? napisa?(a): > Call-by-IMSI got to be supported by BTS, which is not normally the case, however > OpenBTS fork from Fairwaves have testcall function which does just that. > > In general - mobile-terminated call can "by IMSI" because for mobile phone there's no > difference in how it was reached exactly_ as long as BTS exposes that functionlity. > For mobile originated calls I think it can be implemented on BTS side if you simply > use IMSI as a phone number in authentication db/sip backend of OpenBTS. > > From Max.Suraev at fairwaves.ru Mon Mar 3 15:46:34 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Mon, 03 Mar 2014 16:46:34 +0100 Subject: Make phone calls using IMSI In-Reply-To: <1dbb5b19.395e4159.531491a8.883b1@o2.pl> References: <53148680.2080005@fairwaves.ru> <1dbb5b19.395e4159.531491a8.883b1@o2.pl> Message-ID: <5314A3DA.3010500@fairwaves.ru> 03.03.2014 15:28, Sebastian Komorowski ?????: > I have USRP with OpenBTS. I can now make phone calls from phone to phone i this two MS is connected to my BTS. > > Can you explain more precisely how to make phone calls using IMSI and OpenBTS? You have to use this version https://github.com/fairwaves/openbts-2.8 - testcall CLI command was removed from mainline due to some political issues. After you install it you can use testcall command to initiate call to given IMSI. A very thorough description of using it is available at http://www.syssec.rub.de/media/emma/arbeiten/2012/11/16/2011-10-04-Weber.pdf > Secondly - how i can input (enter) IMSI to mobile phone to make phone calls successfully. Software in phones supports functions like this? > > Well, sipauthserv uses sqlite.db which maps IMSI to phone number. If you edit it to make phone number == IMSI you can call using it. In order to avoid manually editing each number/IMSI I'm afraid you've got to modify sipauthserve (or code which interacts with it). Although it's not that hard - I've modified it to avoid calls to sipathserve https://github.com/zabbal/openbts-p2.8 Also a little clarification - IMSI is normally written into SIM card. I think osmocom-bb allows to modify on the fly but I don't remember exact command :( Anyway, you can always use programmable SIM card to put any IMSI you like in there. -- best regards, Max, http://fairwaves.ru From andreas at eversberg.eu Mon Mar 3 17:31:26 2014 From: andreas at eversberg.eu (Andreas Eversberg) Date: Mon, 03 Mar 2014 18:31:26 +0100 Subject: Make phone calls using IMSI In-Reply-To: References: Message-ID: <5314BC6E.5040508@eversberg.eu> Sebastian Komorowski wrote: > Can I make phone calls using IMSI instead traditional phone number? Is Osmocom have function to do this? > If not - is it somehow possible to call somebody using IMSI? hi sebastian, in a traditional network it is not possible, as far as i know. also there is no number type for "imsi" defined, so if you use osmocombb, you can't. if you use openbsc, you can, if you make calls via MNCC interface, by setting IMSI instead of called number (in conjunction with LCR (linux-call-router) application, using a dial string like "imsi-xxxxxxxxxxxxxxx"). i used this for test calls. best regards, andreas From baumgar1 at hm.edu Mon Mar 3 16:23:20 2014 From: baumgar1 at hm.edu (baumgar1) Date: Mon, 03 Mar 2014 17:23:20 +0100 Subject: Get DEA3 working on real devices Message-ID: Hi, we are students at Munich university and we trying to get GEA3 running on openbsc in nitb mode. GSM and GPRS are working, also authentication (+ GSM A5/1 encryption) and libosmo-crypt-a53 is installed, but we didn't get the plugin running (It's loaded, but we think it isn't registered). In the IRC Channel we got the information that it's actually not fully implemented and should ask here. Has anyone got GEA3 working in openbsc with real phones? Thanks for your time and help. With best regards, Alexander and Stoffl (We use the SymoSIM-GR1 SIMs and nanoBTSs 165g) From Max.Suraev at fairwaves.ru Mon Mar 3 17:20:07 2014 From: Max.Suraev at fairwaves.ru (=?UTF-8?B?4piO?=) Date: Mon, 03 Mar 2014 18:20:07 +0100 Subject: Get DEA3 working on real devices In-Reply-To: References: Message-ID: <5314B9C7.6060500@fairwaves.ru> 03.03.2014 17:23, baumgar1 ?????: > Hi, > we are students at Munich university and we trying to get GEA3 running on openbsc in > nitb mode. GSM and GPRS are working, also authentication (+ GSM A5/1 encryption) and > libosmo-crypt-a53 is installed, but we didn't get the plugin running (It's loaded, > but we think it isn't registered). In the IRC Channel we got the information that > it's actually not fully implemented and should ask here. Well my patches to libosmocore implementing GEA3/GEA4 are pending in the list awaiting review for months :) I hope to finally push Holger into merging it during upcoming OsmoDevCon this week. After that you won't need any 3rd-party libraries but I think there got to be some changes made to OpenBSC in order to support that. Most importantly - we use sqlite as HLR at the moment which makes it impossible to handle GSM and GPRS auth. requests at the same time. I think we need dedicated AuC/HLR which is fully async and can hide sqlite ugliness from the rest of the code in order to make it work. > > Has anyone got GEA3 working in openbsc with real phones? > Not yet, but I'm looking forward for your results :) -- best regards, Max, http://fairwaves.ru From baumgar1 at hm.edu Mon Mar 3 22:56:00 2014 From: baumgar1 at hm.edu (baumgar1) Date: Mon, 03 Mar 2014 23:56:00 +0100 Subject: Get DEA3 working on real devices In-Reply-To: <5314B9C7.6060500@fairwaves.ru> References: <5314B9C7.6060500@fairwaves.ru> Message-ID: <32107a2a3da086aaa170ec28dc2ce34c@hm.edu> Am 2014-03-03 18:20, schrieb ?: > Well my patches to libosmocore implementing GEA3/GEA4 are pending in > the list > awaiting review for months :) > I hope to finally push Holger into merging it during upcoming > OsmoDevCon this week. Sounds great! :) Can you provide us a link to your up to date patches, please? We only got this weak left to get the project running. I hope we can make it :) > After that you won't need any 3rd-party libraries but I think there > got to be some > changes made to OpenBSC in order to support that. Most importantly - > we use sqlite as > HLR at the moment which makes it impossible to handle GSM and GPRS > auth. requests at > the same time. I think we need dedicated AuC/HLR which is fully async > and can hide > sqlite ugliness from the rest of the code in order to make it work. Hm, OK. So, for testing we have to disable the GSM auth and enable the GPRS auth? Is that possible? I can't remember a option for that but I'll have a look at the config tomorrow. >> Has anyone got GEA3 working in openbsc with real phones? >> > > Not yet, but I'm looking forward for your results :) I hope we get something useful ;) From max.suraev at fairwaves.co Thu Mar 13 20:36:50 2014 From: max.suraev at fairwaves.co (Max) Date: Thu, 13 Mar 2014 21:36:50 +0100 Subject: [PATCH 1/2] Add generic LE/BE load/store uint type convertors and use them in msgb Message-ID: <1394743011-2705-1-git-send-email-max.suraev@fairwaves.co> --- .gitignore | 3 +- include/Makefile.am | 6 + include/osmocom/core/bitXXgen.h.tpl | 86 ++++++++++++++ include/osmocom/core/bits.h | 45 +++++++- include/osmocom/core/msgb.h | 23 ++-- tests/bits/bitrev_test.c | 218 +++++++++++++++++++++++++++++++++++- tests/bits/bitrev_test.ok | 31 +++++ 7 files changed, 399 insertions(+), 13 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..18011ff 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,8 @@ nobase_include_HEADERS = \ osmocom/codec/codec.h \ osmocom/core/application.h \ osmocom/core/backtrace.h \ + osmocom/core/bit32gen.h \ + osmocom/core/bit64gen.h \ osmocom/core/bits.h \ osmocom/core/bitvec.h \ osmocom/core/conv.h \ @@ -107,6 +109,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..1deffb9 --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,86 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max + * + * 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. + */ + + +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXle_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (8 * i)), i++); + return r; +} + +/* Load unaligned n-byte integer (big-endian encoding) into uintXX_t */ +static inline uintXX_t osmo_loadXXbe_ext(const uint8_t *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + for(i = 0; i < n; r |= ((uintXX_t)p[i] << (XX - 8* (1 + i))), i++); + return r; +} + + +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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++); +} + +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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 */ + + +/* Load unaligned XX-bit integer (little-endian encoding) */ +static inline uintXX_t osmo_loadXXle(const uint8_t *p) +{ + return osmo_loadXXle_ext(p, XX / 8); +} + +/* Load unaligned XX-bit integer (big-endian encoding) */ +static inline uintXX_t osmo_loadXXbe(const uint8_t *p) +{ + return osmo_loadXXbe_ext(p, XX / 8); +} + + +/* Store unaligned XX-bit integer (little-endian encoding) */ +static inline void osmo_storeXXle(uintXX_t x, uint8_t *p) +{ + return osmo_storeXXle_ext(x, p, XX / 8); +} + +/* Store unaligned XX-bit integer (big-endian encoding) */ +static inline void osmo_storeXXbe(uintXX_t x, uint8_t *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..73ffaa6 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,7 +2,9 @@ #define _OSMO_BITS_H #include - +#include +#include +#include /*! \defgroup bits soft, unpacked and packed bits * @{ */ @@ -15,6 +17,37 @@ typedef int8_t sbit_t; /*!< \brief soft bit (-127...127) */ typedef uint8_t ubit_t; /*!< \brief unpacked bit (0 or 1) */ typedef uint8_t pbit_t; /*!< \brief packed bis (8 bits in a byte) */ +/* Load unaligned 16-bit integer (little-endian encoding) */ +static inline uint16_t osmo_load16le(const uint8_t *p) +{ + return p[0] | (p[1] << 8); +} + +/* Load unaligned 16-bit integer (big-endian encoding) */ +static inline uint16_t osmo_load16be(const uint8_t *p) +{ + return (p[0] << 8) | p[1]; +} + +/* Store unaligned 16-bit integer (little-endian encoding) */ +static inline void osmo_store16le(uint16_t a, uint8_t *p) +{ + p[0] = a & 0xFF; + p[1] = (a >> 8) & 0xFF; +} + +/* Store unaligned 16-bit integer (big-endian encoding) */ +static inline void osmo_store16be(uint16_t a, uint8_t *p) +{ + p[0] = (a >> 8) & 0xFF; + p[1] = a & 0xFF; +} + +/* + Less trivial LE/BE functions (24 bits and above) are autogenerated + see included bitXXgen.h files +*/ + /* NOTE on the endianess of pbit_t: Bits in a pbit_t are ordered MSB first, i.e. 0x80 is the first bit. @@ -73,6 +106,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 reverse the order of the bytes in a given buffer */ +void osmo_revbytes_buf(uint8_t *buf, size_t len); + +/* \brief left circular shift */ +static inline uint16_t rol16(uint16_t in, unsigned shift) +{ + return (in << shift) | (in >> (16 - shift)); +} + + /*! @} */ #endif /* _OSMO_BITS_H */ 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 #include #include +#include /*! \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..fc5a811 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,20 +1,192 @@ - +#include #include #include #include #include +#include +#include #include #include 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 -- 1.8.3.2 From max.suraev at fairwaves.co Thu Mar 13 20:36:51 2014 From: max.suraev at fairwaves.co (Max) Date: Thu, 13 Mar 2014 21:36:51 +0100 Subject: [PATCH 2/2] Add Kasumi cipher implementation In-Reply-To: <1394743011-2705-1-git-send-email-max.suraev@fairwaves.co> References: <1394743011-2705-1-git-send-email-max.suraev@fairwaves.co> Message-ID: <1394743011-2705-2-git-send-email-max.suraev@fairwaves.co> --- .gitignore | 1 + include/osmocom/gsm/kasumi.h | 34 ++++++++ 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, 387 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..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 + +/* + * 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 + * + * 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 +#include +#include + +/* 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 +#include +#include +#include +#include + +#include +#include +#include + +/* 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 -- 1.8.3.2 From Max.Suraev at fairwaves.co Thu Mar 13 23:13:01 2014 From: Max.Suraev at fairwaves.co (Max.Suraev at fairwaves.co) Date: Fri, 14 Mar 2014 00:13:01 +0100 Subject: [PATCH 1/2] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <1394743011-2705-1-git-send-email-max.suraev@fairwaves.co> References: <1394743011-2705-1-git-send-email-max.suraev@fairwaves.co> Message-ID: <53223B7D.1060405@fairwaves.co> Re-submit of my older patch to check that it works nicely with "git send-email" and patchwork. cheers, Max. From 246tnt at gmail.com Fri Mar 14 07:58:08 2014 From: 246tnt at gmail.com (Sylvain Munaut) Date: Fri, 14 Mar 2014 08:58:08 +0100 Subject: [PATCH 1/2] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <1394743011-2705-1-git-send-email-max.suraev@fairwaves.co> References: <1394743011-2705-1-git-send-email-max.suraev@fairwaves.co> Message-ID: Hi, > +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ > +static inline uintXX_t osmo_loadXXle_ext(const uint8_t *p, uint8_t n) Is "uint8_t *" the right type here ? I would think "void *" to be better. When loading from a msgb, sure we get uint8_t * (well unsigned char * actually, which just happen to match uint8_t on our architecture). But if you try to load a value from a struct pointer that might not be aligned, you'll get possibly a int16_t or something and you'll need an explicit cast. While casting to void * is implicit in C. like : struct test { int8_t foo; int16_t bar }; struct test *tp = (struct test *) msgb->data; /* Note that I'm not especially happy with the explicit cast here either ... data should be void* imho */ osmo_load16be(&tp->bar); vs osmo_load16be((uint8_t*)&tp->bar); Cheers, Sylvain From max.suraev at fairwaves.co Fri Mar 14 14:08:46 2014 From: max.suraev at fairwaves.co (Max) Date: Fri, 14 Mar 2014 15:08:46 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb Message-ID: <1394806126-20989-1-git-send-email-max.suraev@fairwaves.co> --- .gitignore | 3 +- include/Makefile.am | 7 ++ include/osmocom/core/bitXXgen.h.tpl | 88 +++++++++++++++ include/osmocom/core/bits.h | 15 ++- include/osmocom/core/msgb.h | 23 ++-- tests/bits/bitrev_test.c | 218 +++++++++++++++++++++++++++++++++++- tests/bits/bitrev_test.ok | 31 +++++ 7 files changed, 372 insertions(+), 13 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..65342d3 --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,88 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max + * + * 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. + */ + + +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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; +} + +/* Load unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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; +} + + +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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++); +} + +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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 */ + + +/* Load unaligned XX-bit integer (little-endian encoding) */ +static inline uintXX_t osmo_loadXXle(const void *p) +{ + return osmo_loadXXle_ext(p, XX / 8); +} + +/* Load unaligned XX-bit integer (big-endian encoding) */ +static inline uintXX_t osmo_loadXXbe(const void *p) +{ + return osmo_loadXXbe_ext(p, XX / 8); +} + + +/* 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); +} + +/* 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..157ea1f 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,7 +2,10 @@ #define _OSMO_BITS_H #include - +#include +#include +#include +#include /*! \defgroup bits soft, unpacked and packed bits * @{ */ @@ -73,6 +76,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 reverse the order of the bytes in a given buffer */ +void osmo_revbytes_buf(uint8_t *buf, size_t len); + +/* \brief left circular shift */ +static inline uint16_t rol16(uint16_t in, unsigned shift) +{ + return (in << shift) | (in >> (16 - shift)); +} + + /*! @} */ #endif /* _OSMO_BITS_H */ 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 #include #include +#include /*! \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..fc5a811 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,20 +1,192 @@ - +#include #include #include #include #include +#include +#include #include #include 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 -- 1.8.3.2 From Max.Suraev at fairwaves.co Fri Mar 14 14:14:30 2014 From: Max.Suraev at fairwaves.co (Max.Suraev at fairwaves.co) Date: Fri, 14 Mar 2014 15:14:30 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <1394806126-20989-1-git-send-email-max.suraev@fairwaves.co> References: <1394806126-20989-1-git-send-email-max.suraev@fairwaves.co> Message-ID: <53230EC6.2000208@fairwaves.co> Apparently subject is not enough - I should have added explicit reference so this version of patch would replace previous one. Oops. 14.03.2014 15:08, Max ?????: > --- > .gitignore | 3 +- > include/Makefile.am | 7 ++ > include/osmocom/core/bitXXgen.h.tpl | 88 +++++++++++++++ > include/osmocom/core/bits.h | 15 ++- > include/osmocom/core/msgb.h | 23 ++-- > tests/bits/bitrev_test.c | 218 +++++++++++++++++++++++++++++++++++- > tests/bits/bitrev_test.ok | 31 +++++ > 7 files changed, 372 insertions(+), 13 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..65342d3 > --- /dev/null > +++ b/include/osmocom/core/bitXXgen.h.tpl > @@ -0,0 +1,88 @@ > +/* > + * bitXXgen.h > + * > + * Copyright (C) 2014 Max > + * > + * 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. > + */ > + > + > +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ > +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; > +} > + > +/* Load unaligned n-byte integer (big-endian encoding) into uintXX_t */ > +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; > +} > + > + > +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ > +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++); > +} > + > +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ > +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 */ > + > + > +/* Load unaligned XX-bit integer (little-endian encoding) */ > +static inline uintXX_t osmo_loadXXle(const void *p) > +{ > + return osmo_loadXXle_ext(p, XX / 8); > +} > + > +/* Load unaligned XX-bit integer (big-endian encoding) */ > +static inline uintXX_t osmo_loadXXbe(const void *p) > +{ > + return osmo_loadXXbe_ext(p, XX / 8); > +} > + > + > +/* 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); > +} > + > +/* 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..157ea1f 100644 > --- a/include/osmocom/core/bits.h > +++ b/include/osmocom/core/bits.h > @@ -2,7 +2,10 @@ > #define _OSMO_BITS_H > > #include > - > +#include > +#include > +#include > +#include > /*! \defgroup bits soft, unpacked and packed bits > * @{ > */ > @@ -73,6 +76,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 reverse the order of the bytes in a given buffer */ > +void osmo_revbytes_buf(uint8_t *buf, size_t len); > + > +/* \brief left circular shift */ > +static inline uint16_t rol16(uint16_t in, unsigned shift) > +{ > + return (in << shift) | (in >> (16 - shift)); > +} > + > + > /*! @} */ > > #endif /* _OSMO_BITS_H */ > 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 > #include > #include > +#include > > /*! \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..fc5a811 100644 > --- a/tests/bits/bitrev_test.c > +++ b/tests/bits/bitrev_test.c > @@ -1,20 +1,192 @@ > - > +#include > #include > #include > #include > #include > +#include > +#include > > #include > #include > > 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 > From max.suraev at fairwaves.co Mon Mar 17 16:05:20 2014 From: max.suraev at fairwaves.co (Max) Date: Mon, 17 Mar 2014 17:05:20 +0100 Subject: [PATCH] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <1394806126-20989-1-git-send-email-max.suraev@fairwaves.co> References: <1394806126-20989-1-git-send-email-max.suraev@fairwaves.co> Message-ID: <1395072320-27958-1-git-send-email-max.suraev@fairwaves.co> --- .gitignore | 3 +- include/Makefile.am | 7 ++ include/osmocom/core/bitXXgen.h.tpl | 88 +++++++++++++++ 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, 362 insertions(+), 13 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..47998d1 --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,88 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max + * + * 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. + */ + + +/* Load unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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; +} + +/* Load unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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; +} + + +/* Store unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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++); +} + +/* Store unaligned n-byte integer (big-endian encoding) into uintXX_t */ +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 */ + + +/* Load unaligned XX-bit integer (little-endian encoding) */ +static inline uintXX_t osmo_loadXXle(const void *p) +{ + return osmo_loadXXle_ext(p, XX / 8); +} + +/* Load unaligned XX-bit integer (big-endian encoding) */ +static inline uintXX_t osmo_loadXXbe(const void *p) +{ + return osmo_loadXXbe_ext(p, XX / 8); +} + + +/* 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); +} + +/* 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..b1f4ed6 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,7 +2,10 @@ #define _OSMO_BITS_H #include - +#include +#include +#include +#include /*! \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 #include #include +#include /*! \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..fc5a811 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,20 +1,192 @@ - +#include #include #include #include #include +#include +#include #include #include 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 -- 1.8.3.2 From andrew at kiwidrew.com Mon Mar 17 13:22:44 2014 From: andrew at kiwidrew.com (Andrew Tipton) Date: Mon, 17 Mar 2014 21:22:44 +0800 Subject: Useful article on patching Nokia DCT4+ firmware Message-ID: Hi folks, Came across this article in the latest PoC||GTFO journal describing (part of) the process for patching firmware on Nokia DCT4+ phones. The good stuff is pages 22-29 of this file: http://openwall.info/wiki/_media/people/solar/pocorgtfo03.pdf Alas, this does not appear to permit patching the first 1MB of firmware, so may not be helpful for OsmocomBB. But perhaps someone with more time on their hands can take this and run with it... Cheers, -Andrew -------------- next part -------------- An HTML attachment was scrubbed... URL: From max.suraev at fairwaves.co Mon Mar 17 19:03:48 2014 From: max.suraev at fairwaves.co (Max) Date: Mon, 17 Mar 2014 20:03:48 +0100 Subject: [PATCH 1/3] Add generic LE/BE load/store uint type convertors and use them in msgb Message-ID: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> --- .gitignore | 3 +- include/Makefile.am | 7 ++ include/osmocom/core/bitXXgen.h.tpl | 85 ++++++++++++++ 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, 359 insertions(+), 13 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..528ff7a --- /dev/null +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -0,0 +1,85 @@ +/* + * bitXXgen.h + * + * Copyright (C) 2014 Max + * + * 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 */ +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 */ +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 */ +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 */ +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..b1f4ed6 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -2,7 +2,10 @@ #define _OSMO_BITS_H #include - +#include +#include +#include +#include /*! \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 #include #include +#include /*! \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 #include #include #include #include +#include +#include #include #include 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 -- 1.8.3.2 From max.suraev at fairwaves.co Mon Mar 17 19:03:49 2014 From: max.suraev at fairwaves.co (Max) Date: Mon, 17 Mar 2014 20:03:49 +0100 Subject: [PATCH 2/3] Add left circular shift function In-Reply-To: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> References: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> Message-ID: <1395083030-30425-2-git-send-email-max.suraev@fairwaves.co> --- include/osmocom/core/bits.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/osmocom/core/bits.h b/include/osmocom/core/bits.h index b1f4ed6..98a42f9 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -76,6 +76,15 @@ 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 + */ +static inline uint16_t osmo_rol16(uint16_t in, unsigned shift) +{ + return (in << shift) | (in >> (16 - shift)); +} + /*! @} */ #endif /* _OSMO_BITS_H */ -- 1.8.3.2 From 246tnt at gmail.com Tue Mar 18 06:37:30 2014 From: 246tnt at gmail.com (Sylvain Munaut) Date: Tue, 18 Mar 2014 07:37:30 +0100 Subject: [PATCH 2/3] Add left circular shift function In-Reply-To: <1395083030-30425-2-git-send-email-max.suraev@fairwaves.co> References: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> <1395083030-30425-2-git-send-email-max.suraev@fairwaves.co> Message-ID: Hi, > +/*! \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 > + */ Missing the \returns And yes, I know it's sometimes trivial but when processed by Doxygen you have everything nicely hyperlinked if you filled everything out. While you're at it, you could add the valid range to 'shift' doc (seems to be 0 to 16 included). Could seem obvious but at least it removes any doubt (that for example using negative would do a ror ... or that it would handle multiple complete rotation). Also please _wait_ until the next re-spin. I haven't looked at the third patch yet and haven't tried to actually _run_ them. I'm just sending this feedback know so that you know I'm looking at it, but since I've been away for 2 weeks, I have a bunch of stuff to catch up on. Cheers, Sylvain From max.suraev at fairwaves.co Mon Mar 17 19:03:50 2014 From: max.suraev at fairwaves.co (Max) Date: Mon, 17 Mar 2014 20:03:50 +0100 Subject: [PATCH 3/3] Add Kasumi cipher implementation In-Reply-To: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> References: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> Message-ID: <1395083030-30425-3-git-send-email-max.suraev@fairwaves.co> --- .gitignore | 1 + include/osmocom/gsm/kasumi.h | 32 ++++++++ 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, 385 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..c98652e --- /dev/null +++ b/include/osmocom/gsm/kasumi.h @@ -0,0 +1,32 @@ +/* + * KASUMI header + * + * See kasumi.c for details + * The parameters are described in TS 135 202. + */ + +#pragma once + +#include + +/* + * 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); + +/*! \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 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..c56f3ed --- /dev/null +++ b/src/gsm/kasumi.c @@ -0,0 +1,190 @@ +/* Kasumi cipher and KGcore functions */ + +/* (C) 2013 by Max + * + * 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 +#include +#include + +/* 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 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 +#include +#include +#include +#include + +#include +#include +#include + +/* 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 -- 1.8.3.2 From 246tnt at gmail.com Tue Mar 18 06:37:44 2014 From: 246tnt at gmail.com (Sylvain Munaut) Date: Tue, 18 Mar 2014 07:37:44 +0100 Subject: [PATCH 1/3] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> References: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> Message-ID: Hi Max, > > src/crc*gen.c > include/osmocom/core/crc*gen.h > - > +include/osmocom/core/bit*gen.h When inserting new line, I think trying to keep them alphabetically sorted by group is a nice touch. It doesn't matter here and no real need to change it, but it's just as a general remark for future patches or changes. > > +/*! \brief load unaligned n-byte integer (little-endian encoding) into uintXX_t */ > +static inline uintXX_t osmo_loadXXle_ext(const void *p, uint8_t n) When I said use Doxygen style, I mean the complete doc ... with param & returns and everything. If you want example of good doc, look at osmo-gmr ( eg, a random file http://git.osmocom.org/osmo-gmr/tree/src/sdr/pi4cxpsk.c ). Every function has full doc. For libosmocore or other projects it's not the case because of legacy code, but it is my strong belief that any addition of new code should adhere to the strictest standard to try and converge to a higer code quality and better coverage of the documentation. I know it's a pain, but if you do this from the beginning as something "automatic" like a reflex when writing the code in the first place, it doesn't take up all that much time. > +{ > + 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; > +} Any particular reason you went with this completely generic approach rather than just handling the few cases manually ? There is only a few of them. This is purely informational. I've confirmed that with -O2 the code is 'decent'. and with -O3 it's completely equivalent to hardcoded shift like they were before in msgb. > #include > - > +#include > +#include > +#include > +#include > /*! \defgroup bits soft, unpacked and packed bits > * @{ > */ Try not to change the original spacing without reason. Here there was a space after the include and the start of the code to make things more readable and less "compressed". Something like : ---- #include #include #include #include #include /*! \defgroup bits soft, unpacked and packed bits * @{ */ ----- Cheers, Sylvain From Max.Suraev at fairwaves.co Tue Mar 18 09:24:33 2014 From: Max.Suraev at fairwaves.co (Max.Suraev at fairwaves.co) Date: Tue, 18 Mar 2014 10:24:33 +0100 Subject: [PATCH 1/3] Add generic LE/BE load/store uint type convertors and use them in msgb In-Reply-To: References: <1395083030-30425-1-git-send-email-max.suraev@fairwaves.co> Message-ID: <532810D1.4070208@fairwaves.co> 18.03.2014 07:37, Sylvain Munaut ?????: > When inserting new line, I think trying to keep them alphabetically > sorted by group is a nice touch. > It doesn't matter here and no real need to change it, but it's just as > a general remark for future patches or changes. > I personally think grouping by similarity in function or style have more aesthetic value :) > Any particular reason you went with this completely generic approach > rather than just handling the few cases manually ? There is only a few > of them. > > This is purely informational. I've confirmed that with -O2 the code is > 'decent'. and with -O3 it's completely equivalent to hardcoded shift > like they were before in msgb. > It seems more readable this way, also copy-pasting and adjusting lots of similar but slightly different "boring" code proved to be error-prone. thanks, Max. From max.suraev at fairwaves.co Mon Mar 17 19:40:52 2014 From: max.suraev at fairwaves.co (Max) Date: Mon, 17 Mar 2014 20:40:52 +0100 Subject: [PATCH] Update GPRS cipher API to comply with ETSI TS 155.22 Message-ID: <1395085252-7428-1-git-send-email-max.suraev@fairwaves.co> --- include/osmocom/crypt/gprs_cipher.h | 8 ++++++-- src/gsm/gprs_cipher_core.c | 20 +++++++++++++++++--- src/gsm/libosmogsm.map | 1 + 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/include/osmocom/crypt/gprs_cipher.h b/include/osmocom/crypt/gprs_cipher.h index 3051071..b6b8e93 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 }; @@ -28,7 +29,7 @@ struct gprs_cipher_impl { /* As specified in 04.64 Annex A. Uses Kc, IV and direction * to generate the 1523 bytes cipher stream that need to be * XORed wit the plaintext for encrypt / ciphertext for decrypt */ - int (*run)(uint8_t *out, uint16_t len, uint64_t kc, uint32_t iv, + int (*run)(uint8_t *out, uint16_t len, uint8_t *kc, uint32_t iv, enum gprs_cipher_direction direction); }; @@ -40,11 +41,14 @@ int gprs_cipher_load(const char *path); /* function to be called by core code */ int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo, - uint64_t kc, uint32_t iv, enum gprs_cipher_direction dir); + uint8_t *kc, uint32_t iv, enum gprs_cipher_direction dir); /* Do we have an implementation for this cipher? */ int gprs_cipher_supported(enum gprs_ciph_algo algo); +/* Return key length for supported cipher, in bytes */ +unsigned gprs_cipher_key_length(enum gprs_ciph_algo algo); + /* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */ uint32_t gprs_cipher_gen_input_ui(uint32_t iov_ui, uint8_t sapi, uint32_t lfn, uint32_t oc); diff --git a/src/gsm/gprs_cipher_core.c b/src/gsm/gprs_cipher_core.c index b9a22a1..450272b 100644 --- a/src/gsm/gprs_cipher_core.c +++ b/src/gsm/gprs_cipher_core.c @@ -26,8 +26,8 @@ #include #include #include - #include +#include static LLIST_HEAD(gprs_ciphers); @@ -53,12 +53,14 @@ int gprs_cipher_register(struct gprs_cipher_impl *ciph) int gprs_cipher_load(const char *path) { /* load all plugins available from path */ - return osmo_plugin_load_all(path); + if (path) + return osmo_plugin_load_all(path); + return 0; } /* function to be called by core code */ int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo, - uint64_t kc, uint32_t iv, enum gprs_cipher_direction dir) + uint8_t *kc, uint32_t iv, enum gprs_cipher_direction dir) { if (algo >= ARRAY_SIZE(selected_ciphers)) return -ERANGE; @@ -73,6 +75,18 @@ int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo, return selected_ciphers[algo]->run(out, len, kc, iv, dir); } +unsigned gprs_cipher_key_length(enum gprs_ciph_algo algo) +{ + switch (algo) { + case GPRS_ALGO_GEA0: return 0; + case GPRS_ALGO_GEA1: return 8; + case GPRS_ALGO_GEA2: return 8; + case GPRS_ALGO_GEA3: return 8; + case GPRS_ALGO_GEA4: return 16; + default: return 0; + } +} + int gprs_cipher_supported(enum gprs_ciph_algo algo) { if (algo >= ARRAY_SIZE(selected_ciphers)) diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 3a4a643..3beb1e9 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -31,6 +31,7 @@ gprs_cipher_load; gprs_cipher_register; gprs_cipher_run; gprs_cipher_supported; +gprs_cipher_key_length; gprs_tlli_type; gprs_tmsi2tlli; -- 1.8.3.2 From admin at lishixin.net Tue Mar 18 08:45:30 2014 From: admin at lishixin.net (warriornew) Date: Tue, 18 Mar 2014 01:45:30 -0700 (PDT) Subject: file:/opt/webapps/r350/WEB-INF/classes/struts-retrain-showcase.xml:1224:98 Message-ID: <1395132330541-4026385.post@n3.nabble.com> Recently read some about the GSM CCCH SDCCH TS0 TS1 TS2 TS3 TS4 TS5 TS6 TS7 several data, seemed to understand a few, but about ccch_scan this program, it takes TS0 or??? -- View this message in context: http://baseband-devel.722152.n3.nabble.com/file-opt-webapps-r350-WEB-INF-classes-struts-retrain-showcase-xml-1224-98-tp4026385.html Sent from the baseband-devel mailing list archive at Nabble.com. From rdekema at gmail.com Sat Mar 22 03:39:27 2014 From: rdekema at gmail.com (Rusty Dekema) Date: Fri, 21 Mar 2014 23:39:27 -0400 Subject: Motorola C139 V1.9.24 Won't Load from osmocom-bb Message-ID: Greetings, I have a Motorola C139 handset with SW Ver 1.9.24 and a CP2102 USB/UART adapter, which I hope(d) to use with osmocom-bb. In Ubuntu 13.10 (running on [non-virtualized] hardware with an Intel i5-750 CPU), I compiled the toolchain, prerequisites, and osmocom-bb, but when I run the following command (and then briefly press the phone's power button) : ./osmocon -p /dev/ttyUSB0 -m c140 ../../target/firmware/board/compal_e86/loader.compalram.bin I get the following output: got 7 bytes from modem, data looks like: 66 74 6d 74 6f 6f 6c ftmtool Received FTMTOOL from phone, ramloader has aborted got 1 bytes from modem, data looks like: 65 e got 1 bytes from modem, data looks like: 72 r got 1 bytes from modem, data looks like: 72 r got 1 bytes from modem, data looks like: 6f o got 1 bytes from modem, data looks like: 72 r If I briefly press the power button repeatedly, I receive similar output. I would greatly appreciate any suggestions as to how I might be able to coax this into working. Thanks, Rusty D -------------- next part -------------- An HTML attachment was scrubbed... URL: From 246tnt at gmail.com Sat Mar 22 09:55:34 2014 From: 246tnt at gmail.com (Sylvain Munaut) Date: Sat, 22 Mar 2014 10:55:34 +0100 Subject: Motorola C139 V1.9.24 Won't Load from osmocom-bb In-Reply-To: References: Message-ID: Hi, > ./osmocon -p /dev/ttyUSB0 -m c140 > ../../target/firmware/board/compal_e86/loader.compalram.bin > > I get the following output: > > got 7 bytes from modem, data looks like: 66 74 6d 74 6f 6f 6c ftmtool > Received FTMTOOL from phone, ramloader has aborted > I would greatly appreciate any suggestions as to how I might be able to coax > this into working. Also, try the -c option (see bottom of http://bb.osmocom.org/trac/wiki/MotorolaC140 ) If that doesn't work you can try some of the other -m options If that still doesn't work, just get another phone and/or another cable. Seriously, the compal bootloader is a piece of shit, we can't do anything about it, and trying to remote debug serial loading issue is a waste of our time. If you want to debug it yourself, read the source of the osmocon tool to see what's _supposed_ to happen, then look at the raw bytes exchanged to see what happenned. Also look at the raw signal lines with scope and a logic analyzer to identify timing and signal integrity problems. If that doesn't yield anything you might need to dump the flash (how ? good question ... no idea what option there is without being able to load code. jtag, or chip unsoldering ?), and reverse engineer the boot loader to see what changed. Cheers, Sylain From msokolov at ivan.Harhan.ORG Mon Mar 31 08:53:52 2014 From: msokolov at ivan.Harhan.ORG (Michael Spacefalcon) Date: Mon, 31 Mar 2014 08:53:52 GMT Subject: Motorola C139 V1.9.24 Won't Load from osmocom-bb Message-ID: <1403310853.AA20927@ivan.Harhan.ORG> Sylvain Munaut <246tnt at gmail.com> wrote: > If that doesn't yield anything you might need to > dump the flash (how ? good question ... no idea what option there is > without being able to load code. jtag, or chip unsoldering ?), and > reverse engineer the boot loader to see what changed. I have just posted flash images read out of two C139s and one C140, along with an annotated disassembly of the bootloader and other reverse eng notes: ftp://ftp.ifctf.org/pub/GSM/Compal/ Hopefully someone will find it helpful... To the OP: in case you haven't already figured it out, you need to use -m c140xor with C139 and C140 phones. I don't know what phones would -m c140 (w/o xor) be correct for, if any. Sylvain's direction to use the -c option as well (and then use *.highram.bin instead of *.compalram.bin) is also correct, because the images are bigger than the ~15k max one can download w/o -c on this phone. Also you said your C139 came with fw version "V1.9.24" - are you sure it isn't V1.0.24 instead? The imprint on those stickers is a pain to read, too small... If your fw version is actually V1.0.24, then it is the exact same one I have just dumped and reverse-engineered. HTH, SF From Max.Suraev at fairwaves.co Wed Mar 26 17:26:12 2014 From: Max.Suraev at fairwaves.co (Max.Suraev at fairwaves.co) Date: Wed, 26 Mar 2014 18:26:12 +0100 Subject: GPL v2 vs v3 Message-ID: <53330DB4.1070308@fairwaves.co> Hi all. I've just noticed (yepp, I'm very observant :) that COPYING in libosmocore is GPLv2. Is there any particular reason we still do not use GPLv3? cheers, Max. From steve at steve-m.de Wed Mar 26 19:17:58 2014 From: steve at steve-m.de (Steve Markgraf) Date: Wed, 26 Mar 2014 20:17:58 +0100 Subject: GPL v2 vs v3 In-Reply-To: <53330DB4.1070308@fairwaves.co> References: <53330DB4.1070308@fairwaves.co> Message-ID: <533327E6.8090700@steve-m.de> Hi, On 26.03.2014 18:26, Max.Suraev at fairwaves.co wrote: > I've just noticed (yepp, I'm very observant :) that COPYING in libosmocore is GPLv2. > Is there any particular reason we still do not use GPLv3? Good point, git grep "either version 3" actually shows that there are quite some files that are GPLv3+, so the compiled and linked binaries already make use of the "or any later version" of the other GPLv2+ licensed files. So replacing COPYING with GPLv3 definitely would make sense imho. Regards, Steve From e10007a at gmail.com Mon Mar 31 11:12:13 2014 From: e10007a at gmail.com (Ahmad Jan) Date: Mon, 31 Mar 2014 16:12:13 +0500 Subject: Getting Started Message-ID: Its my 1st mail to the list. I m doing research on osmocom-bb from couple of days. Still m unable to understand what this software EXACTLY do. i.e. what are its applications. Can anyone help me out or share a much useful link which will help me understand the use/applications of this software? I'll be greatful -------------- next part -------------- An HTML attachment was scrubbed... URL: From e10007a at gmail.com Mon Mar 31 13:06:21 2014 From: e10007a at gmail.com (Ahmad Jan) Date: Mon, 31 Mar 2014 18:06:21 +0500 Subject: Required Ububtu Version Message-ID: I have ubuntu 10.04 installed on my system. Will the osmocom-bb work fine on this version or do i have to install some other version of ubutu on my system? -------------- next part -------------- An HTML attachment was scrubbed... URL: