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