encrypt.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * Copyright (c) 2019, Linaro Limited. All rights reserved.
  3. * Author: Sumit Garg <sumit.garg@linaro.org>
  4. *
  5. * SPDX-License-Identifier: BSD-3-Clause
  6. */
  7. #include <firmware_encrypted.h>
  8. #include <openssl/evp.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include "debug.h"
  12. #include "encrypt.h"
  13. #define BUFFER_SIZE 256
  14. #define IV_SIZE 12
  15. #define IV_STRING_SIZE 24
  16. #define TAG_SIZE 16
  17. #define KEY_SIZE 32
  18. #define KEY_STRING_SIZE 64
  19. static int gcm_encrypt(unsigned short fw_enc_status, char *key_string,
  20. char *nonce_string, const char *ip_name,
  21. const char *op_name)
  22. {
  23. FILE *ip_file;
  24. FILE *op_file;
  25. EVP_CIPHER_CTX *ctx;
  26. unsigned char data[BUFFER_SIZE], enc_data[BUFFER_SIZE];
  27. unsigned char key[KEY_SIZE], iv[IV_SIZE], tag[TAG_SIZE];
  28. int bytes, enc_len = 0, i, j, ret = 0;
  29. struct fw_enc_hdr header;
  30. memset(&header, 0, sizeof(struct fw_enc_hdr));
  31. if (strlen(key_string) != KEY_STRING_SIZE) {
  32. ERROR("Unsupported key size: %lu\n", strlen(key_string));
  33. return -1;
  34. }
  35. for (i = 0, j = 0; i < KEY_SIZE; i++, j += 2) {
  36. if (sscanf(&key_string[j], "%02hhx", &key[i]) != 1) {
  37. ERROR("Incorrect key format\n");
  38. return -1;
  39. }
  40. }
  41. if (strlen(nonce_string) != IV_STRING_SIZE) {
  42. ERROR("Unsupported IV size: %lu\n", strlen(nonce_string));
  43. return -1;
  44. }
  45. for (i = 0, j = 0; i < IV_SIZE; i++, j += 2) {
  46. if (sscanf(&nonce_string[j], "%02hhx", &iv[i]) != 1) {
  47. ERROR("Incorrect IV format\n");
  48. return -1;
  49. }
  50. }
  51. ip_file = fopen(ip_name, "rb");
  52. if (ip_file == NULL) {
  53. ERROR("Cannot read %s\n", ip_name);
  54. return -1;
  55. }
  56. op_file = fopen(op_name, "wb");
  57. if (op_file == NULL) {
  58. ERROR("Cannot write %s\n", op_name);
  59. fclose(ip_file);
  60. return -1;
  61. }
  62. ret = fseek(op_file, sizeof(struct fw_enc_hdr), SEEK_SET);
  63. if (ret) {
  64. ERROR("fseek failed\n");
  65. goto out_file;
  66. }
  67. ctx = EVP_CIPHER_CTX_new();
  68. if (ctx == NULL) {
  69. ERROR("EVP_CIPHER_CTX_new failed\n");
  70. ret = -1;
  71. goto out_file;
  72. }
  73. ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
  74. if (ret != 1) {
  75. ERROR("EVP_EncryptInit_ex failed\n");
  76. ret = -1;
  77. goto out;
  78. }
  79. ret = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
  80. if (ret != 1) {
  81. ERROR("EVP_EncryptInit_ex failed\n");
  82. goto out;
  83. }
  84. while ((bytes = fread(data, 1, BUFFER_SIZE, ip_file)) != 0) {
  85. ret = EVP_EncryptUpdate(ctx, enc_data, &enc_len, data, bytes);
  86. if (ret != 1) {
  87. ERROR("EVP_EncryptUpdate failed\n");
  88. ret = -1;
  89. goto out;
  90. }
  91. fwrite(enc_data, 1, enc_len, op_file);
  92. }
  93. ret = EVP_EncryptFinal_ex(ctx, enc_data, &enc_len);
  94. if (ret != 1) {
  95. ERROR("EVP_EncryptFinal_ex failed\n");
  96. ret = -1;
  97. goto out;
  98. }
  99. ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_SIZE, tag);
  100. if (ret != 1) {
  101. ERROR("EVP_CIPHER_CTX_ctrl failed\n");
  102. ret = -1;
  103. goto out;
  104. }
  105. header.magic = ENC_HEADER_MAGIC;
  106. header.flags |= fw_enc_status & FW_ENC_STATUS_FLAG_MASK;
  107. header.dec_algo = KEY_ALG_GCM;
  108. header.iv_len = IV_SIZE;
  109. header.tag_len = TAG_SIZE;
  110. memcpy(header.iv, iv, IV_SIZE);
  111. memcpy(header.tag, tag, TAG_SIZE);
  112. ret = fseek(op_file, 0, SEEK_SET);
  113. if (ret) {
  114. ERROR("fseek failed\n");
  115. goto out;
  116. }
  117. fwrite(&header, 1, sizeof(struct fw_enc_hdr), op_file);
  118. out:
  119. EVP_CIPHER_CTX_free(ctx);
  120. out_file:
  121. fclose(ip_file);
  122. fclose(op_file);
  123. /*
  124. * EVP_* APIs returns 1 as success but enctool considers
  125. * 0 as success.
  126. */
  127. if (ret == 1)
  128. ret = 0;
  129. return ret;
  130. }
  131. int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
  132. char *nonce_string, const char *ip_name, const char *op_name)
  133. {
  134. switch (enc_alg) {
  135. case KEY_ALG_GCM:
  136. return gcm_encrypt(fw_enc_status, key_string, nonce_string,
  137. ip_name, op_name);
  138. default:
  139. return -1;
  140. }
  141. }