Skip to content
This repository was archived by the owner on Dec 26, 2022. It is now read-only.

Commit 63ae5da

Browse files
author
HYChang
committed
feat(endpoint): Add HMAC support for AES encryption
The HMAC is a specific type of message authentication code(MAC) involving a cryptographic hash function and a secret cryptographic key. Same as other MAC, HMAC is used to verify both the data integrity and the authenticity of a message. We used sha256 as default hash function to calculate the HMAC. Two new structure members `hmac` and `timestamp` are added into cipher_ctx. The timestamp used the source from Unix Epoch. The timestamp is one of the source to calculate the HMAC. Close #608
1 parent 1dc5e47 commit 63ae5da

File tree

8 files changed

+158
-59
lines changed

8 files changed

+158
-59
lines changed

endpoint/endpoint.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdio.h>
1111
#include <stdlib.h>
1212
#include <string.h>
13+
#include <time.h>
1314
#include "http_parser.h"
1415
#include "utils/cipher.h"
1516
#include "utils/connectivity/conn_http.h"
@@ -47,14 +48,19 @@ status_t send_transaction_information(int value, const char* message, const char
4748
}
4849

4950
size_t msg_len = 0;
51+
struct timespec t;
52+
clock_gettime(CLOCK_MONOTONIC, &t);
53+
5054
ta_cipher_ctx encrypt_ctx = {.plaintext = raw_msg,
5155
.plaintext_len = ret,
5256
.ciphertext = ciphertext,
5357
.ciphertext_len = MAX_MSG_LEN,
5458
.device_id = device_id,
5559
.iv = {0},
60+
.hmac = {0},
5661
.key = private_key,
57-
.keybits = TA_AES_KEY_BITS};
62+
.keybits = TA_AES_KEY_BITS,
63+
.timestamp = t.tv_sec};
5864
memcpy(encrypt_ctx.iv, iv, AES_IV_SIZE);
5965
ret = aes_encrypt(&encrypt_ctx);
6066
memcpy(iv, encrypt_ctx.iv, AES_IV_SIZE);
@@ -64,7 +70,8 @@ status_t send_transaction_information(int value, const char* message, const char
6470
fprintf(stderr, "%s\n", "encrypt msg error");
6571
return ret;
6672
}
67-
serialize_msg(iv, encrypt_ctx.ciphertext_len, (char*)encrypt_ctx.ciphertext, msg, &msg_len);
73+
serialize_msg(iv, encrypt_ctx.ciphertext_len, (char*)encrypt_ctx.ciphertext, encrypt_ctx.timestamp, encrypt_ctx.hmac,
74+
msg, &msg_len);
6875
bytes_to_trytes((const unsigned char*)msg, msg_len, tryte_msg);
6976

7077
memset(req_body, 0, sizeof(char) * MAX_MSG_LEN);

tests/unit-test/test_cipher.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdio.h>
1111
#include <stdlib.h>
1212
#include <string.h>
13+
#include <time.h>
1314
#include "tests/test_define.h"
1415
#include "utils/cipher.h"
1516

@@ -45,15 +46,19 @@ void tearDown(void) {}
4546
void test_cipher1(void) {
4647
uint8_t ciphertext[MAXLINE] = {0};
4748
uint8_t plaintext[MAXLINE] = {0};
49+
struct timespec t;
50+
clock_gettime(CLOCK_MONOTONIC, &t);
4851

4952
ta_cipher_ctx encrypt_ctx = {.plaintext = (uint8_t*)test_payload1,
5053
.plaintext_len = test_paylen1,
5154
.ciphertext = ciphertext,
5255
.ciphertext_len = MAXLINE,
5356
.device_id = device_id,
5457
.iv = {0},
58+
.hmac = {0},
5559
.key = key,
56-
.keybits = TA_AES_KEY_BITS};
60+
.keybits = TA_AES_KEY_BITS,
61+
.timestamp = t.tv_sec};
5762
// Don't forget to set the initialization vector
5863
memcpy(encrypt_ctx.iv, iv_global, AES_IV_SIZE);
5964
TEST_ASSERT_EQUAL_INT32(SC_OK, aes_encrypt(&encrypt_ctx));
@@ -64,10 +69,14 @@ void test_cipher1(void) {
6469
.ciphertext_len = encrypt_ctx.ciphertext_len,
6570
.device_id = device_id,
6671
.iv = {0},
72+
.hmac = {0},
6773
.key = key,
68-
.keybits = TA_AES_KEY_BITS};
74+
.keybits = TA_AES_KEY_BITS,
75+
.timestamp = encrypt_ctx.timestamp};
6976
// Don't forget to set the initialization vector
7077
memcpy(decrypt_ctx.iv, encrypt_ctx.iv, AES_IV_SIZE);
78+
// Don't forget to set the hmac
79+
memcpy(decrypt_ctx.hmac, encrypt_ctx.hmac, TA_AES_HMAC_SIZE);
7180
TEST_ASSERT_EQUAL_INT32(SC_OK, aes_decrypt(&decrypt_ctx));
7281

