From 3ae3c84d5da8f1b931a5bb2af6eb817f2db7e6b0 Mon Sep 17 00:00:00 2001 From: Ivan Kluchnikov Date: Sat, 1 Dec 2012 17:19:26 +0400 Subject: [PATCH] Implemented encryption and decryption for GSM logical channel. 1. Added functions for encryption and decryption activation and setting KC and CipherID to GSMLogicalChannel. 2. Added functions for encrypt, decrypt, setting KC and CipherID to L1Encoder, L1Decoder and L1FEC. 3. Implemented decrypt and encrypt for XCCHL1 Decoder and Encoder, TCHFACCH Decoder and Encoder. 4. Added xor_apply function to BitVector and SoftVector. 5. Added libosmocore and libosmogsm dependences for using osmo_a5 and osmo_hexparse functions. --- CommonLibs/BitVector.cpp | 20 ++++++++++++ CommonLibs/BitVector.h | 9 ++++++ GSM/GSML1FEC.cpp | 37 +++++++++++++++++++-- GSM/GSML1FEC.h | 49 ++++++++++++++++++++++++++++ GSM/GSMLogicalChannel.cpp | 67 +++++++++++++++++++++++++++++++++++++++ GSM/GSMLogicalChannel.h | 15 +++++++++ apps/Makefile.am | 4 ++- configure.ac | 6 ++++ 8 files changed, 204 insertions(+), 3 deletions(-) diff --git a/CommonLibs/BitVector.cpp b/CommonLibs/BitVector.cpp index 54a3edc..a4ec073 100644 --- a/CommonLibs/BitVector.cpp +++ b/CommonLibs/BitVector.cpp @@ -163,6 +163,15 @@ void BitVector::invert() } +unsigned BitVector::xor_apply(uint8_t * gamma, size_t len) +{ + if (len != size()) return 1; + for (size_t i = 0; i < size(); i++) { + if (gamma[i] > 1) return gamma[i]; + mStart[i] ^= gamma[i]; + } + return 0; +} void BitVector::reverse8() @@ -447,6 +456,17 @@ BitVector SoftVector::sliced() const } +unsigned SoftVector::xor_apply(uint8_t * gamma, size_t len) +{ + if (len != size()) return 1; + for (size_t i = 0; i < size(); i++) { + if (gamma[i] > 1) return gamma[i]; + // soft-bit inversion + if (gamma[i]) mStart[i] = 1.0F - mStart[i]; + } + return 0; +} + void SoftVector::decode(ViterbiR2O4 &decoder, BitVector& target) const { diff --git a/CommonLibs/BitVector.h b/CommonLibs/BitVector.h index 572e6b4..864dd07 100644 --- a/CommonLibs/BitVector.h +++ b/CommonLibs/BitVector.h @@ -296,6 +296,10 @@ class BitVector : public Vector { /** Invert 0<->1. */ void invert(); + // apply gamma bit sequence (1 bit per byte) using xor function: + // return false on non-boolean gamma or length mismatch + unsigned xor_apply(uint8_t * gamma, size_t len); + /**@name Byte-wise operations. */ //@{ /** Reverse an 8-bit vector. */ @@ -409,6 +413,11 @@ class SoftVector: public Vector { const SoftVector tail(size_t start) const { return segment(start,size()-start); } //@} + // apply gamma bit sequence (1 bit per byte) using xor function: + // 1.0-x is the inverse of x soft-bit + // return false on non-boolean gamma or length mismatch + unsigned xor_apply(uint8_t * gamma, size_t len); + /** Decode soft symbols with the GSM rate-1/2 Viterbi decoder. */ void decode(ViterbiR2O4 &decoder, BitVector& target) const; diff --git a/GSM/GSML1FEC.cpp b/GSM/GSML1FEC.cpp index ae86825..55f3ca1 100644 --- a/GSM/GSML1FEC.cpp +++ b/GSM/GSML1FEC.cpp @@ -24,7 +24,10 @@ */ - +extern "C" { +#include +#include +} #include "GSML1FEC.h" #include "GSMCommon.h" #include "GSMSAPMux.h" @@ -230,6 +233,7 @@ void L1Encoder::open() if (!mRunning) start(); mTotalBursts=0; mActive = true; + mCipherID = 0; resync(); } @@ -313,6 +317,16 @@ unsigned L1Encoder::ARFCN() const } +void L1Encoder::encrypt(BitVector &burst, uint32_t FN) const +{ + if (mCipherID > 0) { + ubit_t ks[114]; + osmo_a5(mCipherID, mKc, FN, ks, NULL); + unsigned e = burst.xor_apply(ks, 114); + if (e) LOG(ERR) << "Length mismatch while applying gamma: " << e; + } +} + unsigned L1Decoder::ARFCN() const { @@ -336,6 +350,7 @@ void L1Decoder::open() mT3109.reset(); mT3101.set(); mActive = true; + mCipherID = 0; } @@ -398,7 +413,15 @@ void L1Decoder::countBadFrame() OBJLOG(DEBUG) <<"L1Decoder FER=" << mFER; } - +void L1Decoder::decrypt(SoftVector &burst, uint32_t FN) const +{ + if (mCipherID > 0) { + ubit_t ks[114]; + osmo_a5(mCipherID, mKc, FN, NULL, ks); + unsigned e = burst.xor_apply(ks, 114); + if (e) LOG(ERR) << "Length mismatch while applying gamma: " << e; + } +} void L1FEC::downstream(ARFCNManager* radio) @@ -589,6 +612,9 @@ bool XCCHL1Decoder::processBurst(const RxBurst& inBurst) if (B==0) mReadTime = inBurst.time(); + // Decrypt the burst + decrypt(mI[B], inBurst.time().FN()); + // If the burst index is 3, then this is the last burst in the L2 frame. // Return true to indicate that we are ready to deinterleave. return B==3; @@ -881,6 +907,8 @@ void XCCHL1Encoder::transmit() for (int B=0; B<4; B++) { mBurst.time(mNextWriteTime); + // Encrypt the burst + encrypt(mI[B], mNextWriteTime.FN()); // Copy in the "encrypted" bits, GSM 05.03 4.1.5, 05.02 5.2.3. OBJLOG(DEBUG) << "XCCHL1Encoder mI["<descriptiveString(); } + void setKc(uint8_t *Kc) { + assert(mEncoder); mEncoder->setKc(Kc); + assert(mDecoder); mDecoder->setKc(Kc); + } + + unsigned getEncCipherID() const + { assert(mEncoder); return mEncoder->getCipherID(); } + + unsigned getDecCipherID() const + { assert(mDecoder); return mDecoder->getCipherID(); } + + void setEncCipherID(unsigned cipherID) + { assert(mEncoder); mEncoder->setCipherID(cipherID); } + + void setDecCipherID(unsigned cipherID) + { assert(mDecoder); return mDecoder->setCipherID(cipherID); } //@} diff --git a/GSM/GSMLogicalChannel.cpp b/GSM/GSMLogicalChannel.cpp index f3a04c0..13ebf20 100644 --- a/GSM/GSMLogicalChannel.cpp +++ b/GSM/GSMLogicalChannel.cpp @@ -28,6 +28,10 @@ +extern "C" { +#include +} + #include "GSML3RRElements.h" #include "GSML3Message.h" #include "GSML3RRMessages.h" @@ -64,6 +68,69 @@ void LogicalChannel::open() } +bool LogicalChannel::setKc(const char * key) +{ + uint8_t Kc[8]; + if (!mL1) return false; + if(osmo_hexparse(key, Kc, 8) != 8) return false; + mL1->setKc(Kc); + if (mSACCH) mSACCH->setKc(key); + return true; +} + + +unsigned LogicalChannel::isEncrypting() const +{ + if (mL1) { + return mL1->getEncCipherID(); + } + else { + return 0; + } +} + + +unsigned LogicalChannel::isDecrypting() const +{ + if (mL1) { + return mL1->getDecCipherID(); + } + else { + return 0; + } +} + + +void LogicalChannel::activateEncryption(unsigned cipherID) +{ + if (mL1) { + if (mL1->getEncCipherID() == 0) { + LOG(DEBUG) << "Activate Encryption on "<< mL1->descriptiveString(); + mL1->setEncCipherID(cipherID); + } + else { + LOG(DEBUG) << "Encryption is already activated on " << mL1->descriptiveString(); + } + } + if (mSACCH) ((LogicalChannel*)mSACCH)->activateEncryption(cipherID); +} + + +void LogicalChannel::activateDecryption(unsigned cipherID) +{ + if (mL1) { + if (mL1->getDecCipherID() == 0) { + LOG(DEBUG) << "Activate Dencryption on "<< mL1->descriptiveString(); + mL1->setDecCipherID(cipherID); + } + else { + LOG(DEBUG) << "Decryption is already activated on " << mL1->descriptiveString(); + } + } + if (mSACCH) ((LogicalChannel*)mSACCH)->activateDecryption(cipherID); +} + + void LogicalChannel::connect() { mMux.downstream(mL1); diff --git a/GSM/GSMLogicalChannel.h b/GSM/GSMLogicalChannel.h index 710b30e..63f062e 100644 --- a/GSM/GSMLogicalChannel.h +++ b/GSM/GSMLogicalChannel.h @@ -205,6 +205,21 @@ public: /** Return true if the channel is active. */ bool active() const { assert(mL1); return mL1->active(); } + /** Set Kc for L1 */ + bool setKc(const char * key); + + /** Return CipherID or 0 if encryption is not activated. */ + unsigned isEncrypting() const; + + /** Return CipherID or 0 if decryption is not activated. */ + unsigned isDecrypting() const; + + /** Activate encryption, use A5/1 by default. */ + void activateEncryption(unsigned cipherID = 1); + + /** Activate decryption, use A5/1 by default. */ + void activateDecryption(unsigned cipherID = 1); + /** The TDMA parameters for the transmit side. */ const TDMAMapping& txMapping() const { assert(mL1); return mL1->txMapping(); } diff --git a/apps/Makefile.am b/apps/Makefile.am index 80efa61..556984b 100644 --- a/apps/Makefile.am +++ b/apps/Makefile.am @@ -42,7 +42,9 @@ OpenBTS_LDADD = \ $(SQLITE_LA) \ $(SMS_LA) \ $(OSIP_LIBS) \ - $(ORTP_LIBS) + $(ORTP_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) OpenBTSCLI_SOURCES = OpenBTSCLI.cpp OpenBTSDo_SOURCES = OpenBTSDo.cpp diff --git a/configure.ac b/configure.ac index b1f99b1..f4d14f4 100644 --- a/configure.ac +++ b/configure.ac @@ -124,6 +124,12 @@ PKG_CHECK_MODULES(OSIP, libosip2) # Defines ORTP_CFLAGS, ORTP_INCLUDEDIR, and ORTP_LIBS PKG_CHECK_MODULES(ORTP, ortp) +# Check for A5 and COMP128 library +PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm) + +# Check for Osmocom core library +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore) + # Defines LIBUSB_TRANSFER_CANCELLED, LIBUSB_TRANSFER_COMPLETED, LIBUSB_SUCCESS, LIBUSB_ERROR_* PKG_CHECK_MODULES(LIBUSB, libusb-1.0)