From c51f12bb4eeb43416da93ea64ed33537c79af671 Mon Sep 17 00:00:00 2001 From: Roman Khassraf Date: Fri, 17 Jul 2015 15:18:10 +0200 Subject: [PATCH] Changed decryption block to use osmo_a5 function, in preparation for issue 85 --- lib/decryption/a5_1_2.h | 392 ------------------------------ lib/decryption/decryption_impl.cc | 36 +-- lib/decryption/decryption_impl.h | 11 +- 3 files changed, 26 insertions(+), 413 deletions(-) delete mode 100644 lib/decryption/a5_1_2.h diff --git a/lib/decryption/a5_1_2.h b/lib/decryption/a5_1_2.h deleted file mode 100644 index 75277df..0000000 --- a/lib/decryption/a5_1_2.h +++ /dev/null @@ -1,392 +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 - * - */ - -#ifndef A5_1_2_H -#define A5_1_2_H - -#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_reversed[8], word frame) { - int i; - bit keybit, framebit; - - byte key[8]; - for(i=0; i<8; i++){ - key[i] = key_reversed[7-i]; - } - /* 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)); - } -} - -void runA51(byte AtoBkeystream[], byte BtoAkeystream[]) { - int i; - - /* Zero out the output buffers. */ - for (i = 0; i < 114; i++){ - AtoBkeystream[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] = getbit(); - } - - /* 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] = getbit(); - } -} - - - -#endif /* A5_1_2_H */ diff --git a/lib/decryption/decryption_impl.cc b/lib/decryption/decryption_impl.cc index de02353..836d9d2 100644 --- a/lib/decryption/decryption_impl.cc +++ b/lib/decryption/decryption_impl.cc @@ -26,8 +26,10 @@ #include #include #include "decryption_impl.h" -#include "a5_1_2.h" +extern "C" { + #include +} const uint32_t BURST_SIZE=148; @@ -66,14 +68,24 @@ namespace gr { void decryption_impl::set_k_c(const std::vector & k_c) { - d_k_c = k_c; + if (k_c.size() == 8) + { + for (int i=0; i<8; i++) + { + d_k_c[i] = k_c[i]; + } + } + else + { + for (int i=0; i<8; i++) + { + d_k_c[i] = 0; + } + } } void decryption_impl::decrypt(pmt::pmt_t msg) { - if(d_k_c.size() != 8){ - message_port_pub(pmt::mp("bursts"), msg); - } else if(d_k_c[0] == 0 && d_k_c[1] == 0 && d_k_c[2] == 0 && d_k_c[3] == 0 & d_k_c[4] == 0 && d_k_c[5] == 0 && d_k_c[6] == 0 && d_k_c[7] == 0) { @@ -81,9 +93,7 @@ namespace gr { } else { uint8_t decrypted_data[BURST_SIZE]; - uint8_t AtoBkeystream[114]; - uint8_t BtoAkeystream[114]; - uint8_t * keystream; + uint8_t keystream[114]; pmt::pmt_t header_plus_burst = pmt::cdr(msg); gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(header_plus_burst); @@ -91,19 +101,13 @@ namespace gr { uint32_t frame_number = be32toh(header->frame_number); bool uplink_burst = (be16toh(header->arfcn) & 0x4000) ? true : false; - uint32_t t1 = frame_number / (26*51); - uint32_t t2 = frame_number % 26; - uint32_t t3 = frame_number % 51; - uint32_t frame_number_mod = (t1 << 11) + (t3 << 5) + t2; - keysetup(&d_k_c[0], frame_number_mod); - runA51(AtoBkeystream, BtoAkeystream); if(uplink_burst){ //process uplink burst - keystream = BtoAkeystream; + osmo_a5(1, d_k_c, frame_number, NULL, keystream); } else { //process downlink burst - keystream = AtoBkeystream; + osmo_a5(1, d_k_c, frame_number, keystream, NULL); } /* guard bits */ for (int i = 0; i < 3; i++) { diff --git a/lib/decryption/decryption_impl.h b/lib/decryption/decryption_impl.h index aadd861..fff028b 100644 --- a/lib/decryption/decryption_impl.h +++ b/lib/decryption/decryption_impl.h @@ -1,17 +1,17 @@ /* -*- c++ -*- */ -/* +/* * Copyright 2014 <+YOU OR YOUR COMPANY+>. - * + * * This 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 3, or (at your option) * any later version. - * + * * This software 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 software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, @@ -30,7 +30,8 @@ namespace gr { class decryption_impl : public decryption { private: - std::vector d_k_c; +// std::vector d_k_c; + uint8_t d_k_c[8]; void decrypt(pmt::pmt_t msg); public: decryption_impl(const std::vector & k_c);