7382
TEST_ASSERT_EQUAL_INT(test_paylen1, decrypt_ctx.plaintext_len);
@@ -77,15 +86,18 @@ void test_cipher1(void) {
7786
void test_cipher2(void) {
7887
uint8_t ciphertext[MAXLINE] = {0};
7988
uint8_t plaintext[MAXLINE] = {0};
80-
89+
struct timespec t;
90+
clock_gettime(CLOCK_MONOTONIC, &t);
8191
ta_cipher_ctx encrypt_ctx = {.plaintext = test_payload2,
8292
.plaintext_len = test_paylen2,
8393
.ciphertext = ciphertext,
8494
.ciphertext_len = MAXLINE,
8595
.device_id = device_id,
8696
.iv = {0},
97+
.hmac = {0},
8798
.key = key,
88-
.keybits = TA_AES_KEY_BITS};
99+
.keybits = TA_AES_KEY_BITS,
100+
.timestamp = t.tv_sec};
89101
// Don't forget to set the initialization vector
90102
memcpy(encrypt_ctx.iv, iv_global, AES_IV_SIZE);
91103
TEST_ASSERT_EQUAL_INT32(SC_OK, aes_encrypt(&encrypt_ctx));
@@ -96,10 +108,14 @@ void test_cipher2(void) {
96108
.ciphertext_len = encrypt_ctx.ciphertext_len,
97109
.device_id = device_id,
98110
.iv = {0},
111+
.hmac = {0},
99112
.key = key,
100-
.keybits = TA_AES_KEY_BITS};
113+
.keybits = TA_AES_KEY_BITS,
114+
.timestamp = encrypt_ctx.timestamp};
101115
// Don't forget to set the initialization vector
102116
memcpy(decrypt_ctx.iv, encrypt_ctx.iv, AES_IV_SIZE);
117+
// Don't forget to set the hmac
118+
memcpy(decrypt_ctx.hmac, encrypt_ctx.hmac, TA_AES_HMAC_SIZE);
103119
TEST_ASSERT_EQUAL_INT32(SC_OK, aes_decrypt(&decrypt_ctx));
104120

105121
TEST_ASSERT_EQUAL_UINT(test_paylen2, decrypt_ctx.plaintext_len);

tests/unit-test/test_text_serializer.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,31 @@ const uint8_t payload[] = {
2828
49, 162, 1, 218, 50, 65, 239, 170, 29, 207, 210, 133, 167, 129, 150, 35, 165, 148, 255, 252, 131, 31,
2929
251, 91, 130, 34, 222, 70, 36, 45, 140, 85, 207, 141, 48, 1, 206, 31, 171, 235, 238, 126, 113};
3030
const uint16_t payload_len = 263;
31+
const uint64_t test_timestamp = 1589274915;
32+
const uint8_t test_hmac[TA_AES_HMAC_SIZE] = {37, 39, 48, 30, 53, 63, 45, 61, 87, 60, 60, 90, 63, 63, 13, 94,
33+
53, 93, 52, 7, 19, 38, 15, 31, 29, 32, 97, 2, 47, 67, 59, 62};
3134

3235
void setUp(void) {}
3336

3437
void tearDown(void) {}
3538

