16static const uint8_t IP_TABLE[64] = {
17 58U, 50U, 42U, 34U, 26U, 18U, 10U, 2U,
18 60U, 52U, 44U, 36U, 28U, 20U, 12U, 4U,
19 62U, 54U, 46U, 38U, 30U, 22U, 14U, 6U,
20 64U, 56U, 48U, 40U, 32U, 24U, 16U, 8U,
21 57U, 49U, 41U, 33U, 25U, 17U, 9U, 1U,
22 59U, 51U, 43U, 35U, 27U, 19U, 11U, 3U,
23 61U, 53U, 45U, 37U, 29U, 21U, 13U, 5U,
24 63U, 55U, 47U, 39U, 31U, 23U, 15U, 7U
27static const uint8_t FP_TABLE[64] = {
28 40U, 8U, 48U, 16U, 56U, 24U, 64U, 32U,
29 39U, 7U, 47U, 15U, 55U, 23U, 63U, 31U,
30 38U, 6U, 46U, 14U, 54U, 22U, 62U, 30U,
31 37U, 5U, 45U, 13U, 53U, 21U, 61U, 29U,
32 36U, 4U, 44U, 12U, 52U, 20U, 60U, 28U,
33 35U, 3U, 43U, 11U, 51U, 19U, 59U, 27U,
34 34U, 2U, 42U, 10U, 50U, 18U, 58U, 26U,
35 33U, 1U, 41U, 9U, 49U, 17U, 57U, 25U
38static const uint8_t E_TABLE[48] = {
39 32U, 1U, 2U, 3U, 4U, 5U,
40 4U, 5U, 6U, 7U, 8U, 9U,
41 8U, 9U, 10U, 11U, 12U, 13U,
42 12U, 13U, 14U, 15U, 16U, 17U,
43 16U, 17U, 18U, 19U, 20U, 21U,
44 20U, 21U, 22U, 23U, 24U, 25U,
45 24U, 25U, 26U, 27U, 28U, 29U,
46 28U, 29U, 30U, 31U, 32U, 1U
49static const uint8_t P_TABLE[32] = {
50 16U, 7U, 20U, 21U, 29U, 12U, 28U, 17U,
51 1U, 15U, 23U, 26U, 5U, 18U, 31U, 10U,
52 2U, 8U, 24U, 14U, 32U, 27U, 3U, 9U,
53 19U, 13U, 30U, 6U, 22U, 11U, 4U, 25U
56static const uint8_t SBOX[8][4][16] = {
58 { 14U, 4U, 13U, 1U, 2U, 15U, 11U, 8U, 3U, 10U, 6U, 12U, 5U, 9U, 0U, 7U },
59 { 0U, 15U, 7U, 4U, 14U, 2U, 13U, 1U, 10U, 6U, 12U, 11U, 9U, 5U, 3U, 8U },
60 { 4U, 1U, 14U, 8U, 13U, 6U, 2U, 11U, 15U, 12U, 9U, 7U, 3U, 10U, 5U, 0U },
61 { 15U, 12U, 8U, 2U, 4U, 9U, 1U, 7U, 5U, 11U, 3U, 14U, 10U, 0U, 6U, 13U }
64 { 15U, 1U, 8U, 14U, 6U, 11U, 3U, 4U, 9U, 7U, 2U, 13U, 12U, 0U, 5U, 10U },
65 { 3U, 13U, 4U, 7U, 15U, 2U, 8U, 14U, 12U, 0U, 1U, 10U, 6U, 9U, 11U, 5U },
66 { 0U, 14U, 7U, 11U, 10U, 4U, 13U, 1U, 5U, 8U, 12U, 6U, 9U, 3U, 2U, 15U },
67 { 13U, 8U, 10U, 1U, 3U, 15U, 4U, 2U, 11U, 6U, 7U, 12U, 0U, 5U, 14U, 9U }
70 { 10U, 0U, 9U, 14U, 6U, 3U, 15U, 5U, 1U, 13U, 12U, 7U, 11U, 4U, 2U, 8U },
71 { 13U, 7U, 0U, 9U, 3U, 4U, 6U, 10U, 2U, 8U, 5U, 14U, 12U, 11U, 15U, 1U },
72 { 13U, 6U, 4U, 9U, 8U, 15U, 3U, 0U, 11U, 1U, 2U, 12U, 5U, 10U, 14U, 7U },
73 { 1U, 10U, 13U, 0U, 6U, 9U, 8U, 7U, 4U, 15U, 14U, 3U, 11U, 5U, 2U, 12U }
76 { 7U, 13U, 14U, 3U, 0U, 6U, 9U, 10U, 1U, 2U, 8U, 5U, 11U, 12U, 4U, 15U },
77 { 13U, 8U, 11U, 5U, 6U, 15U, 0U, 3U, 4U, 7U, 2U, 12U, 1U, 10U, 14U, 9U },
78 { 10U, 6U, 9U, 0U, 12U, 11U, 7U, 13U, 15U, 1U, 3U, 14U, 5U, 2U, 8U, 4U },
79 { 3U, 15U, 0U, 6U, 10U, 1U, 13U, 8U, 9U, 4U, 5U, 11U, 12U, 7U, 2U, 14U }
82 { 2U, 12U, 4U, 1U, 7U, 10U, 11U, 6U, 8U, 5U, 3U, 15U, 13U, 0U, 14U, 9U },
83 { 14U, 11U, 2U, 12U, 4U, 7U, 13U, 1U, 5U, 0U, 15U, 10U, 3U, 9U, 8U, 6U },
84 { 4U, 2U, 1U, 11U, 10U, 13U, 7U, 8U, 15U, 9U, 12U, 5U, 6U, 3U, 0U, 14U },
85 { 11U, 8U, 12U, 7U, 1U, 14U, 2U, 13U, 6U, 15U, 0U, 9U, 10U, 4U, 5U, 3U }
88 { 12U, 1U, 10U, 15U, 9U, 2U, 6U, 8U, 0U, 13U, 3U, 4U, 14U, 7U, 5U, 11U },
89 { 10U, 15U, 4U, 2U, 7U, 12U, 9U, 5U, 6U, 1U, 13U, 14U, 0U, 11U, 3U, 8U },
90 { 9U, 14U, 15U, 5U, 2U, 8U, 12U, 3U, 7U, 0U, 4U, 10U, 1U, 13U, 11U, 6U },
91 { 4U, 3U, 2U, 12U, 9U, 5U, 15U, 10U, 11U, 14U, 1U, 7U, 6U, 0U, 8U, 13U }
94 { 4U, 11U, 2U, 14U, 15U, 0U, 8U, 13U, 3U, 12U, 9U, 7U, 5U, 10U, 6U, 1U },
95 { 13U, 0U, 11U, 7U, 4U, 9U, 1U, 10U, 14U, 3U, 5U, 12U, 2U, 15U, 8U, 6U },
96 { 1U, 4U, 11U, 13U, 12U, 3U, 7U, 14U, 10U, 15U, 6U, 8U, 0U, 5U, 9U, 2U },
97 { 6U, 11U, 13U, 8U, 1U, 4U, 10U, 7U, 9U, 5U, 0U, 15U, 14U, 2U, 3U, 12U }
100 { 13U, 2U, 8U, 4U, 6U, 15U, 11U, 1U, 10U, 9U, 3U, 14U, 5U, 0U, 12U, 7U },
101 { 1U, 15U, 13U, 8U, 10U, 3U, 7U, 4U, 12U, 5U, 6U, 11U, 0U, 14U, 9U, 2U },
102 { 7U, 11U, 4U, 1U, 9U, 12U, 14U, 2U, 0U, 6U, 10U, 13U, 15U, 3U, 5U, 8U },
103 { 2U, 1U, 14U, 7U, 4U, 10U, 8U, 13U, 15U, 12U, 9U, 0U, 3U, 5U, 6U, 11U }
107static const uint8_t PC1_TABLE[56] = {
108 57U, 49U, 41U, 33U, 25U, 17U, 9U,
109 1U, 58U, 50U, 42U, 34U, 26U, 18U,
110 10U, 2U, 59U, 51U, 43U, 35U, 27U,
111 19U, 11U, 3U, 60U, 52U, 44U, 36U,
112 63U, 55U, 47U, 39U, 31U, 23U, 15U,
113 7U, 62U, 54U, 46U, 38U, 30U, 22U,
114 14U, 6U, 61U, 53U, 45U, 37U, 29U,
115 21U, 13U, 5U, 28U, 20U, 12U, 4U
118static const uint8_t PC2_TABLE[48] = {
119 14U, 17U, 11U, 24U, 1U, 5U,
120 3U, 28U, 15U, 6U, 21U, 10U,
121 23U, 19U, 12U, 4U, 26U, 8U,
122 16U, 7U, 27U, 20U, 13U, 2U,
123 41U, 52U, 31U, 37U, 47U, 55U,
124 30U, 40U, 51U, 45U, 33U, 48U,
125 44U, 49U, 39U, 56U, 34U, 53U,
126 46U, 42U, 50U, 36U, 29U, 32U
129static const uint8_t ROTATE_TABLE[16] = {
130 1U, 1U, 2U, 2U, 2U, 2U, 2U, 2U, 1U, 2U, 2U, 2U, 2U, 2U, 2U, 1U
135 uint64_t subkeys[16];
138static uint64_t des_permute(uint64_t in,
const uint8_t *table, uint8_t n, uint8_t in_bits)
141 for (uint8_t i = 0U; i < n; i++)
143 uint8_t bit_pos = (uint8_t)(in_bits - table[i]);
144 if (((in >> bit_pos) & 1ULL) != 0ULL)
146 out |= (1ULL << (n - 1U - i));
155 for (
size_t i = 0U; i < 8U; i++)
157 k = (k << 8U) | (uint64_t)key[i];
159 uint64_t pc1 = des_permute(k, PC1_TABLE, 56U, 64U);
160 uint32_t c = (uint32_t)((pc1 >> 28U) & 0x0FFFFFFFU);
161 uint32_t d = (uint32_t)(pc1 & 0x0FFFFFFFU);
163 for (
size_t r = 0U; r < 16U; r++)
165 uint8_t shift = ROTATE_TABLE[r];
166 c = (((c << shift) | (c >> (28U - shift)))) & 0x0FFFFFFFU;
167 d = (((d << shift) | (d >> (28U - shift)))) & 0x0FFFFFFFU;
168 uint64_t cd = ((uint64_t)c << 28U) | (uint64_t)d;
169 ks->subkeys[r] = des_permute(cd, PC2_TABLE, 48U, 56U);
173static uint64_t des_cipher_core(uint64_t in_block,
const des_key_schedule_t *ks,
int decrypt)
175 uint64_t ip = des_permute(in_block, IP_TABLE, 64U, 64U);
176 uint32_t l = (uint32_t)(ip >> 32U);
177 uint32_t r = (uint32_t)(ip & 0xFFFFFFFFU);
179 for (
size_t round = 0U; round < 16U; round++)
181 size_t r_idx = (decrypt != 0) ? (15U - round) : round;
182 uint64_t er = des_permute((uint64_t)r, E_TABLE, 48U, 32U);
183 uint64_t b = er ^ ks->subkeys[r_idx];
186 for (
size_t s = 0U; s < 8U; s++)
188 uint8_t chunk = (uint8_t)((b >> (42U - s * 6U)) & 0x3FU);
189 uint8_t row = (uint8_t)(((chunk & 0x20U) >> 4U) | (chunk & 0x01U));
190 uint8_t col = (uint8_t)((chunk >> 1U) & 0x0FU);
191 uint8_t val = SBOX[s][row][col];
192 s_out = (s_out << 4U) | (uint32_t)val;
195 uint32_t f_res = (uint32_t)des_permute((uint64_t)s_out, P_TABLE, 32U, 32U);
196 uint32_t new_r = l ^ f_res;
201 uint64_t pre_fp = ((uint64_t)r << 32U) | (uint64_t)l;
202 return des_permute(pre_fp, FP_TABLE, 64U, 64U);
205static uint64_t des_bytes_to_u64(
const uint8_t b[8])
208 for (
size_t i = 0U; i < 8U; i++)
210 v = (v << 8U) | (uint64_t)b[i];
215static void des_u64_to_bytes(uint64_t v, uint8_t b[8])
217 for (
size_t i = 8U; i > 0U; i--)
219 b[i - 1U] = (uint8_t)(v & 0xFFU);
227static void des_ecb(
const uint8_t key[8],
const uint8_t in[8],
int decrypt, uint8_t out[8])
230 des_schedule(key, &ks);
231 uint64_t b = des_cipher_core(des_bytes_to_u64(in), &ks, decrypt);
232 des_u64_to_bytes(b, out);
240static void des3_algo3(
const uint8_t key24[24],
const uint8_t in[8], uint8_t out[8])
246 des_ecb(&key24[16], t2, 0, out);
257 des_ecb(&key24[16], in, 0, t1);
259 des_ecb(&key24[0], t2, 0, out);
272 if ((kmac == NULL) || (ra == NULL) || (rb == NULL) || (out_ctx == NULL))
277 (void)memset(out_ctx, 0,
sizeof(*out_ctx));
287 (void)memcpy(&block_l[0], &ra[0], 4U);
288 (void)memcpy(&block_l[4], &rb[0], 4U);
289 (void)memcpy(&block_r[0], &ra[4], 4U);
290 (void)memcpy(&block_r[4], &rb[4], 4U);
301 const uint8_t *msg,
size_t msg_len,
304 if ((ctx == NULL) || (out_mac == NULL) || ((msg == NULL) && (msg_len > 0U)))
320 size_t padded_len = ((msg_len % 8U) == 0U) ? msg_len : (msg_len + (8U - (msg_len % 8U)));
321 if (padded_len == 0U)
325 size_t nblocks = padded_len / 8U;
328 (void)memset(state, 0,
sizeof(state));
330 for (
size_t blk = 0U; blk < nblocks; blk++)
333 for (
size_t i = 0U; i < 8U; i++)
335 size_t idx = (blk * 8U) + i;
336 xi[i] = (idx < msg_len) ? msg[idx] : 0U;
339 if (blk < (nblocks - 1U))
343 (void)memcpy(state, enc, 8U);
356 const uint8_t *msg,
size_t msg_len,
359 if ((ctx == NULL) || (rx_mac == NULL) || ((msg == NULL) && (msg_len > 0U)))
375 diff |= (uint8_t)(expected_mac[i] ^ rx_mac[i]);
static void des3_algo3_reversed(const uint8_t key24[24], const uint8_t in[8], uint8_t out[8])
The same construction with K1 and K3 swapped: E(K1, D(K2, E(K3, block))). Used only for KS3 of the KS...
static void des_ecb(const uint8_t key[8], const uint8_t in[8], int decrypt, uint8_t out[8])
Single DES encrypt/decrypt of one 8-byte block under one 8-byte key.
static void des3_algo3(const uint8_t key24[24], const uint8_t in[8], uint8_t out[8])
Subset-037-2 §6.2.2.1 "single DES with modified MAC algorithm 3": E(K3, D(K2, E(K1,...
Message Authentication Code and session-key derivation (ERTMS/ETCS Subset-037-2 §6....
#define SAFECOMM_MAC_RAND_LEN
#define SAFECOMM_MAC_KEY_LEN
safecomm_status_t safecomm_mac_derive_ksmac(const uint8_t kmac[SAFECOMM_MAC_KEY_LEN], const uint8_t ra[SAFECOMM_MAC_RAND_LEN], const uint8_t rb[SAFECOMM_MAC_RAND_LEN], safecomm_mac_ctx_t *out_ctx)
Derive the session key KSMAC from KMAC and the AU random values.
@ SAFECOMM_MAC_ALG_3DES_SS037
safecomm_status_t safecomm_mac_compute(const safecomm_mac_ctx_t *ctx, const uint8_t *msg, size_t msg_len, uint8_t out_mac[SAFECOMM_MAC_LEN])
Compute the 8-byte EuroRadio MAC over msg.
safecomm_status_t safecomm_mac_verify(const safecomm_mac_ctx_t *ctx, const uint8_t *msg, size_t msg_len, const uint8_t rx_mac[SAFECOMM_MAC_LEN])
Constant-time verify of a received MAC against a freshly computed one.
safecomm_status_t
Result of a Safe Communication Framework operation.
@ SAFECOMM_STATUS_INVALID_PARAM
@ SAFECOMM_STATUS_MAC_MISMATCH
@ SAFECOMM_STATUS_NOT_INITIALISED
Immutable session-key material for one SaF connection.
uint8_t ksmac[SAFECOMM_MAC_KEY_LEN]