--- .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 max.suraev@fairwaves.co + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! \brief load unaligned n-byte integer (little-endian encoding) into uintXX_t */ +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 <stdint.h> - +#include <stddef.h> +#include <osmocom/core/bit16gen.h> +#include <osmocom/core/bit32gen.h> +#include <osmocom/core/bit64gen.h> /*! \defgroup bits soft, unpacked and packed bits * @{ */ diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 33e8081..44a4c1e 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -23,6 +23,7 @@ #include <stdint.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/utils.h> +#include <osmocom/core/bits.h>
/*! \defgroup msgb Message buffers * @{ @@ -205,8 +206,7 @@ static inline void msgb_put_u8(struct msgb *msgb, uint8_t word) static inline void msgb_put_u16(struct msgb *msgb, uint16_t word) { uint8_t *space = msgb_put(msgb, 2); - space[0] = word >> 8 & 0xFF; - space[1] = word & 0xFF; + osmo_store16be(word, space); }
/*! \brief append a uint32 value to the end of the message @@ -216,10 +216,7 @@ static inline void msgb_put_u16(struct msgb *msgb, uint16_t word) static inline void msgb_put_u32(struct msgb *msgb, uint32_t word) { uint8_t *space = msgb_put(msgb, 4); - space[0] = word >> 24 & 0xFF; - space[1] = word >> 16 & 0xFF; - space[2] = word >> 8 & 0xFF; - space[3] = word & 0xFF; + osmo_store32be(word, space); }
/*! \brief remove data from end of message @@ -236,6 +233,7 @@ static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) msgb->len -= len; return tmp; } + /*! \brief remove uint8 from end of message * \param[in] msgb message buffer * \returns 8bit value taken from end of msgb @@ -245,6 +243,7 @@ static inline uint8_t msgb_get_u8(struct msgb *msgb) uint8_t *space = msgb_get(msgb, 1); return space[0]; } + /*! \brief remove uint16 from end of message * \param[in] msgb message buffer * \returns 16bit value taken from end of msgb @@ -252,8 +251,9 @@ static inline uint8_t msgb_get_u8(struct msgb *msgb) static inline uint16_t msgb_get_u16(struct msgb *msgb) { uint8_t *space = msgb_get(msgb, 2); - return space[0] << 8 | space[1]; + return osmo_load16be(space); } + /*! \brief remove uint32 from end of message * \param[in] msgb message buffer * \returns 32bit value taken from end of msgb @@ -261,7 +261,7 @@ static inline uint16_t msgb_get_u16(struct msgb *msgb) static inline uint32_t msgb_get_u32(struct msgb *msgb) { uint8_t *space = msgb_get(msgb, 4); - return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3]; + return osmo_load32be(space); }
/*! \brief prepend (push) some data to start of message @@ -285,6 +285,7 @@ static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) msgb->len += len; return msgb->data; } + /*! \brief remove (pull) a header from the front of the message buffer * \param[in] msgb message buffer * \param[in] len number of octets to be pulled @@ -324,6 +325,7 @@ static inline uint8_t msgb_pull_u8(struct msgb *msgb) uint8_t *space = msgb_pull(msgb, 1) - 1; return space[0]; } + /*! \brief remove uint16 from front of message * \param[in] msgb message buffer * \returns 16bit value taken from end of msgb @@ -331,8 +333,9 @@ static inline uint8_t msgb_pull_u8(struct msgb *msgb) static inline uint16_t msgb_pull_u16(struct msgb *msgb) { uint8_t *space = msgb_pull(msgb, 2) - 2; - return space[0] << 8 | space[1]; + return osmo_load16be(space); } + /*! \brief remove uint32 from front of message * \param[in] msgb message buffer * \returns 32bit value taken from end of msgb @@ -340,7 +343,7 @@ static inline uint16_t msgb_pull_u16(struct msgb *msgb) static inline uint32_t msgb_pull_u32(struct msgb *msgb) { uint8_t *space = msgb_pull(msgb, 4) - 4; - return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3]; + return osmo_load32be(space); }
/*! \brief Increase headroom of empty msgb, reducing the tailroom diff --git a/tests/bits/bitrev_test.c b/tests/bits/bitrev_test.c index 5eca990..e963656 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -1,20 +1,192 @@ - +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> +#include <time.h> +#include <stdbool.h>
#include <osmocom/core/utils.h> #include <osmocom/core/bits.h>
static const uint8_t input[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; static const uint8_t exp_out[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; +static char s[18]; + +enum END {LE, BE}; + +const char * end2str(enum END e) { + if (e == LE) return "LE"; + return "BE"; +} + + +/* convenience wrappers */ + +inline uint64_t load64(enum END e, const uint8_t *buf, unsigned nbytes) { + return (e == BE) ? osmo_load64be_ext(buf, nbytes) : osmo_load64le_ext(buf, nbytes); +} + +inline uint32_t load32(enum END e, const uint8_t *buf, unsigned nbytes) { + return (e == BE) ? osmo_load32be_ext(buf, nbytes) : osmo_load32le_ext(buf, nbytes); +} + +inline uint16_t load16(enum END e, const uint8_t *buf) { + return (e == BE) ? osmo_load16be(buf) : osmo_load16le(buf); +} + +inline void store64(enum END e, uint64_t t, uint8_t *buf, unsigned nbytes) { + (e == BE) ? osmo_store64be_ext(t, buf, nbytes) : osmo_store64le_ext(t, buf, nbytes); +} + +inline void store32(enum END e, uint64_t t, uint8_t *buf, unsigned nbytes) { + (e == BE) ? osmo_store32be_ext(t, buf, nbytes) : osmo_store32le_ext(t, buf, nbytes); +} + +inline void store16(enum END e, uint64_t t, uint8_t *buf) { + (e == BE) ? osmo_store16be(t, buf) : osmo_store16le(t, buf); +} + + +/* helper functions */ + +inline bool printcheck(bool chk, unsigned nbytes, enum END e, bool b) +{ + if (!chk) { + printf("%u %s FAILED", nbytes * 8, end2str(e)); + return true; + } + printf("%u %s OK", nbytes * 8, end2str(e)); + return b; +} + +inline bool dumpcheck(const char *dump, const char *s, unsigned nbytes, bool chk, enum END e, bool b) +{ + bool x = printcheck(chk, nbytes, e, b); + if (!dump) return x; + + int m = memcmp(s, dump, nbytes); + if (0 == m) { + printf(", storage OK"); + return x; + } + printf(", [%d]", m); + + return true; +} + + +/* printcheckXX(): load/store 'test' and check against 'expected' value, compare to 'dump' buffer if given and print if necessary */ + +inline void printcheck64(enum END e, unsigned nbytes, uint64_t test, uint64_t expected, const char *dump, bool print) +{ + uint8_t buf[nbytes]; + + store64(e, test, buf, nbytes); + + char *s = osmo_hexdump_nospc(buf, nbytes); + uint64_t result = load64(e, buf, nbytes); + + print = dumpcheck(dump, s, nbytes, result == expected, e, print); + + if (print) + printf(": buffer %s known buffer %s loaded %.16" PRIx64 " expected %.16" PRIx64, s, dump, result, expected); + printf("\n"); +} + +inline void printcheck32(enum END e, unsigned nbytes, uint32_t test, uint32_t expected, const char *dump, bool print) +{ + uint8_t buf[nbytes]; + + store32(e, test, buf, nbytes); + + char *s = osmo_hexdump_nospc(buf, nbytes); + uint32_t result = load32(e, buf, nbytes); + + print = dumpcheck(dump, s, nbytes, result == expected, e, print); + + if (print) + printf(": buffer %s known buffer %s loaded %.8" PRIx32 " expected %.8" PRIx32, s, dump, result, expected); + printf("\n"); +} + +inline void printcheck16(enum END e, uint32_t test, uint32_t expected, const char *dump, bool print) +{ + uint8_t buf[2]; + + store16(e, test, buf); + + char *s = osmo_hexdump_nospc(buf, 2); + uint16_t result = load16(e, buf); + + print = dumpcheck(dump, s, 2, result == expected, e, print); + + if (print) + printf(": buffer %s known buffer %s loaded %.4" PRIx16 " expected %.4" PRIx16, s, dump, result, expected); + printf("\n"); +} + + +/* compute expected value - zero excessive bytes */ + +inline uint64_t exp64(enum END e, unsigned nbytes, uint64_t value) { + uint8_t adj = 64 - nbytes * 8; + uint64_t v = value << adj; + return (e == LE) ? v >> adj : v; +} + +inline uint32_t exp32(enum END e, unsigned nbytes, uint32_t value) { + uint8_t adj = 32 - nbytes * 8; + uint32_t v = value << adj; + return (e == LE) ? v >> adj : v; +} + + +/* run actual tests - if 'test' is 0 than generate random test value internally */ + +inline void check64(uint64_t test, uint64_t expected, unsigned nbytes, enum END e) +{ + bool print = true; + if (0 == test && 0 == expected) { + test = ((uint64_t)rand() << 32) + rand(); + expected = exp64(e, nbytes, test); + print = false; + } + snprintf(s, 17, "%.16" PRIx64, expected); + printcheck64(e, nbytes, test, expected, (BE == e) ? s : NULL, print); +} + +inline void check32(uint32_t test, uint32_t expected, unsigned nbytes, enum END e) +{ + bool print = true; + if (0 == test && 0 == expected) { + test = rand(); + expected = exp32(e, nbytes, test); + print = false; + } + snprintf(s, 17, "%.8" PRIx32, expected); + printcheck32(e, nbytes, test, expected, (BE == e) ? s : NULL, print); +} + +inline void check16(uint16_t test, enum END e) +{ + bool print = true; + if (0 == test) { + test = (uint16_t)rand(); + print = false; + } + snprintf(s, 17, "%.4" PRIx16, test); + printcheck16(e, test, test, (BE == e) ? s : NULL, print); +} +
int main(int argc, char **argv) { uint8_t out[ARRAY_SIZE(input)]; unsigned int offs;
+ srand(time(NULL)); + for (offs = 0; offs < sizeof(out); offs++) { uint8_t *start = out + offs; uint8_t len = sizeof(out) - offs; @@ -32,5 +204,49 @@ int main(int argc, char **argv) printf("\n"); }
+ printf("checking byte packing...\n"); + + printf("running static tests...\n"); + + check64(0xDEADBEEFF00DCAFE, 0xDEADBEEFF00DCAFE, 8, BE); + check64(0xDEADBEEFF00DCAFE, 0xADBEEFF00DCAFE00, 7, BE); + check64(0xDEADBEEFF00DCAFE, 0xBEEFF00DCAFE0000, 6, BE); + check64(0xDEADBEEFF00DCAFE, 0xEFF00DCAFE000000, 5, BE); + + check64(0xDEADBEEFF00DCAFE, 0xDEADBEEFF00DCAFE, 8, LE); + check64(0xDEADBEEFF00DCAFE, 0x00ADBEEFF00DCAFE, 7, LE); + check64(0xDEADBEEFF00DCAFE, 0x0000BEEFF00DCAFE, 6, LE); + check64(0xDEADBEEFF00DCAFE, 0x000000EFF00DCAFE, 5, LE); + + check32(0xBABEFACE, 0xBABEFACE, 4, BE); + check32(0xBABEFACE, 0xBEFACE00, 3, BE); + + check32(0xBABEFACE, 0xBABEFACE, 4, LE); + check32(0xBABEFACE, 0x00BEFACE, 3, LE); + + check16(0xB00B, BE); + check16(0xB00B, LE); + + printf("running random tests...\n"); + + check64(0, 0, 8, BE); + check64(0, 0, 7, BE); + check64(0, 0, 6, BE); + check64(0, 0, 5, BE); + + check64(0, 0, 8, LE); + check64(0, 0, 7, LE); + check64(0, 0, 6, LE); + check64(0, 0, 5, LE); + + check32(0, 0, 4, BE); + check32(0, 0, 3, BE); + + check32(0, 0, 4, LE); + check32(0, 0, 3, LE); + + check16(0, BE); + check16(0, LE); + return 0; } diff --git a/tests/bits/bitrev_test.ok b/tests/bits/bitrev_test.ok index 47f402f..90cb295 100644 --- a/tests/bits/bitrev_test.ok +++ b/tests/bits/bitrev_test.ok @@ -22,3 +22,34 @@ REVERSED: 02 01 INORDER: 80 REVERSED: 01
+checking byte packing... +running static tests... +64 BE OK, storage OK: buffer deadbeeff00dcafe known buffer deadbeeff00dcafe loaded deadbeeff00dcafe expected deadbeeff00dcafe +56 BE OK, storage OK: buffer adbeeff00dcafe known buffer adbeeff00dcafe00 loaded adbeeff00dcafe00 expected adbeeff00dcafe00 +48 BE OK, storage OK: buffer beeff00dcafe known buffer beeff00dcafe0000 loaded beeff00dcafe0000 expected beeff00dcafe0000 +40 BE OK, storage OK: buffer eff00dcafe known buffer eff00dcafe000000 loaded eff00dcafe000000 expected eff00dcafe000000 +64 LE OK: buffer feca0df0efbeadde known buffer (null) loaded deadbeeff00dcafe expected deadbeeff00dcafe +56 LE OK: buffer feca0df0efbead known buffer (null) loaded 00adbeeff00dcafe expected 00adbeeff00dcafe +48 LE OK: buffer feca0df0efbe known buffer (null) loaded 0000beeff00dcafe expected 0000beeff00dcafe +40 LE OK: buffer feca0df0ef known buffer (null) loaded 000000eff00dcafe expected 000000eff00dcafe +32 BE OK, storage OK: buffer babeface known buffer babeface loaded babeface expected babeface +24 BE OK, storage OK: buffer beface known buffer beface00 loaded beface00 expected beface00 +32 LE OK: buffer cefabeba known buffer (null) loaded babeface expected babeface +24 LE OK: buffer cefabe known buffer (null) loaded 00beface expected 00beface +16 BE OK, storage OK: buffer b00b known buffer b00b loaded b00b expected b00b +16 LE OK: buffer 0bb0 known buffer (null) loaded b00b expected b00b +running random tests... +64 BE OK, storage OK +56 BE OK, storage OK +48 BE OK, storage OK +40 BE OK, storage OK +64 LE OK +56 LE OK +48 LE OK +40 LE OK +32 BE OK, storage OK +24 BE OK, storage OK +32 LE OK +24 LE OK +16 BE OK, storage OK +16 LE OK
--- include/osmocom/core/bits.h | 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 */
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
--- .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 <stdint.h> + +/* + * Single iteration of KASUMI cipher +*/ +uint64_t _kasumi(uint64_t P, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3); + +/*! \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 Max.Suraev@fairwaves.ru + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdint.h> +#include <osmocom/core/bits.h> +#include <osmocom/gsm/kasumi.h> + +/* See TS 135 202 for constants and full Kasumi spec. */ +inline static uint16_t kasumi_FI(uint16_t I, uint16_t skey) +{ + static const uint16_t S7[] = { + 54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18, 123, 33, + 55, 113, 39, 114, 21, 67, 65, 12, 47, 73, 46, 27, 25, 111, 124, 81, + 53, 9, 121, 79, 52, 60, 58, 48, 101, 127, 40, 120, 104, 70, 71, 43, + 20, 122, 72, 61, 23, 109, 13, 100, 77, 1, 16, 7, 82, 10, 105, 98, + 117, 116, 76, 11, 89, 106, 0,125,118, 99, 86, 69, 30, 57, 126, 87, + 112, 51, 17, 5, 95, 14, 90, 84, 91, 8, 35,103, 32, 97, 28, 66, + 102, 31, 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29, 115, 44, + 64, 107, 108, 24, 110, 83, 36, 78, 42, 19, 15, 41, 88, 119, 59, 3 + }; + static const uint16_t S9[] = { + 167, 239, 161, 379, 391, 334, 9, 338, 38, 226, 48, 358, 452, 385, 90, 397, + 183, 253, 147, 331, 415, 340, 51, 362, 306, 500, 262, 82, 216, 159, 356, 177, + 175, 241, 489, 37, 206, 17, 0, 333, 44, 254, 378, 58, 143, 220, 81, 400, + 95, 3, 315, 245, 54, 235, 218, 405, 472, 264, 172, 494, 371, 290, 399, 76, + 165, 197, 395, 121, 257, 480, 423, 212, 240, 28, 462, 176, 406, 507, 288, 223, + 501, 407, 249, 265, 89, 186, 221, 428,164, 74, 440, 196, 458, 421, 350, 163, + 232, 158, 134, 354, 13, 250, 491, 142,191, 69, 193, 425, 152, 227, 366, 135, + 344, 300, 276, 242, 437, 320, 113, 278, 11, 243, 87, 317, 36, 93, 496, 27, + 487, 446, 482, 41, 68, 156, 457, 131, 326, 403, 339, 20, 39, 115, 442, 124, + 475, 384, 508, 53, 112, 170, 479, 151, 126, 169, 73, 268, 279, 321, 168, 364, + 363, 292, 46, 499, 393, 327, 324, 24, 456, 267, 157, 460, 488, 426, 309, 229, + 439, 506, 208, 271, 349, 401, 434, 236, 16, 209, 359, 52, 56, 120, 199, 277, + 465, 416, 252, 287, 246, 6, 83, 305, 420, 345, 153,502, 65, 61, 244, 282, + 173, 222, 418, 67, 386, 368, 261, 101, 476, 291, 195,430, 49, 79, 166, 330, + 280, 383, 373, 128, 382, 408, 155, 495, 367, 388, 274, 107, 459, 417, 62, 454, + 132, 225, 203, 316, 234, 14, 301, 91, 503, 286, 424, 211, 347, 307, 140, 374, + 35, 103, 125, 427, 19, 214, 453, 146, 498, 314, 444, 230, 256, 329, 198, 285, + 50, 116, 78, 410, 10, 205, 510, 171, 231, 45, 139, 467, 29, 86, 505, 32, + 72, 26, 342, 150, 313, 490, 431, 238, 411, 325, 149, 473, 40, 119, 174, 355, + 185, 233, 389, 71, 448, 273, 372, 55, 110, 178, 322, 12, 469, 392, 369, 190, + 1, 109, 375, 137, 181, 88, 75, 308, 260, 484, 98, 272, 370, 275, 412, 111, + 336, 318, 4, 504, 492, 259, 304, 77, 337, 435, 21, 357, 303, 332, 483, 18, + 47, 85, 25, 497, 474, 289, 100, 269, 296, 478, 270, 106, 31, 104, 433, 84, + 414, 486, 394, 96, 99, 154, 511, 148, 413, 361, 409, 255, 162, 215, 302, 201, + 266, 351, 343, 144, 441, 365, 108, 298, 251, 34, 182, 509, 138, 210, 335, 133, + 311, 352, 328, 141, 396, 346, 123, 319, 450, 281, 429, 228, 443, 481, 92, 404, + 485, 422, 248, 297, 23, 213, 130, 466, 22, 217, 283, 70, 294, 360, 419, 127, + 312, 377, 7, 468, 194, 2, 117, 295, 463, 258, 224, 447, 247, 187, 80, 398, + 284, 353, 105, 390, 299, 471, 470, 184, 57, 200, 348, 63, 204, 188, 33, 451, + 97, 30, 310, 219, 94, 160, 129, 493, 64, 179, 263, 102, 189, 207, 114, 402, + 438, 477, 387, 122, 192, 42, 381, 5, 145, 118, 180, 449, 293, 323, 136, 380, + 43, 66, 60, 455, 341, 445, 202, 432, 8, 237, 15, 376, 436, 464, 59, 461 + }; + uint16_t L, R; + + /* Split 16 bit input into two unequal halves: 9 and 7 bits, same for subkey */ + L = I >> 7; /* take 9 bits */ + R = I & 0x7F; /* take 7 bits */ + + L = S9[L] ^ R; + R = S7[R] ^ (L & 0x7F); + + L ^= (skey & 0x1FF); + R ^= (skey >> 9); + + L = S9[L] ^ R; + R = S7[R] ^ (L & 0x7F); + + return (R << 9) + L; +} + +inline static uint32_t kasumi_FO(uint32_t I, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3, unsigned i) +{ + uint16_t L = I >> 16, R = I; /* Split 32 bit input into Left and Right parts */ + + L ^= KOi1[i]; + L = kasumi_FI(L, KIi1[i]); + L ^= R; + + R ^= KOi2[i]; + R = kasumi_FI(R, KIi2[i]); + R ^= L; + + L ^= KOi3[i]; + L = kasumi_FI(L, KIi3[i]); + L ^= R; + + return (((uint32_t)R) << 16) + L; +} + +inline static uint32_t kasumi_FL(uint32_t I, const uint16_t *KLi1, const uint16_t *KLi2, unsigned i) +{ + uint16_t L = I >> 16, R = I, tmp; /* Split 32 bit input into Left and Right parts */ + + tmp = L & KLi1[i]; + R ^= osmo_rol16(tmp, 1); + + tmp = R | KLi2[i]; + L ^= osmo_rol16(tmp, 1); + + return (((uint32_t)L) << 16) + R; +} + +uint64_t _kasumi(uint64_t P, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3) +{ + uint32_t i, L = P >> 32, R = P; /* Split 64 bit input into Left and Right parts */ + + for (i = 0; i < 8; i++) { + R ^= kasumi_FO(kasumi_FL(L, KLi1, KLi2, i), KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i); /* odd round */ + i++; + L ^= kasumi_FL(kasumi_FO(R, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i), KLi1, KLi2, i); /* even round */ + } + return (((uint64_t)L) << 32) + R; /* Concatenate Left and Right 32 bits into 64 bit ciphertext */ +} + +/*! \brief Expand key into set of subkeys + * \param[in] key (128 bits) as array of bytes + * \param[out] arrays of round-specific subkeys - see TS 135 202 for details + */ +void _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3) +{ + uint16_t i, C[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, 0xFEDC, 0xBA98, 0x7654, 0x3210 }; + + /* Work with 16 bit subkeys and create prime subkeys */ + for (i = 0; i < 8; i++) + C[i] ^= osmo_load16be(key + i * 2); + /* C[] now stores K-prime[] */ + + /* Create round-specific subkeys */ + for (i = 0; i < 8; i++) { + KLi1[i] = osmo_rol16(osmo_load16be(key + i * 2), 1); + KLi2[i] = C[(i + 2) & 0x7]; + + KOi1[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 1)) & 0xE)), 5); + KOi2[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 5)) & 0xE)), 8); + KOi3[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 6)) & 0xE)), 13); + + KIi1[i] = C[(i + 4) & 0x7]; + KIi2[i] = C[(i + 3) & 0x7]; + KIi3[i] = C[(i + 7) & 0x7]; + } +} + +void _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck, uint8_t *co, uint16_t cl) +{ + uint16_t KLi1[8], KLi2[8], KOi1[8], KOi2[8], KOi3[8], KIi1[8], KIi2[8], KIi3[8], i; + uint64_t A = ((uint64_t)cc) << 32, BLK = 0, _ca = ((uint64_t)CA << 16) ; + A |= _ca; + _ca = (uint64_t)((cb << 3) | (cd << 2)) << 24; + A |= _ca; + /* Register loading complete: see TR 55.919 8.2 and TS 55.216 3.2 */ + + uint8_t ck_km[16]; + for (i = 0; i < 16; i++) + ck_km[i] = ck[i] ^ 0x55; + /* Modified key established */ + + /* preliminary round with modified key */ + _kasumi_key_expand(ck_km, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); + A = _kasumi(A, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); + + /* Run Kasumi in OFB to obtain enough data for gamma. */ + _kasumi_key_expand(ck, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); + + /* i is a block counter */ + for (i = 0; i < cl / 64 + 1; i++) { + BLK = _kasumi(A ^ i ^ BLK, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); + osmo_store64be(BLK, co + (i * 8)); + } +} diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 9d15d66..3a4a643 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -196,6 +196,10 @@ osmo_a5; osmo_a5_1; osmo_a5_2;
+_kasumi; +_kasumi_key_expand; +_kasumi_kgcore; + osmo_auth_alg_name; osmo_auth_alg_parse; osmo_auth_gen_vec; diff --git a/tests/Makefile.am b/tests/Makefile.am index c6216d5..ddc13dc 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,7 +4,7 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ smscb/smscb_test bits/bitrev_test a5/a5_test \ conv/conv_test auth/milenage_test lapd/lapd_test \ gsm0808/gsm0808_test gsm0408/gsm0408_test \ - gb/bssgp_fc_test gb/gprs_ns_test \ + gb/bssgp_fc_test gb/gprs_ns_test kasumi/kasumi_test \ logging/logging_test fr/fr_test \ loggingrb/loggingrb_test strrb/strrb_test \ vty/vty_test comp128/comp128_test utils/utils_test @@ -19,6 +19,9 @@ utils_utils_test_LDADD = $(top_builddir)/src/libosmocore.la a5_a5_test_SOURCES = a5/a5_test.c a5_a5_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
+kasumi_kasumi_test_SOURCES = kasumi/kasumi_test.c +kasumi_kasumi_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la + comp128_comp128_test_SOURCES = comp128/comp128_test.c comp128_comp128_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
@@ -102,7 +105,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ lapd/lapd_test.ok gsm0408/gsm0408_test.ok \ gsm0808/gsm0808_test.ok gb/bssgp_fc_tests.err \ gb/bssgp_fc_tests.ok gb/bssgp_fc_tests.sh \ - gb/gprs_ns_test.ok \ + gb/gprs_ns_test.ok kasumi/kasumi_test.ok \ msgfile/msgfile_test.ok msgfile/msgconfig.cfg \ logging/logging_test.ok logging/logging_test.err \ fr/fr_test.ok loggingrb/logging_test.ok \ diff --git a/tests/kasumi/kasumi_test.c b/tests/kasumi/kasumi_test.c new file mode 100644 index 0000000..9101407 --- /dev/null +++ b/tests/kasumi/kasumi_test.c @@ -0,0 +1,136 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> + +#include <osmocom/core/bits.h> +#include <osmocom/core/utils.h> +#include <osmocom/gsm/kasumi.h> + +/* Test vectors are taken from TS 135 202 */ + +inline int _compare_mem(uint8_t * x, uint8_t * y, size_t len) +{ + if (0 != memcmp(x, y, len)) { + printf ("X: %s\t", osmo_hexdump_nospc(x, len)); + printf ("Y: %s\n", osmo_hexdump_nospc(y, len)); + return 0; + } + return 1; +} + +inline static void test_expansion(uint8_t * test_key, uint16_t * _KLi1, uint16_t * _KLi2, uint16_t * _KOi1, uint16_t * _KOi2, uint16_t * _KOi3, uint16_t * _KIi1, uint16_t * _KIi2, uint16_t * _KIi3, uint16_t * _KLi1_r, uint16_t * _KLi2_r, uint16_t * _KOi1_r, uint16_t * _KOi2_r, uint16_t * _KOi3_r, uint16_t * _KIi1_r, uint16_t * _KIi2_r, uint16_t * _KIi3_r) +{ + _kasumi_key_expand(test_key, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3); + int passed = 1; + passed = _compare_mem((uint8_t *)_KLi1, (uint8_t *)_KLi1_r, 16); + passed = _compare_mem((uint8_t *)_KLi2, (uint8_t *)_KLi2_r, 16); + passed = _compare_mem((uint8_t *)_KOi1, (uint8_t *)_KOi1_r, 16); + passed = _compare_mem((uint8_t *)_KOi2, (uint8_t *)_KOi2_r, 16); + passed = _compare_mem((uint8_t *)_KOi3, (uint8_t *)_KOi3_r, 16); + passed = _compare_mem((uint8_t *)_KIi1, (uint8_t *)_KIi1_r, 16); + passed = _compare_mem((uint8_t *)_KIi2, (uint8_t *)_KIi2_r, 16); + passed = _compare_mem((uint8_t *)_KIi3, (uint8_t *)_KIi3_r, 16); + printf(passed ? " OK. " : "FAILED!"); +} + +int main(int argc, char **argv) +{ + uint16_t _KLi1[8], _KLi2[8], _KOi1[8], _KOi2[8], _KOi3[8], _KIi1[8], _KIi2[8], _KIi3[8], _KLi1_r[8], _KLi2_r[8], _KOi1_r[8], _KOi2_r[8], _KOi3_r[8], _KIi1_r[8], _KIi2_r[8], _KIi3_r[8]; + + printf("testing KASUMI key expansion and encryption (ETSI TS 135 203):\n"); + printf("KASUMI Test Set 1..."); + + uint8_t _test_key1[] = {0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48}; + _KLi1_r[0] = 0x57AC; _KLi1_r[1] = 0x8B3E; _KLi1_r[2] = 0x058B; _KLi1_r[3] = 0x6601; _KLi1_r[4] = 0x2A59; _KLi1_r[5] = 0x9220; _KLi1_r[6] = 0x9102; _KLi1_r[7] = 0xFE91; + _KLi2_r[0] = 0x0B6E; _KLi2_r[1] = 0x7EEF; _KLi2_r[2] = 0x6BF0; _KLi2_r[3] = 0xF388; _KLi2_r[4] = 0x3ED5; _KLi2_r[5] = 0xCD58; _KLi2_r[6] = 0x2AF5; _KLi2_r[7] = 0x00F8; + _KOi1_r[0] = 0xB3E8; _KOi1_r[1] = 0x58B0; _KOi1_r[2] = 0x6016; _KOi1_r[3] = 0xA592; _KOi1_r[4] = 0x2209; _KOi1_r[5] = 0x1029; _KOi1_r[6] = 0xE91F; _KOi1_r[7] = 0x7AC5; + _KOi2_r[0] = 0x1049; _KOi2_r[1] = 0x8148; _KOi2_r[2] = 0x48FF; _KOi2_r[3] = 0xD62B; _KOi2_r[4] = 0x9F45; _KOi2_r[5] = 0xC582; _KOi2_r[6] = 0x00B3; _KOi2_r[7] = 0x2C95; + _KOi3_r[0] = 0x2910; _KOi3_r[1] = 0x1FE9; _KOi3_r[2] = 0xC57A; _KOi3_r[3] = 0xE8B3; _KOi3_r[4] = 0xB058; _KOi3_r[5] = 0x1660; _KOi3_r[6] = 0x92A5; _KOi3_r[7] = 0x0922; + _KIi1_r[0] = 0x6BF0; _KIi1_r[1] = 0xF388; _KIi1_r[2] = 0x3ED5; _KIi1_r[3] = 0xCD58; _KIi1_r[4] = 0x2AF5; _KIi1_r[5] = 0x00F8; _KIi1_r[6] = 0x0B6E; _KIi1_r[7] = 0x7EEF; + _KIi2_r[0] = 0x7EEF; _KIi2_r[1] = 0x6BF0; _KIi2_r[2] = 0xF388; _KIi2_r[3] = 0x3ED5; _KIi2_r[4] = 0xCD58; _KIi2_r[5] = 0x2AF5; _KIi2_r[6] = 0x00F8; _KIi2_r[7] = 0x0B6E; + _KIi3_r[0] = 0xCD58; _KIi3_r[1] = 0x2AF5; _KIi3_r[2] = 0x00F8; _KIi3_r[3] = 0x0B6E; _KIi3_r[4] = 0x7EEF; _KIi3_r[5] = 0x6BF0; _KIi3_r[6] = 0xF388; _KIi3_r[7] = 0x3ED5; + test_expansion(_test_key1, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3, _KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r); + + if (0xDF1F9B251C0BF45F == _kasumi(0xEA024714AD5C4D84, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3)) + printf("OK."); + else + printf("FAILED!"); + + printf("\nKASUMI Test Set 2..."); + + uint8_t _test_key2[] = {0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, 0x1F, 0x3D, 0xE8, 0xA6, 0xDC, 0x66, 0xB1, 0xF3}; + _KLi1_r[0] = 0x19C7; _KLi1_r[1] = 0x7C58; _KLi1_r[2] = 0x8781; _KLi1_r[3] = 0x6BF9; _KLi1_r[4] = 0x3E7A; _KLi1_r[5] = 0xD14D; _KLi1_r[6] = 0xB8CD; _KLi1_r[7] = 0x63E7; + _KLi2_r[0] = 0x4A6B; _KLi2_r[1] = 0x7813; _KLi2_r[2] = 0xE1E1; _KLi2_r[3] = 0x523E; _KLi2_r[4] = 0xAA32; _KLi2_r[5] = 0x83E3; _KLi2_r[6] = 0x8DC0; _KLi2_r[7] = 0x7B4B; + _KOi1_r[0] = 0xC587; _KOi1_r[1] = 0x7818; _KOi1_r[2] = 0xBF96; _KOi1_r[3] = 0xE7A3; _KOi1_r[4] = 0x14DD; _KOi1_r[5] = 0x8CDB; _KOi1_r[6] = 0x3E76; _KOi1_r[7] = 0x9C71; + _KOi2_r[0] = 0xA6E8; _KOi2_r[1] = 0x66DC; _KOi2_r[2] = 0xF3B1; _KOi2_r[3] = 0xE38C; _KOi2_r[4] = 0x2C3E; _KOi2_r[5] = 0xC0C3; _KOi2_r[6] = 0xFCB5; _KOi2_r[7] = 0x3D1F; + _KOi3_r[0] = 0xDB8C; _KOi3_r[1] = 0x763E; _KOi3_r[2] = 0x719C; _KOi3_r[3] = 0x87C5; _KOi3_r[4] = 0x1878; _KOi3_r[5] = 0x96BF; _KOi3_r[6] = 0xA3E7; _KOi3_r[7] = 0xDD14; + _KIi1_r[0] = 0xE1E1; _KIi1_r[1] = 0x523E; _KIi1_r[2] = 0xAA32; _KIi1_r[3] = 0x83E3; _KIi1_r[4] = 0x8DC0; _KIi1_r[5] = 0x7B4B; _KIi1_r[6] = 0x4A6B; _KIi1_r[7] = 0x7813; + _KIi2_r[0] = 0x7813; _KIi2_r[1] = 0xE1E1; _KIi2_r[2] = 0x523E; _KIi2_r[3] = 0xAA32; _KIi2_r[4] = 0x83E3; _KIi2_r[5] = 0x8DC0; _KIi2_r[6] = 0x7B4B; _KIi2_r[7] = 0x4A6B; + _KIi3_r[0] = 0x83E3; _KIi3_r[1] = 0x8DC0; _KIi3_r[2] = 0x7B4B; _KIi3_r[3] = 0x4A6B; _KIi3_r[4] = 0x7813; _KIi3_r[5] = 0xE1E1; _KIi3_r[6] = 0x523E; _KIi3_r[7] = 0xAA32; + test_expansion(_test_key2, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3, _KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r); + + if (0xDE551988CEB2F9B7 == _kasumi(0xD3C5D592327FB11C, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3)) + printf("OK."); + else + printf("FAILED!"); + + printf("\nKASUMI Test Set 3..."); + + uint8_t _test_key3[] = {0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1, 0xA8, 0xFF, 0x86, 0x67, 0xB1, 0x71, 0x40, 0x13}; + _KLi1_r[0] = 0x806A; _KLi1_r[1] = 0x8CD1; _KLi1_r[2] = 0x15F0; _KLi1_r[3] = 0x8DA3; _KLi1_r[4] = 0x51FF; _KLi1_r[5] = 0x0CCF; _KLi1_r[6] = 0x62E3; _KLi1_r[7] = 0x8026; + _KLi2_r[0] = 0x8353; _KLi2_r[1] = 0x0B3E; _KLi2_r[2] = 0x5623; _KLi2_r[3] = 0x3CFF; _KLi2_r[4] = 0xC725; _KLi2_r[5] = 0x7203; _KLi2_r[6] = 0x4116; _KLi2_r[7] = 0x830F; + _KOi1_r[0] = 0xCD18; _KOi1_r[1] = 0x5F01; _KOi1_r[2] = 0xDA38; _KOi1_r[3] = 0x1FF5; _KOi1_r[4] = 0xCCF0; _KOi1_r[5] = 0x2E36; _KOi1_r[6] = 0x0268; _KOi1_r[7] = 0x06A8; + _KOi2_r[0] = 0x6786; _KOi2_r[1] = 0x71B1; _KOi2_r[2] = 0x1340; _KOi2_r[3] = 0x3540; _KOi2_r[4] = 0x68C6; _KOi2_r[5] = 0xF80A; _KOi2_r[6] = 0xD1C6; _KOi2_r[7] = 0xFFA8; + _KOi3_r[0] = 0x362E; _KOi3_r[1] = 0x6802; _KOi3_r[2] = 0xA806; _KOi3_r[3] = 0x18CD; _KOi3_r[4] = 0x015F; _KOi3_r[5] = 0x38DA; _KOi3_r[6] = 0xF51F; _KOi3_r[7] = 0xF0CC; + _KIi1_r[0] = 0x5623; _KIi1_r[1] = 0x3CFF; _KIi1_r[2] = 0xC725; _KIi1_r[3] = 0x7203; _KIi1_r[4] = 0x4116; _KIi1_r[5] = 0x830F; _KIi1_r[6] = 0x8353; _KIi1_r[7] = 0x0B3E; + _KIi2_r[0] = 0x0B3E; _KIi2_r[1] = 0x5623; _KIi2_r[2] = 0x3CFF; _KIi2_r[3] = 0xC725; _KIi2_r[4] = 0x7203; _KIi2_r[5] = 0x4116; _KIi2_r[6] = 0x830F; _KIi2_r[7] = 0x8353; + _KIi3_r[0] = 0x7203; _KIi3_r[1] = 0x4116; _KIi3_r[2] = 0x830F; _KIi3_r[3] = 0x8353; _KIi3_r[4] = 0x0B3E; _KIi3_r[5] = 0x5623; _KIi3_r[6] = 0x3CFF; _KIi3_r[7] = 0xC725; + test_expansion(_test_key3, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3, _KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r); + + if (0x4592B0E78690F71B == _kasumi(0x62A540981BA6F9B7, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3)) + printf("OK."); + else + printf("FAILED!"); + + printf("\nKASUMI Test Set 4..."); + uint8_t _test_key4[] = {0x3A, 0x3B, 0x39, 0xB5, 0xC3, 0xF2, 0x37, 0x6D, 0x69, 0xF7, 0xD5, 0x46, 0xE5, 0xF8, 0x5D, 0x43}; + uint64_t I4 = 0xCA49C1C75771AB0B, i; + _kasumi_key_expand(_test_key4, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3); + + for (i = 0; i < 50; i++) + I4 = _kasumi(I4, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3); + + if (0x738BAD4C4A690802 == I4) printf(" OK.\n"); else printf("FAILED!"); + + + uint8_t gamma[32]; + + uint8_t _Key1[] = {0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xBC, 0x00, 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xBC, 0x00}, + _gamma1[] = {0x88, 0x9E, 0xEA, 0xAF, 0x9E, 0xD1, 0xBA, 0x1A, 0xBB, 0xD8, 0x43, 0x62, 0x32, 0xE4, 0x57, 0x28, 0xD0, 0x1A, 0xA8, 0x91, 0x33, 0xDA, 0x73, 0xC1, 0x1E, 0xAB, 0x68, 0xB7, 0xD8, 0x9B, 0xC8, 0x41}; + _kasumi_kgcore(0xF, 0, 0x0024F20F, 0, _Key1, gamma, 228); + printf ("KGCORE Test Set 1: %d\n", _compare_mem(gamma, _gamma1, 32)); + + uint8_t _Key2[] = {0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48}, + _gamma2[] = {0xFB, 0x4D, 0x5F, 0xBC, 0xEE, 0x13, 0xA3, 0x33, 0x89, 0x28, 0x56, 0x86, 0xE9, 0xA5, 0xC9, 0x42, 0x40, 0xDE, 0x38, 0x15, 0x01, 0x15, 0xF1, 0x5F, 0x8D, 0x9D, 0x98, 0xB9, 0x1A, 0x94, 0xB2, 0x96}; + _kasumi_kgcore(0xF, 0, 0x00061272, 0, _Key2, gamma, 228); + printf ("KGCORE Test Set 2: %d\n", _compare_mem(gamma, _gamma2, 32)); + + uint8_t _Key3[] = {0xEF, 0xA8, 0xB2, 0x22, 0x9E, 0x72, 0x0C, 0x2A, 0xEF, 0xA8, 0xB2, 0x22, 0x9E, 0x72, 0x0C, 0x2A}, + _gamma3[] = {0x0E, 0x40, 0x15, 0x75, 0x5A, 0x33, 0x64, 0x69, 0xC3, 0xDD, 0x86, 0x80, 0xE3, 0x03, 0x5B, 0xC4, 0x19, 0xA7, 0x8A, 0xD3, 0x86, 0x2C, 0x10, 0x90, 0xC6, 0x8A, 0x39, 0x1F, 0xE8, 0xA6, 0xAD, 0xEB}; + _kasumi_kgcore(0xF, 0, 0x0033FD3F, 0, _Key3, gamma, 228); + printf ("KGCORE Test Set 3: %d\n", _compare_mem(gamma, _gamma3, 32)); + + uint8_t _Key4[] = {0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D, 0x51, 0x20, 0x4E, 0xA5, 0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D}, + _gamma4[] = {0xE0, 0x95, 0x30, 0x6A, 0xD5, 0x08, 0x6E, 0x2E, 0xAC, 0x7F, 0x31, 0x07, 0xDE, 0x4F, 0xA2, 0x2D, 0xC1, 0xDF, 0xC9, 0x7D, 0x5B, 0xC5, 0x66, 0x1D, 0xD6, 0x09, 0x6F, 0x47, 0x6A, 0xED, 0xC6, 0x4B}; + _kasumi_kgcore(0xF, 0, 0x00156B26, 0, _Key4, gamma, 228); + printf ("KGCORE Test Set 4: %d\n", _compare_mem(gamma, _gamma4, 32)); + + uint8_t _Key5[] = {0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, 0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1}, + _gamma5[] = {0xDC, 0xE6, 0x43, 0x62, 0xAB, 0x5F, 0x89, 0xC1, 0x1E, 0xF0, 0xB3, 0x05, 0x16, 0x65, 0x70, 0xF4, 0x88, 0x9D, 0x55, 0x11, 0xE9, 0xE3, 0x57, 0x5D, 0x06, 0x2B, 0x5C, 0xED, 0x60, 0x39, 0x50, 0x6A}; + _kasumi_kgcore(0xF, 0, 0x000A59B4, 0, _Key5, gamma, 228); + printf ("KGCORE Test Set 5: %d\n", _compare_mem(gamma, _gamma5, 32)); + + return 0; +} diff --git a/tests/kasumi/kasumi_test.ok b/tests/kasumi/kasumi_test.ok new file mode 100644 index 0000000..2c2af4c --- /dev/null +++ b/tests/kasumi/kasumi_test.ok @@ -0,0 +1,10 @@ +testing KASUMI key expansion and encryption (ETSI TS 135 203): +KASUMI Test Set 1... OK. OK. +KASUMI Test Set 2... OK. OK. +KASUMI Test Set 3... OK. OK. +KASUMI Test Set 4... OK. +KGCORE Test Set 1: 1 +KGCORE Test Set 2: 1 +KGCORE Test Set 3: 1 +KGCORE Test Set 4: 1 +KGCORE Test Set 5: 1 diff --git a/tests/testsuite.at b/tests/testsuite.at index 9124f25..7ce2ee8 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -9,6 +9,12 @@ cat $abs_srcdir/a5/a5_test.ok > expout AT_CHECK([$abs_top_builddir/tests/a5/a5_test], [0], [expout]) AT_CLEANUP
+AT_SETUP([kasumi]) +AT_KEYWORDS([kasumi]) +cat $abs_srcdir/kasumi/kasumi_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/kasumi/kasumi_test], [0], [expout]) +AT_CLEANUP + AT_SETUP([bits]) AT_KEYWORDS([bits]) cat $abs_srcdir/bits/bitrev_test.ok > expout
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 <stdint.h>
+#include <stddef.h> +#include <osmocom/core/bit16gen.h> +#include <osmocom/core/bit32gen.h> +#include <osmocom/core/bit64gen.h> /*! \defgroup bits soft, unpacked and packed bits
- @{
*/
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 <stddef.h> #include <stdint.h> #include <osmocom/core/bit16gen.h> #include <osmocom/core/bit32gen.h> #include <osmocom/core/bit64gen.h>
/*! \defgroup bits soft, unpacked and packed bits * @{ */ -----
Cheers,
Sylvain
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.
baseband-devel@lists.osmocom.org