From 43640a6e4d574c1c5a99a89a3ab6742b83b2183f Mon Sep 17 00:00:00 2001 From: Piotr Krysik Date: Sat, 27 Jun 2009 13:18:13 +0200 Subject: added dirty tch/f decoding to gsm-receiver (which also should be removed in the future) --- INSTALL | 2 +- Makefile.am | 16 +- Makefile.common | 15 +- bootstrap | 2 +- configure.ac | 10 +- src/lib/Makefile.am | 10 +- src/lib/decoder/Makefile.am | 28 ++- src/lib/decoder/a5-1-2.c | 429 ----------------------------------------- src/lib/gsm.i | 2 +- src/lib/gsm_constants.h | 7 +- src/lib/gsm_receiver_cf.cc | 163 ++++++++++++++-- src/lib/gsm_receiver_cf.h | 31 ++- src/python/gsm_receive.py | 7 +- src/python/gsm_receive_usrp.py | 2 +- 14 files changed, 225 insertions(+), 499 deletions(-) delete mode 100644 src/lib/decoder/a5-1-2.c diff --git a/INSTALL b/INSTALL index b9fb61c..314b196 100644 --- a/INSTALL +++ b/INSTALL @@ -9,5 +9,5 @@ Under Ubuntu 9.04 install: To build the GSM Receiver use: $ ./bootstrap $ cd debug - $ ./configure + $ ../configure $ make diff --git a/Makefile.am b/Makefile.am index 863aebb..734941a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,17 +3,11 @@ include $(top_srcdir)/Makefile.common SUBDIRS = src config DIST_SUBDIRS = src config -#EXTRA_DIST = \ -# bootstrap \ -# configure \ -# config.h.in -# gsm-receiver.pc.in - -#pkgconfigdir = $(libdir)/pkgconfig -#pkgconfig_DATA = gsm-receiver.pc - EXTRA_DIST = \ - gsm-receiver.pc.in - + configure \ + gsm-receiver.pc.in \ + config.h.in +# bootstrap + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = gsm-receiver.pc diff --git a/Makefile.common b/Makefile.common index e662909..0b88813 100644 --- a/Makefile.common +++ b/Makefile.common @@ -19,15 +19,20 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # -DECODER_INCLUDEDIR = $(top_srcdir)/src/lib/decoder -MAIN_INCLUDEDIR = $(top_srcdir)/src/lib -#STD_DEFINES_AND_INCLUDES = \ -# -I$(DECODER_INCLUDEDIR) \ -# -I$(MAIN_INCLUDEDIR) +#!! remove this +TCH_DECODER_INCLUDEDIR = $(top_srcdir)/src/lib/decoder/openbtsstuff +MAIN_INCLUDEDIR = $(top_srcdir)/src/lib +DECODER_INCLUDEDIR = $(top_srcdir)/src/lib/decoder DECODER_LA = $(top_builddir)/src/lib/decoder/libdecoder.la +STD_DEFINES_AND_INCLUDES = \ + -I$(DECODER_INCLUDEDIR) \ + -I$(MAIN_INCLUDEDIR) \ + -I$(GNURADIO_CORE_INCLUDEDIR) \ + -I$(TCH_DECODER_INCLUDEDIR) + # includes grincludedir = $(includedir)/gnuradio diff --git a/bootstrap b/bootstrap index 350e0ff..7e0a2eb 100755 --- a/bootstrap +++ b/bootstrap @@ -29,4 +29,4 @@ libtoolize --automake automake --add-missing if test ! -d debug; then mkdir debug -fi \ No newline at end of file +fi diff --git a/configure.ac b/configure.ac index 709ac12..30fe57a 100644 --- a/configure.ac +++ b/configure.ac @@ -99,7 +99,8 @@ GR_REQUIRE_BOOST_INCLUDES STD_DEFINES_AND_INCLUDES="$GNURADIO_CORE_CFLAGS $BOOST_CFLAGS" AC_SUBST(STD_DEFINES_AND_INCLUDES) - + + AC_CONFIG_FILES([\ Makefile \ config/Makefile \ @@ -107,10 +108,11 @@ AC_CONFIG_FILES([\ src/lib/Makefile \ src/lib/decoder/Makefile \ src/python/Makefile \ - gsm-receiver.pc + src/lib/decoder/openbtsstuff/Makefile \ + gsm-receiver.pc \ ]) -# doc/Makefile \ -# src/python/run_tests \ +dnl # doc/Makefile \ +dnl # src/python/run_tests \ dnl run_tests is created from run_tests.in. Make it executable. #AC_CONFIG_COMMANDS([run_tests], [chmod +x src/python/run_tests]) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 91819fa..925eaca 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -29,7 +29,8 @@ SUBDIRS = decoder ourpythondir = $(grpythondir) ourlibdir = $(grpyexecdir) -AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES) -I$(DECODER_INCLUDEDIR) +AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES) +# -I$(OPEN_BTS_INCLUDES) SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(SWIGGRFLAGS) $(WITH_SWIG_INCLUDES) \ $(WITH_INCLUDES) @@ -76,11 +77,10 @@ _gsm_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version # link the library against some comon swig runtime code and the # c++ standard library _gsm_la_LIBADD = \ - $(PYTHON_LDFLAGS) \ - libgsmdemod.la \ + $(PYTHON_LDFLAGS) \ + libgsmdemod.la \ -lstdc++ \ - decoder/libdecoder.la -# $(DECODER_LA) + $(DECODER_LA) #libgsmdemod_la_LIBADD = diff --git a/src/lib/decoder/Makefile.am b/src/lib/decoder/Makefile.am index 1ad7899..1726d68 100644 --- a/src/lib/decoder/Makefile.am +++ b/src/lib/decoder/Makefile.am @@ -21,28 +21,36 @@ include $(top_srcdir)/Makefile.common -AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) -I$(MAIN_INCLUDEDIR) +AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) + +SUBDIRS = openbtsstuff noinst_LTLIBRARIES = libdecoder.la +libdecoder_la_LIBADD = \ + openbtsstuff/libopenbtsdecoder.la + libdecoder_la_SOURCES = \ sch.c \ cch.c \ fire_crc.c \ gsmstack.c \ + interleave.c \ out_pcap.c \ - tun.c \ - interleave.c - -noinst_HEADERS = \ - sch.h \ + tun.c +# tch.c \ +# conv.c + +noinst_HEADERS = \ + sch.h \ cch.h \ fire_crc.h \ gsmstack.h \ interleave.h \ - system.h \ out_pcap.h \ tun.h \ - gsmtap.h - -# burst_types.h + system.h \ + gsmtap.h \ + a5-1-2.h +# tch.h \ +# conv.h diff --git a/src/lib/decoder/a5-1-2.c b/src/lib/decoder/a5-1-2.c deleted file mode 100644 index 64370d2..0000000 --- a/src/lib/decoder/a5-1-2.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * A pedagogical implementation of the GSM A5/1 and A5/2 "voice privacy" - * encryption algorithms. - * - * Copyright (C) 1998-1999: Marc Briceno, Ian Goldberg, and David Wagner - * - * The source code below is optimized for instructional value and clarity. - * Performance will be terrible, but that's not the point. - * - * This software may be export-controlled by US law. - * - * This software is free for commercial and non-commercial use as long as - * the following conditions are adhered to. - * Copyright remains the authors' and as such any Copyright notices in - * the code are not to be removed. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The license and distribution terms for any publicly available version - * or derivative of this code cannot be changed. i.e. this code cannot - * simply be copied and put under another distribution license - * [including the GNU Public License]. - * - * Background: The Global System for Mobile communications is the most - * widely deployed digital cellular telephony system in the world. GSM - * makes use of four core cryptographic algorithms, none of which has - * been published by the GSM MOU. This failure to subject the - * algorithms to public review is all the more puzzling given that over - * 215 million GSM subscribers are expected to rely on the claimed - * security of the system. - * - * The four core GSM cryptographic algorithms are: - * A3 authentication algorithm - * A5/1 "stronger" over-the-air voice-privacy algorithm - * A5/2 "weaker" over-the-air voice-privacy algorithm - * A8 voice-privacy key generation algorithm - * - * In April of 1998, our group showed that COMP128, the algorithm used by the - * overwhelming majority of GSM providers for both A3 and A8 functionality - * is fatally flawed and allows for cloning of GSM mobile phones. - * - * Furthermore, we demonstrated that all A8 implementations we could locate, - * including the few that did not use COMP128 for key generation, had been - * deliberately weakened by reducing the keyspace from 64 bits to 54 bits. - * The remaining 10 bits are simply set to zero! - * - * See http://www.scard.org/gsm for additional information. - * - * [May 1999] - * One question so far unanswered is if A5/1, the "stronger" of the two - * widely deployed voice-privacy algorithm is at least as strong as the - * key. Meaning: "Does A5/1 have a work factor of at least 54 bits"? - * Absent a publicly available A5/1 reference implementation, this question - * could not be answered. We hope that our reference implementation below, - * which has been verified against official A5/1 test vectors, will provide - * the cryptographic community with the base on which to construct the - * answer to this important question. - * - * Initial indications about the strength of A5/1 are not encouraging. - * A variant of A5, while not A5/1 itself, has been estimated to have a - * work factor of well below 54 bits. See http://jya.com/crack-a5.htm for - * background information and references. - * - * With COMP128 broken and A5/1 published below, we will now turn our - * attention to A5/2. - * - * [August 1999] - * 19th Annual International Cryptology Conference - Crypto'99 - * Santa Barbara, California - * - * A5/2 has been added to the previously published A5/1 source. Our - * implementation has been verified against official test vectors. - * - * This means that our group has now reverse engineered the entire set - * of cryptographic algorithms used in the overwhelming majority of GSM - * installations, including all the over-the-air "voice privacy" algorithms. - * - * The "voice privacy" algorithm A5/2 proved especially weak. Which perhaps - * should come as no surprise, since even GSM MOU members have admitted that - * A5/2 was designed with heavy input by intelligence agencies to ensure - * breakability. Just how insecure is A5/2? It can be broken in real time - * with a work factor of a mere 16 bits. GSM might just as well use no "voice - * privacy" algorithm at all. - * - * We announced the break of A5/2 at the Crypto'99 Rump Session. - * Details will be published in a scientific paper following soon. - * - * - * -- Marc Briceno - * Voice: +1 (925) 798-4042 - * - */ - - -#include - - -/* Masks for the shift registers */ -#define R1MASK 0x07FFFF /* 19 bits, numbered 0..18 */ -#define R2MASK 0x3FFFFF /* 22 bits, numbered 0..21 */ -#define R3MASK 0x7FFFFF /* 23 bits, numbered 0..22 */ -#ifdef A5_2 -#define R4MASK 0x01FFFF /* 17 bits, numbered 0..16 */ -#endif /* A5_2 */ - - -#ifndef A5_2 -/* Middle bit of each of the three shift registers, for clock control */ -#define R1MID 0x000100 /* bit 8 */ -#define R2MID 0x000400 /* bit 10 */ -#define R3MID 0x000400 /* bit 10 */ -#else /* A5_2 */ -/* A bit of R4 that controls each of the shift registers */ -#define R4TAP1 0x000400 /* bit 10 */ -#define R4TAP2 0x000008 /* bit 3 */ -#define R4TAP3 0x000080 /* bit 7 */ -#endif /* A5_2 */ - - -/* Feedback taps, for clocking the shift registers. - * These correspond to the primitive polynomials - * x^19 + x^5 + x^2 + x + 1, x^22 + x + 1, - * x^23 + x^15 + x^2 + x + 1, and x^17 + x^5 + 1. */ - - -#define R1TAPS 0x072000 /* bits 18,17,16,13 */ -#define R2TAPS 0x300000 /* bits 21,20 */ -#define R3TAPS 0x700080 /* bits 22,21,20,7 */ -#ifdef A5_2 -#define R4TAPS 0x010800 /* bits 16,11 */ -#endif /* A5_2 */ - - -typedef unsigned char byte; -typedef unsigned long word; -typedef word bit; - - -/* Calculate the parity of a 32-bit word, i.e. the sum of its bits modulo 2 -*/ -bit parity(word x) { - x ^= x>>16; - x ^= x>>8; - x ^= x>>4; - x ^= x>>2; - x ^= x>>1; - return x&1; -} - - -/* Clock one shift register. For A5/2, when the last bit of the frame - * is loaded in, one particular bit of each register is forced to '1'; - * that bit is passed in as the last argument. */ -#ifndef A5_2 -word clockone(word reg, word mask, word taps) { -#else /* A5_2 */ -word clockone(word reg, word mask, word taps, word loaded_bit) { -#endif /* A5_2 */ - word t = reg & taps; - reg = (reg << 1) & mask; - reg |= parity(t); -#ifdef A5_2 - reg |= loaded_bit; -#endif /* A5_2 */ - return reg; -} - - -/* The three shift registers. They're in global variables to make the code - * easier to understand. - * A better implementation would not use global variables. */ -word R1, R2, R3; -#ifdef A5_2 -word R4; -#endif /* A5_2 */ - - -/* Return 1 iff at least two of the parameter words are non-zero. */ -bit majority(word w1, word w2, word w3) { - int sum = (w1 != 0) + (w2 != 0) + (w3 != 0); - if (sum >= 2) - return 1; - else - return 0; -} - - -/* Clock two or three of R1,R2,R3, with clock control - * according to their middle bits. - * Specifically, we clock Ri whenever Ri's middle bit - * agrees with the majority value of the three middle bits. For A5/2, - * use particular bits of R4 instead of the middle bits. Also, for A5/2, - * always clock R4. - * If allP == 1, clock all three of R1,R2,R3, ignoring their middle bits. - * This is only used for key setup. If loaded == 1, then this is the last - * bit of the frame number, and if we're doing A5/2, we have to set a - * particular bit in each of the four registers. */ -void clock(int allP, int loaded) { -#ifndef A5_2 - bit maj = majority(R1&R1MID, R2&R2MID, R3&R3MID); - if (allP || (((R1&R1MID)!=0) == maj)) - R1 = clockone(R1, R1MASK, R1TAPS); - if (allP || (((R2&R2MID)!=0) == maj)) - R2 = clockone(R2, R2MASK, R2TAPS); - if (allP || (((R3&R3MID)!=0) == maj)) - R3 = clockone(R3, R3MASK, R3TAPS); -#else /* A5_2 */ - bit maj = majority(R4&R4TAP1, R4&R4TAP2, R4&R4TAP3); - if (allP || (((R4&R4TAP1)!=0) == maj)) - R1 = clockone(R1, R1MASK, R1TAPS, loaded<<15); - if (allP || (((R4&R4TAP2)!=0) == maj)) - R2 = clockone(R2, R2MASK, R2TAPS, loaded<<16); - if (allP || (((R4&R4TAP3)!=0) == maj)) - R3 = clockone(R3, R3MASK, R3TAPS, loaded<<18); - R4 = clockone(R4, R4MASK, R4TAPS, loaded<<10); -#endif /* A5_2 */ -} - - -/* Generate an output bit from the current state. - * You grab a bit from each register via the output generation taps; - * then you XOR the resulting three bits. For A5/2, in addition to - * the top bit of each of R1,R2,R3, also XOR in a majority function - * of three particular bits of the register (one of them complemented) - * to make it non-linear. Also, for A5/2, delay the output by one - * clock cycle for some reason. */ -bit getbit() { - bit topbits = (((R1 >> 18) ^ (R2 >> 21) ^ (R3 >> 22)) & 0x01); -#ifndef A5_2 - return topbits; -#else /* A5_2 */ - static bit delaybit = 0; - bit nowbit = delaybit; - delaybit = ( - topbits - ^ majority(R1&0x8000, (~R1)&0x4000, R1&0x1000) - ^ majority((~R2)&0x10000, R2&0x2000, R2&0x200) - ^ majority(R3&0x40000, R3&0x10000, (~R3)&0x2000) - ); - return nowbit; -#endif /* A5_2 */ -} - - -/* Do the A5 key setup. This routine accepts a 64-bit key and - * a 22-bit frame number. */ -void keysetup(byte key[8], word frame) { - int i; - bit keybit, framebit; - - - /* Zero out the shift registers. */ - R1 = R2 = R3 = 0; -#ifdef A5_2 - R4 = 0; -#endif /* A5_2 */ - - - /* Load the key into the shift registers, - * LSB of first byte of key array first, - * clocking each register once for every - * key bit loaded. (The usual clock - * control rule is temporarily disabled.) */ - for (i=0; i<64; i++) { - clock(1,0); /* always clock */ - keybit = (key[i/8] >> (i&7)) & 1; /* The i-th bit of the key */ - R1 ^= keybit; R2 ^= keybit; R3 ^= keybit; -#ifdef A5_2 - R4 ^= keybit; -#endif /* A5_2 */ - } - - - /* Load the frame number into the shift registers, LSB first, - * clocking each register once for every key bit loaded. - * (The usual clock control rule is still disabled.) - * For A5/2, signal when the last bit is being clocked in. */ - for (i=0; i<22; i++) { - clock(1,i==21); /* always clock */ - framebit = (frame >> i) & 1; /* The i-th bit of the frame # */ - R1 ^= framebit; R2 ^= framebit; R3 ^= framebit; -#ifdef A5_2 - R4 ^= framebit; -#endif /* A5_2 */ - } - - - /* Run the shift registers for 100 clocks - * to mix the keying material and frame number - * together with output generation disabled, - * so that there is sufficient avalanche. - * We re-enable the majority-based clock control - * rule from now on. */ - for (i=0; i<100; i++) { - clock(0,0); - } - /* For A5/2, we have to load the delayed output bit. This does _not_ - * change the state of the registers. For A5/1, this is a no-op. */ - getbit(); - - - /* Now the key is properly set up. */ -} - - -/* Generate output. We generate 228 bits of - * keystream output. The first 114 bits is for - * the A->B frame; the next 114 bits is for the - * B->A frame. You allocate a 15-byte buffer - * for each direction, and this function fills - * it in. */ -void run(byte AtoBkeystream[], byte BtoAkeystream[]) { - int i; - - - /* Zero out the output buffers. */ - for (i=0; i<=113/8; i++) - AtoBkeystream[i] = BtoAkeystream[i] = 0; - - - /* Generate 114 bits of keystream for the - * A->B direction. Store it, MSB first. */ - for (i=0; i<114; i++) { - clock(0,0); - AtoBkeystream[i/8] |= getbit() << (7-(i&7)); - } - - - /* Generate 114 bits of keystream for the - * B->A direction. Store it, MSB first. */ - for (i=0; i<114; i++) { - clock(0,0); - BtoAkeystream[i/8] |= getbit() << (7-(i&7)); - } -} - - -/* Test the code by comparing it against - * a known-good test vector. */ -void test() { -#ifndef A5_2 - byte key[8] = {0x12, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - word frame = 0x134; - byte goodAtoB[15] = { 0x53, 0x4E, 0xAA, 0x58, 0x2F, 0xE8, 0x15, - 0x1A, 0xB6, 0xE1, 0x85, 0x5A, 0x72, 0x8C, 0x00 }; - byte goodBtoA[15] = { 0x24, 0xFD, 0x35, 0xA3, 0x5D, 0x5F, 0xB6, - 0x52, 0x6D, 0x32, 0xF9, 0x06, 0xDF, 0x1A, 0xC0 }; -#else /* A5_2 */ - byte key[8] = {0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - word frame = 0x21; - byte goodAtoB[15] = { 0xf4, 0x51, 0x2c, 0xac, 0x13, 0x59, 0x37, - 0x64, 0x46, 0x0b, 0x72, 0x2d, 0xad, 0xd5, 0x00 }; - byte goodBtoA[15] = { 0x48, 0x00, 0xd4, 0x32, 0x8e, 0x16, 0xa1, - 0x4d, 0xcd, 0x7b, 0x97, 0x22, 0x26, 0x51, 0x00 }; -#endif /* A5_2 */ - byte AtoB[15], BtoA[15]; - int i, failed=0; - - - keysetup(key, frame); - run(AtoB, BtoA); - - - /* Compare against the test vector. */ - for (i=0; i<15; i++) - if (AtoB[i] != goodAtoB[i]) - failed = 1; - for (i=0; i<15; i++) - if (BtoA[i] != goodBtoA[i]) - failed = 1; - - - /* Print some debugging output. */ - printf("key: 0x"); - for (i=0; i<8; i++) - printf("%02X", key[i]); - printf("\n"); - printf("frame number: 0x%06X\n", (unsigned int)frame); - printf("known good output:\n"); - printf(" A->B: 0x"); - for (i=0; i<15; i++) - printf("%02X", goodAtoB[i]); - printf(" B->A: 0x"); - for (i=0; i<15; i++) - printf("%02X", goodBtoA[i]); - printf("\n"); - printf("observed output:\n"); - printf(" A->B: 0x"); - for (i=0; i<15; i++) - printf("%02X", AtoB[i]); - printf(" B->A: 0x"); - for (i=0; i<15; i++) - printf("%02X", BtoA[i]); - printf("\n"); - - - if (!failed) { - printf("Self-check succeeded: everything looks ok.\n"); - exit(0); - } else { - /* Problems! The test vectors didn't compare*/ - printf("\nI don't know why this broke; contact the authors.\n"); - } -} - - -int main(void) { - test(); - return 0; -} \ No newline at end of file diff --git a/src/lib/gsm.i b/src/lib/gsm.i index b5a33f2..3a5c561 100644 --- a/src/lib/gsm.i +++ b/src/lib/gsm.i @@ -38,7 +38,7 @@ GR_SWIG_BLOCK_MAGIC(gsm,receiver_cf); -gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr); +gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); class gsm_receiver_cf : public gr_block { diff --git a/src/lib/gsm_constants.h b/src/lib/gsm_constants.h index 74d2e2e..939099d 100644 --- a/src/lib/gsm_constants.h +++ b/src/lib/gsm_constants.h @@ -9,10 +9,11 @@ #define GUARD_BITS 8 #define GUARD_FRACTIONAL 0.25 //fractional part of guard period #define GUARD_PERIOD GUARD_BITS + GUARD_FRACTIONAL -#define DATA_BITS 58 //size of 1 data block in normal burst +#define DATA_BITS 57 //size of 1 data block in normal burst +#define STEALING_BIT 1 #define N_TRAIN_BITS 26 #define N_SYNC_BITS 64 -#define USEFUL_BITS 142 //(2*DATA_BITS + N_TRAIN_BITS ) +#define USEFUL_BITS 142 //(2*(DATA_BITS+STEALING_BIT) + N_TRAIN_BITS ) #define FCCH_BITS USEFUL_BITS #define BURST_SIZE (USEFUL_BITS+2*TAIL_BITS) @@ -22,7 +23,7 @@ #define FRAME_BITS (TS_PER_FRAME * TS_BITS + 2) // 156.25 * 8 #define FCCH_POS TAIL_BITS #define SYNC_POS 39 -#define TRAIN_POS ( TAIL_BITS + DATA_BITS + 5) //first 5 bits of a training sequence +#define TRAIN_POS ( TAIL_BITS + (DATA_BITS+STEALING_BIT) + 5) //first 5 bits of a training sequence //aren't used for channel impulse response estimation #define TRAIN_BEGINNING 5 #define SAFETY_MARGIN 6 // diff --git a/src/lib/gsm_receiver_cf.cc b/src/lib/gsm_receiver_cf.cc index f94e303..4742b33 100644 --- a/src/lib/gsm_receiver_cf.cc +++ b/src/lib/gsm_receiver_cf.cc @@ -33,21 +33,102 @@ #include #include #include +#include #include + +#include "RxBurst.h" +#include "GSMCommon.h" + #define SYNC_SEARCH_RANGE 30 -#define TRAIN_SEARCH_RANGE 40 +// #define TRAIN_SEARCH_RANGE 40 +//FIXME: decide to use this define or not //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready +void decrypt(const unsigned char * burst_binary, byte * KC, float * decrypted_data, unsigned FN) +{ + byte AtoB[2*DATA_BITS]; + + keysetup(KC, FN); + runA51(AtoB); + + for (int i = 0; i < 148; i++) { + decrypted_data[i] = burst_binary[i]; + } + + for (int i = 0; i < 57; i++) { + decrypted_data[i+3] = AtoB[i] ^ burst_binary[i+3]; + } + + for (int i = 0; i < 57; i++) { + decrypted_data[i+88] = AtoB[i+57] ^ burst_binary[i+88]; + } +} + +void gsm_receiver_cf::read_key(std::string key) +{ + int i; + int b; + for (i = 0;i < 8;i++) { + b = d_hex_to_int[(char)key[(i)*2]]*16 + d_hex_to_int[(char)key[i*2+1]]; + d_KC[i] = (byte)b; + } +} + void gsm_receiver_cf::process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary) { - if (burst_nr.get_timeslot_nr() == 0) { -// printf(" %2d %6x %6x", burst_nr.get_t2(), burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod()); -// for (int i = 0; i < BURST_SIZE ; i++) { -// printf(" %d", burst_binary[i]); -// } -// std::cout << "\n"; -// std::cout << " bcc: " << d_bcc << "\n"; +// static byte KC[] = { 0xAD, 0x6A, 0x3E, 0xC2, 0xB4, 0x42, 0xE4, 0x00 }; +// static byte KC[] = { 0x2B, 0x08, 0x74, 0x9F, 0xDD, 0x0D, 0x9C, 0x00 }; +// printf("%x", KC[0]); + float decrypted_data[148]; + unsigned char * voice_frame; + +// if (burst_nr.get_timeslot_nr() == 7) { + if (burst_nr.get_timeslot_nr() >= 1 && burst_nr.get_timeslot_nr() <= 7) { + decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod()); + + GSM::Time time(burst_nr.get_frame_nr(), burst_nr.get_timeslot_nr()); + GSM::RxBurst rxbrst(decrypted_data, time); + switch (burst_nr.get_timeslot_nr()) { + case 1: + if ( d_tch_decoder1.processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder1.get_voice_frame(), 1 , 33, d_gsm_file); + } + break; + case 2: + if ( d_tch_decoder2.processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder2.get_voice_frame(), 1 , 33, d_gsm_file); + } + break; + case 3: + if ( d_tch_decoder3.processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder3.get_voice_frame(), 1 , 33, d_gsm_file); + } + break; + case 4: + if ( d_tch_decoder4.processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder4.get_voice_frame(), 1 , 33, d_gsm_file); + } + break; + case 5: + if ( d_tch_decoder5.processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder5.get_voice_frame(), 1 , 33, d_gsm_file); + } + break; + case 6: + if ( d_tch_decoder6.processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder6.get_voice_frame(), 1 , 33, d_gsm_file); + } + break; + case 7: + if ( d_tch_decoder7.processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder7.get_voice_frame(), 1 , 33, d_gsm_file); + } + break; + } + } + + if (burst_nr.get_timeslot_nr() == 0) { GS_process(&d_gs_ctx, TIMESLOT0, 6, &burst_binary[3], burst_nr.get_frame_nr()); } } @@ -59,8 +140,24 @@ void gsm_receiver_cf::configure_receiver() d_channel_conf.set_burst_types(TSC0, TEST_CCH_FRAMES, sizeof(TEST_CCH_FRAMES) / sizeof(unsigned), normal_burst); d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); + d_channel_conf.set_multiframe_type(TIMESLOT1, multiframe_26); + d_channel_conf.set_burst_types(TIMESLOT1, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + d_channel_conf.set_multiframe_type(TIMESLOT2, multiframe_26); + d_channel_conf.set_burst_types(TIMESLOT2, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + + d_channel_conf.set_multiframe_type(TIMESLOT3, multiframe_26); + d_channel_conf.set_burst_types(TIMESLOT3, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + d_channel_conf.set_multiframe_type(TIMESLOT4, multiframe_26); + d_channel_conf.set_burst_types(TIMESLOT4, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + + d_channel_conf.set_multiframe_type(TIMESLOT5, multiframe_26); + d_channel_conf.set_burst_types(TIMESLOT5, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + d_channel_conf.set_multiframe_type(TIMESLOT6, multiframe_26); + d_channel_conf.set_burst_types(TIMESLOT6, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + d_channel_conf.set_multiframe_type(TIMESLOT7, multiframe_26); d_channel_conf.set_burst_types(TIMESLOT7, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + } @@ -70,9 +167,9 @@ typedef std::vector vector_float; typedef boost::circular_buffer circular_buffer_float; gsm_receiver_cf_sptr -gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr) +gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key) { - return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr)); + return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr, key)); } static const int MIN_IN = 1; // mininum number of input streams @@ -83,7 +180,7 @@ static const int MAX_OUT = 1; // maximum number of output streams /* * The private constructor */ -gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr) +gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key) : gr_block("gsm_receiver", gr_make_io_signature(MIN_IN, MAX_IN, sizeof(gr_complex)), gr_make_io_signature(MIN_OUT, MAX_OUT, 142 * sizeof(float))), @@ -95,15 +192,21 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, d_freq_offset(0), d_state(first_fcch_search), d_burst_nr(osr), - d_failed_sch(0) + d_failed_sch(0), + d_tch_decoder1( GSM::gFACCH_TCHFMapping ), + d_tch_decoder2( GSM::gFACCH_TCHFMapping ), + d_tch_decoder3( GSM::gFACCH_TCHFMapping ), + d_tch_decoder4( GSM::gFACCH_TCHFMapping ), + d_tch_decoder5( GSM::gFACCH_TCHFMapping ), + d_tch_decoder6( GSM::gFACCH_TCHFMapping ), + d_tch_decoder7( GSM::gFACCH_TCHFMapping ) { int i; gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0)); - for (i = 0; i < TRAIN_SEQ_NUM; i++) { gr_complex startpoint; if (i == 6) { //this is nasty hack - startpoint = gr_complex(-1.0, 0.0); //if I don't change it here all bits of normal bursts for BTSes with bcc=6 will have negative values + startpoint = gr_complex(-1.0, 0.0); //if I don't change it here all bits of normal bursts for BTSes with bcc=6 will have reversed values } else { startpoint = gr_complex(1.0, 0.0); //I've checked this hack for bcc==0,1,2,3,4,6 } //I don't know what about bcc==5 and 7 yet @@ -111,7 +214,25 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint); } - + d_gsm_file = fopen( "speech.gsm", "wb" ); + + d_hex_to_int['0'] = 0; + d_hex_to_int['4'] = 4; + d_hex_to_int['8'] = 8; + d_hex_to_int['c'] = 0xc; + d_hex_to_int['1'] = 1; + d_hex_to_int['5'] = 5; + d_hex_to_int['9'] = 9; + d_hex_to_int['d'] = 0xd; + d_hex_to_int['2'] = 2; + d_hex_to_int['6'] = 6; + d_hex_to_int['a'] = 0xa; + d_hex_to_int['e'] = 0xe; + d_hex_to_int['3'] = 3; + d_hex_to_int['7'] = 7; + d_hex_to_int['b'] = 0xb; + d_hex_to_int['f'] = 0xf; + read_key(key); /* Initialize GSM Stack */ GS_new(&d_gs_ctx); //TODO: remove it! it's not a right place for a decoder } @@ -153,7 +274,7 @@ gsm_receiver_cf::general_work(int noutput_items, break; case next_fcch_search: { //this state is used because it takes some time (a bunch of buffered samples) - float prev_freq_offset = d_freq_offset; //before previous set_frequqency cause change + float prev_freq_offset = d_freq_offset; //before previous set_frequqency cause change if (find_fcch_burst(input, nitems_items[0])) { if (abs(prev_freq_offset - d_freq_offset) > FCCH_MAX_FREQ_OFFSET) { set_frequency(d_freq_offset); //call set_frequncy only frequency offset change is greater than some value @@ -253,13 +374,13 @@ gsm_receiver_cf::general_work(int noutput_items, break; case normal_burst: //if it's normal burst - burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, d_bcc); //get channel impulse response for given training sequence number - d_bcc + burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); //get channel impulse response for given training sequence number - d_bcc detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //MLSE detection of bits process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready break; case dummy_or_normal: { - burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, TS_DUMMY); + burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TS_DUMMY); detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); std::vector v(20); @@ -268,7 +389,7 @@ gsm_receiver_cf::general_work(int noutput_items, int different_bits = (it - v.begin()); if (different_bits > 2) { - burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, d_bcc); + burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); if (!output_binary[0] && !output_binary[1] && !output_binary[2]) { process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready @@ -283,7 +404,7 @@ gsm_receiver_cf::general_work(int noutput_items, break; case dummy: //if it's dummy - burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, TS_DUMMY); //read dummy + burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TS_DUMMY); //read dummy detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); // but as far as I know it's pointless break; case empty: //if it's empty burst @@ -652,7 +773,7 @@ inline void gsm_receiver_cf::mafi(const gr_complex * input, int nitems, gr_compl //TODO: get_norm_chan_imp_resp is similar to get_sch_chan_imp_resp - consider joining this two functions //TODO: this is place where most errors are introduced and can be corrected by improvements to this fuction //especially computations of strongest_window_nr -int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *input, gr_complex * chan_imp_resp, unsigned search_range, int bcc) +int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *input, gr_complex * chan_imp_resp, int bcc) { vector_complex correlation_buffer; vector_float power_buffer; diff --git a/src/lib/gsm_receiver_cf.h b/src/lib/gsm_receiver_cf.h index 9454997..21cb1ff 100644 --- a/src/lib/gsm_receiver_cf.h +++ b/src/lib/gsm_receiver_cf.h @@ -31,13 +31,17 @@ #include #include //TODO: remember to remove this line in the future! +#include "GSML1FEC.h" //!! +#include //!! +#include //!! +#include //!! class gsm_receiver_cf; typedef boost::shared_ptr gsm_receiver_cf_sptr; typedef std::vector vector_complex; -gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr); +gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); /** GSM Receiver GNU Radio block * @@ -50,7 +54,16 @@ gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synch class gsm_receiver_cf : public gr_block { private: - + std::map d_hex_to_int; + FILE * d_gsm_file; //!! + byte d_KC[8]; //!! + GSM::TCHFACCHL1Decoder d_tch_decoder1; //!! + GSM::TCHFACCHL1Decoder d_tch_decoder2; //!! + GSM::TCHFACCHL1Decoder d_tch_decoder3; //!! + GSM::TCHFACCHL1Decoder d_tch_decoder4; //!! + GSM::TCHFACCHL1Decoder d_tch_decoder5; //!! + GSM::TCHFACCHL1Decoder d_tch_decoder6; //!! + GSM::TCHFACCHL1Decoder d_tch_decoder7; //!! /**@name Configuration of the receiver */ //@{ const int d_OSR; ///< oversampling ratio @@ -104,8 +117,8 @@ class gsm_receiver_cf : public gr_block // GSM Stack GS_CTX d_gs_ctx;//TODO: remove it! it'a not right place for a decoder - friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr); - gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr); + friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); + gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); /** Function whis is used to search a FCCH burst and to compute frequency offset before * "synchronized" state of the receiver @@ -209,8 +222,14 @@ class gsm_receiver_cf : public gr_block * @param bcc base station color code - number of a training sequence * @return first sample number of normal burst */ - int get_norm_chan_imp_resp(const gr_complex * input, gr_complex * chan_imp_resp, unsigned search_range, int bcc); + int get_norm_chan_imp_resp(const gr_complex * input, gr_complex * chan_imp_resp, int bcc); + + /** + * + */ + void read_key(std::string key); + /** * */ @@ -220,6 +239,8 @@ class gsm_receiver_cf : public gr_block * */ void configure_receiver(); + + public: ~gsm_receiver_cf(); diff --git a/src/python/gsm_receive.py b/src/python/gsm_receive.py index 40c1520..4cfb876 100755 --- a/src/python/gsm_receive.py +++ b/src/python/gsm_receive.py @@ -6,7 +6,7 @@ from gnuradio.eng_option import eng_option from optparse import OptionParser from os import sys -for extdir in ['../../debug/src/lib','../../debug/src/lib/.libs']: +for extdir in ['../../debug/src/lib','../../debug/src/lib/.libs','../lib','../lib/.libs','../..debug/src/lib/decoder/openbts/SIP']: if extdir not in sys.path: sys.path.append(extdir) import gsm @@ -82,7 +82,7 @@ class gsm_receiver_first_blood(gr.top_block): return interpolator def _set_receiver(self): - receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr) + receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr, self.options.key.replace(' ', '').lower()) return receiver def _process_options(self): @@ -95,6 +95,9 @@ class gsm_receiver_first_blood(gr.top_block): help="Input filename") parser.add_option("-O", "--outputfile", type="string", default="cfile2.out", help="Output filename") + parser.add_option("-k", "--key", type="string", default="2B 08 74 9F DD 0D 9C 00", + help="KC session key") + (options, args) = parser.parse_args () return (options, args) diff --git a/src/python/gsm_receive_usrp.py b/src/python/gsm_receive_usrp.py index 7d28633..a4e9720 100755 --- a/src/python/gsm_receive_usrp.py +++ b/src/python/gsm_receive_usrp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python #this file isn't ready to use now - gsm-receiver lacks realtime processing capability -#there are many underruns of buffer from usrp's samples, many blocks of samples get lost and +#there are many underruns of buffer for samples from usrp's, many blocks of samples get lost and #receiver isn't prepared for this situation too well from gnuradio import gr, gru, blks2 -- cgit v1.2.3