Skip to content

Commit 297ac66

Browse files
committed
SC: Compute MAC progressively block by block
osdp_compute_mac copies the entire packet buffer into stack to perform the MAC computation. This implementaion is from LibOSDP's initial days. Since then it has not been touched and is not an optimal way to compute the MAC. With the memory optimization pass, this got flagged up as a serious stack user. So this patch rewrites the method to compute the MAC progressively block-by-block. Since we have a proper unit-test suite to excericise this path, we can be fairly certain that this code does what it should. Related-to: #281 Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
1 parent e3e0236 commit 297ac66

1 file changed

Lines changed: 35 additions & 15 deletions

File tree

src/osdp_sc.c

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,11 @@ int osdp_encrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int length)
185185
int osdp_compute_mac(struct osdp_pd *pd, int is_cmd,
186186
const uint8_t *data, int len)
187187
{
188-
int pad_len;
189-
uint8_t buf[OSDP_PACKET_BUF_SIZE] = { 0 };
188+
int i, j, n, full_blocks, rem;
189+
const uint8_t *p;
190+
uint8_t block[16] = { 0 };
190191
uint8_t iv[16];
191192

192-
memcpy(buf, data, len);
193-
pad_len = (len % 16 == 0) ? len : AES_PAD_LEN(len);
194-
if (len % 16 != 0) {
195-
buf[len] = 0x80; /* end marker */
196-
}
197193
/**
198194
* MAC for data blocks B[1] .. B[N] (post padding) is computed as:
199195
* IV1 = R_MAC (or) C_MAC -- depending on is_cmd
@@ -202,16 +198,40 @@ int osdp_compute_mac(struct osdp_pd *pd, int is_cmd,
202198
*/
203199

204200
memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16);
205-
if (pad_len > 16) {
206-
/* N-1 blocks -- encrypted with SMAC-1 */
207-
osdp_encrypt(pd->sc.s_mac1, iv, buf, pad_len - 16);
208-
/* N-1 th block is the IV for N th block */
209-
memcpy(iv, buf + pad_len - 32, 16);
201+
p = data;
202+
full_blocks = len / 16;
203+
rem = len % 16;
204+
n = (rem == 0) ? full_blocks : (full_blocks + 1);
205+
if (n == 0) {
206+
/* Empty message still contributes a padded terminal block. */
207+
n = 1;
208+
}
209+
210+
/* Process B[1]..B[N-1] with SMAC-1 in CBC fashion. */
211+
for (i = 0; i < n - 1; i++, p += 16) {
212+
memcpy(block, p, 16);
213+
for (j = 0; j < 16; j++) {
214+
block[j] ^= iv[j];
215+
}
216+
osdp_encrypt(pd->sc.s_mac1, NULL, block, 16);
217+
memcpy(iv, block, 16);
218+
}
219+
220+
/* Build B[N], using 0x80 + zero padding when len is not block aligned. */
221+
memset(block, 0, sizeof(block));
222+
if (rem == 0 && full_blocks > 0) {
223+
memcpy(block, p, 16);
224+
} else {
225+
memcpy(block, p, rem);
226+
block[rem] = 0x80; /* end marker */
227+
}
228+
for (i = 0; i < 16; i++) {
229+
block[i] ^= iv[i];
210230
}
211231

212-
/* N-th Block encrypted with SMAC-2 == MAC */
213-
osdp_encrypt(pd->sc.s_mac2, iv, buf + pad_len - 16, 16);
214-
memcpy(is_cmd ? pd->sc.c_mac : pd->sc.r_mac, buf + pad_len - 16, 16);
232+
/* B[N] encrypted with SMAC-2 == MAC */
233+
osdp_encrypt(pd->sc.s_mac2, NULL, block, 16);
234+
memcpy(is_cmd ? pd->sc.c_mac : pd->sc.r_mac, block, 16);
215235

216236
return 0;
217237
}

0 commit comments

Comments
 (0)