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