1 #include "test_common.h"
2
3 #include <CommonCrypto/CommonDigest.h>
4 #include <CommonCrypto/CommonHMAC.h>
5 #include <CommonCrypto/CommonCryptor.h>
6
7 #include <stdio.h>
8
test_random_generator(uint8_t * data,size_t len,void * user_data)9 int test_random_generator(uint8_t *data, size_t len, void *user_data)
10 {
11 arc4random_buf(data, len);
12 return 0;
13
14 #if 0
15 /*
16 * Apple's documentation recommends this method for generating secure
17 * random numbers. However, it is too slow for the purpose of unit tests.
18 */
19 int result = 0;
20
21 FILE *fp = fopen("/dev/random", "r");
22 if(!fp) {
23 result = SG_ERR_UNKNOWN;
24 goto complete;
25 }
26
27 size_t n = fread(data, 1, len, fp);
28 if(n != len) {
29 result = SG_ERR_UNKNOWN;
30 goto complete;
31 }
32
33 complete:
34 if(fp) {
35 fclose(fp);
36 }
37 return result;
38 #endif
39 }
40
test_hmac_sha256_init(void ** hmac_context,const uint8_t * key,size_t key_len,void * user_data)41 int test_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data)
42 {
43 CCHmacContext *ctx = malloc(sizeof(CCHmacContext));
44 if(!ctx) {
45 return SG_ERR_NOMEM;
46 }
47
48 CCHmacInit(ctx, kCCHmacAlgSHA256, key, key_len);
49 *hmac_context = ctx;
50
51 return 0;
52 }
53
test_hmac_sha256_update(void * hmac_context,const uint8_t * data,size_t data_len,void * user_data)54 int test_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data)
55 {
56 CCHmacContext *ctx = hmac_context;
57 CCHmacUpdate(ctx, data, data_len);
58 return 0;
59 }
60
test_hmac_sha256_final(void * hmac_context,signal_buffer ** output,void * user_data)61 int test_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data)
62 {
63 CCHmacContext *ctx = hmac_context;
64
65 signal_buffer *output_buffer = signal_buffer_alloc(CC_SHA256_DIGEST_LENGTH);
66 if(!output_buffer) {
67 return SG_ERR_NOMEM;
68 }
69
70 CCHmacFinal(ctx, signal_buffer_data(output_buffer));
71
72 *output = output_buffer;
73
74 return 0;
75 }
76
test_hmac_sha256_cleanup(void * hmac_context,void * user_data)77 void test_hmac_sha256_cleanup(void *hmac_context, void *user_data)
78 {
79 if(hmac_context) {
80 CCHmacContext *ctx = hmac_context;
81 free(ctx);
82 }
83 }
84
test_sha512_digest_init(void ** digest_context,void * user_data)85 int test_sha512_digest_init(void **digest_context, void *user_data)
86 {
87 int result = 0;
88
89 CC_SHA512_CTX *ctx = malloc(sizeof(CC_SHA512_CTX));
90 if(!ctx) {
91 result = SG_ERR_NOMEM;
92 goto complete;
93 }
94
95 result = CC_SHA512_Init(ctx);
96 if(result != 1) {
97 result = SG_ERR_UNKNOWN;
98 goto complete;
99 }
100
101 complete:
102 if(result < 0) {
103 if(ctx) {
104 free(ctx);
105 }
106 }
107 else {
108 *digest_context = ctx;
109 }
110 return result;
111 }
112
test_sha512_digest_update(void * digest_context,const uint8_t * data,size_t data_len,void * user_data)113 int test_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data)
114 {
115 CC_SHA512_CTX *ctx = digest_context;
116
117 int result = CC_SHA512_Update(ctx, data, data_len);
118
119 return (result == 1) ? SG_SUCCESS : SG_ERR_UNKNOWN;
120 }
121
test_sha512_digest_final(void * digest_context,signal_buffer ** output,void * user_data)122 int test_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data)
123 {
124 int result = 0;
125 unsigned char md[CC_SHA512_DIGEST_LENGTH];
126 CC_SHA512_CTX *ctx = digest_context;
127
128 result = CC_SHA512_Final(md, ctx);
129 if(result == 1) {
130 result = SG_SUCCESS;
131 }
132 else {
133 result = SG_ERR_UNKNOWN;
134 goto complete;
135 }
136
137 result = CC_SHA512_Init(ctx);
138 if(result == 1) {
139 result = SG_SUCCESS;
140 }
141 else {
142 result = SG_ERR_UNKNOWN;
143 goto complete;
144 }
145
146 signal_buffer *output_buffer = signal_buffer_create(md, CC_SHA512_DIGEST_LENGTH);
147 if(!output_buffer) {
148 result = SG_ERR_NOMEM;
149 goto complete;
150 }
151
152 *output = output_buffer;
153
154 complete:
155 return result;
156 }
157
test_sha512_digest_cleanup(void * digest_context,void * user_data)158 void test_sha512_digest_cleanup(void *digest_context, void *user_data)
159 {
160 if(digest_context) {
161 CC_SHA512_CTX *ctx = digest_context;
162 free(ctx);
163 }
164 }
165
cc_status_to_result(CCCryptorStatus status)166 int cc_status_to_result(CCCryptorStatus status)
167 {
168 switch(status) {
169 case kCCSuccess:
170 return SG_SUCCESS;
171 case kCCParamError:
172 case kCCBufferTooSmall:
173 return SG_ERR_INVAL;
174 case kCCMemoryFailure:
175 return SG_ERR_NOMEM;
176 case kCCAlignmentError:
177 case kCCDecodeError:
178 case kCCUnimplemented:
179 case kCCOverflow:
180 case kCCRNGFailure:
181 case kCCUnspecifiedError:
182 case kCCCallSequenceError:
183 default:
184 return SG_ERR_UNKNOWN;
185 }
186 }
187
test_encrypt(signal_buffer ** output,int cipher,const uint8_t * key,size_t key_len,const uint8_t * iv,size_t iv_len,const uint8_t * plaintext,size_t plaintext_len,void * user_data)188 int test_encrypt(signal_buffer **output,
189 int cipher,
190 const uint8_t *key, size_t key_len,
191 const uint8_t *iv, size_t iv_len,
192 const uint8_t *plaintext, size_t plaintext_len,
193 void *user_data)
194 {
195 int result = 0;
196 uint8_t *out_buf = 0;
197 CCCryptorStatus status = kCCSuccess;
198 CCCryptorRef ref = 0;
199
200 if(cipher == SG_CIPHER_AES_CBC_PKCS5) {
201 status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key, key_len, iv, &ref);
202 }
203 else if(cipher == SG_CIPHER_AES_CTR_NOPADDING) {
204 status = CCCryptorCreateWithMode(kCCEncrypt, kCCModeCTR, kCCAlgorithmAES, ccNoPadding,
205 iv, key, key_len, 0, 0, 0, kCCModeOptionCTR_BE, &ref);
206 }
207 else {
208 status = kCCParamError;
209 }
210 if(status != kCCSuccess) {
211 result = cc_status_to_result(status);
212 goto complete;
213 }
214
215 size_t available_len = CCCryptorGetOutputLength(ref, plaintext_len, 1);
216 out_buf = malloc(available_len);
217 if(!out_buf) {
218 fprintf(stderr, "cannot allocate output buffer\n");
219 result = SG_ERR_NOMEM;
220 goto complete;
221 }
222
223 size_t update_moved_len = 0;
224 status = CCCryptorUpdate(ref, plaintext, plaintext_len, out_buf, available_len, &update_moved_len);
225 if(status != kCCSuccess) {
226 result = cc_status_to_result(status);
227 goto complete;
228 }
229
230 size_t final_moved_len = 0;
231 status = CCCryptorFinal(ref, out_buf + update_moved_len, available_len - update_moved_len, &final_moved_len);
232 if(status != kCCSuccess) {
233 result = cc_status_to_result(status);
234 goto complete;
235 }
236
237 signal_buffer *output_buffer = signal_buffer_create(out_buf, update_moved_len + final_moved_len);
238 if(!output_buffer) {
239 result = SG_ERR_NOMEM;
240 goto complete;
241 }
242
243 *output = output_buffer;
244
245 complete:
246 if(ref) {
247 CCCryptorRelease(ref);
248 }
249 if(out_buf) {
250 free(out_buf);
251 }
252 return result;
253 }
254
test_decrypt(signal_buffer ** output,int cipher,const uint8_t * key,size_t key_len,const uint8_t * iv,size_t iv_len,const uint8_t * ciphertext,size_t ciphertext_len,void * user_data)255 int test_decrypt(signal_buffer **output,
256 int cipher,
257 const uint8_t *key, size_t key_len,
258 const uint8_t *iv, size_t iv_len,
259 const uint8_t *ciphertext, size_t ciphertext_len,
260 void *user_data)
261 {
262 int result = 0;
263 uint8_t *out_buf = 0;
264 CCCryptorStatus status = kCCSuccess;
265 CCCryptorRef ref = 0;
266
267 if(cipher == SG_CIPHER_AES_CBC_PKCS5) {
268 status = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key, key_len, iv, &ref);
269 }
270 else if(cipher == SG_CIPHER_AES_CTR_NOPADDING) {
271 status = CCCryptorCreateWithMode(kCCDecrypt, kCCModeCTR, kCCAlgorithmAES, ccNoPadding,
272 iv, key, key_len, 0, 0, 0, kCCModeOptionCTR_BE, &ref);
273 }
274 else {
275 status = kCCParamError;
276 }
277 if(status != kCCSuccess) {
278 result = cc_status_to_result(status);
279 goto complete;
280 }
281
282 out_buf = malloc(sizeof(uint8_t) * ciphertext_len);
283 if(!out_buf) {
284 fprintf(stderr, "cannot allocate output buffer\n");
285 result = SG_ERR_UNKNOWN;
286 goto complete;
287 }
288
289 size_t update_moved_len = 0;
290 status = CCCryptorUpdate(ref, ciphertext, ciphertext_len, out_buf, ciphertext_len, &update_moved_len);
291 if(status != kCCSuccess) {
292 result = cc_status_to_result(status);
293 goto complete;
294 }
295
296 size_t final_moved_len = 0;
297 status = CCCryptorFinal(ref, out_buf + update_moved_len, ciphertext_len - update_moved_len, &final_moved_len);
298 if(status != kCCSuccess) {
299 result = cc_status_to_result(status);
300 goto complete;
301 }
302
303 signal_buffer *output_buffer = signal_buffer_create(out_buf, update_moved_len + final_moved_len);
304 if(!output_buffer) {
305 result = SG_ERR_NOMEM;
306 goto complete;
307 }
308
309 *output = output_buffer;
310
311 complete:
312 if(ref) {
313 CCCryptorRelease(ref);
314 }
315 if(out_buf) {
316 free(out_buf);
317 }
318 return result;
319 }
320