diff --git a/examples/example_aes_keys.csv b/examples/example_aes_keys.csv
new file mode 100644
index 0000000..66067e4
--- /dev/null
+++ b/examples/example_aes_keys.csv
@@ -0,0 +1,7 @@
+keyid(hex), keyvalue(hex)
+0001,0000000000000000,0000000000000000,0000000000000000,0000002823d87923
+0003,0101010101010101,0101010101010101
+0004,0101010101010101,0101010101010101,0101010101010101,0101010101010101
+C197,A753BC945DE5E0F1,EC1970F8565154E6,D9DF2FAC6278FA93,B531D2CC046E93A2
+0067,0000000000000000,0000000000000000,0000000000000000,DEADBEEFBAADF00D
+0000,0000000000000000,0000000000000000,0000000000000000,0000000000000001
\ No newline at end of file
diff --git a/include/dsd.h b/include/dsd.h
index f79f4b7..529c32f 100644
--- a/include/dsd.h
+++ b/include/dsd.h
@@ -596,6 +596,16 @@ typedef struct
unsigned long long int K4;
int M;
int menuopen;
+
+ //AES Key Segments
+ unsigned long long int A1[2];
+ unsigned long long int A2[2];
+ unsigned long long int A3[3];
+ unsigned long long int A4[4];
+ int aes_key_loaded[2];
+
+ //xl specific, we need to know if the ESS is from HDU, or from LDU2
+ int xl_is_hdu;
unsigned int debug_audio_errors;
unsigned int debug_audio_errorsR;
@@ -718,6 +728,23 @@ typedef struct
int DMRvcL;
int DMRvcR;
+ //keystream octet and bit arrays
+ uint8_t ks_octetL[129*18]; //arbitary size, but large enough for the largest packed PDUs
+ uint8_t ks_octetR[129*18]; //arbitary size, but large enough for the largest packed PDUs
+ uint8_t ks_bitstreamL[128*18*8]; //arbitary size, but large enough for the largest PDUs
+ uint8_t ks_bitstreamR[129*18*8]; //arbitary size, but large enough for the largest PDUs
+ int octet_counter;
+ long int bit_counterL;
+ long int bit_counterR;
+
+ //AES Specific Variables
+ uint8_t aes_key[32]; //was 64 for some reason
+ uint8_t aes_iv[16];
+ uint8_t aes_ivR[16];
+
+ //NXDN DES and AES, signal new VCALL_IV and new IV
+ uint8_t nxdn_new_iv; //1 when a new IV comes in, else 0
+
short int dmr_encL;
short int dmr_encR;
@@ -828,7 +855,7 @@ typedef struct
uint8_t nxdn_bw;
//multi-key array
- unsigned long long int rkey_array[0xFFFF];
+ unsigned long long int rkey_array[0x1FFFF];
int keyloader; //let us know the keyloader is active
//dmr late entry mi
@@ -1477,9 +1504,25 @@ int udp_socket_connectM17(dsd_opts * opts, dsd_state * state);
int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
//RC4 function prototypes
-void RC4(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[]);
+void rc4_voice_decrypt (int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[]);
void rc4_block_output (int drop, int keylen, int meslen, uint8_t * key, uint8_t * output_blocks);
+//DES function prototypes
+void des_multi_keystream_output (unsigned long long int mi, unsigned long long int key_ulli, uint8_t * output, int type, int len);
+void tdea_multi_keystream_output (unsigned long long int mi, uint8_t * key, uint8_t * output, int type, int len);
+
+//AES function prototypes
+void aes_ofb_keystream_output (uint8_t * iv, uint8_t * key, uint8_t * output, int type, int nblocks);
+void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de);
+void aes_cbc_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de);
+void aes_cfb_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de);
+void aes_ctr_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type);
+void aes_ctr_bitwise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type);
+
+//LFSR to expand either a DMR 32-bit or P25 64-bit MI into a 128-bit IV for AES
+void LFSR128(dsd_state * state);
+void LFSR128d(dsd_state * state);
+
#ifdef __cplusplus
extern "C" {
diff --git a/src/2.c b/src/2.c
deleted file mode 100644
index 6275863..0000000
--- a/src/2.c
+++ /dev/null
@@ -1,7 +0,0 @@
-/*-------------------------------------------------------------------------------
- * 2.c
- * Placeholder File 2 -- This file is for temporary code storage
- *
- *
- *
- *-----------------------------------------------------------------------------*/
\ No newline at end of file
diff --git a/src/4.c b/src/4.c
deleted file mode 100644
index 801a052..0000000
--- a/src/4.c
+++ /dev/null
@@ -1,7 +0,0 @@
-/*-------------------------------------------------------------------------------
- * 4.c
- * Placeholder File 4 -- This file is for temporary code storage
- *
- *
- *
- *-----------------------------------------------------------------------------*/
\ No newline at end of file
diff --git a/src/5.c b/src/5.c
deleted file mode 100644
index f05bb01..0000000
--- a/src/5.c
+++ /dev/null
@@ -1,7 +0,0 @@
-/*-------------------------------------------------------------------------------
- * 5.c
- * Placeholder File 5 -- This file is for temporary code storage
- *
- *
- *
- *-----------------------------------------------------------------------------*/
\ No newline at end of file
diff --git a/src/crypt-aes.c b/src/crypt-aes.c
new file mode 100644
index 0000000..99e03d7
--- /dev/null
+++ b/src/crypt-aes.c
@@ -0,0 +1,921 @@
+/*-------------------------------------------------------------------------------
+ * aes.c Tinier AES
+ * Easy To Use (and configurable) AES Output and Utility Bit/Byte Functions
+ *
+ * Modified Tiny AES code for more variable nk/nr/nb values, all in one file
+ * https://github.com/kokke/tiny-AES-c
+ *-----------------------------------------------------------------------------*/
+
+
+/*
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ For more information, please refer to
+
+*/
+
+#include
+#include
+#include
+// #include "aes.h"
+
+#define AES_BLOCKLEN 16
+unsigned Nb = 4;
+unsigned Nk = 8;
+unsigned Nr = 14;
+
+struct AES_ctx
+{
+ uint8_t RoundKey[240];
+ uint8_t Iv[16];
+};
+
+//internal function prototypes
+void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
+void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
+void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
+void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
+void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
+void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
+void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
+void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
+
+typedef uint8_t state_t[4][4];
+
+static const uint8_t sbox[256] = {
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
+
+static const uint8_t rsbox[256] = {
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
+
+static const uint8_t Rcon[11] = {
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
+
+#define getSBoxValue(num) (sbox[(num)])
+
+static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
+{
+ unsigned i, j, k;
+ uint8_t tempa[4]; // Used for the column/row operations
+
+ // The first round key is the key itself.
+ for (i = 0; i < Nk; ++i)
+ {
+ RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
+ RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
+ RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
+ RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
+ }
+
+ // All other round keys are found from the previous round keys.
+ for (i = Nk; i < Nb * (Nr + 1); ++i)
+ {
+ {
+ k = (i - 1) * 4;
+ tempa[0]=RoundKey[k + 0];
+ tempa[1]=RoundKey[k + 1];
+ tempa[2]=RoundKey[k + 2];
+ tempa[3]=RoundKey[k + 3];
+
+ }
+
+ if (i % Nk == 0)
+ {
+ // This function shifts the 4 bytes in a word to the left once.
+ // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
+
+ // Function RotWord()
+ {
+ const uint8_t u8tmp = tempa[0];
+ tempa[0] = tempa[1];
+ tempa[1] = tempa[2];
+ tempa[2] = tempa[3];
+ tempa[3] = u8tmp;
+ }
+
+ // SubWord() is a function that takes a four-byte input word and
+ // applies the S-box to each of the four bytes to produce an output word.
+
+ // Function Subword()
+ {
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+ }
+
+ tempa[0] = tempa[0] ^ Rcon[i/Nk];
+ }
+
+ if (Nk == 8) //only run if using AES256 (Nk == 8)
+ {
+ if (i % Nk == 4)
+ {
+ // Function Subword()
+ {
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+ }
+ }
+ }
+
+ j = i * 4; k=(i - Nk) * 4;
+ RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
+ RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
+ RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
+ RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
+ }
+}
+
+//input bit array, return output as up to a 64-bit value
+uint64_t convert_bits_into_output_ta(uint8_t * input, int len)
+{
+ int i;
+ uint64_t output = 0;
+ for(i = 0; i < len; i++)
+ {
+ output <<= 1;
+ output |= (uint64_t)(input[i] & 1);
+ }
+ return output;
+}
+
+//take x amount of bits and pack into len amount of bytes (symmetrical)
+void pack_bit_array_into_byte_array_ta (uint8_t * input, uint8_t * output, int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ output[i] = (uint8_t)convert_bits_into_output_ta(&input[i*8], 8);
+}
+
+//take len amount of bytes and unpack back into a bit array
+void unpack_byte_array_into_bit_array_ta (uint8_t * input, uint8_t * output, int len)
+{
+ int i = 0, k = 0;
+ for (i = 0; i < len; i++)
+ {
+ output[k++] = (input[i] >> 7) & 1;
+ output[k++] = (input[i] >> 6) & 1;
+ output[k++] = (input[i] >> 5) & 1;
+ output[k++] = (input[i] >> 4) & 1;
+ output[k++] = (input[i] >> 3) & 1;
+ output[k++] = (input[i] >> 2) & 1;
+ output[k++] = (input[i] >> 1) & 1;
+ output[k++] = (input[i] >> 0) & 1;
+ }
+}
+
+void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
+{
+ KeyExpansion(ctx->RoundKey, key);
+}
+void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
+{
+ KeyExpansion(ctx->RoundKey, key);
+ memcpy (ctx->Iv, iv, AES_BLOCKLEN);
+}
+void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
+{
+ memcpy (ctx->Iv, iv, AES_BLOCKLEN);
+}
+
+static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
+{
+ uint8_t i,j;
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 4; ++j)
+ {
+ (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
+ }
+ }
+}
+
+static void SubBytes(state_t* state)
+{
+ uint8_t i, j;
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 4; ++j)
+ {
+ (*state)[j][i] = getSBoxValue((*state)[j][i]);
+ }
+ }
+}
+
+static void ShiftRows(state_t* state)
+{
+ uint8_t temp;
+
+ // Rotate first row 1 columns to left
+ temp = (*state)[0][1];
+ (*state)[0][1] = (*state)[1][1];
+ (*state)[1][1] = (*state)[2][1];
+ (*state)[2][1] = (*state)[3][1];
+ (*state)[3][1] = temp;
+
+ // Rotate second row 2 columns to left
+ temp = (*state)[0][2];
+ (*state)[0][2] = (*state)[2][2];
+ (*state)[2][2] = temp;
+
+ temp = (*state)[1][2];
+ (*state)[1][2] = (*state)[3][2];
+ (*state)[3][2] = temp;
+
+ // Rotate third row 3 columns to left
+ temp = (*state)[0][3];
+ (*state)[0][3] = (*state)[3][3];
+ (*state)[3][3] = (*state)[2][3];
+ (*state)[2][3] = (*state)[1][3];
+ (*state)[1][3] = temp;
+}
+
+static uint8_t xtime(uint8_t x)
+{
+ return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
+}
+
+static void MixColumns(state_t* state)
+{
+ uint8_t i;
+ uint8_t Tmp, Tm, t;
+ for (i = 0; i < 4; ++i)
+ {
+ t = (*state)[i][0];
+ Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
+ Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
+ Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
+ Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
+ Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
+ }
+}
+
+#define Multiply(x, y) \
+ ( ((y & 1) * x) ^ \
+ ((y>>1 & 1) * xtime(x)) ^ \
+ ((y>>2 & 1) * xtime(xtime(x))) ^ \
+ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
+ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
+
+
+#define getSBoxInvert(num) (rsbox[(num)])
+
+static void InvMixColumns(state_t* state)
+{
+ int i;
+ uint8_t a, b, c, d;
+ for (i = 0; i < 4; ++i)
+ {
+ a = (*state)[i][0];
+ b = (*state)[i][1];
+ c = (*state)[i][2];
+ d = (*state)[i][3];
+
+ (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
+ (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
+ (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
+ (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
+ }
+}
+
+static void InvSubBytes(state_t* state)
+{
+ uint8_t i, j;
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 4; ++j)
+ {
+ (*state)[j][i] = getSBoxInvert((*state)[j][i]);
+ }
+ }
+}
+
+static void InvShiftRows(state_t* state)
+{
+ uint8_t temp;
+
+ // Rotate first row 1 columns to right
+ temp = (*state)[3][1];
+ (*state)[3][1] = (*state)[2][1];
+ (*state)[2][1] = (*state)[1][1];
+ (*state)[1][1] = (*state)[0][1];
+ (*state)[0][1] = temp;
+
+ // Rotate second row 2 columns to right
+ temp = (*state)[0][2];
+ (*state)[0][2] = (*state)[2][2];
+ (*state)[2][2] = temp;
+
+ temp = (*state)[1][2];
+ (*state)[1][2] = (*state)[3][2];
+ (*state)[3][2] = temp;
+
+ // Rotate third row 3 columns to right
+ temp = (*state)[0][3];
+ (*state)[0][3] = (*state)[1][3];
+ (*state)[1][3] = (*state)[2][3];
+ (*state)[2][3] = (*state)[3][3];
+ (*state)[3][3] = temp;
+}
+
+// Cipher is the main function that encrypts the PlainText,
+// or produces a keystream, depending on application.
+static void Cipher(state_t* state, const uint8_t* RoundKey)
+{
+ uint8_t round = 0;
+
+ // Add the First round key to the state before starting the rounds.
+ AddRoundKey(0, state, RoundKey);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr rounds are executed in the loop below.
+ // Last one without MixColumns()
+ for (round = 1; ; ++round)
+ {
+ SubBytes(state);
+ ShiftRows(state);
+ if (round == Nr) {
+ break;
+ }
+ MixColumns(state);
+ AddRoundKey(round, state, RoundKey);
+ }
+ // Add round key to last round
+ AddRoundKey(Nr, state, RoundKey);
+}
+
+static void InvCipher(state_t* state, const uint8_t* RoundKey)
+{
+ uint8_t round = 0;
+
+ // Add the First round key to the state before starting the rounds.
+ AddRoundKey(Nr, state, RoundKey);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr rounds are executed in the loop below.
+ // Last one without InvMixColumn()
+ for (round = (Nr - 1); ; --round)
+ {
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(round, state, RoundKey);
+ if (round == 0) {
+ break;
+ }
+ InvMixColumns(state);
+ }
+
+}
+
+void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
+{
+ // The next function call encrypts the PlainText with the Key using AES algorithm.
+ Cipher((state_t*)buf, ctx->RoundKey);
+}
+
+void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
+{
+ // The next function call decrypts the PlainText with the Key using AES algorithm.
+ InvCipher((state_t*)buf, ctx->RoundKey);
+}
+
+static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
+{
+ uint8_t i;
+ for (i = 0; i < AES_BLOCKLEN; ++i)
+ {
+ buf[i] ^= Iv[i];
+ }
+}
+
+void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length)
+{
+ size_t i;
+ uint8_t *Iv = ctx->Iv;
+ for (i = 0; i < length; i += AES_BLOCKLEN)
+ {
+ XorWithIv(buf, Iv);
+ Cipher((state_t*)buf, ctx->RoundKey);
+ Iv = buf;
+ buf += AES_BLOCKLEN;
+ }
+ /* store Iv in ctx for next call */
+ memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
+}
+
+void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
+{
+ size_t i;
+ uint8_t storeNextIv[AES_BLOCKLEN];
+ for (i = 0; i < length; i += AES_BLOCKLEN)
+ {
+ memcpy(storeNextIv, buf, AES_BLOCKLEN);
+ InvCipher((state_t*)buf, ctx->RoundKey);
+ XorWithIv(buf, ctx->Iv);
+ memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
+ buf += AES_BLOCKLEN;
+ }
+
+}
+
+/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
+void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
+{
+ uint8_t buffer[AES_BLOCKLEN];
+
+ size_t i;
+ int bi;
+ for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
+ {
+ if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
+ {
+
+ memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
+ Cipher((state_t*)buffer,ctx->RoundKey);
+
+ /* Increment Iv and handle overflow */
+ for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
+ {
+ /* inc will overflow */
+ if (ctx->Iv[bi] == 255)
+ {
+ ctx->Iv[bi] = 0;
+ continue;
+ }
+ ctx->Iv[bi] += 1;
+ break;
+ }
+ bi = 0;
+ }
+
+ buf[i] = (buf[i] ^ buffer[bi]);
+ }
+
+}
+
+//byte-wise output of AES OFB Keystream
+//input iv is a 16-byte uint8_t array of initialization vector
+//input key is up to 32-byte uint8_t array of key value
+//input type is the type/key len of AES required (0-128, 1-192, 2-256)
+//input nblocks is the number of rounds of 16-byte keystream output blocks requried
+//output is a uint8_t bytewise array, each round filled with 16-bytes from aes keystream output
+void aes_ofb_keystream_output (uint8_t * iv, uint8_t * key, uint8_t * output, int type, int nblocks)
+{
+
+ int i;
+ uint8_t input_register[16]; //OFB Input Register
+ memset (input_register, 0, sizeof(input_register));
+
+ //Set values specific to type (128/192/256)
+ if (type == 0) //128
+ {
+ Nb = 4;
+ Nk = 4;
+ Nr = 10;
+ }
+ else if (type == 1) //192
+ {
+ Nb = 4;
+ Nk = 6;
+ Nr = 12;
+ }
+ else //if (type == 2) //256
+ {
+ Nb = 4;
+ Nk = 8;
+ Nr = 14;
+ }
+
+ struct AES_ctx ctx;
+
+ //load first round of input_register with received IV (OFB First Input Register)
+ memcpy (input_register, iv, 16*sizeof(uint8_t) );
+
+ //initialize the key variable for the Cipher function
+ memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
+ KeyExpansion(ctx.RoundKey, key);
+
+ //execute the cipher function, and copy ciphered input_register to output for required number of rounds
+ for (i = 0; i < nblocks; i++)
+ {
+ Cipher((state_t*)input_register, ctx.RoundKey); //input_register is returned as output, and is put back in as object feedback
+ memcpy (output+(i*16), input_register, 16*sizeof(uint8_t) ); //copy ciphered input_register to output
+ }
+
+}
+
+//byte-wise AES CFB (Cipher Feedback) Payload operating in 128-bit block mode
+//input in is a uint8_t bytewise array,is the input to be ciphered (encrypted or decrypted)
+//input iv is a 16-byte uint8_t array of initialization vector
+//input key is up to 32-byte uint8_t array of key value
+//input type is the type/key len of AES required (0-128, 1-192, 2-256)
+//input nblocks is the number of rounds of 16-byte payload blocks requried (last block will need padding if not flush)
+//output out is a uint8_t bytewise array, each round filled with 16-bytes of cfb ciphered output (encrypted or decrypted)
+//de is a bit-flag signalling to run Cipher (encrypt) on 1, or InvCipher (decrypt) on 0
+void aes_cfb_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de)
+{
+
+ int i, j;
+ uint8_t input_register[16]; //Input Register
+ memset (input_register, 0, sizeof(input_register));
+
+ //Set values specific to type (128/192/256)
+ if (type == 0) //128
+ {
+ Nb = 4;
+ Nk = 4;
+ Nr = 10;
+ }
+ else if (type == 1) //192
+ {
+ Nb = 4;
+ Nk = 6;
+ Nr = 12;
+ }
+ else //if (type == 2) //256
+ {
+ Nb = 4;
+ Nk = 8;
+ Nr = 14;
+ }
+
+ struct AES_ctx ctx;
+
+ //load first round of input_register with received IV (CFB First Input Register)
+ memcpy (input_register, iv, 16*sizeof(uint8_t) );
+
+ //initialize the key variable for the Cipher function
+ memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
+ KeyExpansion(ctx.RoundKey, key);
+
+ //execute the cipher function, and copy ciphered input_register to output for required number of rounds
+ for (i = 0; i < nblocks; i++)
+ {
+
+ //the cipher is always run in the foward, or encryption mode
+ Cipher((state_t*)input_register, ctx.RoundKey);
+
+ //xor the current input 'in' to the current state of the input_register for cipher feedback
+ for (j = 0; j < 16; j++)
+ input_register[j] ^= in[j+(i*16)];
+
+ //copy ciphered/xor'd input_register to output 'out'
+ memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
+
+ //if running in decryption mode, we feed in the next round of input
+ if (!de)
+ memcpy(input_register, in+(i*16), 16*sizeof(uint8_t));
+
+ }
+
+}
+
+//byte-wise AES CBC (Cipher Block Chaining) //Yeah, I know this already exists, but wanted a custom convenience wrapper version
+//input in is a uint8_t bytewise array,is the input to be ciphered (encrypted or decrypted)
+//input iv is a 16-byte uint8_t array of initialization vector
+//input key is up to 32-byte uint8_t array of key value
+//input type is the type/key len of AES required (0-128, 1-192, 2-256)
+//input nblocks is the number of rounds of 16-byte payload blocks requried (last block will need padding if not flush)
+//output out is a uint8_t bytewise array, each round filled with 16-bytes of cfb ciphered output (encrypted or decrypted)
+//de is a bit-flag signalling to run Cipher (encrypt) on 1, or InvCipher (decrypt) on 0
+void aes_cbc_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de)
+{
+
+ int i, j;
+ uint8_t input_register[16]; //Input Register
+ memset (input_register, 0, sizeof(input_register));
+
+ //Set values specific to type (128/192/256)
+ if (type == 0) //128
+ {
+ Nb = 4;
+ Nk = 4;
+ Nr = 10;
+ }
+ else if (type == 1) //192
+ {
+ Nb = 4;
+ Nk = 6;
+ Nr = 12;
+ }
+ else //if (type == 2) //256
+ {
+ Nb = 4;
+ Nk = 8;
+ Nr = 14;
+ }
+
+ struct AES_ctx ctx;
+
+ //load first round of input_register accordingly
+ if (de)
+ memcpy (input_register, iv, 16*sizeof(uint8_t) );
+ else memcpy (input_register, in, 16*sizeof(uint8_t) );
+
+ //initialize the key variable for the Cipher function
+ memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
+ KeyExpansion(ctx.RoundKey, key);
+
+ //
+ for (i = 0; i < nblocks; i++)
+ {
+
+ //run encryption or decryption depending on de value
+ if (de) //encrypt
+ {
+
+ //xor the current input 'in' pt to the current state of the input_register for cbc feedback
+ for (j = 0; j < 16; j++)
+ input_register[j] ^= in[j+(i*16)];
+
+ Cipher((state_t*)input_register, ctx.RoundKey);
+
+ //copy ciphered input_register to output 'out'
+ memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
+
+ }
+
+ else //decrypt
+ {
+
+ InvCipher((state_t*)input_register, ctx.RoundKey);
+
+ //copy ciphered input_register to output 'out'
+ memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
+
+ //xor the current output by IV, or by last received CT
+ if (i == 0)
+ {
+ for (j = 0; j < 16; j++)
+ out[j] ^= iv[j];
+ }
+ else
+ {
+ for (j = 0; j < 16; j++)
+ out[j+(i*16)] ^= in[j+((i-1)*16)];
+ }
+
+ //copy in next segment for input_register (if not last)
+ if (i < nblocks)
+ memcpy(input_register, in+((i+1)*16), 16*sizeof(uint8_t) );
+
+ }
+
+ }
+
+}
+
+//byte-wise AES CBC_MAC (Cipher Block Chaining Message Authentication) //This is slightly different than above, no IV is present,
+//but if iv is desireable, it will need to be pre-XOR'd with the first plaintext input block by the calling function
+//input in is a uint8_t bytewise array, is the input to be ciphered.
+//input key is up to 32-byte uint8_t array of key value
+//input type is the type/key len of AES required (0-128, 1-192, 2-256)
+//input nblocks is the number of rounds of 16-byte payload blocks requried (last block will need padding if not flush)
+//output out is a uint8_t bytewise array, with only the final round output as the MAC octets
+//NOTE: When doing a cbc_mac, you should only run it in the forward (encryption) mode to get the mac bytes
+void aes_cbc_mac_generator (uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks)
+{
+
+ int i, j;
+ uint8_t input_register[16]; //Input Register
+ memset (input_register, 0, sizeof(input_register));
+
+ //Set values specific to type (128/192/256)
+ if (type == 0) //128
+ {
+ Nb = 4;
+ Nk = 4;
+ Nr = 10;
+ }
+ else if (type == 1) //192
+ {
+ Nb = 4;
+ Nk = 6;
+ Nr = 12;
+ }
+ else //if (type == 2) //256
+ {
+ Nb = 4;
+ Nk = 8;
+ Nr = 14;
+ }
+
+ struct AES_ctx ctx;
+
+ //initialize the key variable for the Cipher function
+ memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
+ KeyExpansion(ctx.RoundKey, key);
+
+ //
+ for (i = 0; i < nblocks; i++)
+ {
+
+ //xor the current input 'in' pt to the current state of the input_register for cbc feedback
+ //if this is the first iteration, this will load the first round plain text instead
+ for (j = 0; j < 16; j++)
+ input_register[j] ^= in[j+((i+0)*16)];
+
+ Cipher((state_t*)input_register, ctx.RoundKey);
+
+ //debug, load out all intermediate output register values
+ // memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
+
+ }
+
+ //copy final ciphered input_register to output 'out', user will determine how many bytes of output they want for MAC
+ memcpy (out, input_register, 16*sizeof(uint8_t) );
+
+}
+
+//byte-wise output of AES ECB Ciphering/Deciphering
+//input is uint8_t byte-wise (16-bytes) data to be ciphered or deciphered
+//input key is up to 32-byte uint8_t array of key value
+//input type is the type/len of AES required (0-128, 1-192, 2-256)
+//output is a uint8_t bytewise array of ciphered or deciphered input
+//de is a bit-flag signalling to run Cipher (encrypt) on 1, or InvCipher (decrypt) on 0
+void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de)
+{
+
+ uint8_t input_register[16]; //ECB Input Register
+ memset (input_register, 0, sizeof(input_register));
+
+ //Set values specific to type (128/192/256)
+ if (type == 0) //128
+ {
+ Nb = 4;
+ Nk = 4;
+ Nr = 10;
+ }
+ else if (type == 1) //192
+ {
+ Nb = 4;
+ Nk = 6;
+ Nr = 12;
+ }
+ else //if (type == 2) //256
+ {
+ Nb = 4;
+ Nk = 8;
+ Nr = 14;
+ }
+
+ struct AES_ctx ctx;
+
+ //load input_register with received input (ECB Payload)
+ memcpy (input_register, input, 16*sizeof(uint8_t) );
+
+ //initialize the key variable for the Cipher function
+ memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
+ KeyExpansion(ctx.RoundKey, key);
+
+ //run encryption or decryption depending on de value
+ if (de) //encrypt
+ Cipher((state_t*)input_register, ctx.RoundKey);
+ else //decrypt
+ InvCipher((state_t*)input_register, ctx.RoundKey);
+
+ //copy ciphered/deciphered input_register to output
+ memcpy (output, input_register, 16*sizeof(uint8_t) );
+
+}
+
+//symmetrical ctr mode payload encryption and decryption
+void aes_ctr_bitwise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type)
+{
+
+ //Set values specific to type (128/192/256)
+ if (type == 0) //128
+ {
+ Nb = 4;
+ Nk = 4;
+ Nr = 10;
+ }
+ else if (type == 1) //192
+ {
+ Nb = 4;
+ Nk = 6;
+ Nr = 12;
+ }
+ else //if (type == 2) //256
+ {
+ Nb = 4;
+ Nk = 8;
+ Nr = 14;
+ }
+
+ struct AES_ctx ctx;
+
+ //init and set the iv and key variables
+ memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
+ memset (ctx.Iv, 0, 16*sizeof(uint8_t));
+
+ KeyExpansion(ctx.RoundKey, key);
+ memcpy (ctx.Iv, iv, AES_BLOCKLEN);
+
+ //pack input bit-wise payload to byte array
+ uint8_t payload_bytes[16];
+ memset (payload_bytes, 0, sizeof(payload_bytes));
+ pack_bit_array_into_byte_array_ta (payload, payload_bytes, 16);
+
+ //pass to internal CTR handler for payload
+ AES_CTR_xcrypt_buffer(&ctx, payload_bytes, 16);
+
+ //unpack output bytes back to bits
+ unpack_byte_array_into_bit_array_ta(payload_bytes, payload, 16);
+
+}
+
+//symmetrical ctr mode payload encryption and decryption
+void aes_ctr_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type)
+{
+
+ //Set values specific to type (128/192/256)
+ if (type == 0) //128
+ {
+ Nb = 4;
+ Nk = 4;
+ Nr = 10;
+ }
+ else if (type == 1) //192
+ {
+ Nb = 4;
+ Nk = 6;
+ Nr = 12;
+ }
+ else //if (type == 2) //256
+ {
+ Nb = 4;
+ Nk = 8;
+ Nr = 14;
+ }
+
+ struct AES_ctx ctx;
+
+ //init and set the iv and key variables
+ memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
+ memset (ctx.Iv, 0, 16*sizeof(uint8_t));
+
+ KeyExpansion(ctx.RoundKey, key);
+ memcpy (ctx.Iv, iv, AES_BLOCKLEN);
+
+ //pass to internal CTR handler for payload
+ AES_CTR_xcrypt_buffer(&ctx, payload, 16);
+
+}
diff --git a/src/crypt-des.c b/src/crypt-des.c
new file mode 100644
index 0000000..44afae3
--- /dev/null
+++ b/src/crypt-des.c
@@ -0,0 +1,831 @@
+/*-------------------------------------------------------------------------------
+ * des.c Crypthings
+ * DES Alg
+ *-----------------------------------------------------------------------------*/
+
+#include
+#include
+#include
+
+#include
+#include
+
+//NOTE: The SLUT boxes are S boxes with additional calculations so we don't have
+//to manually sort out row and column values and can cut down on operations
+
+uint8_t SLUT1[64] = {
+0xE0,0x00,0x40,0xF0,0xD0,0x70,0x10,0x40,
+0x20,0xE0,0xF0,0x20,0xB0,0xD0,0x80,0x10,
+0x30,0xA0,0xA0,0x60,0x60,0xC0,0xC0,0xB0,
+0x50,0x90,0x90,0x50,0x00,0x30,0x70,0x80,
+0x40,0xF0,0x10,0xC0,0xE0,0x80,0x80,0x20,
+0xD0,0x40,0x60,0x90,0x20,0x10,0xB0,0x70,
+0xF0,0x50,0xC0,0xB0,0x90,0x30,0x70,0xE0,
+0x30,0xA0,0xA0,0x00,0x50,0x60,0x00,0xD0
+};
+
+uint8_t SLUT2[64] = {
+0x0F,0x03,0x01,0x0D,0x08,0x04,0x0E,0x07,
+0x06,0x0F,0x0B,0x02,0x03,0x08,0x04,0x0E,
+0x09,0x0C,0x07,0x00,0x02,0x01,0x0D,0x0A,
+0x0C,0x06,0x00,0x09,0x05,0x0B,0x0A,0x05,
+0x00,0x0D,0x0E,0x08,0x07,0x0A,0x0B,0x01,
+0x0A,0x03,0x04,0x0F,0x0D,0x04,0x01,0x02,
+0x05,0x0B,0x08,0x06,0x0C,0x07,0x06,0x0C,
+0x09,0x00,0x03,0x05,0x02,0x0E,0x0F,0x09
+};
+
+uint8_t SLUT3[64] = {
+0xA0,0xD0,0x00,0x70,0x90,0x00,0xE0,0x90,
+0x60,0x30,0x30,0x40,0xF0,0x60,0x50,0xA0,
+0x10,0x20,0xD0,0x80,0xC0,0x50,0x70,0xE0,
+0xB0,0xC0,0x40,0xB0,0x20,0xF0,0x80,0x10,
+0xD0,0x10,0x60,0xA0,0x40,0xD0,0x90,0x00,
+0x80,0x60,0xF0,0x90,0x30,0x80,0x00,0x70,
+0xB0,0x40,0x10,0xF0,0x20,0xE0,0xC0,0x30,
+0x50,0xB0,0xA0,0x50,0xE0,0x20,0x70,0xC0
+};
+
+uint8_t SLUT4[64] = {
+0x07,0x0D,0x0D,0x08,0x0E,0x0B,0x03,0x05,
+0x00,0x06,0x06,0x0F,0x09,0x00,0x0A,0x03,
+0x01,0x04,0x02,0x07,0x08,0x02,0x05,0x0C,
+0x0B,0x01,0x0C,0x0A,0x04,0x0E,0x0F,0x09,
+0x0A,0x03,0x06,0x0F,0x09,0x00,0x00,0x06,
+0x0C,0x0A,0x0B,0x01,0x07,0x0D,0x0D,0x08,
+0x0F,0x09,0x01,0x04,0x03,0x05,0x0E,0x0B,
+0x05,0x0C,0x02,0x07,0x08,0x02,0x04,0x0E
+};
+
+uint8_t SLUT5[64] = {
+0x20,0xE0,0xC0,0xB0,0x40,0x20,0x10,0xC0,
+0x70,0x40,0xA0,0x70,0xB0,0xD0,0x60,0x10,
+0x80,0x50,0x50,0x00,0x30,0xF0,0xF0,0xA0,
+0xD0,0x30,0x00,0x90,0xE0,0x80,0x90,0x60,
+0x40,0xB0,0x20,0x80,0x10,0xC0,0xB0,0x70,
+0xA0,0x10,0xD0,0xE0,0x70,0x20,0x80,0xD0,
+0xF0,0x60,0x90,0xF0,0xC0,0x00,0x50,0x90,
+0x60,0xA0,0x30,0x40,0x00,0x50,0xE0,0x30
+};
+
+uint8_t SLUT6[64] = {
+0x0C,0x0A,0x01,0x0F,0x0A,0x04,0x0F,0x02,
+0x09,0x07,0x02,0x0C,0x06,0x09,0x08,0x05,
+0x00,0x06,0x0D,0x01,0x03,0x0D,0x04,0x0E,
+0x0E,0x00,0x07,0x0B,0x05,0x03,0x0B,0x08,
+0x09,0x04,0x0E,0x03,0x0F,0x02,0x05,0x0C,
+0x02,0x09,0x08,0x05,0x0C,0x0F,0x03,0x0A,
+0x07,0x0B,0x00,0x0E,0x04,0x01,0x0A,0x07,
+0x01,0x06,0x0D,0x00,0x0B,0x08,0x06,0x0D
+};
+
+uint8_t SLUT7[64] = {
+0x40,0xD0,0xB0,0x00,0x20,0xB0,0xE0,0x70,
+0xF0,0x40,0x00,0x90,0x80,0x10,0xD0,0xA0,
+0x30,0xE0,0xC0,0x30,0x90,0x50,0x70,0xC0,
+0x50,0x20,0xA0,0xF0,0x60,0x80,0x10,0x60,
+0x10,0x60,0x40,0xB0,0xB0,0xD0,0xD0,0x80,
+0xC0,0x10,0x30,0x40,0x70,0xA0,0xE0,0x70,
+0xA0,0x90,0xF0,0x50,0x60,0x00,0x80,0xF0,
+0x00,0xE0,0x50,0x20,0x90,0x30,0x20,0xC0
+};
+
+uint8_t SLUT8[64] = {
+0x0D,0x01,0x02,0x0F,0x08,0x0D,0x04,0x08,
+0x06,0x0A,0x0F,0x03,0x0B,0x07,0x01,0x04,
+0x0A,0x0C,0x09,0x05,0x03,0x06,0x0E,0x0B,
+0x05,0x00,0x00,0x0E,0x0C,0x09,0x07,0x02,
+0x07,0x02,0x0B,0x01,0x04,0x0E,0x01,0x07,
+0x09,0x04,0x0C,0x0A,0x0E,0x08,0x02,0x0D,
+0x00,0x0F,0x06,0x0C,0x0A,0x09,0x0D,0x00,
+0x0F,0x03,0x03,0x05,0x05,0x06,0x08,0x0B
+};
+
+//initial permutation IP (on input)
+uint8_t initial_register_permutation[64] = {
+58, 50, 42, 34, 26, 18, 10, 2,
+60, 52, 44, 36, 28, 20, 12, 4,
+62, 54, 46, 38, 30, 22, 14, 6,
+64, 56, 48, 40, 32, 24, 16, 8,
+57, 49, 41, 33, 25, 17, 9, 1,
+59, 51, 43, 35, 27, 19, 11, 3,
+61, 53, 45, 37, 29, 21, 13, 5,
+63, 55, 47, 39, 31, 23, 15, 7};
+
+//D-Box Expansion (sometimes noted as E BIT-SELECTION TABLE)
+uint8_t message_expansion[48] = {
+32, 1, 2, 3, 4, 5,
+4, 5, 6, 7, 8, 9,
+8, 9, 10, 11, 12, 13,
+12, 13, 14, 15, 16, 17,
+16, 17, 18, 19, 20, 21,
+20, 21, 22, 23, 24, 25,
+24, 25, 26, 27, 28, 29,
+28, 29, 30, 31, 32, 1};
+
+// (sometimes noted as simply 'P')
+uint8_t right_half_permutation[32] = {
+16, 7, 20, 21,
+29, 12, 28, 17,
+1, 15, 23, 26,
+5, 18, 31, 10,
+2, 8, 24, 14,
+32, 27, 3, 9,
+19, 13, 30, 6,
+22, 11, 4, 25};
+
+//inverse initial PI, a.k.a. final permutation (on output)
+uint8_t final_register_permutation[64] = {
+40, 8, 48, 16, 56, 24, 64, 32,
+39, 7, 47, 15, 55, 23, 63, 31,
+38, 6, 46, 14, 54, 22, 62, 30,
+37, 5, 45, 13, 53, 21, 61, 29,
+36, 4, 44, 12, 52, 20, 60, 28,
+35, 3, 43, 11, 51, 19, 59, 27,
+34, 2, 42, 10, 50, 18, 58, 26,
+33, 1, 41, 9, 49, 17, 57, 25};
+
+//initial key permutation
+uint8_t pc1_key_permutation[56] = {
+57, 49, 41, 33, 25, 17, 9,
+1, 58, 50, 42, 34, 26, 18,
+10, 2, 59, 51, 43, 35, 27,
+19, 11, 3, 60, 52, 44, 36,
+63, 55, 47, 39, 31, 23, 15,
+7, 62, 54, 46, 38, 30, 22,
+14, 6, 61, 53, 45, 37, 29,
+21, 13, 5, 28, 20, 12, 4};
+
+//sub c and d key permutation
+uint8_t pc2_key_permutation[48] = {
+//c bits
+14,17,11,24,1,5,
+3,28,15,6,21,10,
+23,19,12,4,26,8,
+16,7,27,20,13,2,
+//d bits (with -28 offset to simply/only have one permute function)
+13,24,3,9,19,27,
+2,12,23,17,5,20,
+16,21,11,28,6,25,
+18,14,22,8,1,4
+};
+
+uint8_t key_shift_sizes[17] = {
+1,
+1, 1, 2, 2,
+2, 2, 2, 2,
+1, 2, 2, 2,
+2, 2, 2, 1};
+
+uint8_t key_shift_bytes[17] = {
+0x80,
+0x80, 0x80, 0xC0, 0xC0,
+0xC0, 0xC0, 0xC0, 0xC0,
+0x80, 0xC0, 0xC0, 0xC0,
+0xC0, 0xC0, 0xC0, 0x80};
+
+uint8_t key_shift_x[4] = {8,8,8,4};
+
+uint8_t key_shift_y[4] = {1,2,3,0};
+
+//input is byte-wise array, output is byte-wise array
+void permute(uint8_t * input, uint8_t * output, uint8_t * table, uint8_t start, uint8_t end)
+{
+
+ for (uint8_t i = start; i < end; i++)
+ {
+ uint8_t tdiv = (table[i] - 1) / 8;
+ uint8_t tmod = (table[i] - 1) % 8;
+ uint8_t idiv = i/8;
+ uint8_t imod = i%8;
+
+ //need a way to simplify or get rid of all these shifts
+ uint8_t bit = (((input[tdiv] & (0x80 >> tmod)) << tmod) >> imod);
+ output[idiv] |= bit;
+ }
+
+}
+
+void rotate_sub_keys(uint8_t * Kc, uint8_t * Kd, uint8_t shift_size, uint8_t shift_byte)
+{
+
+ uint8_t sb1[4]; memset(sb1, 0, sizeof(sb1));
+ uint8_t sb2[4]; memset(sb2, 0, sizeof(sb2));
+
+ for (uint8_t i = 0; i < 4; i++)
+ {
+ sb1[i] = shift_byte & Kc[i];
+ sb2[i] = shift_byte & Kd[i];
+ }
+
+ for (uint8_t i = 0; i < 4; i++)
+ {
+
+ uint8_t x = key_shift_x[i];
+ uint8_t y = key_shift_y[i];
+
+ Kc[i] <<= shift_size;
+ Kd[i] <<= shift_size;
+
+ Kc[i] |= (sb1[y] >> (x - shift_size));
+ Kd[i] |= (sb2[y] >> (x - shift_size));
+
+ }
+}
+
+void des_cipher (uint8_t * main_key, uint8_t * input_register, uint8_t * output_register, uint8_t de)
+{
+
+ //starting and ending permutations
+ uint8_t initial_permutation[8]; memset(initial_permutation, 0, sizeof(initial_permutation));
+ uint8_t pre_end_permutation[8]; memset(pre_end_permutation, 0, sizeof(pre_end_permutation));
+
+ //intermediate left, right, and expansion/selection arrays
+ uint8_t left[4]; memset(left, 0, sizeof(left));
+ uint8_t right[4]; memset(right, 0, sizeof(right));
+ uint8_t rperm[4]; memset(rperm, 0, sizeof(rperm));
+ uint8_t exp[6]; memset(exp, 0, sizeof(exp));
+ uint8_t sel[4]; memset(sel, 0, sizeof(sel));
+
+ //key sets
+ uint8_t Ks[16][7]; memset(Ks, 0, sizeof(Ks));
+ uint8_t Kc[4]; memset(Kc, 0, sizeof(Kc));
+ uint8_t Kd[4]; memset(Kd, 0, sizeof(Kd));
+
+ //initial Ks permutation and shuffle to Kc and Kd
+ permute (main_key, Ks[0], pc1_key_permutation, 0, 56);
+ for (uint8_t i = 0; i < 3; i++)
+ {
+ Kc[i] = Ks[0][i];
+ }
+ Kc[3] = Ks[0][3] & 0xF0;
+ for (uint8_t i = 0; i < 3; i++)
+ {
+ Kd[i] = (Ks[0][i+3] & 0x0F) << 4;
+ Kd[i] |= (Ks[0][i+4] & 0xF0) >> 4;
+ }
+ Kd[3] = (Ks[0][6] & 0x0F) << 4;
+
+ //reset Ks
+ memset(Ks, 0, sizeof(Ks));
+
+ //create the 16 Ks rounds
+ for (uint8_t i = 0; i < 16; i++)
+ {
+ uint8_t shift_size = key_shift_sizes[i+1];
+ uint8_t shift_byte = key_shift_bytes[i+1];
+ rotate_sub_keys(Kc, Kd, shift_size, shift_byte);
+ permute (Kc, Ks[i], pc2_key_permutation, 0, 24);
+ permute (Kd, Ks[i], pc2_key_permutation, 24, 48);
+ }
+
+ //permute the input_register with the ip (initial_register_permutation) table
+ permute (input_register, initial_permutation, initial_register_permutation, 0, 64);
+
+ //copy the initial permutation to left and right half arrays
+ memcpy (left, initial_permutation+0, sizeof(left));
+ memcpy (right, initial_permutation+4, sizeof(right));
+
+ //16 fiestel rounds
+ for (uint8_t f = 0; f < 16; f++)
+ {
+
+ //reset rperm and exp arrays
+ memset(rperm, 0, sizeof(rperm));
+ memset(exp, 0, sizeof(exp));
+
+ //expand right half from 32-bit to 48-bit
+ permute (right, exp, message_expansion, 0, 48);
+
+ //apply current iteration keyset to the expanded array (encryption cycles Ks forward, decryption goes in reverse)
+ if (de == 1)
+ {
+ for (uint8_t i = 0; i < 6; i++)
+ exp[i] ^= Ks[f][i];
+ }
+ else
+ {
+ for (uint8_t i = 0; i < 6; i++)
+ exp[i] ^= Ks[15-f][i];
+ }
+
+ //extract 6 bits for each sbox swap from the expanded array
+ uint8_t e1 = exp[0] >> 2;
+ uint8_t e2 = ((exp[0] & 0x3) << 4) | (exp[1] >> 4);
+ uint8_t e3 = ((exp[1] & 0xF) << 2) | (exp[2] >> 6);
+ uint8_t e4 = exp[2] & 0x3F;
+
+ uint8_t e5 = exp[3] >> 2;
+ uint8_t e6 = ((exp[3] & 0x3) << 4) | (exp[4] >> 4);
+ uint8_t e7 = ((exp[4] & 0xF) << 2) | (exp[5] >> 6);
+ uint8_t e8 = exp[5] & 0x3F;
+
+ //select 32-bits of each 48-bit expansion via modified S Box Look Up Tables
+ //swap the 6 bits for 4 bits via SLUT tables and OR them together into a selection array
+ sel[0] = SLUT1[e1] | SLUT2[e2];
+ sel[1] = SLUT3[e3] | SLUT4[e4];
+ sel[2] = SLUT5[e5] | SLUT6[e6];
+ sel[3] = SLUT7[e7] | SLUT8[e8];
+
+ //permute the selected 32-bits into a new right half
+ permute (sel, rperm, right_half_permutation, 0, 32);
+
+ //xor new right half against left half
+ for (uint8_t i = 0; i < 4; i++)
+ rperm[i] ^= left[i];
+
+ //swap old right half to left, set new right half to rperm
+ memcpy (left, right, sizeof(left));
+ memcpy (right, rperm, sizeof(right));
+
+ } //end fiestel rounds f
+
+ //combine right and left into the pre_end_permutation array
+ memcpy (pre_end_permutation+0, right, sizeof(right));
+ memcpy (pre_end_permutation+4, left, sizeof(left));
+
+ //carry out the final permuation to get the completed output_register for this cipher iteration
+ permute (pre_end_permutation, output_register, final_register_permutation, 0, 64);
+
+}
+
+void des56_ofb_keystream_output (uint8_t * main_key, uint8_t * iv, uint8_t * ks_bytes, uint8_t de, int16_t nblocks)
+{
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
+ memcpy(input_register, iv, sizeof(input_register));
+
+ //execute the des_cipher in output feedback mode
+ for (int16_t i = 0; i < nblocks; i++)
+ {
+ //de should be 1 here for encryption mode
+ des_cipher(main_key, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input register
+ memcpy(ks_bytes+(i*8), output_register, sizeof(output_register)); //copy output_register to ks_bytes + iteration offset of times 8
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+ }
+
+}
+
+//the des_cipher function is already ECB mode, this convenience wrapper is just available as a reminder to illustrate that point
+void des56_ecb_payload_crypt (uint8_t * main_key, uint8_t * input_register, uint8_t * output_register, uint8_t de)
+{
+ //de 1 for encryption mode, 0 for decryption mode
+ des_cipher(main_key, input_register, output_register, de);
+}
+
+//TDEA, or triple data encryption algorithm, or triple DES, in electronic codebook mode
+void tdea_ecb_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * input, uint8_t * output, uint8_t de)
+{
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //copy the input to the input_register (make copy so we don't manipulate the calling functions copy)
+ memcpy(input_register, input, sizeof(input_register));
+
+ //For TDEA, the cipher alternates between encryption and decryption to the payload
+ //so, for example, K1 is run as de=1, K2 is run as de=0, and K3 is run as de=1,
+ //K1 and K3 will always use the same mode and K2 will be the opposite
+
+ //NOTE: If running ECB mode in decryption, make sure to send the keys in reverse order
+ //so that its K3, K2, and K1 for decryption, and K1, K2, K3 for encryption
+
+ //K1
+ des_cipher(K1, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K2
+ de = (de ^ 1) & 1; //flip the de bit
+ des_cipher(K2, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K3
+ de = (de ^ 1) & 1; //flip the de bit back
+ des_cipher(K3, input_register, output_register, de);
+
+ //copy payload out
+ memcpy(output, output_register, sizeof(output_register)); //copy output_register to output
+
+}
+
+//TDEA, or triple data encryption algorithm, or triple DES, in cipher block chain mode (64-bit)
+//same as usual inputs (byte wise), also, if needing DES56, just feed the same key into K1, K2, and K3
+//if running in decryption mode, this will reverse the key bundle order from (K1, K2, K3) to (K3, K2, K1) on this end
+void tdea_cbc_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * in, uint8_t * out, int16_t nblocks, uint8_t de)
+{
+
+ int16_t i, j;
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //load first round of input_register accordingly
+ if (de)
+ memcpy (input_register, iv, sizeof(input_register)); //load the IV as first input_register if encrypting
+ else memcpy (input_register, in, sizeof(input_register)); //load first cipher text as input_register is decrypting
+
+ //run payload for number of payload nblocks required
+ for (i = 0; i < nblocks; i++)
+ {
+
+ if (de)
+ {
+
+ //xor the current input 'in' pt to the current state of the input_register for cbc feedback
+ for (j = 0; j < 8; j++)
+ input_register[j] ^= in[j+(i*8)];
+
+ //K1
+ des_cipher(K1, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K2
+ de = (de ^ 1) & 1; //flip the de bit
+ des_cipher(K2, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K3
+ de = (de ^ 1) & 1; //flip the de bit back
+ des_cipher(K3, input_register, output_register, de);
+ memcpy (input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+
+ //copy ciphered output_register to output 'out'
+ memcpy (out+(i*8), output_register, sizeof(output_register));
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ }
+ else
+ {
+
+ //K3
+ des_cipher(K3, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K2
+ de = (de ^ 1) & 1; //flip the de bit
+ des_cipher(K2, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K1
+ de = (de ^ 1) & 1; //flip the de bit back
+ des_cipher(K1, input_register, output_register, de);
+ memcpy (input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+
+ //copy ciphered input_register to output 'out'
+ memcpy (out+(i*8), output_register, sizeof(output_register));
+
+ //xor the current output by IV, or by last received CT, depending on round
+ if (i == 0)
+ {
+ for (j = 0; j < 8; j++)
+ out[j] ^= iv[j];
+ }
+ else
+ {
+ for (j = 0; j < 8; j++)
+ out[j+(i*8)] ^= in[j+((i-1)*8)];
+ }
+
+ //copy in next segment for input_register (if not last)
+ if (i < nblocks)
+ memcpy(input_register, in+((i+1)*8), sizeof(input_register));
+
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+ }
+
+ }
+
+}
+
+//TDEA, or triple data encryption algorithm, or triple DES, in cipher block chain mode (64-bit)
+//same as usual inputs (byte wise), also, if needing DES56, just feed the same key into K1, K2, and K3
+//only the last output_register is returned for the variable len MAC bytes, always run in encryption mode
+//but if iv is desireable, it will need to be pre-XOR'd with the first plaintext input block by the calling function
+void tdea_cbc_mac_generator (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * in, uint8_t * out, int16_t nblocks)
+{
+
+ int16_t i, j;
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //run payload for number of payload nblocks required
+ for (i = 0; i < nblocks; i++)
+ {
+
+ //the cipher is always run in the foward, or encryption mode (1,0,1)
+
+ //xor the current input 'in' pt to the current state of the input_register for cbc feedback
+ for (j = 0; j < 8; j++)
+ input_register[j] ^= in[j+(i*8)];
+
+ //K1
+ des_cipher(K1, input_register, output_register, 1);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K2
+ des_cipher(K2, input_register, output_register, 0);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K3
+ des_cipher(K3, input_register, output_register, 1);
+ memcpy (input_register, output_register, sizeof(output_register));
+
+ //copy ciphered output_register to output 'out'
+ //Since we only want the last output_register,
+ //this will overwrite the out until completion
+ memcpy (out, output_register, sizeof(output_register));
+
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ }
+
+}
+
+//TDEA, or triple data encryption algorithm, or triple DES, in cihper feedback mode (64-bit)
+//same as usual inputs (byte wise), also, if needing DES56, just feed the same key into K1, K2, and K3
+void tdea_cfb_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * in, uint8_t * out, int16_t nblocks, uint8_t de)
+{
+
+ int16_t i, j;
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
+ memcpy(input_register, iv, sizeof(input_register));
+
+ //execute the des_cipher in output feedback mode 3 times using each key and transferring output to input each time
+ for (i = 0; i < nblocks; i++)
+ {
+
+ //the cipher is always run in the foward, or encryption mode (1,0,1)
+
+ //K1
+ des_cipher(K1, input_register, output_register, 1);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K2
+ des_cipher(K2, input_register, output_register, 0);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K3
+ des_cipher(K3, input_register, output_register, 1);
+
+ //xor the current input 'in' to the current state of the input_register for cipher feedback
+ for (j = 0; j < 8; j++)
+ output_register[j] ^= in[j+(i*8)];
+
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+
+ //copy keystream out and reset
+ memcpy(out+(i*8), output_register, sizeof(output_register)); //copy output_register to ks_bytes + iteration offset of times 8
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //if running in decryption mode, we feed in the next round of input
+ if (!de)
+ memcpy(input_register, in+(i*8), sizeof(input_register));
+ }
+
+}
+
+//TDEA, or triple data encryption algorithm, or triple DES, in IV counter mode (tested, working)
+void tdea_ctr_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * input, uint8_t * output, int16_t nblocks)
+{
+
+ int16_t i, j;
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //copy the IV to the input_register (ctr mode will manipulate the IV, since it needs to keep a rolling counter
+ memcpy(input_register, iv, sizeof(input_register));
+
+ //execute the des_cipher in counter mode 3 times using each key and transferring output to input each time
+ //then the IV is iterated and fed back into the input_register to start the next nblocks loop
+ for (i = 0; i < nblocks; i++)
+ {
+
+ //CTR mode cipher should always run in the forward (encryption) mode
+
+ //K1
+ des_cipher(K1, input_register, output_register, 1);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K2
+ des_cipher(K2, input_register, output_register, 0);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K3
+ des_cipher(K3, input_register, output_register, 1);
+
+ //set output at current pointer to the xor of input current pointer and the output_register
+ for (j = 0; j < 8; j++)
+ output[j+(i*8)] = input[j+(i*8)] ^ output_register[j];
+
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //increment the IV, and handle roll over (uint8_t will rollover to 0 after 0xFF)
+ for (j = 7; j >= 0; j--)
+ {
+ iv[j]++;
+ if (iv[j] == 0)
+ continue;
+ else break;
+ }
+
+ //debug IV iteration
+ // fprintf (stderr, "\n IV: ");
+ // for (j = 0; j < 8; j++)
+ // fprintf (stderr, "%02X", iv[j]);
+
+ //feed the new IV into the input register
+ memcpy (input_register, iv, sizeof(input_register));
+
+ }
+
+}
+
+//TDEA, or triple data encryption algorithm, or triple DES, in output feedback mode
+void tdea_tofb_keystream_output (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * ks_bytes, uint8_t de, int16_t nblocks)
+{
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
+ memcpy(input_register, iv, sizeof(input_register));
+
+ //execute the des_cipher in output feedback mode 3 times using each key and transferring output to input each time
+ for (int16_t i = 0; i < nblocks; i++)
+ {
+ //K1
+ des_cipher(K1, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K2
+ de = (de ^ 1) & 1; //flip the de bit
+ des_cipher(K2, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+
+ //K3
+ de = (de ^ 1) & 1; //flip the de bit back
+ des_cipher(K3, input_register, output_register, de);
+ memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
+
+ //copy keystream out and reset
+ memcpy(ks_bytes+(i*8), output_register, sizeof(output_register)); //copy output_register to ks_bytes + iteration offset of times 8
+ memset(output_register, 0, sizeof(output_register)); //reset output register
+ }
+
+}
+
+//a linear feedback shift register with maximal taps on 64-bit values that can be run to any specified len,
+//its input is a byte array of up to 8 bytes, and its output is same array packed with new LFSR value in it.
+uint64_t lfsr_64_to_len_ca(uint8_t * iv, int16_t len)
+{
+
+ uint64_t lfsr = 0, bit = 0;
+
+ lfsr = ((uint64_t)iv[0] << 56ULL) + ((uint64_t)iv[1] << 48ULL) + ((uint64_t)iv[2] << 40ULL) + ((uint64_t)iv[3] << 32ULL) +
+ ((uint64_t)iv[4] << 24ULL) + ((uint64_t)iv[5] << 16ULL) + ((uint64_t)iv[6] << 8ULL) + ((uint64_t)iv[7] << 0ULL);
+
+ memset (iv, 0, 8*sizeof(uint8_t));
+
+ for(int16_t cnt = 0; cnt < len; cnt++)
+ {
+ //63,61,45,37,27,14
+ // Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
+ bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1;
+ lfsr = (lfsr << 1) | bit;
+ }
+
+ for (int16_t i = 0; i < 8; i++)
+ iv[i] = (lfsr >> (56-(i*8))) & 0xFF;
+
+ // fprintf (stderr, "\n IV(%02d): ", len);
+ // for (int16_t i = 0; i < 8; i++)
+ // fprintf (stderr, "%02X", iv[i]);
+
+ return bit;
+
+}
+
+void des56_ca_keystream_output (uint8_t * main_key, uint8_t * iv, uint8_t * ks_bytes, uint8_t de, int16_t ff, int16_t nbits)
+{
+
+ //cipher input and output
+ uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
+ uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
+
+ //copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
+ memcpy(input_register, iv, sizeof(input_register));
+
+ //fast forward the current input_register state
+ lfsr_64_to_len_ca(input_register, ff);
+
+ //execute the des_cipher in (CA) mode with 1-bit output
+ for (int16_t i = 0; i < nbits; i++)
+ {
+
+ //de should be 1 here for encryption mode
+ des_cipher(main_key, input_register, output_register, de);
+
+ //keystream accumulation, shift current byte and append
+ //single bit from current output register's most significant bit
+ ks_bytes[i/8] <<= 1;
+ ks_bytes[i/8] |= ((output_register[0] >> 7) & 1);
+
+ //advance the input_register with the lfsr 1 time
+ lfsr_64_to_len_ca(input_register, 1);
+
+ //reset output register
+ memset(output_register, 0, sizeof(output_register));
+
+ }
+
+ // fprintf (stderr, "\n IR: ");
+ // for (int16_t i = 0; i < 8; i++)
+ // fprintf (stderr, "%02X", input_register[i]);
+
+}
+
+//transitional function mainly to load key and iv into an array
+void des_multi_keystream_output (unsigned long long int mi, unsigned long long int key_ulli, uint8_t * output, int type, int len)
+{
+ int i = 0;
+ uint8_t iv[8]; memset (iv, 0, sizeof(iv));
+ uint8_t key[8]; memset(key, 0, sizeof(key));
+
+ //convert unsinged long long int values into array values
+ for (i = 7; i >= 0; i--)
+ iv[7-i] = (mi >> (8*i)) & 0xFF;
+
+ for (i = 7; i >= 0; i--)
+ key[7-i] = (key_ulli >> (8*i)) & 0xFF;
+
+ //debug
+ // fprintf (stderr, "\n IV: ");
+ // for (i = 0; i < 8; i++)
+ // fprintf (stderr, "%02X", iv[i]);
+ // fprintf (stderr, "\n Key: ");
+ // for (i = 0; i < 8; i++)
+ // fprintf (stderr, "%02X", key[i]);
+
+ //types: 1 = DES56 OFB; 2 = DES56 CA (XL)
+ if (type == 2)
+ {
+ if (len == 0)
+ des56_ca_keystream_output(key, iv, output, 1, 110+696, 1704);
+ else des56_ca_keystream_output(key, iv, output, 1, 110+000, 1704);
+ }
+ else des56_ofb_keystream_output(key, iv, output, 1, len);
+
+}
+
+//transitional function mainly to load iv into an array
+void tdea_multi_keystream_output (unsigned long long int mi, uint8_t * key, uint8_t * output, int type, int len)
+{
+ int i = 0;
+ uint8_t iv[8]; memset (iv, 0, sizeof(iv));
+
+ //convert unsinged long long int values into array values
+ for (i = 7; i >= 0; i--)
+ iv[7-i] = (mi >> (8*i)) & 0xFF;
+
+ //debug
+ // fprintf (stderr, "\n IV: ");
+ // for (i = 0; i < 8; i++)
+ // fprintf (stderr, "%02X", iv[i]);
+
+ //type 1 = TDEA TOFB //TODO: Add more types like 2DES?
+ if (type == 1)
+ tdea_tofb_keystream_output(key, key+8, key+16, iv, output, 1, len);
+ else tdea_tofb_keystream_output(key, key+8, key+16, iv, output, 1, len);
+
+}
\ No newline at end of file
diff --git a/src/1.c b/src/crypt-rc4.c
similarity index 54%
rename from src/1.c
rename to src/crypt-rc4.c
index 1637ece..ca95944 100644
--- a/src/1.c
+++ b/src/crypt-rc4.c
@@ -1,13 +1,49 @@
/*-------------------------------------------------------------------------------
- * 1.c
- * RC4 and RC4 Block Output For Keystream Application
- *
- *
- *
+ * rc4.c Crypthings
+ * RC4 Alg
*-----------------------------------------------------------------------------*/
#include "dsd.h"
+//this version is for voice, going to transition to a block output version
+void rc4_voice_decrypt(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[])
+{
+ int i, j, count;
+ uint8_t t, b;
+
+ //init Sbox
+ uint8_t S[256];
+ for(int i = 0; i < 256; i++) S[i] = i;
+
+ //Key Scheduling
+ j = 0;
+ for(i = 0; i < 256; i++)
+ {
+ j = (j + S[i] + key[i % keylength]) % 256;
+ t = S[i];
+ S[i] = S[j];
+ S[j] = t;
+ }
+
+ //Drop Bytes and Cipher Byte XOR
+ i = j = 0;
+ for(count = 0; count < (messagelength + drop); count++)
+ {
+ i = (i + 1) % 256;
+ j = (j + S[i]) % 256;
+ t = S[i];
+ S[i] = S[j];
+ S[j] = t;
+ b = S[(S[i] + S[j]) % 256];
+
+ //return mbe payload byte here
+ if (count >= drop)
+ plain[count - drop] = b^cipher[count - drop];
+
+ }
+
+}
+
//this is for PDU usage
void rc4_block_output (int drop, int keylen, int meslen, uint8_t * key, uint8_t * output_blocks)
{
diff --git a/src/dmr_block.c b/src/dmr_block.c
index f3818eb..ff64379 100644
--- a/src/dmr_block.c
+++ b/src/dmr_block.c
@@ -913,6 +913,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
if (end < 0) end = 3096;
int alg = 0;
int kid = 0;
+ int akl = 0;
if (state->currentslot == 0)
alg = state->payload_algid;
else alg = state->payload_algidR;
@@ -936,6 +937,21 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
else
R = state->rkey_array[state->payload_keyidR];
+ //loader for aes keys
+ uint8_t kaes[32];
+ uint8_t empt[32];
+ uint8_t maes[16];
+ for (i = 0; i < 8; i++)
+ {
+ kaes[i+0] = ((state->rkey_array[kid+0x000]) >> (56-(i*8))) & 0xFF;
+ kaes[i+8] = ((state->rkey_array[kid+0x101]) >> (56-(i*8))) & 0xFF;
+ kaes[i+16] = ((state->rkey_array[kid+0x201]) >> (56-(i*8))) & 0xFF;
+ kaes[i+24] = ((state->rkey_array[kid+0x301]) >> (56-(i*8))) & 0xFF;
+
+ //if kaes is loaded with a key, then flag on the key loaded variable
+ if (memcmp(kaes, empt, sizeof(kaes)) != 0) akl = 1;
+ }
+
if (R == 0 && state->R != 0) R = state->R;
//easier to manually load up rather than make a loop (RC4)
@@ -959,12 +975,47 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
if (alg == 4) fprintf (stderr, " AES256;");
if (R && alg != 0) fprintf (stderr, " Key: %010llX;", R);
+ //generate 128-bit IV from 32-bit MI
+ //expand 32-bit MI to 128-bit IV for AES mode data decryption
+ //we only want to do this at the moment of keystream generation
+ if (alg == 5)
+ {
+ fprintf (stderr, "\n");
+ LFSR128d(state);
+ if (state->currentslot == 0)
+ memcpy (maes, state->aes_iv, sizeof(maes));
+ if (state->currentslot == 1)
+ memcpy (maes, state->aes_ivR, sizeof(maes));
+ }
+
if (alg == 1 && R != 0) //RC4
{
rc4_block_output (256, 9, (int)state->data_byte_ctr[slot], kiv, ob);
decrypted_pdu = 1;
}
+ if (alg == 5 && akl == 1) //AES-256
+ {
+ int nblocks = (state->data_byte_ctr[slot] / 16) + 1;
+ aes_ofb_keystream_output (maes, kaes, ob, 2, nblocks);
+ decrypted_pdu = 1;
+ }
+
+ //other algs available, not sure if others will be used in any DMRA offerings
+ if (alg == 2 && R != 0) //Tait DES
+ {
+ int nblocks = (state->data_byte_ctr[slot] / 8) + 1;
+ des_multi_keystream_output (mi, R, ob, 1, nblocks);
+ decrypted_pdu = 1;
+ }
+
+ if (alg == 4 && akl == 1) //AES-128
+ {
+ int nblocks = (state->data_byte_ctr[slot] / 16) + 1;
+ aes_ofb_keystream_output (maes, kaes, ob, 0, nblocks);
+ decrypted_pdu = 1;
+ }
+
//NOTE: Observed that keystream should not be applied to pad bytes or CRC
//apply keystream here, only if alg is 1 or 4 AND key is available!
if (alg == 1 && R != 0)
@@ -972,6 +1023,22 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
for (i = 0; i < end; i++)
state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
}
+
+ else if (alg == 2 && R != 0)
+ {
+ for (i = 0; i < end; i++)
+ state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
+ }
+ else if (alg == 4 && akl != 0)
+ {
+ for (i = 0; i < end; i++)
+ state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
+ }
+ else if (alg == 5 && akl != 0)
+ {
+ for (i = 0; i < end; i++)
+ state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
+ }
//BP key application
else if (alg == 0)
diff --git a/src/dmr_flco.c b/src/dmr_flco.c
index 7cb716a..2bff90e 100644
--- a/src/dmr_flco.c
+++ b/src/dmr_flco.c
@@ -620,6 +620,26 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
fprintf (stderr, "Key %010llX ", state->RR);
fprintf (stderr, "%s ", KNRM);
}
+
+ if (slot == 0 && (state->payload_algid == 0x25 || state->payload_algid == 0x24) && state->aes_key_loaded[0] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "%s", KYEL);
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[0], state->A2[0]);
+ if (state->payload_algid == 0x25)
+ fprintf (stderr, "%016llX %016llX", state->A3[0], state->A4[0]);
+ fprintf (stderr, "%s ", KNRM);
+ }
+
+ if (slot == 1 && (state->payload_algidR == 0x25 || state->payload_algidR == 0x24) && state->aes_key_loaded[1] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "%s", KYEL);
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[1], state->A2[1]);
+ if (state->payload_algidR == 0x25)
+ fprintf (stderr, "%016llX %016llX", state->A3[1], state->A4[1]);
+ fprintf (stderr, "%s ", KNRM);
+ }
}
diff --git a/src/dmr_le.c b/src/dmr_le.c
index 7a89fa5..68fcefd 100644
--- a/src/dmr_le.c
+++ b/src/dmr_le.c
@@ -115,12 +115,23 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
fprintf (stderr, "\n");
fprintf (stderr, "%s", KNRM);
}
- //run afterwards, or le verification won't match up properly
- if (state->payload_algid != 0x21)
+
+ //run expansions afterwards, or le verification won't match up properly
+
+ //DES1
+ if (state->payload_algid == 0x22)
{
LFSR64 (state);
fprintf (stderr, "\n");
- }
+ }
+
+ //AES-128 or AES-256
+ if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
+ {
+ LFSR128d (state);
+ fprintf (stderr, "\n");
+ }
+
}
if (slot == 1 && state->payload_algidR != 0)
{
@@ -134,16 +145,62 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
fprintf (stderr, "\n");
fprintf (stderr, "%s", KNRM);
}
- //run afterwards, or le verification won't match up properly
- if (state->payload_algidR != 0x21)
+
+ //run expansions afterwards, or le verification won't match up properly
+
+ //DES1
+ if (state->payload_algidR == 0x22)
{
LFSR64 (state);
fprintf (stderr, "\n");
- }
+ }
+
+ //AES-128 or AES-256
+ if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
+ {
+ LFSR128d (state);
+ fprintf (stderr, "\n");
+ }
+
}
}
+ //run LFSR even if golay fails
+ else if (slot == 0 && state->payload_algid != 0)
+ {
+ //DES1
+ if (state->payload_algid == 0x22)
+ {
+ LFSR64 (state);
+ fprintf (stderr, "\n");
+ }
+
+ //AES-128 or AES-256
+ if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
+ {
+ LFSR128d (state);
+ fprintf (stderr, "\n");
+ }
+ }
+ else if (slot == 1 && state->payload_algidR != 0)
+ {
+ //DES1
+ if (state->payload_algidR == 0x22)
+ {
+ LFSR64 (state);
+ fprintf (stderr, "\n");
+ }
+
+ //AES-128 or AES-256
+ if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
+ {
+ LFSR128d (state);
+ fprintf (stderr, "\n");
+ }
+ }
+
+
}
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
@@ -195,8 +252,8 @@ void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
state->dropR = 256;
state->DMRvcL = 0;
state->DMRvcR = 0;
- state->payload_miP = 0;
- state->payload_miN = 0;
+ // state->payload_miP = 0; //running these clears out before we can create a new keystream
+ // state->payload_miN = 0; //running these clears out before we can create a new keystream
}
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
diff --git a/src/dmr_pi.c b/src/dmr_pi.c
index 7542c61..1238522 100644
--- a/src/dmr_pi.c
+++ b/src/dmr_pi.c
@@ -38,15 +38,38 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
//Anytone RC4 Shim
if (state->payload_algid == 0x01)
{
- fprintf (stderr, " Anytone (0x01)");
+ fprintf (stderr, " Anytone RC4 (0x01)");
state->payload_algid = 0x21;
}
+ //Anytone/Hytera AES-128 Shim
+ if (state->payload_algid == 0x04)
+ {
+ fprintf (stderr, " Anytone/Hytera AES-128 (0x04)");
+ state->payload_algid = 0x24;
+ }
+
+ //Anytone/Hytera AES-256 Shim
+ if (state->payload_algid == 0x05)
+ {
+ fprintf (stderr, " Anytone/Hytera AES-256 (0x05)");
+ state->payload_algid = 0x25;
+ }
+
fprintf (stderr, "%s ", KNRM);
- if (state->payload_algid != 0x21)
+
+ //expand the 32-bit MI to a 64-bit DES1 IV
+ if (state->payload_algid == 0x22)
{
fprintf (stderr, "\n");
LFSR64 (state);
+ }
+
+ //expand the 32-bit MI to a 128-bit AES IV
+ if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
+ {
+ fprintf (stderr, "\n");
+ LFSR128d (state);
}
}
@@ -77,11 +100,34 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
state->payload_algidR = 0x21;
}
+ //Anytone/Hytera AES-128 Shim
+ if (state->payload_algidR == 0x04)
+ {
+ fprintf (stderr, " Anytone/Hytera AES-128 (0x04)");
+ state->payload_algidR = 0x24;
+ }
+
+ //Anytone/Hytera AES-256 Shim
+ if (state->payload_algidR == 0x05)
+ {
+ fprintf (stderr, " Anytone/Hytera AES-256 (0x05)");
+ state->payload_algidR = 0x25;
+ }
+
fprintf (stderr, "%s ", KNRM);
- if (state->payload_algidR != 0x21)
+
+ //expand the 32-bit MI to a 64-bit DES1 IV
+ if (state->payload_algidR == 0x22)
{
fprintf (stderr, "\n");
LFSR64 (state);
+ }
+
+ //expand the 32-bit MI to a 128-bit AES IV
+ if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
+ {
+ fprintf (stderr, "\n");
+ LFSR128d (state);
}
}
@@ -120,7 +166,7 @@ void LFSR(dsd_state * state)
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
- fprintf(stderr, " MI: 0x%08X", lfsr);
+ fprintf(stderr, " MI(32): 0x%08X", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_mi = lfsr;
}
@@ -131,12 +177,13 @@ void LFSR(dsd_state * state)
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
- fprintf(stderr, " MI: 0x%08X", lfsr);
+ fprintf(stderr, " MI(32): 0x%08X", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_miR = lfsr;
}
}
+//Expand a 32-bit MI into a 64-bit IV for DES
void LFSR64(dsd_state * state)
{
{
@@ -161,9 +208,11 @@ void LFSR64(dsd_state * state)
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
- fprintf (stderr, " MI: 0x%016llX", lfsr);
+ fprintf (stderr, " MI(64): 0x%016llX", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_mi = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
+ state->payload_miP = lfsr;
+ state->DMRvcL = 0;
}
if (state->currentslot == 1)
@@ -171,10 +220,94 @@ void LFSR64(dsd_state * state)
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
- fprintf (stderr, " MI: 0x%016llX", lfsr);
+ fprintf (stderr, " MI(64): 0x%016llX", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_miR = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
+ state->payload_miN = lfsr;
+ state->DMRvcR = 0;
}
}
+}
+
+
+//Expand a 32-bit MI into a 128-bit IV for AES
+void LFSR128d(dsd_state * state)
+{
+ unsigned long long int lfsr = 0;
+
+ if (state->currentslot == 0)
+ lfsr = state->payload_mi;
+ else lfsr = state->payload_miR;
+
+ unsigned long long int next_mi;
+
+ //start packing aes_iv
+ if (state->currentslot == 0)
+ {
+ state->aes_iv[0] = (lfsr >> 24) & 0xFF;
+ state->aes_iv[1] = (lfsr >> 16) & 0xFF;
+ state->aes_iv[2] = (lfsr >> 8 ) & 0xFF;
+ state->aes_iv[3] = (lfsr >> 0 ) & 0xFF;
+ }
+ else if (state->currentslot == 1)
+ {
+ state->aes_ivR[0] = (lfsr >> 24) & 0xFF;
+ state->aes_ivR[1] = (lfsr >> 16) & 0xFF;
+ state->aes_ivR[2] = (lfsr >> 8 ) & 0xFF;
+ state->aes_ivR[3] = (lfsr >> 0 ) & 0xFF;
+ }
+
+ int cnt = 0; int x = 32;
+ unsigned long long int bit;
+ for(cnt=0;cnt<96;cnt++)
+ {
+ //32,22,2,1
+ bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
+ lfsr = (lfsr << 1) | bit;
+
+ //continue packing aes_iv
+ if (state->currentslot == 0)
+ state->aes_iv[x/8] = (state->aes_iv[x/8] << 1) + bit;
+ else if (state->currentslot == 1)
+ state->aes_ivR[x/8] = (state->aes_ivR[x/8] << 1) + bit;
+ x++;
+ }
+
+ //assign the next 32-bit short MI from 4,5,6,7 so it'll match up with OTA late entry
+ if (state->currentslot == 0)
+ next_mi = (state->aes_iv[4] << 24) + (state->aes_iv[5] << 16) + (state->aes_iv[6] << 8) + (state->aes_iv[7] << 0);
+ if (state->currentslot == 1)
+ next_mi = (state->aes_ivR[4] << 24) + (state->aes_ivR[5] << 16) + (state->aes_ivR[6] << 8) + (state->aes_ivR[7] << 0);
+
+ if (state->currentslot == 0)
+ {
+ fprintf (stderr, "%s", KYEL);
+ fprintf (stderr, " Slot 1");
+ fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X MI(128): ", state->payload_algid, state->payload_keyid);
+ for (x = 0; x < 16; x++)
+ fprintf (stderr, "%02X", state->aes_iv[x]);
+ fprintf (stderr, "%s", KNRM);
+ // fprintf (stderr, "\n");
+
+ state->payload_mi = next_mi;
+ state->DMRvcL = 0;
+
+ }
+
+ if (state->currentslot == 1)
+ {
+ fprintf (stderr, "%s", KYEL);
+ fprintf (stderr, " Slot 2");
+ fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X MI(128): ", state->payload_algidR, state->payload_keyidR);
+ for (x = 0; x < 16; x++)
+ fprintf (stderr, "%02X", state->aes_ivR[x]);
+ fprintf (stderr, "%s", KNRM);
+ // fprintf (stderr, "\n");
+
+ state->payload_miR = next_mi;
+ state->DMRvcR = 0;
+
+ }
+
}
\ No newline at end of file
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
index a93d72e..bab8028 100644
--- a/src/dsd_audio2.c
+++ b/src/dsd_audio2.c
@@ -93,13 +93,21 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
encL = 0;
}
}
- else if (state->payload_algid == 0x21)
+ else if (state->payload_algid == 0x21 || state->payload_algid == 0x22)
{
if (state->R != 0)
{
encL = 0;
}
}
+ else if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
+ {
+ //going to need a better check for this later on, or seperated keys or something
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
}
if (encR)
@@ -111,15 +119,27 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
encR = 0;
}
}
- else if (state->payload_algidR == 0x21)
+ else if (state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
{
if (state->RR != 0)
{
encR = 0;
}
}
+ else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
+ {
+ //going to need a better check for this later on, or seperated keys or something
+ if (state->aes_key_loaded[1] == 1)
+ {
+ encR = 0;
+ }
+ }
}
+ //debug disable enc check for AES testing
+ // encL = 0;
+ // encR = 0;
+
//TODO: add option to bypass enc with a toggle as well
//CHEAT: Using the slot on/off, use that to set encL or encR back on
@@ -312,6 +332,20 @@ void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state)
encL = 0;
}
}
+ else if (state->payload_algid == 0x81)
+ {
+ if (state->R != 0)
+ {
+ encL = 0;
+ }
+ }
+ else if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
}
if (encR)
@@ -323,6 +357,20 @@ void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state)
encR = 0;
}
}
+ else if (state->payload_algidR == 0x81)
+ {
+ if (state->R != 0)
+ {
+ encR = 0;
+ }
+ }
+ else if (state->payload_algidR == 0x84 || state->payload_algidR == 0x89)
+ {
+ if (state->aes_key_loaded[1] == 1)
+ {
+ encR = 0;
+ }
+ }
}
//CHEAT: Using the slot on/off, use that to set encL or encR back on
@@ -520,13 +568,20 @@ void playSynthesizedVoiceFS (dsd_opts * opts, dsd_state * state)
//checkdown to see if we can lift the 'mute' if a key is available
if (encL)
{
- if (state->payload_algid == 0xAA)
+ if (state->payload_algid == 0xAA || state->payload_algid == 0x81 || state->payload_algid == 0x9F)
{
if (state->R != 0)
{
encL = 0;
}
}
+ else if (state->payload_algid == 0x84 || state->payload_algid == 0x89 || state->payload_algid == 0x83)
+ {
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
}
//TODO: add option to bypass enc with a toggle as well
@@ -654,13 +709,20 @@ void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state)
//checkdown to see if we can lift the 'mute' if a key is available
if (encL)
{
- if (state->payload_algid == 0xAA || state->nxdn_cipher_type == 0x1)
+ if (state->payload_algid == 0xAA || state->payload_algid == 0x81 || state->payload_algid == 0x83 || state->payload_algid == 0x9F || state->nxdn_cipher_type == 0x1 || state->nxdn_cipher_type == 0x2)
{
if (state->R != 0)
{
encL = 0;
}
}
+ else if (state->payload_algid == 0x84 || state->payload_algid == 0x89 || state->nxdn_cipher_type == 0x3)
+ {
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
}
//WIP: Mute if on B list (or not W list)
@@ -870,13 +932,20 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state)
//checkdown to see if we can lift the 'mute' if a key is available
if (encL)
{
- if (state->payload_algid == 0xAA)
+ if (state->payload_algid == 0xAA || state->payload_algid == 0x81 || state->payload_algid == 0x9F || state->payload_algid == 0x83)
{
if (state->R != 0)
{
encL = 0;
}
}
+ else if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
}
//TODO: add option to bypass enc with a toggle as well
@@ -993,7 +1062,7 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
encL = (state->dmr_so >> 6) & 0x1;
encR = (state->dmr_soR >> 6) & 0x1;
- //checkdown to see if we can lift the 'mute' if a key is available
+ //checkdown to see if we can lift the 'mute' if a key is available
if (encL)
{
if (state->payload_algid == 0)
@@ -1003,13 +1072,21 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
encL = 0;
}
}
- else if (state->payload_algid == 0x21)
+ else if (state->payload_algid == 0x21 || state->payload_algid == 0x22)
{
if (state->R != 0)
{
encL = 0;
}
}
+ else if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
+ {
+ //going to need a better check for this later on, or seperated keys or something
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
}
if (encR)
@@ -1021,15 +1098,26 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
encR = 0;
}
}
- else if (state->payload_algidR == 0x21)
+ else if (state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
{
if (state->RR != 0)
{
encR = 0;
}
}
+ else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
+ {
+ //going to need a better check for this later on, or seperated keys or something
+ if (state->aes_key_loaded[1] == 1)
+ {
+ encR = 0;
+ }
+ }
}
+ //debug for AES
+ // encL = encR = 0;
+
//TODO: add option to bypass enc with a toggle as well
//CHEAT: Using the slot on/off, use that to set encL or encR back on
@@ -1342,6 +1430,20 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
encL = 0;
}
}
+ else if (state->payload_algid == 0x81)
+ {
+ if (state->R != 0)
+ {
+ encL = 0;
+ }
+ }
+ else if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
}
if (encR)
@@ -1353,6 +1455,20 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
encR = 0;
}
}
+ else if (state->payload_algidR == 0x81)
+ {
+ if (state->R != 0)
+ {
+ encR = 0;
+ }
+ }
+ else if (state->payload_algidR == 0x84 || state->payload_algidR == 0x89)
+ {
+ if (state->aes_key_loaded[1] == 1)
+ {
+ encR = 0;
+ }
+ }
}
@@ -1552,26 +1668,52 @@ void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
//checkdown to see if we can lift the 'mute' if a key is available
if (encL)
{
- if (state->payload_algid == 0xAA)
+ //RC4 or DES
+ if (state->payload_algid == 0xAA || state->payload_algid == 0x81)
{
if (state->R != 0)
{
encL = 0;
}
}
+
+ //AES
+ if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ if (state->aes_key_loaded[0] == 1)
+ {
+ encL = 0;
+ }
+ }
+
}
if (encR)
{
- if (state->payload_algidR == 0xAA)
+ //RC4 or DES
+ if (state->payload_algidR == 0xAA || state->payload_algidR == 0x81)
{
if (state->RR != 0)
{
encR = 0;
}
}
+
+ //AES
+ if (state->payload_algidR == 0x84 || state->payload_algidR == 0x89)
+ {
+ if (state->aes_key_loaded[1] == 1)
+ {
+ encR = 0;
+ }
+ }
+
}
+ //debug, unmute both slots
+ // encL = 0;
+ // encR = 0;
+
//WIP: Mute if on B list (or not W list)
char modeL[8];
sprintf (modeL, "%s", "");
diff --git a/src/dsd_file.c b/src/dsd_file.c
index 6b91326..72dd332 100644
--- a/src/dsd_file.c
+++ b/src/dsd_file.c
@@ -632,4 +632,49 @@ void unpack_ambe (uint8_t * input, char * ambe)
ambe[k++] = (input[i] >> 0) & 1;
}
ambe[48] = input[6] >> 7;
+}
+
+//convert a user string into a uint8_t array
+uint16_t parse_raw_user_string (char * input, uint8_t * output)
+{
+ //since we want this as octets, get strlen value, then divide by two
+ uint16_t len = strlen((const char*)input);
+
+ uint8_t shift = 0;
+
+ //if zero is returned, just do two
+ // if (len == 0) len = 2;
+
+ //if zero, return as 0 len string
+ if (len == 0) return 0;
+
+ //if odd number, then user didn't pass complete octets,
+ //add one to len value and set the shift flag to left shift
+ if (len&1)
+ {
+ shift = 1;
+ len++;
+ }
+
+ //divide by two to get octet len
+ len /= 2;
+
+ char octet_char[3];
+ octet_char[2] = 0;
+ uint16_t k = 0;
+ uint16_t i = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ strncpy (octet_char, input+k, 2);
+ octet_char[2] = 0;
+ sscanf (octet_char, "%hhX", &output[i]);
+
+ k += 2;
+ }
+
+ //if we had an odd input value, then left shift the last octet 4 to make it flush
+ if (shift) output[len-1] <<= 4;
+
+ return len;
}
\ No newline at end of file
diff --git a/src/dsd_import.c b/src/dsd_import.c
index 572895a..907ae43 100644
--- a/src/dsd_import.c
+++ b/src/dsd_import.c
@@ -214,7 +214,7 @@ int csvKeyImportDec(dsd_opts * opts, dsd_state * state) //multi-key support
}
//Hex Variant of Key Import
-int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for rc4 keys
+int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for hex keys
{
char filename[1024] = "filename.csv";
sprintf (filename, "%s", opts->key_in_file);
@@ -247,10 +247,31 @@ int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for rc4 key
sscanf (field, "%llX", &state->rkey_array[keynumber]);
}
+ //this could also theoretically nuke other keys that are at the same offset
+ if (field_count == 2)
+ {
+ sscanf (field, "%llX", &state->rkey_array[keynumber+0x101]);
+ }
+
+ if (field_count == 3)
+ {
+ sscanf (field, "%llX", &state->rkey_array[keynumber+0x201]);
+ }
+
+ if (field_count == 4)
+ {
+ sscanf (field, "%llX", &state->rkey_array[keynumber+0x301]);
+ }
+
field = strtok(NULL, ",");
field_count++;
}
+
fprintf (stderr, "Key [%04llX] [%016llX]", keynumber, state->rkey_array[keynumber]);
+
+ //if longer key is loaded (or clash with the 0x101, 0x201, 0x301 offset, then print the full key listing)
+ if ( (state->rkey_array[keynumber+0x101] != 0) || (state->rkey_array[keynumber+0x201] != 0) || (state->rkey_array[keynumber+0x301] != 0) )
+ fprintf (stderr, " [%016llX] [%016llX] [%016llX]", state->rkey_array[keynumber+0x101], state->rkey_array[keynumber+0x201], state->rkey_array[keynumber+0x301]);
fprintf (stderr, "\n");
}
diff --git a/src/dsd_main.c b/src/dsd_main.c
index 3a9091a..81d0cab 100644
--- a/src/dsd_main.c
+++ b/src/dsd_main.c
@@ -347,6 +347,21 @@ noCarrier (dsd_opts * opts, dsd_state * state)
state->p25vc = 0;
state->payload_miP = 0;
+ //ks array storage and counters
+ memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
+ memset (state->ks_octetR, 0, sizeof(state->ks_octetR));
+ memset (state->ks_bitstreamL, 0, sizeof(state->ks_bitstreamL));
+ memset (state->ks_bitstreamR, 0, sizeof(state->ks_bitstreamR));
+ state->octet_counter = 0;
+ state->bit_counterL = 0;
+ state->bit_counterR = 0;
+
+ //xl specific, we need to know if the ESS is from HDU, or from LDU2
+ state->xl_is_hdu = 0;
+
+ //NXDN, when a new IV has arrived
+ state->nxdn_new_iv = 0;
+
//initialize dmr data header source
state->dmr_lrrp_source[0] = 0;
state->dmr_lrrp_source[1] = 0;
@@ -412,7 +427,15 @@ noCarrier (dsd_opts * opts, dsd_state * state)
state->R = 0; //NXDN, or RC4 (slot 1)
state->RR = 0; //RC4 (slot 2)
state->K = 0; //BP
- state->K1 = 0; //tera 10 char BP
+ state->K1 = 0; //tera 10/32/64 char BP
+ state->K2 = 0;
+ state->K3 = 0;
+ state->K4 = 0;
+ memset (state->A1, 0, sizeof(state->A1));
+ memset (state->A2, 0, sizeof(state->A2));
+ memset (state->A3, 0, sizeof(state->A3));
+ memset (state->A4, 0, sizeof(state->A4));
+ memset (state->aes_key_loaded, 0, sizeof (state->aes_key_loaded));
state->H = 0; //shim for above
}
@@ -1020,9 +1043,34 @@ initState (dsd_state * state)
state->dropL = 256;
state->dropR = 256;
- state->p25vc = 0;
+ //ks array storage and counters
+ memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
+ memset (state->ks_octetR, 0, sizeof(state->ks_octetR));
+ memset (state->ks_bitstreamL, 0, sizeof(state->ks_bitstreamL));
+ memset (state->ks_bitstreamR, 0, sizeof(state->ks_bitstreamR));
+ state->octet_counter = 0;
+ state->bit_counterL = 0;
+ state->bit_counterR = 0;
+ //AES Specific Variables
+ memset (state->aes_key, 0, sizeof(state->aes_key));
+ memset (state->aes_iv, 0, sizeof(state->aes_iv));
+ memset (state->aes_ivR, 0, sizeof(state->aes_ivR));
+ memset (state->A1, 0, sizeof(state->A1));
+ memset (state->A2, 0, sizeof(state->A2));
+ memset (state->A3, 0, sizeof(state->A3));
+ memset (state->A4, 0, sizeof(state->A4));
+ memset (state->aes_key_loaded, 0, sizeof (state->aes_key_loaded));
+
+ //xl specific, we need to know if the ESS is from HDU, or from LDU2
+ state->xl_is_hdu = 0;
+
+ //NXDN, when a new IV has arrived
+ state->nxdn_new_iv = 0;
+
+ state->p25vc = 0;
state->payload_miP = 0;
+ state->payload_miN = 0;
//initialize dmr data header source
state->dmr_lrrp_source[0] = 0;
@@ -1453,24 +1501,33 @@ usage ()
printf (" -b Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
printf (" (NOTE: This used to be the 'K' option! \n");
printf ("\n");
- printf (" -H Manually Enter **tera 10/32/64 Char Basic Privacy Hex Key (see example below)\n");
+ printf (" -H Manually Enter Hytera 10/32/64 Char Basic Privacy Hex Key (see example below)\n");
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
printf (" -H 0B57935150 \n");
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
+ printf ("\n"); //may move to using the rkey_array with an offset for additional key values
+ printf (" -H Manually Enter AES-128 or AES-256 Hex Key (see example below)\n");
+ printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
+ printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
+ printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
printf ("\n");
printf (" -R Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n");
printf (" \n");
- printf (" -1 Manually Enter RC4 Key Value (DMR, P25) (Hex Value) \n");
+ printf (" -1 Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) \n");
+ printf (" \n");
+ printf (" -2 Manually Enter TYT and Enforce 16-bit BP Key Value (DMR) (Hex Value) \n");
+ printf (" \n");
+ printf (" -5 Manually Enter 48-bit BP Key Value (DMR) (Hex Value) \n");
printf (" \n");
printf (" -k Import Key List from csv file (Decimal Format) -- Lower Case 'k'.\n");
printf (" Only supports NXDN, DMR Basic Privacy (decimal value). \n");
- printf (" (dPMR and **tera 32/64 char not supported, DMR uses TG value as key id -- EXPERIMENTAL!!). \n");
+ printf (" (dPMR and Hytera 32/64 char not supported, DMR uses TG value as key id -- EXPERIMENTAL!!). \n");
printf (" \n");
printf (" -K Import Key List from csv file (Hexidecimal Format) -- Capital 'K'.\n");
- printf (" Use for Hex Value **tera 10-char BP keys and RC4 10-Char Hex Keys. \n");
+ printf (" Use for Hex Value Hytera 10-char BP keys, RC4 10-char, DES 16-char Hex Keys, and AES128/256 32/64-char keys. \n");
printf (" \n");
- printf (" -4 Force Privacy Key over Encryption Identifiers (DMR BP and NXDN Scrambler) \n");
+ printf (" -4 Force Privacy Key over Encryption Identifiers (DMR MBP/HBP and NXDN Scrambler) \n");
printf (" \n");
printf (" -0 Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR) \n");
printf (" \n");
@@ -1497,7 +1554,6 @@ usage ()
printf (" P25 - 12000; NXDN48 - 7000; NXDN96: 12000; DMR - 7000-12000; EDACS/PV - 12000-24000;\n"); //redo this, or check work, or whatever
printf (" May vary based on system stregnth, etc.\n");
printf (" -t Set Trunking or Scan Speed VC/sync loss hangtime in seconds. (default = 1 second)\n");
- // printf (" -9 Force Enable EDACS Standard or Networked Mode if Auto Detection Fails \n");
printf ("\n");
printf (" Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
printf (" Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
@@ -1699,11 +1755,6 @@ main (int argc, char **argv)
char versionstr[25];
mbe_printVersion (versionstr);
- #ifdef LIMAZULUTWEAKS
- fprintf (stderr," Digital Speech Decoder: LimaZulu Edition VI\n");
- #else
- fprintf (stderr," Digital Speech Decoder: Florida Man Edition\n");
- #endif
for (short int i = 1; i < 7; i++) {
fprintf (stderr,"%s\n", FM_banner[i]);
}
@@ -1801,15 +1852,31 @@ main (int argc, char **argv)
fprintf (stderr,"Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR)\n");
break;
- //load single rc4 key
+ //load single rc4/des key
case '1':
sscanf (optarg, "%llX", &state.R);
state.RR = state.R; //put key on both sides
- fprintf (stderr, "RC4 Encryption Key Value set to 0x%llX \n", state.R);
+ fprintf (stderr, "RC4/DES Encryption Key Value set to 0x%llX \n", state.R);
opts.unmute_encrypted_p25 = 0;
state.keyloader = 0; //turn off keyloader
break;
+ //get user TYT BP Key and Force Its application
+ case '2':
+ state.M = 0x16; //16-bit TYT 'BP' Keys
+ sscanf (optarg, "%llX", &state.H);
+ state.H = state.H & 0xFFFF; //truncate to 16-bits
+ fprintf (stderr,"DMR TYT 16-bit Key %llX with Forced Application\n", state.H);
+ break;
+
+ //Enter and Force Applicaiton of a a 48-bit AMBE Keystream (hex) for 'CCR' radios and weird 'BP'
+ case '5':
+ state.M = 0x48; //48-bit AMBE Keystream for any generic keystream application
+ sscanf (optarg, "%llX", &state.H);
+ state.H = state.H & 0xFFFFFFFFFFFF; //truncate to 48-bits
+ fprintf (stderr,"AMBE+2 48-bit Key %llX with Forced Application\n", state.H);
+ break;
+
case '3':
opts.dmr_le = 0;
fprintf (stderr,"DMR Late Entry Encryption Identifiers Disabled (VC6 Single Burst)\n");
@@ -2018,7 +2085,7 @@ main (int argc, char **argv)
state.K2 = strtoull (pEnd, &pEnd, 16);
state.K3 = strtoull (pEnd, &pEnd, 16);
state.K4 = strtoull (pEnd, &pEnd, 16);
- fprintf (stderr, "**tera Key = %016llX %016llX %016llX %016llX\n", state.K1, state.K2, state.K3, state.K4);
+ fprintf (stderr, "Hytera40/128/256 BP or AES128/256 Key = %016llX %016llX %016llX %016llX\n", state.K1, state.K2, state.K3, state.K4);
opts.dmr_mute_encL = 0;
opts.dmr_mute_encR = 0;
if (state.K1 == 0 && state.K2 == 0 && state.K3 == 0 && state.K4 == 0)
@@ -2027,6 +2094,15 @@ main (int argc, char **argv)
opts.dmr_mute_encR = 1;
}
state.H = state.K1; //shim still required?
+ //load the AES keys into a seperate handler
+ state.A1[0] = state.A1[1] = state.K1;
+ state.A2[0] = state.A2[1] = state.K2;
+ state.A3[0] = state.A3[1] = state.K3;
+ state.A4[0] = state.A4[1] = state.K4;
+ //disable keyloader function
+ state.keyloader = 0;
+ //signal an aes key is loaded into each slot -- if no value presented, then this won't matter anyways
+ state.aes_key_loaded[0] = state.aes_key_loaded[1] = 1;
break;
case '4':
@@ -2618,7 +2694,7 @@ main (int argc, char **argv)
opts.pulse_digi_out_channels = 2;
sprintf (opts.output_name, "DMR");
- fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
+ fprintf (stderr,"Decoding DMR BS/MS Simplex\n");
}
//change ft to only do P25 and DMR (TDMA trunking modes)
else if (optarg[0] == 't')
@@ -2699,9 +2775,9 @@ main (int argc, char **argv)
opts.dmr_stereo = 1;
state.dmr_stereo = 0; //0
// opts.setmod_bw = 7000;
- sprintf (opts.output_name, "DMR Stereo");
+ sprintf (opts.output_name, "DMR");
fprintf (stderr,"-fr / DMR Mono switch has been deprecated.\n");
- fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
+ fprintf (stderr,"Decoding DMR BS/MS Simplex\n");
}
else if (optarg[0] == 'm')
diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c
index ea361f6..1edc5e9 100644
--- a/src/dsd_mbe.c
+++ b/src/dsd_mbe.c
@@ -29,41 +29,33 @@ void keyring(dsd_opts * opts, dsd_state * state)
if (state->currentslot == 1)
state->RR = state->rkey_array[state->payload_keyidR];
-}
-void RC4(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[])
-{
- int i, j, count;
- uint8_t t, b;
-
- //init Sbox
- uint8_t S[256];
- for(int i = 0; i < 256; i++) S[i] = i;
-
- //Key Scheduling
- j = 0;
- for(i = 0; i < 256; i++)
+ //load any large keys (AES)
+ if (state->currentslot == 0)
{
- j = (j + S[i] + key[i % keylength]) % 256;
- t = S[i];
- S[i] = S[j];
- S[j] = t;
+ state->A1[0] = state->rkey_array[state->payload_keyid+0x000];
+ state->A2[0] = state->rkey_array[state->payload_keyid+0x101];
+ state->A3[0] = state->rkey_array[state->payload_keyid+0x201];
+ state->A4[0] = state->rkey_array[state->payload_keyid+0x301];
+
+ //check to see if there is a value loaded or not
+ if (state->A1[0] == 0 && state->A2[0] == 0 && state->A3[0] == 0 && state->A4[0] == 0)
+ state->aes_key_loaded[0] = 0;
+ else state->aes_key_loaded[0] = 1;
+
}
- //Drop Bytes and Cipher Byte XOR
- i = j = 0;
- for(count = 0; count < (messagelength + drop); count++)
+ if (state->currentslot == 1)
{
- i = (i + 1) % 256;
- j = (j + S[i]) % 256;
- t = S[i];
- S[i] = S[j];
- S[j] = t;
- b = S[(S[i] + S[j]) % 256];
+ state->A1[1] = state->rkey_array[state->payload_keyidR+0x000];
+ state->A2[1] = state->rkey_array[state->payload_keyidR+0x101];
+ state->A3[1] = state->rkey_array[state->payload_keyidR+0x201];
+ state->A4[1] = state->rkey_array[state->payload_keyidR+0x301];
- //return mbe payload byte here
- if (count >= drop)
- plain[count - drop] = b^cipher[count - drop];
+ //check to see if there is a value loaded or not
+ if (state->A1[1] == 0 && state->A2[1] == 0 && state->A3[1] == 0 && state->A4[1] == 0)
+ state->aes_key_loaded[1] = 0;
+ else state->aes_key_loaded[1] = 1;
}
@@ -261,6 +253,90 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
mbe_demodulateImbe7200x4400Data (imbe_fr);
state->errs2 += mbe_eccImbe7200x4400Data (imbe_fr, imbe_d);
+ //P25p1 Multi Crypt Handler (DES1, DES3, DES-XL and AES)
+ if ( (state->payload_algid == 0x81 && state->R != 0) || //DES-56
+ (state->payload_algid == 0x9F && state->R != 0) || //DES-XL
+ (state->payload_algid == 0x84 && state->aes_key_loaded[0] == 1) ||
+ (state->payload_algid == 0x89 && state->aes_key_loaded[0] == 1) ||
+ (state->payload_algid == 0x83 && state->aes_key_loaded[0] == 1) ) //3DES
+ {
+ uint8_t cipher[11];
+ uint8_t plain[11];
+ memset (cipher, 0, sizeof(cipher));
+ memset (plain, 0, sizeof(plain));
+
+ uint8_t aes_key[32];
+ memset (aes_key, 0, sizeof(aes_key));
+
+ //Load key from A1 - A4
+ for (i = 0; i < 8; i++)
+ {
+ aes_key[i+0] = (state->A1[0] >> (56-(i*8))) & 0xFF;
+ aes_key[i+8] = (state->A2[0] >> (56-(i*8))) & 0xFF;
+ aes_key[i+16] = (state->A3[0] >> (56-(i*8))) & 0xFF;
+ aes_key[i+24] = (state->A4[0] >> (56-(i*8))) & 0xFF;
+ }
+
+ if (state->p25vc == 0)
+ {
+ if (state->payload_algid == 0x81 || state->payload_algid == 0x83) //DES1 and DES3
+ state->octet_counter = 11+8; //start on 19 for DES-OFB (8 discard + 8 LC + 3 reserved)
+ else if (state->payload_algid == 0x9F)
+ state->octet_counter = 11; //11 with info from LFSR run values (no discard)
+ else
+ state->octet_counter = 11+16; //start on 27 for AES (16 discard + 8 LC + 3 reserved)
+ memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
+
+ //debug
+ // fprintf (stderr, "\n KO: %d; ", state->octet_counter);
+
+ if (state->payload_algid == 0x81) //DES-56
+ des_multi_keystream_output (state->payload_miP, state->R, state->ks_octetL, 1, 28);
+ if (state->payload_algid == 0x83) //3DES, or TDEA
+ tdea_multi_keystream_output (state->payload_miP, aes_key, state->ks_octetL, 1, 28);
+ if (state->payload_algid == 0x9F) //DES-XL
+ des_multi_keystream_output (state->payload_miP, state->R, state->ks_octetL, 2, state->xl_is_hdu); //hard coded bit count value, xl_is_hdu determines lfsr run values
+ if (state->payload_algid == 0x84) //AES256
+ aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 2, 14); //14 + 1 discard round
+ if (state->payload_algid == 0x89) //AES128
+ aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 0, 14); //14 + 1 discard round
+
+ }
+
+ int z = 0; int j = 0;
+ for (i = 0; i < 11; i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ cipher[i] = cipher[i] << 1;
+ cipher[i] = cipher[i] + imbe_d[z];
+ imbe_d[z] = 0;
+ z++;
+ }
+ }
+
+ //debug output blocks
+ // fprintf (stderr, "\n OB:");
+ for (i = 0; i < 11; i++)
+ {
+ // fprintf (stderr, " %02X", state->ks_octetL[state->octet_counter]);
+ plain[i] = cipher[i] ^ state->ks_octetL[state->octet_counter++];
+ }
+
+ z = 0;
+ for (i = 0; i < 11; i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ imbe_d[z] = (plain[i] & 0x80) >> 7;
+ plain[i] = plain[i] << 1;
+ z++;
+ }
+
+ }
+
+ }
+
//P25p1 RC4 Handling
if (state->payload_algid == 0xAA && state->R != 0)
{
@@ -313,7 +389,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
}
- RC4(state->dropL, 13, 11, rckey, cipher, plain);
+ rc4_voice_decrypt(state->dropL, 13, 11, rckey, cipher, plain);
state->dropL += 11;
z = 0;
@@ -357,6 +433,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
if (opts->payload == 1)
{
PrintIMBEData (opts, state, imbe_d);
+ fprintf (stderr, " 7100");
}
mbe_convertImbe7100to7200(imbe_d);
@@ -388,7 +465,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
mbe_demodulateAmbe3600x2450Data (ambe_fr);
state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
- if ( (state->nxdn_cipher_type == 0x01 && state->R > 0) ||
+ if ( (state->nxdn_cipher_type == 0x01 && state->R != 0) ||
(state->M == 1 && state->R > 0) )
{
@@ -407,6 +484,68 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
+ //NXDN Generic Cipher 2 and Cipher 3 Keystream Application (to be tested)
+ else if ( (state->nxdn_cipher_type == 0x02 && state->R != 0) ||
+ (state->nxdn_cipher_type == 0x03 && state->aes_key_loaded[0] == 1) )
+ {
+
+ if (state->nxdn_cipher_type == 0x02 && state->nxdn_new_iv == 1 && state->nxdn_part_of_frame == 0)
+ {
+
+ //more debug
+ // fprintf (stderr, " IV: %016llX; Key: %016llX", state->payload_miN, state->R);
+
+ memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
+ memset (state->ks_bitstreamL, 0, sizeof(state->ks_bitstreamL));
+
+ des_multi_keystream_output (state->payload_miN, state->R, state->ks_octetL, 1, 26); //32 4V at 49 bits = 1568/64 = 24.5 + 1 discard block
+
+ //reset bit_counter
+ state->bit_counterL = 0;
+
+ //unpack the octets into a bit-wise keystream
+ unpack_byte_array_into_bit_array(state->ks_octetL+8, state->ks_bitstreamL, 26*8);
+
+ //reset flag to 0
+ state->nxdn_new_iv = 0;
+
+ }
+
+ //untested, but same setup as DES, so it 'SHOULD' work...maybe
+ if (state->nxdn_cipher_type == 0x03 && state->nxdn_new_iv == 1 && state->nxdn_part_of_frame == 0)
+ {
+
+ //more debug
+ fprintf (stderr, " IV: %016llX; Key: %016llX", state->payload_miN, state->R);
+
+ memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
+ memset (state->ks_bitstreamL, 0, sizeof(state->ks_bitstreamL));
+
+ aes_ofb_keystream_output (state->aes_ivR, state->aes_key, state->ks_octetL, 2, 15); //14 + 1 discard round
+
+ //reset bit_counter
+ state->bit_counterL = 0;
+
+ //unpack the octets into a bit-wise keystream
+ unpack_byte_array_into_bit_array(state->ks_octetL+8, state->ks_bitstreamL, 15*8);
+
+ //reset flag to 0
+ state->nxdn_new_iv = 0;
+
+ }
+
+ //sanity check, don't exceed bit application counter
+ if (state->bit_counterL > (1568-49))
+ state->bit_counterL = (1568-49);
+
+ //Keystream creation is currently inside of the NXDN_decode_VCALL_IV function
+ for (i = 0; i < 49; i++)
+ ambe_d[i] ^= state->ks_bitstreamL[state->bit_counterL++];
+
+ // fprintf (stderr, " bc: %04d;", state->bit_counterL); //debug to see what the counter value is up to currently (seems nominal)
+
+ }
+
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
@@ -432,6 +571,53 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
mbe_demodulateAmbe3600x2450Data (ambe_fr);
state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
+ //TYT (Tytera) 16-bit Key (Shuffle/Shift/Inversion Method)
+ if (state->M == 0x16)
+ {
+ //insert an expansion function here
+ unsigned long long int k = 0;
+ uint8_t pNT[56]; memset (pNT, 0, sizeof(pNT));
+
+ //I believe I have this one figured out now
+ //its just a shuffle, shift, invert, shift, invert, shift pattern
+ //could be an lfsr attached, but couldn't figure out the taps
+
+ //below is the pattern found for the 16-bit keys listed on the right
+ // k = 0xFFFF00FFFF00; // 0xFFFF
+ // k = 0x3412CB1234ED; // 0x1234
+
+ //shuffle, invert, shift...and organize into proper key value
+ k = ((state->H & 0xFF) << 8) + ((state->H & 0xFF00) >> 8);
+ k = k << 8 | ((~(state->H & 0xFF) >> 0) & 0xFF);
+ k = k << 16 | state->H;
+ k = k << 8 | ((~(state->H & 0xFF00) >> 8) & 0xFF);
+
+ //debug -- print 48-bit expanded key value
+ // fprintf (stderr, "K: %012llX", k);
+
+ for (int j = 0; j < 48; j++)
+ {
+ x = ( ((k << j) & 0x800000000000) >> 47 ) & 1;
+ ambe_d[j] ^= x;
+ }
+
+ }
+
+ //Forced 48-bit Keystream Application "Quick and Dirty" XOR
+ if (state->M == 0x48)
+ {
+ // k = 0xD991633EC82E; //F811A5B94C2D ⊻ 2180C6878403 (1234 EP Key)
+ // k = 0x7F5363362BBE; //F811A5B94C2D ⊻ 8742C68F6793 (AAAA EP Key)
+ // k = 0x409231C77C08; (FFFF EP Key)
+ k = state->H;
+ for (int j = 0; j < 48; j++) //49
+ {
+ x = ( ((k << j) & 0x800000000000) >> 47 );
+ ambe_d[j] ^= x;
+ }
+ }
+
+
//EXPERIMENTAL!!
//load basic privacy key number from array by the tg value (if not forced)
//currently only Moto BP and Hytera 10 Char BP
@@ -535,6 +721,125 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->DMRvcL++;
}
+ //DMR and P25p2 DES-OFB 56 Handling, Slot 1, VCH 0 -- consider moving into the AES handler
+ if ( (state->currentslot == 0 && state->payload_algid == 0x22 && state->R != 0) ||
+ (state->currentslot == 0 && state->payload_algid == 0x81 && state->R != 0) )
+ {
+
+ //sanity check in case of error
+ if (state->DMRvcL > 17) state->DMRvcL = 17;
+
+ int j; int z = 0; int n = 8; uint8_t b = 0;
+ if (state->DMRvcL == 0)
+ {
+ memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
+ memset (state->ks_bitstreamL, 0, sizeof(state->ks_bitstreamL));
+ state->bit_counterL = 0;
+
+ //check all these comments I'm making for accuracy
+ des_multi_keystream_output (state->payload_miP, state->R, state->ks_octetL, 1, 19); //18 + 1
+
+ //Load Keystream Octet Bytes directly into a bit array, that way we don't have
+ //to keep track of the byte positions and masks for the 49th bit
+ for (i = 0; i < 18 * 8; i++) //19 blocks minus 1 discard block at 8 bits each
+ {
+ for (j = 0; j < 8; j++)
+ {
+ b = (( (state->ks_octetL[n] << j) & 0x80) >> 7);
+ state->ks_bitstreamL[z++] = b;
+ }
+ n++;
+ }
+ }
+
+ //now we do the bit by bit xor depending on the frame and position of the state bit counter
+ //run 6 instead of 7 so we can just do bit 49 outside of loop to keep extra bits overloading the array
+ z = 0;
+ for (i = 0; i < 6; i++)
+ {
+ for (j = 0; j < 8; j++)
+ ambe_d[z++] ^= state->ks_bitstreamL[state->bit_counterL++];
+ }
+
+ //last bit
+ ambe_d[48] ^= state->ks_bitstreamL[state->bit_counterL++];
+
+ //skip the next 7 bits of the array
+ state->bit_counterL += 7;
+
+ //increment vc counter by one
+ state->DMRvcL++;
+
+ }
+
+ //DMR and P25p2 AES 256, Slot 1, VCH 0 -- need a way to make sure we have a key when zero fill on some parts of it //&& state->aes_key_loaded[0] == 1
+ if ( (state->currentslot == 0 && state->payload_algid == 0x24 && state->aes_key_loaded[0] == 1 ) || //DMR AES128
+ (state->currentslot == 0 && state->payload_algid == 0x25 && state->aes_key_loaded[0] == 1 ) || //DMR AES256
+ (state->currentslot == 0 && state->payload_algid == 0x89 && state->aes_key_loaded[0] == 1 ) || //P25 AES128
+ (state->currentslot == 0 && state->payload_algid == 0x84 && state->aes_key_loaded[0] == 1) ) //P25 AES256
+ {
+
+ int j; int z = 0; int n = 16; uint8_t b = 0; //n=16 for AES-OFB discard round
+ uint8_t aes_key[32];
+ memset (aes_key, 0, sizeof(aes_key));
+
+ //Load key from A1 - A4
+ for (i = 0; i < 8; i++)
+ {
+ aes_key[i+0] = (state->A1[0] >> (56-(i*8))) & 0xFF;
+ aes_key[i+8] = (state->A2[0] >> (56-(i*8))) & 0xFF;
+ aes_key[i+16] = (state->A3[0] >> (56-(i*8))) & 0xFF;
+ aes_key[i+24] = (state->A4[0] >> (56-(i*8))) & 0xFF;
+ }
+
+ //sanity check in case of error
+ if (state->DMRvcL > 17) state->DMRvcL = 17;
+
+ if (state->DMRvcL == 0)
+ {
+ memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
+ memset (state->ks_bitstreamL, 0, sizeof(state->ks_bitstreamL));
+ state->bit_counterL = 0;
+
+ if(state->payload_algid == 0x24 || state->payload_algid == 0x89) //AES128
+ aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 0, 10); //9 + 1 discard round
+ if(state->payload_algid == 0x25 || state->payload_algid == 0x84) //AES256
+ aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 2, 10); //9 + 1 discard round
+
+ //Load Keystream Octet Bytes directly into keystream array
+ for (i = 0; i < 9 * 16; i++) //9 rounds at 16 octets
+ {
+ for (j = 0; j < 8; j++)
+ {
+ b = (( (state->ks_octetL[n] << j) & 0x80) >> 7);
+ state->ks_bitstreamL[z++] = b;
+ }
+ n++;
+ }
+ }
+
+ //now we do the bit by bit xor depending on the frame and position of the state bit counter
+ //run 6 instead of 7 so we can just do bit 49 outside of loop to keep extra bits overloading the array
+ z = 0;
+ for (i = 0; i < 6; i++)
+ {
+ for (j = 0; j < 8; j++)
+ ambe_d[z++] ^= state->ks_bitstreamL[state->bit_counterL++];
+ }
+
+ //last bit
+ ambe_d[48] ^= state->ks_bitstreamL[state->bit_counterL++];
+
+ //skip the next 7 bits of the array
+ state->bit_counterL += 7;
+
+ //increment vc counter by one
+ state->DMRvcL++;
+
+ opts->dmr_mute_encL = 0; //shim to unmute
+
+ }
+
//DMR RC4, Slot 1
if (state->currentslot == 0 && state->payload_algid == 0x21 && state->R != 0)
{
@@ -562,7 +867,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
//this occurs because we are supposed to either have a a 'repeat' frame, or 'silent' frame play
//due to the error, but the keystream application makes it random 'pfft pop' sound instead
if (state->errs < 3)
- RC4(state->dropL, 9, 7, rckey, cipher, plain);
+ rc4_voice_decrypt(state->dropL, 9, 7, rckey, cipher, plain);
else memcpy (plain, cipher, sizeof(plain));
state->dropL += 7;
@@ -602,7 +907,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
//pack cipher byte array from ambe_d bit array
pack_ambe(ambe_d, cipher, 49);
- RC4(state->dropL, 13, 7, rckey, cipher, plain);
+ rc4_voice_decrypt(state->dropL, 13, 7, rckey, cipher, plain);
state->dropL += 7;
//unpack deciphered plain array back into ambe_d bit array
@@ -638,6 +943,52 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
mbe_demodulateAmbe3600x2450Data (ambe_fr);
state->errs2R += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
+ //TYT (Tytera) 16-bit Key (Shuffle/Shift/Inversion Method)
+ if (state->M == 0x16)
+ {
+ //insert an expansion function here
+ unsigned long long int k = 0;
+ uint8_t pNT[56]; memset (pNT, 0, sizeof(pNT));
+
+ //I believe I have this one figured out now
+ //its just a shuffle, shift, invert, shift, invert, shift pattern
+ //could be an lfsr attached, but couldn't figure out the taps
+
+ //below is the pattern found for the 16-bit keys listed on the right
+ // k = 0xFFFF00FFFF00; // 0xFFFF
+ // k = 0x3412CB1234ED; // 0x1234
+
+ //shuffle, invert, shift...and organize into proper key value
+ k = ((state->H & 0xFF) << 8) + ((state->H & 0xFF00) >> 8);
+ k = k << 8 | ((~(state->H & 0xFF) >> 0) & 0xFF);
+ k = k << 16 | state->H;
+ k = k << 8 | ((~(state->H & 0xFF00) >> 8) & 0xFF);
+
+ //debug -- print 48-bit expanded key value
+ fprintf (stderr, "K: %012llX", k);
+
+ for (int j = 0; j < 48; j++)
+ {
+ x = ( ((k << j) & 0x800000000000) >> 47 ) & 1;
+ ambe_d[j] ^= x;
+ }
+
+ }
+
+ //Forced 48-bit Keystream Application "Quick and Dirty" XOR
+ if (state->M == 0x48)
+ {
+ // k = 0xD991633EC82E; //F811A5B94C2D ⊻ 2180C6878403 (1234 EP Key)
+ // k = 0x7F5363362BBE; //F811A5B94C2D ⊻ 8742C68F6793 (AAAA EP Key)
+ // k = 0x409231C77C08; (FFFF EP Key)
+ k = state->H;
+ for (int j = 0; j < 48; j++) //49
+ {
+ x = ( ((k << j) & 0x800000000000) >> 47 );
+ ambe_d[j] ^= x;
+ }
+ }
+
//EXPERIMENTAL!!
//load basic privacy key number from array by the tg value (if not forced)
//currently only Moto BP and Hytera 10 Char BP
@@ -741,6 +1092,125 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->DMRvcR++;
}
+ //DMR and P25p2 DES-OFB 56 Handling, Slot 2, VCH 1 -- Consider moving into AES handler
+ if ( (state->currentslot == 1 && state->payload_algidR == 0x22 && state->RR != 0) ||
+ (state->currentslot == 1 && state->payload_algidR == 0x81 && state->RR != 0) )
+ {
+
+ //sanity check in case of error
+ if (state->DMRvcR > 17) state->DMRvcR = 17;
+
+ int j; int z = 0; int n = 8; uint8_t b = 0;
+ if (state->DMRvcR == 0)
+ {
+ memset (state->ks_octetR, 0, sizeof(state->ks_octetR));
+ memset (state->ks_bitstreamR, 0, sizeof(state->ks_bitstreamR));
+ state->bit_counterR = 0;
+
+ //check all these comments I'm making for accuracy
+ des_multi_keystream_output (state->payload_miN, state->RR, state->ks_octetR, 1, 19); //18 + 1
+
+ //Load Keystream Octet Bytes directly into a bit array, that way we don't have
+ //to keep track of the byte positions and masks for the 49th bit
+ for (i = 0; i < 18 * 8; i++) //19 blocks minus 1 discard block at 8 bits each
+ {
+ for (j = 0; j < 8; j++)
+ {
+ b = (( (state->ks_octetR[n] << j) & 0x80) >> 7);
+ state->ks_bitstreamR[z++] = b;
+ }
+ n++;
+ }
+ }
+
+ //now we do the bit by bit xor depending on the frame and position of the state bit counter
+ //run 6 instead of 7 so we can just do bit 49 outside of loop to keep extra bits overloading the array
+ z = 0;
+ for (i = 0; i < 6; i++)
+ {
+ for (j = 0; j < 8; j++)
+ ambe_d[z++] ^= state->ks_bitstreamR[state->bit_counterR++];
+ }
+
+ //last bit
+ ambe_d[48] ^= state->ks_bitstreamR[state->bit_counterR++];
+
+ //skip the next 7 bits of the array
+ state->bit_counterR += 7;
+
+ //increment vc counter by one
+ state->DMRvcR++;
+
+ }
+
+ //DMR and P25p2 AES, Slot 2, VCH 1
+ if ( (state->currentslot == 1 && state->payload_algidR == 0x24 && state->aes_key_loaded[1] == 1 ) || //DMR AES128
+ (state->currentslot == 1 && state->payload_algidR == 0x25 && state->aes_key_loaded[1] == 1 ) || //DMR AES256
+ (state->currentslot == 1 && state->payload_algidR == 0x89 && state->aes_key_loaded[1] == 1 ) || //P25 AES128
+ (state->currentslot == 1 && state->payload_algidR == 0x84 && state->aes_key_loaded[1] == 1) ) //P25 AES256
+ {
+
+ int j; int z = 0; int n = 16; uint8_t b = 0; //n=16 for AES-OFB discard round
+ uint8_t aes_key[32];
+ memset (aes_key, 0, sizeof(aes_key));
+
+ //Load key from A1 - A4
+ for (i = 0; i < 8; i++)
+ {
+ aes_key[i+0] = (state->A1[1] >> (56-(i*8))) & 0xFF;
+ aes_key[i+8] = (state->A2[1] >> (56-(i*8))) & 0xFF;
+ aes_key[i+16] = (state->A3[1] >> (56-(i*8))) & 0xFF;
+ aes_key[i+24] = (state->A4[1] >> (56-(i*8))) & 0xFF;
+ }
+
+ //sanity check in case of error
+ if (state->DMRvcR > 17) state->DMRvcR = 17;
+
+ if (state->DMRvcR == 0)
+ {
+ memset (state->ks_octetR, 0, sizeof(state->ks_octetR));
+ memset (state->ks_bitstreamR, 0, sizeof(state->ks_bitstreamR));
+ state->bit_counterR = 0;
+
+ if (state->payload_algidR == 0x24 || state->payload_algidR == 0x89)
+ aes_ofb_keystream_output (state->aes_ivR, aes_key, state->ks_octetR, 0, 10); //9 + 1 discard round
+ if (state->payload_algidR == 0x25 || state->payload_algidR == 0x84)
+ aes_ofb_keystream_output (state->aes_ivR, aes_key, state->ks_octetR, 2, 10); //9 + 1 discard round
+
+ //Load Keystream Octet Bytes directly into keystream array
+ for (i = 0; i < 9 * 16; i++) //9 rounds at 16 octets
+ {
+ for (j = 0; j < 8; j++)
+ {
+ b = (( (state->ks_octetR[n] << j) & 0x80) >> 7);
+ state->ks_bitstreamR[z++] = b;
+ }
+ n++;
+ }
+ }
+
+ //now we do the bit by bit xor depending on the frame and position of the state bit counter
+ //run 6 instead of 7 so we can just do bit 49 outside of loop to keep extra bits overloading the array
+ z = 0;
+ for (i = 0; i < 6; i++)
+ {
+ for (j = 0; j < 8; j++)
+ ambe_d[z++] ^= state->ks_bitstreamR[state->bit_counterR++];
+ }
+
+ //last bit
+ ambe_d[48] ^= state->ks_bitstreamR[state->bit_counterR++];
+
+ //skip the next 7 bits of the array
+ state->bit_counterR += 7;
+
+ //increment vc counter by one
+ state->DMRvcR++;
+
+ opts->dmr_mute_encR = 0; //shim to unmute
+
+ }
+
//DMR RC4, Slot 2
if (state->currentslot == 1 && state->payload_algidR == 0x21 && state->RR != 0)
{
@@ -768,7 +1238,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
//this occurs because we are supposed to either have a a 'repeat' frame, or 'silent' frame play
//due to the error, but the keystream application makes it random 'pfft pop' sound instead
if (state->errsR < 3)
- RC4(state->dropR, 9, 7, rckey, cipher, plain);
+ rc4_voice_decrypt(state->dropR, 9, 7, rckey, cipher, plain);
else memcpy (plain, cipher, sizeof(plain));
state->dropR += 7;
@@ -807,7 +1277,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
//pack cipher byte array from ambe_d bit array
pack_ambe(ambe_d, cipher, 49);
- RC4(state->dropR, 13, 7, rckey, cipher, plain);
+ rc4_voice_decrypt(state->dropR, 13, 7, rckey, cipher, plain);
state->dropR += 7;
//unpack deciphered plain array back into ambe_d bit array
diff --git a/src/3.c b/src/dsd_misc.c
similarity index 98%
rename from src/3.c
rename to src/dsd_misc.c
index e104993..ae5e34a 100644
--- a/src/3.c
+++ b/src/dsd_misc.c
@@ -1,9 +1,9 @@
/*-------------------------------------------------------------------------------
- * 3.c
- * Placeholder File 3 -- This file is for temporary code storage
+ * dsd_misc.c
+ * Misc Code that needs to be reorganized and sorted out
*
- * Multiple 1/2 Rate Convolutional Decoders for NXDN/M17/YSF
- * Used as a secondary decoder in case convolutional decoder fails (second opinion)
+ *
+ *
*-----------------------------------------------------------------------------*/
#include "dsd.h"
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
index 0a76e06..a95e6c4 100644
--- a/src/dsd_ncurses.c
+++ b/src/dsd_ncurses.c
@@ -1192,24 +1192,26 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
refresh();
}
- //Privacy Key Entry
+ //Key Entry
if (choice == 14)
{
state->payload_keyid = 0;
state->payload_keyidR = 0;
short int option = 0;
- entry_win = newwin(14, WIDTH+6, starty+10, startx+10);
+ entry_win = newwin(16, WIDTH+6, starty+10, startx+10);
box (entry_win, 0, 0);
mvwprintw(entry_win, 2, 2, "Key Type Selection");
mvwprintw(entry_win, 3, 2, " ");
mvwprintw(entry_win, 4, 2, "1 - Basic Privacy ");
- mvwprintw(entry_win, 5, 2, "2 - **tera Privacy ");
+ mvwprintw(entry_win, 5, 2, "2 - Hytera Privacy ");
mvwprintw(entry_win, 6, 2, "3 - NXDN/dPMR Scrambler ");
mvwprintw(entry_win, 7, 2, "4 - Force BP/Scr Key Priority ");
mvwprintw(entry_win, 8, 3, "-------------------------------- ");
- mvwprintw(entry_win, 9, 2, "5 - RC4 Key ");
- mvwprintw(entry_win, 10, 2, "6 - Force DMR RC4 Priority/LE ");
- mvwprintw(entry_win, 11, 3, " ");
+ mvwprintw(entry_win, 9, 2, "5 - RC4 or DES Key ");
+ // mvwprintw(entry_win, 10, 2, "6 - Force DMR RC4 Priority/LE ");
+ mvwprintw(entry_win, 10, 2, "6 - AES-128 or AES-256 Key ");
+ mvwprintw(entry_win, 11, 3, "-------------------------------- ");
+ mvwprintw(entry_win, 14, 3, " ");
echo();
refresh();
wscanw(entry_win, "%hd", &option); //%d
@@ -1312,28 +1314,106 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
state->R = 0;
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
box (entry_win, 0, 0);
- mvwprintw(entry_win, 2, 2, "RC4 Key Value (HEX):");
+ mvwprintw(entry_win, 2, 2, "RC4/DES Key Value (HEX):");
mvwprintw(entry_win, 3, 3, " ");
echo();
refresh();
wscanw(entry_win, "%llX", &state->R);
noecho();
- if (state->R > 0xFFFFFFFFFF)
- {
- state->R = 0xFFFFFFFFFF;
- }
+ //disable size check for DES keys
+ // if (state->R > 0xFFFFFFFFFF)
+ // {
+ // state->R = 0xFFFFFFFFFF;
+ // }
state->RR = state->R; //assign for both slots
state->keyloader = 0; //turn off keyloader
}
//toggle enforcement of rc4 key over missing pi header/le on DMR
+ // if (option == 6)
+ // {
+ // if (state->M == 1 || state->M == 0x21)
+ // {
+ // state->M = 0;
+ // }
+ // else state->M = 0x21;
+ // }
+
+ //load AES keys
if (option == 6)
{
- if (state->M == 1 || state->M == 0x21)
- {
- state->M = 0;
- }
- else state->M = 0x21;
+ state->K1 = 0;
+ state->K2 = 0;
+ state->K3 = 0;
+ state->K4 = 0;
+ state->H = 0;
+
+ memset (state->A1, 0, sizeof(state->A1));
+ memset (state->A2, 0, sizeof(state->A2));
+ memset (state->A3, 0, sizeof(state->A3));
+ memset (state->A4, 0, sizeof(state->A4));
+
+ entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
+ box (entry_win, 0, 0);
+ mvwprintw(entry_win, 2, 2, " Enter AES128/256 Key Value (HEX) ");
+ mvwprintw(entry_win, 3, 2, " First 16 Chars or Zero");
+ mvwprintw(entry_win, 4, 3, " ");
+ echo();
+ refresh();
+ wscanw(entry_win, "%llX", &state->K1);
+ noecho();
+
+ entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
+ box (entry_win, 0, 0);
+ // mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 2 (HEX) ");
+ mvwprintw(entry_win, 3, 2, " Second 16 Chars or Zero");
+ mvwprintw(entry_win, 4, 3, " ");
+ echo();
+ refresh();
+ wscanw(entry_win, "%llX", &state->K2);
+ noecho();
+
+ entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
+ box (entry_win, 0, 0);
+ // mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 3 (HEX) ");
+ mvwprintw(entry_win, 3, 2, " Third 16 Chars or Zero");
+ mvwprintw(entry_win, 4, 3, " ");
+ echo();
+ refresh();
+ wscanw(entry_win, "%llX", &state->K3);
+ noecho();
+
+ entry_win = newwin(7, WIDTH+8, starty+10, startx+10);
+ box (entry_win, 0, 0);
+ // mvwprintw(entry_win, 2, 2, " Enter **tera Privacy Key Value 4 (HEX) ");
+ mvwprintw(entry_win, 3, 2, " Fourth 16 Chars or Zero");
+ mvwprintw(entry_win, 4, 3, " ");
+ echo();
+ refresh();
+ wscanw(entry_win, "%llX", &state->K4);
+ noecho();
+
+ //load the AES keys into a seperate handler
+ state->A1[0] = state->A1[1] = state->K1;
+ state->A2[0] = state->A2[1] = state->K2;
+ state->A3[0] = state->A3[1] = state->K3;
+ state->A4[0] = state->A4[1] = state->K4;
+
+ //zero out the K1-K4
+ state->K1 = 0;
+ state->K2 = 0;
+ state->K3 = 0;
+ state->K4 = 0;
+
+ state->keyloader = 0; //turn off keyloader
+
+ //check to see if there is a value loaded or not
+ if (state->A1[0] == 0 && state->A2[0] == 0 && state->A3[0] == 0 && state->A4[0] == 0)
+ state->aes_key_loaded[0] = 0;
+ else state->aes_key_loaded[0] = 1;
+
+ //mirror
+ state->aes_key_loaded[1] = state->aes_key_loaded[0];
}
if (state->K == 0 && state->K1 == 0 && state->K2 == 0 && state->K3 == 0 && state->K4 == 0)
@@ -2781,13 +2861,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R);
if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K);
- if (state->K1 != 0) printw ("| Forcing Key Priority -- tera BP Key: %016llX \n", state->K1);
+ if (state->K1 != 0) printw ("| Forcing Key Priority -- Hytera BP Key: %016llX \n", state->K1);
if (state->K != 0 && state->K1 != 0) printw ("| Warning! Multiple DMR Key Types Loaded! \n"); //warning may not be required
}
if (state->M == 0x21)
{
if (state->R != 0) printw ("| Forcing Key Priority -- RC4 Key: %010llX \n", state->R);
}
+ if (state->M == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
if (opts->scanner_mode == 1)
{
@@ -2923,9 +3004,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (state->m17_enc == 2)
{
- printw (" AES-CTR - IV: ");
+ attron(COLOR_PAIR(1));
+ printw ("AES-CTR - IV: ");
//display packed meta as IV
- for (i = 0; i < 14; i++)
+ for (i = 0; i < 16; i++)
printw ("%02X", state->m17_meta[i]);
}
@@ -3085,7 +3167,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("\n|");
if (state->nxdn_cipher_type > 0)
{
- printw (" ALG: [0x%02X] KEY: [0x%02X] ", state->nxdn_cipher_type, state->nxdn_key);
+ // printw (" ALG: %d Key ID: %02X ", state->nxdn_cipher_type, state->nxdn_key);
+ printw (" ALG: %d Key ID: %02d ", state->nxdn_cipher_type, state->nxdn_key);
}
if (state->nxdn_cipher_type == 0x1 && state->carrier == 1)
{
@@ -3096,26 +3179,28 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (state->R != 0)
{
attron(COLOR_PAIR(1));
- printw ("KEY VALUE: [%05lld] ", state->R );
- printw ("SEED: [%04llX]", state->payload_miN);
+ printw ("Seed: %04llX ", state->payload_miN);
+ printw ("Key: %05lld ", state->R );
attron(COLOR_PAIR(3));
}
}
if (state->nxdn_cipher_type == 0x2 && state->carrier == 1)
{
attron(COLOR_PAIR(1));
- printw ("IV: [%016llX] ", state->payload_miN);
+ printw ("IV: %016llX ", state->payload_miN);
attron(COLOR_PAIR(2));
printw ("DES1 ");
+ if (state->R != 0) printw ("Key: %016llX ", state->R);
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
}
if (state->nxdn_cipher_type == 0x3 && state->carrier == 1)
{
attron(COLOR_PAIR(1));
- printw ("IV: [%016llX] ", state->payload_miN);
+ printw ("IV: %016llX ", state->payload_miN);
attron(COLOR_PAIR(2));
printw ("AES-256 ");
+ if (state->aes_key_loaded[0] == 1) printw ("KS: %016llX", state->A4[0]);
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
}
@@ -3268,32 +3353,32 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("| V XTRA | "); //10 spaces
- if(state->dmrburstL == 16 && state->payload_algid == 0 && (state->dmr_so & 0xCF) == 0x40) //4F or CF mask? & 0xCF currently
+ if(state->dmrburstL == 16 && state->payload_algid == 0 && state->dmr_so & 0x40) //4F or CF mask? & 0xCF currently //&& (state->dmr_so & 0xCF) == 0x40
{
attron(COLOR_PAIR(5));
- printw (" **Pr** ");
+ printw (" **BP** ");
attroff(COLOR_PAIR(5));
attron(COLOR_PAIR(3));
}
- if(state->dmrburstL == 16 && state->payload_algid == 0 && state->K > 0 && state->dmr_fid == 0x10 && (state->dmr_so & 0xCF) == 0x40)
+ if(state->dmrburstL == 16 && state->payload_algid == 0 && state->K > 0 && state->dmr_fid == 0x10 && state->dmr_so & 0x40)
{
attron(COLOR_PAIR(1));
- printw ("Pr Key [%3lld] ", state->K);
+ printw ("BP Key: %3lld ", state->K);
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(3));
}
- if(state->dmrburstL == 16 && state->payload_algid == 0 && state->H > 0 && state->dmr_fid == 0x68 && ((state->dmr_so & 0xCF) == 0x40) )
+ if(state->dmrburstL == 16 && state->payload_algid == 0 && state->H > 0 && state->dmr_fid == 0x68 && state->dmr_so & 0x40)
{
attron(COLOR_PAIR(1));
- printw ("**tera Pr Key [%010llX] ", state->H);
+ printw ("Hytera BP Key: %010llX ", state->H);
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(3));
}
//ALG, KeyID, MI //was key_id
- if(state->dmrburstL == 16 && state->payload_algid > 0 && (state->dmr_so & 0xCF) == 0x40)
+ if(state->dmrburstL == 16 && state->payload_algid > 0 && state->dmr_so & 0x40)
{
attron(COLOR_PAIR(1));
printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08X ", state->payload_algid, state->payload_keyid, state->payload_mi);
@@ -3322,6 +3407,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
attron(COLOR_PAIR(1));
printw("DES1 ");
+ if (state->R != 0) { printw("Key: %010llX ", state->R); }
+ attron(COLOR_PAIR(3));
+ }
+ if (state->payload_algid == 0x9F)
+ {
+ attron(COLOR_PAIR(1));
+ printw("DES-XL ");
+ if (state->R != 0) { printw("Key: %010llX ", state->R); }
attron(COLOR_PAIR(3));
}
if (state->payload_algid == 0x82)
@@ -3336,16 +3429,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("DES3 ");
attron(COLOR_PAIR(3));
}
- if (state->payload_algid == 0x85 || state->payload_algid == 0x24)
+ if (state->payload_algid == 0x89 || state->payload_algid == 0x24)
{
attron(COLOR_PAIR(1));
- printw("AES-128");
+ printw("AES-128 ");
+ if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A2[0]); }
attron(COLOR_PAIR(3));
}
if (state->payload_algid == 0x84 || state->payload_algid == 0x25 || state->payload_algid == 0x05)
{
attron(COLOR_PAIR(1));
- printw("AES-256");
+ printw("AES-256 ");
+ if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
attron(COLOR_PAIR(3));
}
if (state->payload_algid == 0x02)
@@ -3468,30 +3563,30 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("| V XTRA | "); //10 spaces
- if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask?
+ if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->dmr_soR & 0x40) //4F or CF mask?
{
attron(COLOR_PAIR(5));
- printw (" **Pr** ");
+ printw (" **BP** ");
attroff(COLOR_PAIR(5));
attron(COLOR_PAIR(3));
}
- if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->K > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x10)
+ if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->K > 0 && state->dmr_soR & 0x40 && state->dmr_fidR == 0x10)
{
attron(COLOR_PAIR(1));
- printw ("Pr Key [%3lld] ", state->K);
+ printw ("BP Key: %3lld ", state->K);
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(3));
}
- if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->H > 0 && ((state->dmr_soR & 0xCF) == 0x40) && state->dmr_fidR == 0x68)
+ if(state->dmrburstR == 16 && state->payload_algidR == 0 && state->H > 0 && state->dmr_soR & 0x40 && state->dmr_fidR == 0x68)
{
attron(COLOR_PAIR(1));
- printw ("**tera Pr Key [%010llX] ", state->H);
+ printw ("Hytera BP Key: %010llX ", state->H);
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(3));
}
//ALG, KeyID, MI 2 //was keyidR
- if(state->dmrburstR == 16 && state->payload_algidR > 0 && (state->dmr_soR & 0xCF) == 0x40)
+ if(state->dmrburstR == 16 && state->payload_algidR > 0 && state->dmr_soR & 0x40)
{
attron(COLOR_PAIR(1));
printw ("ALG: 0x%02X KEY: 0x%02X MI: 0x%08X ", state->payload_algidR, state->payload_keyidR, state->payload_miR);
@@ -3519,6 +3614,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
attron(COLOR_PAIR(1));
printw("DES1 ");
+ if (state->RR != 0) { printw("Key: %010llX ", state->RR); }
+ attron(COLOR_PAIR(3));
+ }
+ if (state->payload_algidR == 0x9F)
+ {
+ attron(COLOR_PAIR(1));
+ printw("DES-XL ");
+ if (state->RR != 0) { printw("Key: %010llX ", state->RR); }
attron(COLOR_PAIR(3));
}
if (state->payload_algidR == 0x82)
@@ -3533,16 +3636,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("DES3 ");
attron(COLOR_PAIR(3));
}
- if (state->payload_algidR == 0x85 || state->payload_algidR == 0x24)
+ if (state->payload_algidR == 0x89 || state->payload_algidR == 0x24)
{
attron(COLOR_PAIR(1));
- printw("AES-128");
+ printw("AES-128 ");
+ if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A2[1]); }
attron(COLOR_PAIR(3));
}
if (state->payload_algidR == 0x84 || state->payload_algidR == 0x25 || state->payload_algidR == 0x05)
{
attron(COLOR_PAIR(1));
- printw("AES-256");
+ printw("AES-256 ");
+ if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
attron(COLOR_PAIR(3));
}
if (state->payload_algidR == 0x02)
@@ -3710,11 +3815,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
if (opts->p25_is_tuned == 0)
{
- printw ("| Monitoring Control Channel\n");
+ printw ("| Monitoring CC - LCN [%02d]\n", state->edacs_cc_lcn);
}
else
{
- printw ("| Monitoring Voice Channel - LCN [%02d]\n", state->edacs_tuned_lcn);
+ printw ("| Monitoring VC - LCN [%02d]", state->edacs_tuned_lcn);
//since we are tuned, keep updating the time so it doesn't disappear during call
call_matrix[state->edacs_tuned_lcn][5] = time(NULL);
}
diff --git a/src/nxdn_deperm.c b/src/nxdn_deperm.c
index 304da1e..e3e6ff1 100644
--- a/src/nxdn_deperm.c
+++ b/src/nxdn_deperm.c
@@ -266,6 +266,9 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " ");
+ //needed for DES and AES
+ state->nxdn_part_of_frame = 0;
+
uint8_t nsf_sacch[26];
memset (nsf_sacch, 0, sizeof(nsf_sacch));
for (int i = 0; i < 26; i++)
@@ -327,6 +330,9 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
else if (sf == 0) part_of_frame = 3;
else part_of_frame = 0;
+ //needed for DES and AES
+ state->nxdn_part_of_frame = part_of_frame;
+
fprintf (stderr, "%s", KCYN);
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " ");
diff --git a/src/nxdn_element.c b/src/nxdn_element.c
index a542e79..4d8ed38 100644
--- a/src/nxdn_element.c
+++ b/src/nxdn_element.c
@@ -1264,8 +1264,11 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
else if (state->rkey_array[DestinationID] != 0) state->R = state->rkey_array[DestinationID];
- //Don't zero key if no keyloader
- if (CipherType != 0x1 && state->keyloader == 1) state->R = 0;
+ //Don't zero key if no keyloader, if we need this, do it when its nots NXDN96, causes issue when 96 VCALL comes in on all data frames
+ // if (CipherType != 0x1 && state->keyloader == 1) state->R = 0; //what did this do again? for mont system or something?
+
+ //safe alternative?
+ if (CipherType == 0 && state->keyloader == 1) state->R = 0;
/* Print the "Cipher Type" */
if(CipherType != 0 && MessageType == 0x1)
@@ -1289,6 +1292,20 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
fprintf (stderr, "%s", KNRM);
}
+ if (CipherType == 0x02 && state->R > 0) //DES key value
+ {
+ fprintf (stderr, "%s", KYEL);
+ fprintf(stderr, "Value: %016llX", state->R);
+ fprintf (stderr, "%s", KNRM);
+ }
+
+ if (CipherType == 0x03 && state->R > 0) //AES key stub
+ {
+ fprintf (stderr, "%s", KYEL);
+ fprintf(stderr, "KS: %016llX", state->R);
+ fprintf (stderr, "%s", KNRM);
+ }
+
//only grab if VCALL
if(MessageType == 0x1)
{
@@ -1373,11 +1390,60 @@ void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message)
//At this point, I would assume an LFSR function is needed to expand the 22-bit IV collected here into a 64-bit IV, or 128-bit IV
state->payload_miN = IV;
- state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 2;
- state->NxdnElementsContent.PartOfNextEncryptedFrame = 1;
-
fprintf (stderr, "\n VCALL_IV: %016llX", state->payload_miN);
+
+ if ( ((state->nxdn_cipher_type == 0x02) || (state->nxdn_cipher_type == 0x03)) )
+ {
+
+ if (state->nxdn_cipher_type == 0x03 && state->keyloader == 1)
+ {
+ state->A1[0] = state->rkey_array[state->nxdn_key+0x000];
+ state->A2[0] = state->rkey_array[state->nxdn_key+0x101];
+ state->A3[0] = state->rkey_array[state->nxdn_key+0x201];
+ state->A4[0] = state->rkey_array[state->nxdn_key+0x301];
+
+ //check to see if there is a value loaded or not
+ if (state->A1[0] == 0 && state->A2[0] == 0 && state->A3[0] == 0 && state->A4[0] == 0)
+ state->aes_key_loaded[0] = 0;
+ else state->aes_key_loaded[0] = 1;
+
+ for (int i = 0; i < 8; i++)
+ {
+ state->aes_key[i+0] = (state->A1[0] >> (56-(i*8))) & 0xFF;
+ state->aes_key[i+8] = (state->A2[0] >> (56-(i*8))) & 0xFF;
+ state->aes_key[i+16] = (state->A3[0] >> (56-(i*8))) & 0xFF;
+ state->aes_key[i+24] = (state->A4[0] >> (56-(i*8))) & 0xFF;
+ }
+
+ state->R = state->A1[0]; //display KS stub
+
+ }
+
+ //use the P25 Slot 1 LFSR128 to generate a 128-bit IV (state->payload_miN is on slot1)
+ if (state->nxdn_cipher_type == 0x03)
+ {
+ state->currentslot = 1; //quickly change to slot 1
+ fprintf (stderr, "\n NXDN -- ");
+ LFSR128(state); //TODO: Make a different function so we don't see the LDU2/ESS-B info and null key values, or something
+ state->currentslot = 0; //change back to slot 0
+ }
+
+ if (state->nxdn_cipher_type == 0x02 && state->keyloader == 1)
+ {
+ if (state->rkey_array[state->nxdn_key] != 0)
+ state->R = state->rkey_array[state->nxdn_key];
+ }
+
+ //signal a new IV is available, but only when the other checks pass
+ if (state->nxdn_cipher_type == 0x02 && state->R != 0)
+ state->nxdn_new_iv = 1;
+
+ if (state->nxdn_cipher_type == 0x03 && state->aes_key_loaded[0] == 1)
+ state->nxdn_new_iv = 1;
+
+ }
+
} /* End NXDN_decode_VCALL_IV() */
//SCCH messages have a unique format that can be used in a super frame, but each 'unit'
diff --git a/src/nxdn_frame.c b/src/nxdn_frame.c
index 8408351..968a76f 100644
--- a/src/nxdn_frame.c
+++ b/src/nxdn_frame.c
@@ -432,6 +432,10 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
}
}
+ //correct the bit counter if NXDN96 Data Frames (or double FACCH1 steal)
+ if (state->nxdn_cipher_type == 0x2 || state->nxdn_cipher_type == 0x3)
+ state->bit_counterL += (49*4);
+
}
if (voice && facch == 1) //facch steal 1 -- before voice
@@ -453,6 +457,10 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
LFSRN(ambe_temp, ambe_d, state);
}
}
+
+ //correct the bit counter if FACCH1 steal)
+ if (state->nxdn_cipher_type == 0x2 || state->nxdn_cipher_type == 0x3)
+ state->bit_counterL += 49*2;
}
if (lich == 0x20 || lich == 0x21 || lich == 0x61 || lich == 0x40 || lich == 0x41) state->nxdn_sacch_non_superframe = TRUE;
@@ -525,6 +533,10 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
LFSRN(ambe_temp, ambe_d, state);
}
}
+
+ //correct the bit counter if FACCH1 steal)
+ if (state->nxdn_cipher_type == 0x2 || state->nxdn_cipher_type == 0x3)
+ state->bit_counterL += 49*2;
}
if (opts->payload == 1 && !voice) fprintf (stderr, "\n");
diff --git a/src/p25p1_hdu.c b/src/p25p1_hdu.c
index 515c780..5a4aee8 100644
--- a/src/p25p1_hdu.c
+++ b/src/p25p1_hdu.c
@@ -473,11 +473,32 @@ processHDU(dsd_opts* opts, dsd_state* state)
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX", algidhex, kidhex, mihex1, mihex2);
state->payload_algid = algidhex;
state->payload_keyid = kidhex;
+ if (mihex3) fprintf (stderr, "-%02llX", mihex3);
if (state->R != 0 && state->payload_algid == 0xAA)
{
fprintf (stderr, " Key: %010llX", state->R);
opts->unmute_encrypted_p25 = 1;
}
+ else if (state->R != 0 && state->payload_algid == 0x81)
+ {
+ fprintf (stderr, " Key: %010llX", state->R);
+ opts->unmute_encrypted_p25 = 1;
+ }
+ else if (state->R != 0 && state->payload_algid == 0x9F)
+ {
+ fprintf (stderr, " Key: %010llX", state->R);
+ opts->unmute_encrypted_p25 = 1;
+ }
+ else if ( (state->payload_algid == 0x84 || state->payload_algid == 0x89) && state->aes_key_loaded[0] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "%s", KYEL);
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[0], state->A2[0]);
+ if (state->payload_algid == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[0], state->A4[0]);
+ fprintf (stderr, "%s ", KNRM);
+ opts->unmute_encrypted_p25 = 1;
+ }
else if (state->payload_algid != 0 && state->payload_algid != 0x80)
{
//may want to mute this again, or may not want to
@@ -495,6 +516,17 @@ processHDU(dsd_opts* opts, dsd_state* state)
}
fprintf (stderr, "\n");
+
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ LFSR128(state);
+ fprintf (stderr, "\n");
+ }
+
+ //xl, we need to know if the ESS is from HDU, or LDU2
+ state->xl_is_hdu = 1;
+
}
else
{
diff --git a/src/p25p1_ldu1.c b/src/p25p1_ldu1.c
index 2950a71..a9b7a61 100644
--- a/src/p25p1_ldu1.c
+++ b/src/p25p1_ldu1.c
@@ -49,6 +49,9 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
// so we start counter at 36-14-1 = 21
status_count = 21;
+ //set vc counter to 0 -- just playing it safe, shouldn't matter since rotating MIs are only in the LDU2 frame
+ state->p25vc = 0;
+
if (opts->errorbars == 1)
{
//fprintf (stderr, "e:");
@@ -253,6 +256,8 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
// TODO: do something useful with the LSD bytes... <--THIS!
state->dropL += 2; //need to skip 2 here for the LSD bytes
+ //same for octet counter
+ state->octet_counter += 2;
}
// IMBE 9
diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c
index 86b15b2..a1e5e69 100644
--- a/src/p25p1_ldu2.c
+++ b/src/p25p1_ldu2.c
@@ -256,6 +256,9 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
// TODO: do something useful with the LSD bytes... <--THIS!
state->dropL += 2; //need to skip 2 here for the LSD bytes
+ //same for octet counter
+ state->octet_counter += 2;
+
}
// IMBE 9
@@ -277,6 +280,8 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
//reset dropbytes -- skip first 11 for next LCW
state->dropL = 267;
+ //reset octet counter
+ state->octet_counter = 0;
if (opts->errorbars == 1)
{
@@ -476,11 +481,38 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX", algidhex, kidhex, mihex1, mihex2);
state->payload_algid = algidhex;
state->payload_keyid = kidhex;
+ if (mihex3) fprintf (stderr, "-%02llX", mihex3);
if (state->R != 0 && state->payload_algid == 0xAA)
{
fprintf (stderr, " Key: %010llX", state->R);
opts->unmute_encrypted_p25 = 1;
}
+ else if (state->R != 0 && state->payload_algid == 0x81)
+ {
+ fprintf (stderr, " Key: %010llX", state->R);
+ opts->unmute_encrypted_p25 = 1;
+ }
+ else if (state->R != 0 && state->payload_algid == 0x9F)
+ {
+ fprintf (stderr, " Key: %010llX", state->R);
+ opts->unmute_encrypted_p25 = 1;
+ }
+ /* //going to want to update this for OFB, CBC, and ECB
+ { 0x84, "AES-256-OFB" },
+ { 0x85, "AES-128-ECB"},
+ { 0x88, "AES-CBC"},
+ { 0x89, "AES-128-OFB"},
+ */
+ else if ( (state->payload_algid == 0x84 || state->payload_algid == 0x89) && state->aes_key_loaded[0] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "%s", KYEL);
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[0], state->A2[0]);
+ if (state->payload_algid == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[0], state->A4[0]);
+ fprintf (stderr, "%s ", KNRM);
+ opts->unmute_encrypted_p25 = 1;
+ }
else if (state->payload_algid != 0 && state->payload_algid != 0x80)
{
//may want to mute this again, or may not want to
@@ -627,6 +659,15 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
fprintf (stderr, "\n");
}
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ LFSR128(state);
+ fprintf (stderr, "\n");
+ }
+
+ //xl, we need to know if the ESS is from HDU, or LDU2
+ state->xl_is_hdu = 0;
#define P25p1_ENC_LO //disable if this behavior is detremental
#ifdef P25p1_ENC_LO
@@ -703,3 +744,86 @@ void LFSRP(dsd_state * state)
fprintf (stderr, "\n LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algidR, state->payload_keyidR, state->payload_miN);
fprintf (stderr, "%s", KNRM);
}
+
+void LFSR128(dsd_state * state)
+{
+ //generate a 128-bit IV from a 64-bit IV for AES blocks
+ unsigned long long int lfsr = 0;
+
+ int slot = state->currentslot;
+
+ if (state->currentslot == 0)
+ lfsr = state->payload_miP;
+ else lfsr = state->payload_miN;
+
+ //start packing aes_iv
+ if (slot == 0)
+ {
+ state->aes_iv[0] = (lfsr >> 56) & 0xFF;
+ state->aes_iv[1] = (lfsr >> 48) & 0xFF;
+ state->aes_iv[2] = (lfsr >> 40) & 0xFF;
+ state->aes_iv[3] = (lfsr >> 32) & 0xFF;
+ state->aes_iv[4] = (lfsr >> 24) & 0xFF;
+ state->aes_iv[5] = (lfsr >> 16) & 0xFF;
+ state->aes_iv[6] = (lfsr >> 8 ) & 0xFF;
+ state->aes_iv[7] = (lfsr >> 0 ) & 0xFF;
+ }
+ if (slot == 1)
+ {
+ state->aes_ivR[0] = (lfsr >> 56) & 0xFF;
+ state->aes_ivR[1] = (lfsr >> 48) & 0xFF;
+ state->aes_ivR[2] = (lfsr >> 40) & 0xFF;
+ state->aes_ivR[3] = (lfsr >> 32) & 0xFF;
+ state->aes_ivR[4] = (lfsr >> 24) & 0xFF;
+ state->aes_ivR[5] = (lfsr >> 16) & 0xFF;
+ state->aes_ivR[6] = (lfsr >> 8 ) & 0xFF;
+ state->aes_ivR[7] = (lfsr >> 0 ) & 0xFF;
+ }
+
+ int cnt = 0; int x = 64;
+ unsigned long long int bit;
+ //polynomial P(x) = 1 + X15 + X27 + X38 + X46 + X62 + X64
+ for(cnt=0;cnt<64;cnt++)
+ {
+ //63,61,45,37,27,14
+ // Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
+ bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1;
+ lfsr = (lfsr << 1) | bit;
+
+ //continue packing aes_iv
+ if (slot == 0)
+ state->aes_iv[x/8] = (state->aes_iv[x/8] << 1) + bit;
+ if (slot == 1)
+ state->aes_ivR[x/8] = (state->aes_ivR[x/8] << 1) + bit;
+ x++;
+ }
+
+ if (state->currentslot == 0)
+ {
+ fprintf (stderr, "%s", KYEL);
+ if (state->dmrburstL != 27) //if not LDU2
+ fprintf (stderr, "\n");
+ fprintf (stderr, " ");
+ fprintf (stderr, " ALG ID: 0x%02X KEY ID: 0x%04X MI(128): 0x", state->payload_algid, state->payload_keyid);
+ for (x = 0; x < 16; x++)
+ fprintf (stderr, "%02X", state->aes_iv[x]);
+ fprintf (stderr, "%s", KNRM);
+ // fprintf (stderr, "\n");
+
+ }
+
+ if (state->currentslot == 1)
+ {
+ fprintf (stderr, "%s", KYEL);
+ if (state->dmrburstL != 27) //if not LDU2, shouldn't matter on P25p2 for the second slot
+ fprintf (stderr, "\n");
+ fprintf (stderr, " ");
+ fprintf (stderr, " ALG ID: 0x%02X KEY ID: 0x%04X MI(128): 0x", state->payload_algidR, state->payload_keyidR);
+ for (x = 0; x < 16; x++)
+ fprintf (stderr, "%02X", state->aes_ivR[x]);
+ fprintf (stderr, "%s", KNRM);
+ // fprintf (stderr, "\n");
+
+ }
+
+}
diff --git a/src/p25p1_pdu_data.c b/src/p25p1_pdu_data.c
index de935ec..47af54c 100644
--- a/src/p25p1_pdu_data.c
+++ b/src/p25p1_pdu_data.c
@@ -62,20 +62,192 @@ void p25_decode_sap(uint8_t SAP, char * sap_string)
}
+void lfsr_64_to_128(uint8_t * iv)
+{
+ uint64_t lfsr = 0, bit = 0;
+
+ lfsr = ((uint64_t)iv[0] << 56ULL) + ((uint64_t)iv[1] << 48ULL) + ((uint64_t)iv[2] << 40ULL) + ((uint64_t)iv[3] << 32ULL) +
+ ((uint64_t)iv[4] << 24ULL) + ((uint64_t)iv[5] << 16ULL) + ((uint64_t)iv[6] << 8ULL) + ((uint64_t)iv[7] << 0ULL);
+
+ uint8_t cnt = 0, x = 64;
+
+ for(cnt = 0;cnt < 64; cnt++)
+ {
+ //63,61,45,37,27,14
+ // Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
+ bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1;
+ lfsr = (lfsr << 1) | bit;
+
+ //continue packing iv
+ iv[x/8] = (iv[x/8] << 1) + bit;
+
+ x++;
+ }
+
+}
+
uint8_t p25_decrypt_pdu(dsd_opts * opts, dsd_state * state, uint8_t * input, uint8_t alg_id, uint16_t key_id, unsigned long long int mi, int len)
{
+ UNUSED(opts);
uint8_t encrypted = 1;
- UNUSED(opts);
- UNUSED(state);
- UNUSED(input);
- UNUSED(mi);
- UNUSED(key_id);
- UNUSED(alg_id);
- UNUSED(len);
+ int i = 0;
+ int ks_idx = 0;
+ uint8_t ks_bytes[3096]; memset (ks_bytes, 0, sizeof(ks_bytes));
+ //create keystream
+ if (alg_id == 0x84 || alg_id == 0x89) //AES -- dsd-fme -f1 -i '/SSD_STORAGE/2024_DEV/otar shit/OTAR/SUGARLOAF DATA OUTPUT/CC-DSDPlus-Raw-Input_2024-08-27@134540.wav' -s 96000 -K testaeskeys.csv
+ {
+ //aes specific arrays and things
+ uint8_t aes_iv[16]; memset (aes_iv, 0, sizeof(aes_iv));
+ uint8_t aes_key[32]; memset (aes_key, 0, sizeof(aes_key));
+ uint8_t empt[64]; memset (empt, 0, sizeof(empt));
+
+ uint8_t akl = 0; //aes key loaded into array flag
+ unsigned long long int a1 = state->rkey_array[key_id+0x000];
+ unsigned long long int a2 = state->rkey_array[key_id+0x101];
+ unsigned long long int a3 = state->rkey_array[key_id+0x201];
+ unsigned long long int a4 = state->rkey_array[key_id+0x301];
+
+ //checkdown to see if anything in a1-a4
+ if ( (a1 == 0) && (a2 == 0) && (a3 == 0) && (a4 == 0) )
+ {
+ //try loading from state->H instead (could clash if keys loaded that trigger any a1-a4 above)
+ a1 = state->K1;
+ a2 = state->K2;
+ a3 = state->K3;
+ a4 = state->K4;
+ }
+
+ //loader for aes keys
+ for (uint64_t i = 0; i < 8; i++)
+ {
+ aes_key[i+0] = (a1 >> (56ULL-(i*8))) & 0xFF;
+ aes_key[i+8] = (a2 >> (56ULL-(i*8))) & 0xFF;
+ aes_key[i+16] = (a3 >> (56ULL-(i*8))) & 0xFF;
+ aes_key[i+24] = (a4 >> (56ULL-(i*8))) & 0xFF;
+ }
+
+ //check to see if a key is loaded into any part of the array
+ if (memcmp(aes_key, empt, sizeof(aes_key)) != 0) akl = 1;
+ else akl = 0;
+
+ //convert mi to aes_iv and expand it
+ aes_iv[0] = ((mi & 0xFF00000000000000) >> 56);
+ aes_iv[1] = ((mi & 0xFF000000000000) >> 48);
+ aes_iv[2] = ((mi & 0xFF0000000000) >> 40);
+ aes_iv[3] = ((mi & 0xFF00000000) >> 32);
+ aes_iv[4] = ((mi & 0xFF000000) >> 24);
+ aes_iv[5] = ((mi & 0xFF0000) >> 16);
+ aes_iv[6] = ((mi & 0xFF00) >> 8);
+ aes_iv[7] = ((mi & 0xFF) >> 0);
+
+ lfsr_64_to_128(aes_iv);
+
+ ks_idx = 16; //offset for OFB discard round
+
+ if (akl == 1)
+ {
+ int nblocks = (len / 16) + 1;
+ if (alg_id == 0x84) //AES256
+ aes_ofb_keystream_output (aes_iv, aes_key, ks_bytes, 2, nblocks);
+ else aes_ofb_keystream_output (aes_iv, aes_key, ks_bytes, 0, nblocks);
+
+ fprintf (stderr, "\n Key: ");
+ for (i = 0; i < 32; i++)
+ {
+ if ( (i != 0) && ((i%8) == 0) )
+ fprintf (stderr, " ");
+ fprintf (stderr, "%02X", aes_key[i]);
+ }
+
+ encrypted = 0;
+ }
+
+ fprintf (stderr, "\n IV(128): ");
+ for (i = 0; i < 16; i++)
+ fprintf (stderr, "%02X", aes_iv[i]);
+
+ }
+
+ if (alg_id == 0x81) //DES56
+ {
+
+ int nblocks = (len / 8) + 1;
+ unsigned long long int des_key = 0;
+
+ des_key = state->rkey_array[key_id];
+
+ //if no key loaded from loader, check state->R for key
+ if (des_key == 0) des_key = state->R;
+
+ ks_idx = 8; //offset for OFB discard round
+
+ if (des_key)
+ des_multi_keystream_output (mi, des_key, ks_bytes, 1, nblocks);
+
+ encrypted = 0;
+
+ //debug, print key, iv, and keystream stuff
+ fprintf (stderr, "\n Key: %16llX", des_key);
+
+ }
+
+ if (alg_id == 0xAA) //RC4, or 'ADP'
+ {
+
+ unsigned long long int rc4_key = 0;
+
+ rc4_key = state->rkey_array[key_id];
+
+ //if no key loaded from loader, check state->R for key
+ if (rc4_key == 0) rc4_key = state->R;
+
+ ks_idx = 0; //offset
+
+ uint8_t rc4_kiv[13]; memset (rc4_kiv, 0, sizeof(rc4_key));
+
+ rc4_kiv[0] = ((rc4_key & 0xFF00000000) >> 32);
+ rc4_kiv[1] = ((rc4_key & 0xFF000000) >> 24);
+ rc4_kiv[2] = ((rc4_key & 0xFF0000) >> 16);
+ rc4_kiv[3] = ((rc4_key & 0xFF00) >> 8);
+ rc4_kiv[4] = ((rc4_key & 0xFF) >> 0);
+
+ rc4_kiv[5] = ((mi & 0xFF00000000000000) >> 56);
+ rc4_kiv[6] = ((mi & 0xFF000000000000) >> 48);
+ rc4_kiv[7] = ((mi & 0xFF0000000000) >> 40);
+ rc4_kiv[8] = ((mi & 0xFF00000000) >> 32);
+ rc4_kiv[9] = ((mi & 0xFF000000) >> 24);
+ rc4_kiv[10] = ((mi & 0xFF0000) >> 16);
+ rc4_kiv[11] = ((mi & 0xFF00) >> 8);
+ rc4_kiv[12] = ((mi & 0xFF) >> 0);
+
+ if (rc4_key)
+ rc4_block_output (256, 13, len, rc4_kiv, ks_bytes);
+
+ encrypted = 0;
+
+ //debug, print key, iv, and keystream stuff
+ fprintf (stderr, "\n Key: %16llX", rc4_key);
+
+ }
+
+ //debug input offset
+ // fprintf (stderr, "\n INPUT: ");
+ // for (i = 0; i < 16; i++)
+ // fprintf (stderr, "%02X", input[i]);
+
+ // fprintf (stderr, "\n KS: ");
+ // for (i = 0; i < 16; i++)
+ // fprintf (stderr, "%02X", ks_bytes[i]);
+
+ //apply keystream
+ for (i = 0; i < len; i++) //need to subtract pad bytes and crc bytes from keystream application
+ input[i] ^= ks_bytes[i+ks_idx];
+
+ if (alg_id == 0x80) encrypted = 0;
return encrypted;
}
diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c
index 4bacb1a..dce904e 100644
--- a/src/p25p2_frame.c
+++ b/src/p25p2_frame.c
@@ -597,7 +597,7 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
if (opts->payload == 1)
{
- fprintf (stderr, "\n");
+ // fprintf (stderr, "\n");
fprintf (stderr, " VCH %d - ESS_B %08llX%016llX ERR = %02d", state->currentslot, essb_hex1, essb_hex2, ec);
}
@@ -610,12 +610,30 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
state->payload_miP = ((essb_hex1 & 0xFF) << 56) | ((essb_hex2 & 0xFFFFFFFFFFFFFF00) >> 8);
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
{
- fprintf (stderr, "\n VCH 0 -");
- fprintf (stderr, " ALG ID 0x%02X", state->payload_algid);
- fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
- fprintf (stderr, " MI 0x%016llX", state->payload_miP);
- if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
+ fprintf (stderr, "\n");
+ fprintf (stderr, " VCH 0 -");
+ fprintf (stderr, " ALG ID: 0x%02X", state->payload_algid);
+ fprintf (stderr, " KEY ID: 0x%04X", state->payload_keyid);
+ fprintf (stderr, " MI: 0x%016llX", state->payload_miP);
fprintf (stderr, " ESSB");
+
+ if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
+ if (state->R != 0 && state->payload_algid == 0x81) fprintf (stderr, " Key 0x%016llX", state->R);
+ if ( (state->payload_algid == 0x84 || state->payload_algid == 0x89) && state->aes_key_loaded[0] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[0], state->A2[0]);
+ if (state->payload_algid == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[0], state->A4[0]);
+ // opts->unmute_encrypted_p25 = 1; //needed?
+ }
+
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
}
}
@@ -626,12 +644,31 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
state->payload_miN = ((essb_hex1 & 0xFF) << 56) | ((essb_hex2 & 0xFFFFFFFFFFFFFF00) >> 8);
if (state->payload_algidR != 0x80 && state->payload_algidR != 0x0)
{
- fprintf (stderr, "\n VCH 1 -");
- fprintf (stderr, " ALG ID 0x%02X", state->payload_algidR);
- fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
- fprintf (stderr, " MI 0x%016llX", state->payload_miN);
- if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
+ fprintf (stderr, "\n");
+ fprintf (stderr, " VCH 1 -");
+ fprintf (stderr, " ALG ID: 0x%02X", state->payload_algidR);
+ fprintf (stderr, " KEY ID: 0x%04X", state->payload_keyidR);
+ fprintf (stderr, " MI: 0x%016llX", state->payload_miN);
fprintf (stderr, " ESSB");
+
+ if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
+ if (state->RR != 0 && state->payload_algidR == 0x81) fprintf (stderr, " Key 0x%016llX", state->RR);
+ if ( (state->payload_algidR == 0x84 || state->payload_algidR == 0x89) && state->aes_key_loaded[1] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[1], state->A2[1]);
+ if (state->payload_algidR == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[1], state->A4[1]);
+ // opts->unmute_encrypted_p25 = 1; //needed?
+ }
+
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algidR == 0x84 || state->payload_algidR == 0x89)
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
+
}
}
@@ -702,11 +739,28 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
}
if (ec == -1 || ec >= 15)
{
+ //below needs a line break before LFSRP runs (when payload == 0)
//ESS R-S Failure -- run LFSR on current MI if applicable
if (state->currentslot == 0 && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
LFSRP(state);
if (state->currentslot == 1 && state->payload_algidR != 0x80 && state->payload_keyidR != 0 && state->payload_miN != 0)
LFSRP(state);
+
+ //expand 64-bit MI to 128-bit for AES, vch 0
+ // if (state->currentslot == 0 && state->payload_algid == 0x84 || state->payload_algid == 0x89) //old version
+ if (state->currentslot == 0 && (state->payload_algid == 0x84 || state->payload_algid == 0x89))
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
+
+ //expand 64-bit MI to 128-bit for AES, vch 1
+ // if (state->currentslot == 1 && state->payload_algidR == 0x84 || state->payload_algidR == 0x89) //old version if break
+ if (state->currentslot == 1 && (state->payload_algidR == 0x84 || state->payload_algidR == 0x89)) //new version with parenthesis
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
}
fprintf (stderr, "%s", KNRM);
@@ -817,6 +871,27 @@ void process_2V (dsd_opts * opts, dsd_state * state)
if (state->currentslot == 1 && state->payload_algidR == 0xAA)
state->dropR = 256;
+ //reset voice counter after 2V (DES)
+ if (state->currentslot == 0 && state->payload_algid == 0x81)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 1 && state->payload_algidR == 0x81)
+ state->DMRvcR = 0;
+
+ //reset voice counter after 2V (AES 256)
+ if (state->currentslot == 0 && state->payload_algid == 0x84)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 1 && state->payload_algidR == 0x84)
+ state->DMRvcR = 0;
+
+ //reset voice counter after 2V (AES 128)
+ if (state->currentslot == 0 && state->payload_algid == 0x89)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 1 && state->payload_algidR == 0x89)
+ state->DMRvcR = 0;
+
}
//P2 Data Unit ID
diff --git a/src/p25p2_xcch.c b/src/p25p2_xcch.c
index bccd89b..fc0b94b 100644
--- a/src/p25p2_xcch.c
+++ b/src/p25p2_xcch.c
@@ -153,11 +153,28 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
{
fprintf (stderr, "%s", KYEL);
- fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
- fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
- fprintf (stderr, " MI 0x%016llX", state->payload_miP);
- if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
+ fprintf (stderr, "\n ALG ID: 0x%02X", state->payload_algid);
+ fprintf (stderr, " KEY ID: 0x%04X", state->payload_keyid);
+ fprintf (stderr, " MI: 0x%016llX", state->payload_miP);
fprintf(stderr, " MPTT");
+ if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
+ if (state->R != 0 && state->payload_algid == 0x81) fprintf (stderr, " Key 0x%016llX", state->R);
+
+ if ( (state->payload_algid == 0x84 || state->payload_algid == 0x89) && state->aes_key_loaded[0] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[0], state->A2[0]);
+ if (state->payload_algid == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[0], state->A4[0]);
+ // opts->unmute_encrypted_p25 = 1; //needed?
+ }
+
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
}
@@ -195,11 +212,28 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
if (state->payload_algidR != 0x80 && state->payload_algidR != 0x0)
{
fprintf (stderr, "%s", KYEL);
- fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
- fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
- fprintf (stderr, " MI 0x%016llX", state->payload_miN);
- if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
+ fprintf (stderr, "\n ALG ID: 0x%02X", state->payload_algidR);
+ fprintf (stderr, " KEY ID: 0x%04X", state->payload_keyidR);
+ fprintf (stderr, " MI: 0x%016llX", state->payload_miN);
fprintf(stderr, " MPTT");
+
+ if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
+ if (state->RR != 0 && state->payload_algidR == 0x81) fprintf (stderr, " Key 0x%016llX", state->RR);
+ if ( (state->payload_algidR == 0x84 || state->payload_algidR == 0x89) && state->aes_key_loaded[1] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[1], state->A2[1]);
+ if (state->payload_algidR == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[1], state->A4[1]);
+ // opts->unmute_encrypted_p25 = 1; //needed?
+ }
+
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algidR == 0x84 || state->payload_algidR == 0x89)
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
}
@@ -220,6 +254,27 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
}
}
+ //reset voice counter at MAC_PTT (inverted, triple check please)
+ if (state->currentslot == 1 && state->payload_algidR == 0x81)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 0 && state->payload_algid == 0x81)
+ state->DMRvcR = 0;
+
+ //reset voice counter after 2V (AES 256)
+ if (state->currentslot == 1 && state->payload_algidR == 0x84)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 0 && state->payload_algid == 0x84)
+ state->DMRvcR = 0;
+
+ //reset voice counter after 2V (AES 128)
+ if (state->currentslot == 1 && state->payload_algidR == 0x89)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 0 && state->payload_algid == 0x89)
+ state->DMRvcR = 0;
+
fprintf (stderr, "%s", KNRM);
}
//do not permit MAC_PTT_END with CRC errs, help prevent false positives on calls
@@ -538,11 +593,28 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
{
fprintf (stderr, "%s", KYEL);
- fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
- fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
- fprintf (stderr, " MI 0x%016llX", state->payload_miP);
- if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
+ fprintf (stderr, "\n ALG ID: 0x%02X", state->payload_algid);
+ fprintf (stderr, " KEY ID: 0x%04X", state->payload_keyid);
+ fprintf (stderr, " MI: 0x%016llX", state->payload_miP);
fprintf(stderr, " MPTT");
+ if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
+ if (state->R != 0 && state->payload_algid == 0x81) fprintf (stderr, " Key 0x%016llX", state->R);
+
+ if ( (state->payload_algid == 0x84 || state->payload_algid == 0x89) && state->aes_key_loaded[0] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[0], state->A2[0]);
+ if (state->payload_algid == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[0], state->A4[0]);
+ // opts->unmute_encrypted_p25 = 1; //needed?
+ }
+
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algid == 0x84 || state->payload_algid == 0x89)
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
}
@@ -579,11 +651,28 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
if (state->payload_algidR != 0x80 && state->payload_algidR != 0x0)
{
fprintf (stderr, "%s", KYEL);
- fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
- fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
- fprintf (stderr, " MI 0x%016llX", state->payload_miN);
- if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
+ fprintf (stderr, "\n ALG ID: 0x%02X", state->payload_algidR);
+ fprintf (stderr, " KEY ID: 0x%04X", state->payload_keyidR);
+ fprintf (stderr, " MI: 0x%016llX", state->payload_miN);
fprintf(stderr, " MPTT");
+
+ if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
+ if (state->RR != 0 && state->payload_algidR == 0x81) fprintf (stderr, " Key 0x%016llX", state->RR);
+ if ( (state->payload_algidR == 0x84 || state->payload_algidR == 0x89) && state->aes_key_loaded[1] == 1)
+ {
+ fprintf (stderr, "\n ");
+ fprintf (stderr, "Key: %016llX %016llX ", state->A1[1], state->A2[1]);
+ if (state->payload_algidR == 0x84)
+ fprintf (stderr, "%016llX %016llX", state->A3[1], state->A4[1]);
+ // opts->unmute_encrypted_p25 = 1; //needed?
+ }
+
+ //expand 64-bit MI to 128-bit for AES
+ if (state->payload_algidR == 0x84 || state->payload_algidR == 0x89)
+ {
+ LFSR128(state);
+ // fprintf (stderr, "\n");
+ }
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
}
@@ -605,6 +694,27 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
}
fprintf (stderr, "%s", KNRM);
+ //reset voice counter at MAC_PTT
+ if (state->currentslot == 0 && state->payload_algid == 0x81)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 1 && state->payload_algidR == 0x81)
+ state->DMRvcR = 0;
+
+ //reset voice counter after 2V (AES 256)
+ if (state->currentslot == 0 && state->payload_algid == 0x84)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 1 && state->payload_algidR == 0x84)
+ state->DMRvcR = 0;
+
+ //reset voice counter after 2V (AES 128)
+ if (state->currentslot == 0 && state->payload_algid == 0x89)
+ state->DMRvcL = 0;
+
+ if (state->currentslot == 1 && state->payload_algidR == 0x89)
+ state->DMRvcR = 0;
+
}
if (opcode == 0x2 && err == 0)
{