3639
void test_serialize_deserialize(void) {
3740
uint8_t out[1024], iv_out[AES_BLOCK_SIZE], payload_out[1024];
38-
3941
size_t payload_len_out, out_msg_len;
40-
int rc1 = serialize_msg(iv, payload_len, (char*)payload, (char*)out, &out_msg_len);
41-
TEST_ASSERT(rc1 == SC_OK);
42-
int rc2 = deserialize_msg((char*)out, iv_out, &payload_len_out, (char*)payload_out);
43-
TEST_ASSERT(rc2 == SC_OK);
42+
uint64_t timestamp;
43+
uint8_t hmac[TA_AES_HMAC_SIZE];
44+
45+
int rc1 = serialize_msg(iv, payload_len, (char*)payload, test_timestamp, test_hmac, (char*)out, &out_msg_len);
46+
TEST_ASSERT_EQUAL_INT32(SC_OK, rc1);
47+
int rc2 = deserialize_msg((char*)out, iv_out, &payload_len_out, (char*)payload_out, &timestamp, hmac);
48+
TEST_ASSERT_EQUAL_INT32(SC_OK, rc2);
4449

4550
out[1023] = 0;
4651
payload_out[payload_len] = 0;
47-
4852
TEST_ASSERT_EQUAL_UINT8_ARRAY(iv, iv_out, AES_BLOCK_SIZE);
49-
53+
TEST_ASSERT_EQUAL_UINT64(test_timestamp, timestamp);
54+
TEST_ASSERT_EQUAL_UINT8_ARRAY(test_hmac, hmac, TA_AES_HMAC_SIZE);
5055
TEST_ASSERT_EQUAL_UINT32(payload_len, payload_len_out);
51-
5256
TEST_ASSERT_EQUAL_UINT8_ARRAY(payload, payload_out, payload_len);
5357
}
5458

utils/BUILD

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ cc_library(
6868
name = "text_serializer",
6969
srcs = ["text_serializer.c"],
7070
hdrs = ["text_serializer.h"],
71-
deps = ["//common:ta_errors"],
71+
deps = [
72+
":cipher",
73+
"//common:ta_errors",
74+
],
7275
)
7376

7477
cc_library(

utils/cipher.c

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,42 @@
2020
status_t aes_decrypt(ta_cipher_ctx* cipher_ctx) {
2121
// FIXME: Add logger and some checks here
2222
mbedtls_aes_context ctx;
23+
mbedtls_md_context_t sha_ctx;
2324
int status;
24-
char* err;
25+
char* err = NULL;
2526
uint8_t buf[AES_BLOCK_SIZE];
26-
27+
uint8_t digest[AES_BLOCK_SIZE * 2];
28+
uint8_t nonce[IMSI_LEN + MAX_TIMESTAMP_LEN + 1] = {0};
2729
/* Create and initialise the context */
2830
mbedtls_aes_init(&ctx);
31+
mbedtls_md_init(&sha_ctx);
32+
if (mbedtls_md_setup(&sha_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) != 0) {
33+
err = "Failed to set up message-digest information";
34+
status = SC_UTILS_CIPHER_ERROR;
35+
goto exit;
36+
}
2937
mbedtls_platform_zeroize(cipher_ctx->plaintext, sizeof(cipher_ctx->plaintext));
3038
mbedtls_platform_zeroize(buf, AES_BLOCK_SIZE);
39+
mbedtls_platform_zeroize(digest, AES_BLOCK_SIZE * 2);
3140

3241
/* set decryption key */
3342
if ((status = mbedtls_aes_setkey_dec(&ctx, cipher_ctx->key, TA_AES_KEY_BITS)) != EXIT_SUCCESS) {
34-
err = "set aes key failed";
43+
err = "Failed to set AES key";
44+
status = SC_UTILS_CIPHER_ERROR;
3545
goto exit;
3646
}
3747

48+
// concatenate (Device_ID, timestamp)
49+
snprintf((char*)nonce, IMSI_LEN + MAX_TIMESTAMP_LEN + 1, "%s-%ld", cipher_ctx->device_id, cipher_ctx->timestamp);
50+
// hash base data
51+
mbedtls_md_starts(&sha_ctx);
52+
mbedtls_md_update(&sha_ctx, digest, AES_BLOCK_SIZE * 2);
53+
mbedtls_md_update(&sha_ctx, nonce, IMSI_LEN + MAX_TIMESTAMP_LEN);
54+
mbedtls_md_update(&sha_ctx, cipher_ctx->key, TA_AES_KEY_BITS / 8);
55+
mbedtls_md_finish(&sha_ctx, digest);
56+
57+
mbedtls_md_hmac_starts(&sha_ctx, digest, TA_AES_HMAC_SIZE);
58+
3859
// Provide the message to be decrypted, and obtain the plaintext output.
3960
const size_t ciphertext_len = cipher_ctx->ciphertext_len;
4061
uint8_t* ciphertext = cipher_ctx->ciphertext;
@@ -43,21 +64,30 @@ status_t aes_decrypt(ta_cipher_ctx* cipher_ctx) {
4364
memset(buf, 0, AES_BLOCK_SIZE);
4465
int n = (ciphertext_len - i > AES_BLOCK_SIZE) ? AES_BLOCK_SIZE : (int)(ciphertext_len - i);
4566
memcpy(buf, ciphertext + i, n);
67+
mbedtls_md_hmac_update(&sha_ctx, buf, AES_BLOCK_SIZE);
4668
if ((status = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, AES_BLOCK_SIZE, cipher_ctx->iv, buf, buf)) != 0) {
47-
err = "aes decrpyt failed";
69+
err = "Failed to decrypt AES message";
70+
status = SC_UTILS_CIPHER_ERROR;
4871
goto exit;
4972
}
5073
memcpy(plaintext, buf, AES_BLOCK_SIZE);
5174
plaintext += AES_BLOCK_SIZE;
5275
}
5376

54-
/* Clean up */
55-
mbedtls_aes_free(&ctx);
56-
return SC_OK;
77+
// compare hmac
78+
mbedtls_md_hmac_finish(&sha_ctx, digest);
79+
if (memcmp(digest, cipher_ctx->hmac, TA_AES_HMAC_SIZE) != 0) {
80+
err = "Failed to validate HMAC";
81+
status = SC_UTILS_CIPHER_ERROR;
82+
goto exit;
83+
}
84+
status = SC_OK;
5785
exit:
58-
fprintf(stderr, "%s\n", err);
86+
// FIXME: Use default logger instead
87+
if (!err) fprintf(stderr, "%s\n", err);
5988
mbedtls_aes_free(&ctx);
60-
return SC_UTILS_CIPHER_ERROR;
89+
mbedtls_md_free(&sha_ctx);
90+
return status;
6191
}
6292

