laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-tetra/+/34001 )

Change subject: Added functions that prepare for decryption
......................................................................

Added functions that prepare for decryption

Added functions that will eventually allow for mac resource decryption,
voice/traffic decryption and identity decryption. Calls to the true TEA
keystream generator functions and TA61 identity decryption function
will need to be added in a later patch.

Change-Id: I4e6147f206ad6046f32e08015ec9721b64382ca1
---
M src/crypto/tetra_crypto.c
M src/crypto/tetra_crypto.h
2 files changed, 131 insertions(+), 13 deletions(-)

Approvals:
  laforge: Looks good to me, approved; Verified




diff --git a/src/crypto/tetra_crypto.c b/src/crypto/tetra_crypto.c
index 9515a25..d7df293 100644
--- a/src/crypto/tetra_crypto.c
+++ b/src/crypto/tetra_crypto.c
@@ -150,19 +150,123 @@
        return ((tm->tn - 1) | (tm->fn << 2) | (tm->mn << 7) | ((hn & 0x7FFF) 
<< 13) | (dir << 28));
 }

-int decrypt_identity(struct tetra_crypto_state *tcs, struct tetra_addr *addr)
+static bool generate_keystream(struct tetra_crypto_state *tcs, struct 
tetra_key *key, struct tetra_tdma_time *t, int num_bits, uint8_t *ks_out)
 {
-       return 0;
+       if (!key)
+               return false;
+
+       /* Construct IV and prepare buf for bytewise keystream */
+       int num_bytes = (num_bits + 7) / 8;
+       uint8_t ks_bytes[num_bytes];
+       uint32_t iv = tea_build_iv(t, tcs->hn, 0);
+
+       /* Compute ECK from net info and CK */
+       if (tcs->cn < 0 || tcs->la < 0 || tcs->cc < 0)
+               /* Missing data for TB5 */
+               return false;
+
+       uint8_t eck[10];
+       uint8_t cn[2] = {(tcs->cn >> 8) & 0xFF, tcs->cn & 0xFF};
+       uint8_t la[2] = {(tcs->la >> 8) & 0xFF, tcs->la & 0xFF};
+       uint8_t cc[1] = {tcs->cc & 0xFF};
+       /* TODO FIXME add call to TB5 to derive eck */
+
+       /* Generate keystream with required KSG */
+       switch (key->network_info->ksg_type) {
+       /* TODO FIXME add cases/calls to TEA keystream generator functions */
+       default:
+               fprintf(stderr, "tetra_crypto: KSG type %d not supported\n", 
key->network_info->ksg_type);
+               return false;
+       }
+
+       for (int i = 0; i < num_bytes; i++)
+               for (int j = 0; j < 8; j++)
+                       ks_out[i * 8 + j] = (ks_bytes[i] >> (7-j)) & 1;
+
+       /* Expand keystream bytes into ubit format */
+       for (int i = 0; i < num_bits; i++)
+               ks_out[i] = (ks_bytes[num_bits / 8] >> (7-(num_bits % 8))) & 1;
+
+       return true;
 }

-int decrypt_mac_element(struct tetra_crypto_state *tcs, struct 
tetra_tmvsap_prim *tmvp, struct tetra_key *key, int l1_len, int tmpdu_offset)
+bool decrypt_identity(struct tetra_crypto_state *tcs, struct tetra_addr *addr)
 {
-       return 0;
+       /* TODO FIXME implement TA61 decryption */
+       return false;
 }

