RDK Documentation (Open Sourced RDK Components)
ecdh.c
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/pem.h>
23 
24 #include <string.h>
25 #include <errno.h>
26 #include <string.h>
27 
28 #include <cJSON.h>
29 #include "btrMgr_logger.h"
30 #include "ecdh.h"
31 
32 #define _DEBUG_CRYPTO_ 1
33 
34 
35 typedef unsigned char byte_t;
36 
37 
38 typedef struct
39 {
40  byte_t* data;
41  int length;
42 } byteArray_t;
43 
44 void
45 baInit(
46  byteArray_t* v,
47  int length);
48 
49 void
50 baClear(
51  byteArray_t* v);
52 
53 #if _DEBUG_CRYPTO_
54 void
55 baPrint(
56  byteArray_t const* v,
57  char const* name);
58 #endif
59 
60 char*
61 baToString(
62  byteArray_t const* v);
63 
64 int
65 baFromBase64(
66  byteArray_t* decoded_data,
67  char const* encoded_data);
68 
69 int
70 ECDH_SharedKeyDerive(
71  EVP_PKEY* private_key,
72  EVP_PKEY* peer_key,
73  byteArray_t* secret_key);
74 
75 int
76 AESDecrypt(
77  byteArray_t const* key,
78  byteArray_t const* iv,
79  byteArray_t const* encrypted_data,
80  byteArray_t* plain_data);
81 
82 EVP_PKEY*
83 ECC_ReadPrivateKeyFromFile(
84  char const* fname);
85 
86 EVP_PKEY*
87 ECC_ReadPublicKeyFromPEM(
88  char const* pem_data);
89 
90 EVP_PKEY*
91 ECC_ReadPublicKeyFromFile(
92  char const* fname);
93 
94 int
95 ECDH_Decrypt(
96  char const* private_key_path,
97  char const* peer_public_key,
98  char const* iv,
99  char const* cipher_text,
100  char** clear_text,
101  int* clear_text_length);
102 
103 static char const*
104 CRYPTO_Error();
105 
106 #if 0
107 int main(int argc, char* argv[])
108 {
109  FILE* fin;
110  cJSON* reply;
111  cJSON* wifi_settings;
112  byteArray_t buff;
113 
114  fin = NULL;
115  reply = NULL;
116  wifi_settings = NULL;
117  baInit(&buff, 2048);
118 
119  // do this on startup
120  ERR_load_crypto_strings();
121 
122  fin = fopen(argv[1], "r");
123  fread(buff.data, 1, buff.length, fin);
124  fclose(fin);
125 
126  reply = cJSON_Parse((char const *)buff.data);
127  ECDH_DecryptWiFiSettings(reply, &wifi_settings);
128 
129  if (wifi_settings)
130  {
131  char* s = cJSON_Print(wifi_settings);
132  printf("%s\n", s);
133  free(s);
134  cJSON_Delete(wifi_settings);
135  }
136 
137  baClear(&buff);
138  cJSON_Delete(reply);
139  return 0;
140 }
141 #endif
142 
143 int
144 ECDH_Decrypt(
145  char const* private_key_path,
146  char const* peer_public_key,
147  char const* iv,
148  char const* cipher_text,
149  char** clear_text,
150  int* clear_text_length)
151 {
152  int ret;
153  char* p;
154 
155  EVP_PKEY* private_key;
156  EVP_PKEY* peer_key;
157 
158  byteArray_t shared_secret;
159  byteArray_t encdata;
160  byteArray_t ivector;
161  byteArray_t encrypted;
162  byteArray_t decrypted;
163 
164  ret = 0;
165  p = NULL;
166  private_key = NULL;
167  peer_key = NULL;
168 
169  baInit(&shared_secret, 0);
170  baInit(&encdata, 0);
171  baInit(&decrypted, 0);
172 
173  baFromBase64(&ivector, iv);
174  baFromBase64(&encrypted, cipher_text);
175 
176  // read my private key
177  private_key = ECC_ReadPrivateKeyFromFile(private_key_path);
178  if (!private_key)
179  {
180  BTRMGRLOG_ERROR("failed to read private key from '%s'\n", private_key_path);
181  ret = 0;
182  goto error;
183  }
184 
185  // parse peer's public key
186  peer_key = ECC_ReadPublicKeyFromPEM(peer_public_key);
187  if (!peer_key)
188  {
189  BTRMGRLOG_ERROR("failed to read public key from pem data\n");
190  BTRMGRLOG_INFO(" --------- PEER PUBLIC KEY -----------\n%s\n",
191  peer_public_key);
192  ret = 0;
193  goto error;
194  }
195 
196  // create shared/derived key
197  ret = ECDH_SharedKeyDerive(private_key, peer_key, &shared_secret);
198  if (!ret)
199  {
200  BTRMGRLOG_ERROR("failed to derive shared key\n");
201  goto error;
202  }
203 
204  // use shared/derived key to decrypt payload
205  ret = AESDecrypt(&shared_secret, &ivector, &encrypted, &decrypted);
206  if (!ret)
207  {
208  BTRMGRLOG_ERROR("failed to decrypt data\n");
209  goto error;
210  }
211 
212  // copy payload to output parameters
213  p = (char *) malloc(sizeof(byte_t) * (decrypted.length + 1));
214  memcpy(p, decrypted.data, decrypted.length);
215  p[decrypted.length] = '\0';
216 
217  *clear_text = p;
218  *clear_text_length = decrypted.length;
219 
220  // cleanup
221 error:
222  baClear(&shared_secret);
223  baClear(&encdata);
224  baClear(&ivector);
225  baClear(&encrypted);
226  baClear(&decrypted);
227 
228  if (private_key)
229  EVP_PKEY_free(private_key);
230 
231  if (peer_key)
232  EVP_PKEY_free(peer_key);
233 
234  return ret;
235 }
236 
237 int
238 baFromBase64(byteArray_t* decoded_data, char const* encoded_data)
239 {
240  BIO* b64;
241  BIO* buff;
242  size_t encoded_length;
243  size_t bytes_written;
244 
245  b64 = NULL;
246  buff = NULL;
247  encoded_length = 0;
248  bytes_written = 0;
249 
250  if (!decoded_data)
251  {
252  BTRMGRLOG_ERROR("no parameter sepcified to base64 decode into\n");
253  return 0;
254  }
255 
256  if (!encoded_data)
257  {
258  BTRMGRLOG_ERROR("no parameter specified to base64 decode\n");
259  return 0;
260  }
261 
262  encoded_length = strlen(encoded_data);
263 
264  b64 = BIO_new(BIO_f_base64());
265  buff = BIO_new_mem_buf(encoded_data, encoded_length);
266  buff = BIO_push(b64, buff);
267  BIO_set_flags(buff, BIO_FLAGS_BASE64_NO_NL);
268  BIO_set_flags(buff, BIO_CLOSE);
269 
270  baInit(decoded_data, encoded_length);
271  memset(decoded_data->data, 0, encoded_length);
272  decoded_data->length = 0;
273 
274  bytes_written = BIO_read(buff, decoded_data->data, encoded_length);
275  decoded_data->length = bytes_written;
276 
277  BIO_free_all(buff);
278 
279  return 0;
280 }
281 
282 char*
283 baToString(
284  byteArray_t const* v)
285 {
286  int i;
287  char* s;
288 
289  i = 0;
290  s = (char *) malloc(v->length + 1);
291 
292  for (i = 0; i < v->length; ++i)
293  s[i] = (char) v->data[i];
294 
295  s[v->length] = '\0';
296  return s;
297 }
298 
299 int
300 AESDecrypt(
301  byteArray_t const* key,
302  byteArray_t const* iv,
303  byteArray_t const* encrypted_data,
304  byteArray_t* plain_data)
305 {
306  int n;
307  int ret;
308  int length;
309  EVP_CIPHER_CTX* cipher_ctx;
310 
311  n = 0;
312  ret = 0;
313  length = 0;
314  cipher_ctx = NULL;
315 
316  baInit(plain_data, encrypted_data->length);
317 
318  #if _DEBUG_CRYPTO_
319  baPrint(key, "KEY\n");
320  baPrint(iv, "IV\n");
321  baPrint(encrypted_data, "ENCRYPTED DATA\n");
322  #endif
323 
324  cipher_ctx = EVP_CIPHER_CTX_new();
325  if (!cipher_ctx)
326  {
327  BTRMGRLOG_ERROR("EVP_CIPHER_CTX_new failed. %s\n", CRYPTO_Error());
328  baClear(plain_data);
329  return 0;
330  }
331 
332  ret = EVP_DecryptInit_ex(cipher_ctx, EVP_aes_256_cbc(), NULL, key->data, iv->data);
333  if (!ret)
334  {
335  BTRMGRLOG_ERROR("EVP_DecryptInit_ex failed. %s\n", CRYPTO_Error());
336  EVP_CIPHER_CTX_free(cipher_ctx);
337  return 0;
338  }
339 
340 #if 0
341  EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
342  EVP_CIPHER_CTX_set_key_length(ctx.get(), 16);
343 #endif
344 
345  ret = EVP_DecryptUpdate(cipher_ctx, plain_data->data, &n, encrypted_data->data, encrypted_data->length);
346  if (ret == 1)
347  {
348  length += n;
349  }
350  else
351  {
352  BTRMGRLOG_ERROR("EVP_DecryptUpdate failed. %s\n", CRYPTO_Error());
353  EVP_CIPHER_CTX_free(cipher_ctx);
354  return 0;
355  }
356 
357  ret = EVP_DecryptFinal_ex(cipher_ctx, (plain_data->data + length), &n);
358  if (ret == 1)
359  {
360  length += n;
361  }
362  else
363  {
364  BTRMGRLOG_ERROR("EVP_DecryptFinal_ex failed. %s\n", CRYPTO_Error());
365  EVP_CIPHER_CTX_free(cipher_ctx);
366  return 0;
367  }
368 
369  if (length > 0 && length < plain_data->length)
370  {
371  plain_data->length = length;
372  plain_data->data[length] = '\0';
373  }
374 
375  EVP_CIPHER_CTX_free(cipher_ctx);
376  return 1;
377 }
378 
379 EVP_PKEY*
380 ECC_ReadPublicKeyFromPEM(
381  char const* pem_data)
382 {
383  EVP_PKEY* public_key;
384  BIO* buff;
385 
386  // The only way I can figure out how to get openssl to parse an elliptical
387  // key was to include headers, otherwise, the sequence of calls is
388  // different
389  static char const pem_header[] = "-----BEGIN PUBLIC KEY-----";
390  static char const pem_footer[] = "-----END PUBLIC KEY-----";
391 
392  public_key = NULL;
393  buff = NULL;
394 
395  buff = BIO_new(BIO_s_mem());
396  BIO_write(buff, pem_header, strlen(pem_header));
397  BIO_write(buff, "\n", 1);
398  BIO_write(buff, pem_data, strlen(pem_data));
399  BIO_write(buff, "\n", 1);
400  BIO_write(buff, pem_footer, strlen(pem_footer));
401 
402  public_key = PEM_read_bio_PUBKEY(buff, NULL, NULL, NULL);
403  if (!public_key)
404  {
405  BTRMGRLOG_ERROR("failed to parse PEM data for public key. %s\n", CRYPTO_Error());
406  }
407  BIO_free_all(buff);
408 
409  return public_key;
410 }
411 
412 EVP_PKEY*
413 ECC_ReadPublicKeyFromFile(
414  char const* fname)
415 {
416  FILE* fin;
417  EVP_PKEY* public_key;
418 
419  fin = NULL;
420  public_key = NULL;
421 
422  if (!fname)
423  {
424  BTRMGRLOG_ERROR("can't read public key from NULL filename\n");
425  return NULL;
426  }
427 
428  fin = fopen(fname, "r");
429  if (!fin)
430  {
431  int err = errno;
432  BTRMGRLOG_ERROR("failed to open file to read public key '%s'. %d\n",
433  fname, err);
434  return NULL;
435  }
436 
437  public_key = PEM_read_PUBKEY(fin, NULL, NULL, NULL);
438  fclose(fin);
439 
440  return public_key;
441 }
442 
443 EVP_PKEY*
444 ECC_ReadPrivateKeyFromFile(char const* fname)
445 {
446  FILE* fin;
447  EVP_PKEY* private_key;
448 
449  fin = NULL;
450  private_key = NULL;
451 
452  fin = fopen(fname, "r");
453  if (!fin)
454  {
455  int err = errno;
456  BTRMGRLOG_ERROR("failed to open file to read private key '%s'. %d\n",
457  fname, err);
458  return NULL;
459  }
460 
461  private_key = PEM_read_PrivateKey(fin, NULL, NULL, NULL);
462  fclose(fin);
463 
464  return private_key;
465 }
466 
467 int
468 ECDH_SharedKeyDerive(
469  EVP_PKEY* private_key,
470  EVP_PKEY* peer_key,
471  byteArray_t* shared_secret)
472 {
473  size_t len;
474  EVP_PKEY_CTX* key_ctx;
475 
476  len = 0;
477  baInit(shared_secret, 0);
478  key_ctx = NULL;
479 
480  key_ctx = EVP_PKEY_CTX_new(private_key, NULL);
481  if (!key_ctx)
482  {
483  unsigned long err = ERR_get_error();
484  BTRMGRLOG_ERROR("EVP_PKEY_CTX_new failed:%lu", err);
485  return 0;
486  }
487 
488  if (!EVP_PKEY_derive_init(key_ctx))
489  {
490  BTRMGRLOG_ERROR("EVP_PKEY_derive_init failed. %s", CRYPTO_Error());
491  EVP_PKEY_CTX_free(key_ctx);
492  return 0;
493  }
494 
495  if (!EVP_PKEY_derive_set_peer(key_ctx, peer_key))
496  {
497  BTRMGRLOG_ERROR("EVP_PKEY_derive_set_peer failed. %s", CRYPTO_Error());
498  EVP_PKEY_CTX_free(key_ctx);
499  return 0;
500  }
501 
502  if (!EVP_PKEY_derive(key_ctx, NULL, &len))
503  {
504  BTRMGRLOG_ERROR("EVP_PKEY_derive failed. %s", CRYPTO_Error());
505  EVP_PKEY_CTX_free(key_ctx);
506  return 0;
507  }
508 
509  baInit(shared_secret, len);
510 
511  if (!EVP_PKEY_derive(key_ctx, shared_secret->data, &len))
512  {
513  BTRMGRLOG_ERROR("EVP_PKEY_derive failed. %s", CRYPTO_Error());
514  EVP_PKEY_CTX_free(key_ctx);
515  return 0;
516  }
517  else
518  {
519  shared_secret->length = len;
520  }
521 
522  EVP_PKEY_CTX_free(key_ctx);
523  return 1;
524 }
525 
526 
527 void
528 baInit(
529  byteArray_t* v,
530  int length)
531 {
532  if (v)
533  {
534  if (length > 0)
535  {
536  size_t n = sizeof(byte_t) * length;
537  v->data = (byte_t *) malloc(n);
538  memset(v->data, 0, n);
539  v->length = length;
540  }
541  else
542  {
543  v->data = NULL;
544  v->length = 0;
545  }
546  }
547 }
548 
549 void
550 baClear(
551  byteArray_t* v)
552 {
553  if (v)
554  {
555  if (v->data)
556  free(v->data);
557  v->data = NULL;
558  v->length = 0;
559  }
560 }
561 
562 #if _DEBUG_CRYPTO_
563 void
564 baPrint(
565  byteArray_t const* v,
566  char const* name)
567 {
568  int i;
569 
570  printf("\n");
571  printf("----- BEGIN %s -----\n", name);
572  for (i = 0; i < v->length; ++i)
573  {
574  if (i > 0 && i % 8 == 0)
575  printf("\n");
576  printf("0x%02x ", v->data[i]);
577  }
578  printf("\n----- END %s -----\n", name);
579  printf("\n");
580 }
581 #endif
582 
583 int
584 ECDH_DecryptWiFiSettings(
585  cJSON * server_reply,
586  cJSON** wifi_settings)
587 {
588  int ret;
589  cJSON* iv;
590  cJSON* peer_key;
591  cJSON* settings;
592  char* clear_text;
593  int clear_text_length;
594 
595  ret = 0;
596  iv = NULL;
597  peer_key = NULL;
598  settings = NULL;
599  clear_text = NULL;
600  clear_text_length = 0;
601 
602  if (!server_reply)
603  {
604  BTRMGRLOG_ERROR("null server_reply\n");
605  return 1;
606  }
607 
608  if (!wifi_settings)
609  {
610  BTRMGRLOG_ERROR("null wifi_settings\n");
611  return 1;
612  }
613 
614  settings = cJSON_GetObjectItem(server_reply, "wifi-settings");
615  if (settings)
616  {
617  BTRMGRLOG_INFO("found un-encrypted settings, using those\n");
618  *wifi_settings = cJSON_Duplicate(settings, 1);
619  return 1;
620  }
621 
622  settings = cJSON_GetObjectItem(server_reply, "secure-wifi-settings");
623  if (!settings)
624  {
625  BTRMGRLOG_ERROR("failed to find 'secure-wifi-settings' in wifi settings object\n");
626  *wifi_settings = NULL;
627  return 0;
628  }
629 
630  iv = cJSON_GetObjectItem(server_reply, "iv");
631  if (!iv)
632  {
633  BTRMGRLOG_ERROR("failed to find 'iv' in wifi settings object\n");
634  *wifi_settings = NULL;
635  return 0;
636  }
637 
638  peer_key = cJSON_GetObjectItem(server_reply, "pubKey");
639  if (!peer_key)
640  {
641  BTRMGRLOG_ERROR("failed to find 'pubKey' in wifi settings object\n");
642  return 0;
643  }
644 
645  ret = ECDH_Decrypt(kPrivateKeyPath, peer_key->valuestring, iv->valuestring,
646  settings->valuestring, &clear_text, &clear_text_length);
647  if (!ret)
648  {
649  BTRMGRLOG_ERROR("failed to decrypt secure wifi settings from '%s'",
650  settings->valuestring);
651  return 0;
652  }
653 
654  if (!clear_text)
655  {
656  BTRMGRLOG_ERROR("encryption returned NULL clear text string\n");
657  return 0;
658  }
659 
660  *wifi_settings = cJSON_Parse(clear_text);
661  if (!*wifi_settings)
662  {
663  BTRMGRLOG_ERROR("failed to parse secure wifi settings json string '%s'",
664  clear_text);
665  return 0;
666  }
667 
668  free(clear_text);
669  return 1;
670 }
671 
672 char const*
673 CRYPTO_Error()
674 {
675  static char buff[512];
676 
677  unsigned long err = ERR_get_error();
678  ERR_error_string_n(err, buff, sizeof(buff));
679 
680  return buff;
681 }
682 
byteArray_t
Definition: ecdh.c:38