-
Notifications
You must be signed in to change notification settings - Fork 156
/
aes.c
175 lines (142 loc) · 5.67 KB
/
aes.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "aes.h"
#include "types.h"
#include "utils.h"
/* Allocate a new context. */
aes_ctx_t *new_aes_ctx(const void *key, unsigned int key_size, aes_mode_t mode) {
aes_ctx_t *ctx;
if ((ctx = malloc(sizeof(*ctx))) == NULL) {
FATAL_ERROR("Failed to allocate aes_ctx_t!");
}
mbedtls_cipher_init(&ctx->cipher_dec);
mbedtls_cipher_init(&ctx->cipher_enc);
if (mbedtls_cipher_setup(&ctx->cipher_dec, mbedtls_cipher_info_from_type(mode))
|| mbedtls_cipher_setup(&ctx->cipher_enc, mbedtls_cipher_info_from_type(mode))) {
FATAL_ERROR("Failed to set up AES context!");
}
if (mbedtls_cipher_setkey(&ctx->cipher_dec, key, key_size * 8, AES_DECRYPT)
|| mbedtls_cipher_setkey(&ctx->cipher_enc, key, key_size * 8, AES_ENCRYPT)) {
FATAL_ERROR("Failed to set key for AES context!");
}
return ctx;
}
/* Free an allocated context. */
void free_aes_ctx(aes_ctx_t *ctx) {
/* Explicitly allow NULL. */
if (ctx == NULL) {
return;
}
mbedtls_cipher_free(&ctx->cipher_dec);
mbedtls_cipher_free(&ctx->cipher_enc);
free(ctx);
}
/* Set AES CTR or IV for a context. */
void aes_setiv(aes_ctx_t *ctx, const void *iv, size_t l) {
if (mbedtls_cipher_set_iv(&ctx->cipher_dec, iv, l)
|| mbedtls_cipher_set_iv(&ctx->cipher_enc, iv, l)) {
FATAL_ERROR("Failed to set IV for AES context!");
}
}
/* Calculate CMAC. */
void aes_calculate_cmac(void *dst, void *src, size_t size, const void *key) {
mbedtls_cipher_context_t m_ctx;
mbedtls_cipher_init(&m_ctx);
if (mbedtls_cipher_setup(&m_ctx, mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB))
|| mbedtls_cipher_cmac_starts(&m_ctx, key, 0x80)
|| mbedtls_cipher_cmac_update(&m_ctx, src, size)
|| mbedtls_cipher_cmac_finish(&m_ctx, dst)) {
FATAL_ERROR("Failed to calculate CMAC!");
}
}
/* Encrypt with context. */
void aes_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) {
size_t out_len = 0;
/* Prepare context */
mbedtls_cipher_reset(&ctx->cipher_enc);
/* XTS doesn't need per-block updating */
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_XTS || mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_CBC)
mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
else
{
unsigned int blk_size = mbedtls_cipher_get_block_size(&ctx->cipher_enc);
/* Do per-block updating */
for (int offset = 0; (unsigned int)offset < l; offset += blk_size)
{
int len = ((unsigned int)(l - offset) > blk_size) ? blk_size : (unsigned int) (l - offset);
mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src + offset, len, (unsigned char *)dst + offset, &out_len);
}
}
/* Flush all data */
mbedtls_cipher_finish(&ctx->cipher_enc, NULL, NULL);
}
/* Decrypt with context. */
void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l)
{
bool src_equals_dst = false;
if (src == dst)
{
src_equals_dst = true;
dst = malloc(l);
if (dst == NULL) {
fprintf(stderr, "Error: AES buffer allocation failure!\n");
exit(EXIT_FAILURE);
}
}
size_t out_len = 0;
/* Prepare context */
mbedtls_cipher_reset(&ctx->cipher_dec);
/* XTS doesn't need per-block updating */
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_dec) == MBEDTLS_MODE_XTS || mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_CBC)
mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
else
{
unsigned int blk_size = mbedtls_cipher_get_block_size(&ctx->cipher_dec);
/* Do per-block updating */
for (int offset = 0; (unsigned int)offset < l; offset += blk_size)
{
int len = ((unsigned int)(l - offset) > blk_size) ? blk_size : (unsigned int) (l - offset);
mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src + offset, len, (unsigned char *)dst + offset, &out_len);
}
}
/* Flush all data */
mbedtls_cipher_finish(&ctx->cipher_dec, NULL, NULL);
if (src_equals_dst)
{
memcpy((void*)src, dst, l);
free(dst);
}
}
static void get_tweak(unsigned char *tweak, size_t sector) {
for (int i = 0xF; i >= 0; i--) { /* Nintendo LE custom tweak... */
tweak[i] = (unsigned char)(sector & 0xFF);
sector >>= 8;
}
}
/* Encrypt with context for XTS. */
void aes_xts_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l, size_t sector, size_t sector_size) {
unsigned char tweak[0x10];
if (l % sector_size != 0) {
FATAL_ERROR("Length must be multiple of sectors!");
}
for (size_t i = 0; i < l; i += sector_size) {
/* Workaround for Nintendo's custom sector...manually generate the tweak. */
get_tweak(tweak, sector++);
aes_setiv(ctx, tweak, 16);
aes_encrypt(ctx, (char *)dst + i, (const char *)src + i, sector_size);
}
}
/* Decrypt with context for XTS. */
void aes_xts_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l, size_t sector, size_t sector_size) {
unsigned char tweak[0x10];
if (l % sector_size != 0) {
FATAL_ERROR("Length must be multiple of sectors!");
}
for (size_t i = 0; i < l; i += sector_size) {
/* Workaround for Nintendo's custom sector...manually generate the tweak. */
get_tweak(tweak, sector++);
aes_setiv(ctx, tweak, 16);
aes_decrypt(ctx, (char *)dst + i, (const char *)src + i, sector_size);
}
}