-int decrypt_voice_timeslot(struct tetra_crypto_state *tcs, struct 
tetra_tdma_time *tdma_time, int16_t *type1_block)
+bool decrypt_mac_element(struct tetra_crypto_state *tcs, struct 
tetra_tmvsap_prim *tmvp, struct tetra_key *key, int l1_len, int tmpdu_offset)
 {
-       return 0;
+       if (!key || l1_len - tmpdu_offset <= 0)
+               return false;
+
+       if (tcs->cn < 0 || tcs->la < 0 || tcs->cc < 0) {
+               printf("tetra_crypto: can't compute TB5 due to incomplete 
network info (carr %d la %d cc %d)\n",
+                       tcs->cn, tcs->la, tcs->cc);
+               return false;
+       }
+
+       struct tetra_tdma_time *tdma_time = &tmvp->u.unitdata.tdma_time;
+
+       /* Compute keystream offset to apply */
+       /* TODO FIXME maybe we can rework channel type setting in lower mac, and
+          avoid using TETRA_LC_UNKNOWN below */
+       uint32_t ks_skip_bits = 0;
+       if (tmvp->u.unitdata.blk_num == BLK_2 && (
+                       tmvp->u.unitdata.lchan == TETRA_LC_SCH_HD ||
+                       tmvp->u.unitdata.lchan == TETRA_LC_UNKNOWN)) {
+               ks_skip_bits = 216;
+               printf("tetra_crypto: 2nd half slot; skipping bits\n");
+       }
+
+       /* Generate keystream */
+       struct msgb *msg = tmvp->oph.msg;
+       int ct_len = l1_len - tmpdu_offset;
+       int ks_num_bits = ks_skip_bits + ct_len;
+       uint8_t *ct_start = msg->l1h + tmpdu_offset;
+       uint8_t ks[ks_num_bits];
+       if (!generate_keystream(tcs, key, tdma_time, ks_num_bits, ks))
+               return false;
+
+       /* Apply keystream */
+       for (int i = 0; i < ct_len; i++)
+               ct_start[i] = ct_start[i] ^ ks[i + ks_skip_bits];
+
+       printf("tetra_crypto: addr %8d -> key %4d, time %5d/%s, tmpdu offset 
%d, decrypting %d bits\n",
+               key->addr, key->index, tcs->hn, 
tetra_tdma_time_dump(tdma_time), tmpdu_offset, ct_len);
+
+       return true;
+}
+
+bool decrypt_voice_timeslot(struct tetra_crypto_state *tcs, struct 
tetra_tdma_time *tdma_time, int16_t *type1_block)
+{
+       /* TODO FIXME implement proper key selection for voice blocks */
+       struct tetra_key *key = tcs->cck;
+       if (!key)
+               return false;
+
+       if (tcs->cn < 0 || tcs->la < 0 || tcs->cc < 0) {
+               printf("tetra_crypto: can't compute TB5 due to incomplete 
network info (carr %d la %d cc %d)\n",
+                       tcs->cn, tcs->la, tcs->cc);
+               return false;
+       }
+
+       /* Generate keystream */
+       int ks_num_bits = 137*2; // two half slots of voice
+       uint8_t ks[ks_num_bits];
+       if (!generate_keystream(tcs, key, tdma_time, ks_num_bits, ks))
+               return false;
+
+       /* Apply keystream */
+       for (int i = 0; i < 137; i++) {
+               type1_block[i + 1] = type1_block[i + 1] ^ ks[i];
+               type1_block[i + 139] = type1_block[i + 139] ^ ks[i + 137];
+       }
+
+       printf("tetra_crypto: addr %8d -> key %4d, time %5d/%s, decrypted 
voice\n",
+               key->addr, key->index, tcs->hn, 
tetra_tdma_time_dump(tdma_time));
+       return true;
 }

 int load_keystore(char *tetra_keyfile)
@@ -197,7 +301,7 @@
        while (fgets(buf, sizeof(buf), fp)) {

                if (strlen(buf) <= 1 || buf[0] == '#') {
-                       // Commented/empty line
+                       /* Commented/empty line */
                        continue;

                } else if (!strncmp(buf, "network ", 8)) {
@@ -299,11 +403,11 @@

 void update_current_network(struct tetra_crypto_state *tcs, int mcc, int mnc)
 {
-       // Update globals
+       /* Update globals */
        tcs->mcc = mcc;
        tcs->mnc = mnc;

-       // Network changed, update reference to current network
+       /* Network changed, update reference to current network */
        tcs->network = 0;
        for (int i = 0; i < tcdb->num_nets; i++) {
                struct tetra_netinfo *network = &tcdb->nets[i];
@@ -313,7 +417,7 @@
                }
        }

-       // (Try to) select new CCK/SCK
+       /* (Try to) select new CCK/SCK */
        update_current_cck(tcs);
 }

diff --git a/src/crypto/tetra_crypto.h b/src/crypto/tetra_crypto.h
index e50a45e..ace4c04 100644
--- a/src/crypto/tetra_crypto.h
+++ b/src/crypto/tetra_crypto.h
@@ -111,9 +111,9 @@

 /* Keystream generation and decryption functions */
 uint32_t tea_build_iv(struct tetra_tdma_time *tm, uint16_t hn, uint8_t dir);
-int decrypt_identity(struct tetra_crypto_state *tcs, struct tetra_addr *addr);
-int decrypt_mac_element(struct tetra_crypto_state *tcs, struct 
tetra_tmvsap_prim *tmvp, struct tetra_key *key, int l1_len, int tmpdu_offset);
-int decrypt_voice_timeslot(struct tetra_crypto_state *tcs, struct 
tetra_tdma_time *tdma_time, int16_t *type1_bits);
+bool decrypt_identity(struct tetra_crypto_state *tcs, struct tetra_addr *addr);
+bool decrypt_mac_element(struct tetra_crypto_state *tcs, struct 
tetra_tmvsap_prim *tmvp, struct tetra_key *key, int l1_len, int tmpdu_offset);
+bool decrypt_voice_timeslot(struct tetra_crypto_state *tcs, struct 
tetra_tdma_time *tdma_time, int16_t *type1_bits);

 /* Key selection and crypto state management */
 struct tetra_netinfo *get_network_info(int mcc, int mnc);

--
To view, visit https://gerrit.osmocom.org/c/osmo-tetra/+/34001
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-tetra
Gerrit-Branch: master
Gerrit-Change-Id: I4e6147f206ad6046f32e08015ec9721b64382ca1
Gerrit-Change-Number: 34001
Gerrit-PatchSet: 5
Gerrit-Owner: wbokslag <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-MessageType: merged

Reply via email to