6393
status_t aes_encrypt(ta_cipher_ctx* cipher_ctx) {
@@ -79,29 +109,29 @@ status_t aes_encrypt(ta_cipher_ctx* cipher_ctx) {
79109
mbedtls_md_init(&sha_ctx);
80110
mbedtls_aes_init(&ctx);
81111
if (mbedtls_md_setup(&sha_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) != 0) {
82-
err = "mbedtls_md_setup error";
112+
err = "Failed to set up message-digest information";
83113
goto exit;
84114
}
85115

86116
// Check ciphertext has enough space
87117
size_t new_len = plaintext_len + (AES_BLOCK_SIZE - plaintext_len % 16);
88118
if (new_len > ciphertext_len) {
89-
err = "ciphertext has not enough space";
119+
err = "Failed to get enough space inside ciphertext buffer";
120+
status = SC_UTILS_CIPHER_ERROR;
90121
goto exit;
91122
}
92123
cipher_ctx->ciphertext_len = new_len;
93124
mbedtls_platform_zeroize(tmp, sizeof(tmp));
94125
mbedtls_platform_zeroize(digest, sizeof(digest));
95126
mbedtls_platform_zeroize(ciphertext, sizeof(ciphertext));
96127

97-
// fetch timestamp
98-
uint64_t timestamp = time(NULL);
99128
// concatenate (Device_ID, timestamp)
100-
snprintf((char*)nonce, IMSI_LEN + MAX_TIMESTAMP_LEN + 1, "%s-%ld", cipher_ctx->device_id, timestamp);
129+
snprintf((char*)nonce, IMSI_LEN + MAX_TIMESTAMP_LEN + 1, "%s-%ld", cipher_ctx->device_id, cipher_ctx->timestamp);
101130
// hash base data
102131
mbedtls_md_starts(&sha_ctx);
103132
mbedtls_md_update(&sha_ctx, digest, AES_BLOCK_SIZE * 2);
104133
mbedtls_md_update(&sha_ctx, nonce, IMSI_LEN + MAX_TIMESTAMP_LEN);
134+
mbedtls_md_update(&sha_ctx, cipher_ctx->key, TA_AES_KEY_BITS / 8);
105135
mbedtls_md_finish(&sha_ctx, digest);
106136

107137
for (int i = 0; i < AES_BLOCK_SIZE; ++i) {
@@ -111,7 +141,14 @@ status_t aes_encrypt(ta_cipher_ctx* cipher_ctx) {
111141

112142
/* set encryption key */
113143
if ((status = mbedtls_aes_setkey_enc(&ctx, cipher_ctx->key, TA_AES_KEY_BITS)) != 0) {
114-
err = "set aes key failed";
144+
err = "Failed to set AES key";
145+
status = SC_UTILS_CIPHER_ERROR;
146+
goto exit;
147+
}
148+
149+
if ((status = mbedtls_md_hmac_starts(&sha_ctx, digest, TA_AES_HMAC_SIZE)) != 0) {
150+
err = "Failed to initialize HMAC context";
151+
status = SC_UTILS_CIPHER_ERROR;
115152
goto exit;
116153
}
117154

@@ -121,19 +158,22 @@ status_t aes_encrypt(ta_cipher_ctx* cipher_ctx) {
121158
int n = (plaintext_len - i > AES_BLOCK_SIZE) ? AES_BLOCK_SIZE : (int)(plaintext_len - i);
122159
memcpy(buf, plaintext + i, n);
123160
if ((status = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, AES_BLOCK_SIZE, tmp, buf, buf)) != 0) {
124-
err = "aes decrpyt failed";
161+
err = "Failed to encrypt AES message";
162+
status = SC_UTILS_CIPHER_ERROR;
125163
goto exit;
126164
}
165+
mbedtls_md_hmac_update(&sha_ctx, buf, AES_BLOCK_SIZE);
127166
memcpy(ciphertext, buf, AES_BLOCK_SIZE);
128167
ciphertext += AES_BLOCK_SIZE;
129168
}
130169

131-
mbedtls_aes_free(&ctx);
132-
mbedtls_md_free(&sha_ctx);
133-
return SC_OK;
170+
mbedtls_md_hmac_finish(&sha_ctx, digest);
171+
memcpy(cipher_ctx->hmac, digest, TA_AES_HMAC_SIZE);
172+
status = SC_OK;
134173
exit:
135-
fprintf(stderr, "%s", err);
174+
// FIXME: Use default logger instead
175+
if (!err) fprintf(stderr, "%s\n", err);
136176
mbedtls_aes_free(&ctx);
137177
mbedtls_md_free(&sha_ctx);
138-
return SC_UTILS_CIPHER_ERROR;
178+
return status;
139179
}

utils/cipher.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,20 @@ extern "C" {
2222
#define AES_IV_SIZE AES_BLOCK_SIZE
2323
#define IMSI_LEN 16
2424
#define TA_AES_KEY_BITS 256
25+
#define TA_AES_HMAC_SIZE AES_BLOCK_SIZE * 2
2526

2627
/** context of aes cipher */
2728
typedef struct ta_cipher_ctx {
28-
uint8_t* plaintext; /**< Plaintext */
29-
size_t plaintext_len; /**< Plaintext length */
30-
uint8_t* ciphertext; /**< Ciphrtext */
31-
size_t ciphertext_len; /**< Ciphertext length */
32-
uint8_t iv[AES_IV_SIZE]; /**< Initialization vector, mbedtls_aes needs r/w iv[] */
33-
const uint8_t* key; /**< Encryption key */
34-
const size_t keybits; /**< Bits of key, valid options are 128,192,256 bits */
35-
const char* device_id; /**< Device id */
29+
uint8_t* plaintext; /**< Plaintext */
30+
size_t plaintext_len; /**< Plaintext length */
31+
uint8_t* ciphertext; /**< Ciphrtext */
32+
size_t ciphertext_len; /**< Ciphertext length */
33+
uint8_t iv[AES_IV_SIZE]; /**< Initialization vector, mbedtls_aes needs r/w iv[] */
34+
const uint8_t* key; /**< Encryption key */
35+
const size_t keybits; /**< Bits of key, valid options are 128,192,256 bits */
36+
const char* device_id; /**< Device id */
37+
uint8_t hmac[TA_AES_HMAC_SIZE]; /**< r/w buffer for hash-based message authentication code */
38+
uint64_t timestamp; /**< Timestamp for generate hmac */
3639
} ta_cipher_ctx;
3740

3841
/**

0 commit comments

Comments
 (0)