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 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 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