/****************************************************************
* Project TCAM2
* (c) copyright 2022
* Company Harman International(India) Pvt. Ltd.
* All rights reserved
* Secrecy Level STRICTLY CONFIDENTIAL
****************************************************************/
/**
* @file opendisk.c
* @ingroup Security & Intelligent Systems
* @author adarsh.adarsh.SSO@harman.com
* @brief Opendisk code for Mounting Encrypted partition
*/
#include "opendisk.h"
/* ---- Base64 Encoding/Decoding Table --- */
static char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t b64_encoded_size(size_t inlen)
{
size_t ret;
ret = inlen;
if (inlen % 3 != 0)
ret += 3 - (inlen % 3);
ret /= 3;
ret *= 4;
return ret;
}
char *b64_encode(char *in, size_t len)
{
char *out;
size_t elen;
size_t i;
size_t j;
size_t v;
if (in == NULL || len == 0)
return NULL;
elen = b64_encoded_size(len);
out = malloc(elen+1);
out[elen] = '\0';
for (i=0, j=0; i<len; i+=3, j+=4) {
v = in[i];
v = i+1 < len ? v << 8 | in[i+1] : v << 8;
v = i+2 < len ? v << 8 | in[i+2] : v << 8;
out[j] = b64chars[(v >> 18) & 0x3F];
out[j+1] = b64chars[(v >> 12) & 0x3F];
if (i+1 < len) {
out[j+2] = b64chars[(v >> 6) & 0x3F];
} else {
out[j+2] = '=';
}
if (i+2 < len) {
out[j+3] = b64chars[v & 0x3F];
} else {
out[j+3] = '=';
}
}
return out;
}
int32_t mount_partition()
{
int retval = 0;
retval = mount(ENCRYPTED_MAPPER, ENCRYPTED_MOUNT_POINT, "ext4", MS_MGC_VAL, NULL);
if (retval == 0) {
dprintf(LOG_INFO,"Mount [%s] Succeed \n", ENCRYPTED_MOUNT_POINT);
}
else
dprintf(LOG_CRITICAL,"Devide already mounted or failed to mount %s [%d] \n", strerror(errno), errno);
retval = mount(PRIVACY_MAPPER, PRIVACY_MOUNT_POINT, "ext4", MS_MGC_VAL, NULL);
if (retval == 0) {
dprintf(LOG_INFO,"Mount [%s] Succeed \n", PRIVACY_MOUNT_POINT);
}
else
dprintf(LOG_CRITICAL,"Devide already mounted or failed to mount %s [%d] \n", strerror(errno), errno);
return retval;
}
int activate_and_check_status(const char *device_name, const char *mapper, char *key, size_t key_len)
{
struct crypt_device *cd;
int r;
/*
*LUKS device activation.
*/
r = crypt_init(&cd, device_name);
if (r < 0 ) {
dprintf(LOG_CRITICAL,"crypt_init() failed for %s.\n", device_name);
return r;
}
/*
* crypt_load() is used to load the LUKS header from block device
* into crypt_device context.
*/
r = crypt_load(cd, /* crypt context */
CRYPT_LUKS1, /* requested type */
NULL); /* additional parameters (not used) */
if (r < 0) {
dprintf(LOG_CRITICAL,"crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
crypt_free(cd);
return r;
}
/*
* Device activation creates device-mapper devie mapping with name device_name.
*/
#ifdef DEBUG_ENABLED
dprintf(LOG_INFO,"mapper : %s : key : %s : key_length : %ld \n", mapper, key, key_len);
#endif
r = crypt_activate_by_passphrase(cd, /* crypt context */
mapper, /* mapper name to activate */
CRYPT_ANY_SLOT, /* which slot use (ANY - try all) */
key, key_len, /* passphrase */
0); /* flags */
if (r < 0) {
dprintf(LOG_CRITICAL,"Device %s already activated or failed to activate\n", device_name);
crypt_free(cd);
return r;
}
#ifdef DEBUG_ENABLED
dprintf(LOG_INFO,"LUKS device %s/%s is active.\n", crypt_get_dir(), mapper);
dprintf(LOG_INFO,"\tcipher used: %s\n", crypt_get_cipher(cd));
dprintf(LOG_INFO,"\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
dprintf(LOG_INFO,"\tdevice UUID: %s\n", crypt_get_uuid(cd));
/*
* Get info about active device (query DM backend)
*/
struct crypt_active_device cad;
r = crypt_get_active_device(cd, mapper, &cad);
if (r < 0) {
dprintf(LOG_CRITICAL,"Get info about active device %s failed.\n", mapper);
crypt_deactivate(cd, mapper);
crypt_free(cd);
return r;
}
dprintf(LOG_INFO,"Active device parameters for %s:\n"
"\tDevice offset (in sectors): %" PRIu64 "\n"
"\tIV offset (in sectors) : %" PRIu64 "\n"
"\tdevice size (in sectors) : %" PRIu64 "\n"
"\tread-only flag : %s\n",
mapper, cad.offset, cad.iv_offset, cad.size,
cad.flags & CRYPT_ACTIVATE_READONLY ? "1" : "0");
crypt_free(cd);
#endif
return 0;
}
int format_and_add_keyslots(const char *path, char *key, size_t key_len)
{
struct crypt_device *cd;
int r;
/*
* The crypt_init() call is used to initialize crypt_device context,
* The path parameter specifies a device path.
*
* For path, you can use either link to a file or block device.
* The loopback device will be detached automatically.
*/
r = crypt_init(&cd, path);
if (r < 0) {
printf("crypt_init() failed for %s.\n", path);
return r;
}
dprintf(LOG_INFO,"Context is attached to block device %s.\n", crypt_get_device_name(cd));
/*
* So far, no data were written to the device.
*/
printf("Device %s will be formatted as a LUKS device after 5 seconds.\n"
"Press CTRL+C now if you want to cancel this operation.\n", path);
sleep(1);
/*
* NULLs for uuid and volume_key means that these attributes will be
* generated during crypt_format().
*/
r = crypt_format(cd, /* crypt context */
CRYPT_LUKS1, /* LUKS2 is a new LUKS format; use CRYPT_LUKS1 for LUKS1 */
"aes", /* used cipher */
"cbc-plain64", /* used block mode and IV */
NULL, /* generate UUID */
NULL, /* generate volume key from RNG */
128 / 8, /* 512bit key - here AES-256 in XTS mode, size is in bytes */
NULL); /* default parameters */
if (r < 0) {
printf("crypt_format() failed on device %s r:%d\n", crypt_get_device_name(cd), r);
crypt_free(cd);
return r;
}
/*
* The device now contains a LUKS header, but there is no active keyslot.
*
* crypt_keyslot_add_* call stores the volume_key in the encrypted form into the keyslot.
*
* After format, the volume key is stored internally.
*/
r = crypt_keyslot_add_by_volume_key(cd, /* crypt context */
CRYPT_ANY_SLOT, /* just use first free slot */
NULL, /* use internal volume key */
0, /* unused (size of volume key) */
key, /* passphrase - NULL means query*/
key_len); /* size of passphrase */
if (r < 0) {
printf("Adding keyslot failed.\n");
crypt_free(cd);
return r;
}
printf("The first keyslot is initialized.\n");
crypt_free(cd);
return 0;
}
int32_t seccryptoprivacy(SECCRYPT_HANDLE handle, char *key, size_t key_len)
{
tErrorStatus retStatus = SECCRYPTO_OK;
char privacysecureData[MAX_DATA_SIZE] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0};
size_t privacygetDataSize = MAX_DATA_SIZE;
FILE *fp = NULL;
char fstype[Type_Size];
char *myb64 = NULL;
char b64len = 0;
fp = popen("lsblk -no FSTYPE /dev/mmcblk0p37", "r");
if (fp == NULL) {
dprintf(LOG_CRITICAL,"Failed to run command\n");
}
while (fgets(fstype, sizeof(fstype), fp) != NULL) {
dprintf(LOG_CRITICAL,"%s", fstype);
}
pclose(fp);
if (strncmp(fstype, "crypto_LUKS", strlen("crypto_LUKS") != 0)) {
retStatus = seccryptoGenRand(handle, &privacysecureData, privacygetDataSize);
if (SECCRYPTO_OK != retStatus) {
dprintf(LOG_CRITICAL,"Error: Generate Random Number failed\n");
return EXIT_FAILURE;
}
else {
myb64 = b64_encode(privacysecureData,privacygetDataSize);
b64len = b64_encoded_size(privacygetDataSize);
}
}
if (strncmp(fstype, "crypto_LUKS", strlen("crypto_LUKS") != 0)) {
retStatus = seccryptoWriteData(handle, FMP_KEY_ID2, myb64, b64len);
if (SECCRYPTO_OK != retStatus) {
dprintf(LOG_CRITICAL,"Error: seccryptoWriteData failed\n");
return EXIT_FAILURE;
}
}
strcpy(key, myb64);
memset(privacysecureData,'\0',privacygetDataSize);
memset(myb64,'\0',b64len);
return EXIT_SUCCESS;
}
int32_t seccryptoencrypt(SECCRYPT_HANDLE handle, char *key, size_t key_len)
{
tErrorStatus retStatus = SECCRYPTO_OK;
char encryptsecureData[MAX_DATA_SIZE] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0};
size_t encryptgetDataSize = MAX_DATA_SIZE;
FILE *fp = NULL;
char fstype[Type_Size];
char *myb64 = NULL;
char b64len = 0;
fp = popen("lsblk -no FSTYPE /dev/mmcblk0p36", "r");
if (fp == NULL) {
dprintf(LOG_CRITICAL,"Failed to run command\n");
}
while (fgets(fstype, sizeof(fstype), fp) != NULL) {
dprintf(LOG_CRITICAL,"%s", fstype);
}
pclose(fp);
if (strncmp(fstype, "crypto_LUKS", strlen("crypto_LUKS") != 0)) {
retStatus = seccryptoGenRand(handle, &encryptsecureData, encryptgetDataSize);
if (SECCRYPTO_OK != retStatus) {
dprintf(LOG_CRITICAL,"Error: Generate Random Number failed\n");
return EXIT_FAILURE;
}
else {
myb64 = b64_encode(encryptsecureData,encryptgetDataSize);
b64len = b64_encoded_size(encryptgetDataSize);
}
}
if (strncmp(fstype, "crypto_LUKS", strlen("crypto_LUKS") != 0)) {
retStatus = seccryptoWriteData(handle, FMP_KEY_ID1, myb64, b64len);
if (SECCRYPTO_OK != retStatus) {
dprintf(LOG_CRITICAL,"Error: seccryptoWriteData failed\n");
return EXIT_FAILURE;
}
}
strcpy(key, myb64);
memset(encryptsecureData,'\0',encryptgetDataSize);
memset(myb64,'\0',b64len);
return EXIT_SUCCESS;
}
bool isPartitionEncyptFormatted()
{
const char *type;
bool retval = false;
blkid_probe pre = blkid_new_probe_from_filename(ENCRYPTED_DISK);
if (!pre) {
dprintf(LOG_CRITICAL, "Error: Failed to open device %s\n", ENCRYPTED_DISK);
return false;
}
blkid_do_probe(pre);
if (blkid_probe_lookup_value(pre, "TYPE", &type, NULL)) {
return false;
}
if ((strncmp(type, "crypto_LUKS", strlen("crypto_LUKS"))) == 0)
retval = true;
else {
dprintf(LOG_CRITICAL, "Error: Type:%s\n", type);
}
blkid_free_probe(pre);
return retval;
}
bool isPartitionPrivacyFormatted()
{
const char *type;
bool retval = false;
blkid_probe prp = blkid_new_probe_from_filename(PRIVACY_DISK);
if (!prp) {
dprintf(LOG_CRITICAL, "Error: Failed to open device %s\n", PRIVACY_DISK);
return false;
}
blkid_do_probe(prp);
if (blkid_probe_lookup_value(prp, "TYPE", &type, NULL)) {
return false;
}
if ((strncmp(type, "crypto_LUKS", strlen("crypto_LUKS"))) == 0)
retval = true;
else {
dprintf(LOG_CRITICAL, "Error: Type:%s\n", type);
}
blkid_free_probe(prp);
return retval;
}
int32_t checkAndMount(SECCRYPT_HANDLE handle)
{
tErrorStatus retStatus = SECCRYPTO_OK;
char encryptsecureData[RAND_DATA_SIZE] = {0};
size_t encryptgetDataSize = RAND_DATA_SIZE;
char privacysecureData[RAND_DATA_SIZE] = {0};
size_t privacygetDataSize = RAND_DATA_SIZE;
bool ext4_encrypt_format_needed = false;
bool ext4_privacy_format_needed = false;
FILE *timelog;
timelog = fopen("/mnt/swdl/OpendiskTimeLog.txt", "wb");
if (timelog == NULL) {
dprintf(LOG_CRITICAL,"Error: failed to open file or file not found.\n");
}
clock_t t,a,b;
t = clock();
if (!isPartitionEncyptFormatted()) {
dprintf(LOG_INFO,"Partition type is not Crypt_LUKS");
if(seccryptoencrypt(handle, encryptsecureData, encryptgetDataSize)!=0) {
dprintf(LOG_CRITICAL, "seccryptoencrypt failed\n");
}
if (!format_and_add_keyslots(ENCRYPTED_DISK, encryptsecureData, encryptgetDataSize)) {
dprintf(LOG_INFO, "LUKS Format partition:%s done\n", ENCRYPTED_DISK);
ext4_encrypt_format_needed = true;
}
else {
dprintf(LOG_CRITICAL, "LUKS Format partition:%s failed\n", ENCRYPTED_DISK);
return EXIT_FAILURE;
}
}
memset(encryptsecureData,'\0',encryptgetDataSize);
t = clock() - t;
double time_t = ((double)t)/CLOCKS_PER_SEC;
a = clock();
if (!isPartitionPrivacyFormatted()) {
dprintf(LOG_INFO,"Partition type is not Crypt_LUKS");
if(seccryptoprivacy(handle, privacysecureData, privacygetDataSize)!=0) {
dprintf(LOG_CRITICAL, "seccryptoprivacy failed\n");
}
if (!format_and_add_keyslots(PRIVACY_DISK, privacysecureData, privacygetDataSize)) {
dprintf(LOG_INFO, "LUKS Format partition:%s done\n", PRIVACY_DISK);
ext4_privacy_format_needed = true;
}
else {
dprintf(LOG_CRITICAL, "LUKS Format partition:%s failed\n", PRIVACY_DISK);
return EXIT_FAILURE;
}
}
memset(privacysecureData,'\0',privacygetDataSize);
a = clock() - a;
double time_a = ((double)a)/CLOCKS_PER_SEC;
b = clock();
retStatus = seccryptoReadData(handle, FMP_KEY_ID1, encryptsecureData, &encryptgetDataSize);
if (SECCRYPTO_OK != retStatus) {
dprintf(LOG_CRITICAL,"Error: Reading of encrypt passphrase failed\n");
return EXIT_FAILURE;
}
retStatus = seccryptoReadData(handle, FMP_KEY_ID2, privacysecureData, &privacygetDataSize);
if (SECCRYPTO_OK != retStatus) {
dprintf(LOG_CRITICAL,"Error: Reading of privacy passphrase failed\n");
return EXIT_FAILURE;
}
if(activate_and_check_status(ENCRYPTED_DISK, "encrypted", encryptsecureData, encryptgetDataSize) !=0)
dprintf(LOG_CRITICAL,"LUKS device already activated encrypted partition or failed to activate\n");
else
dprintf(LOG_INFO,"LUKS device activated ENCRYPTED_DISK\n");
if(ext4_encrypt_format_needed)
ext4_format(ENCRYPTED_MAPPER);
if(activate_and_check_status(PRIVACY_DISK, "privacy", privacysecureData, privacygetDataSize) !=0)
dprintf(LOG_CRITICAL,"LUKS device already activated privacy partition or failed to activate\n");
else
dprintf(LOG_INFO,"LUKS device activated PRIVACY_DISK\n");
if(ext4_privacy_format_needed)
ext4_format(PRIVACY_MAPPER);
dprintf(LOG_INFO,"ext4 formated\n");
mount_partition();
memset(encryptsecureData,'\0',encryptgetDataSize);
memset(privacysecureData,'\0',privacygetDataSize);
b = clock() - b;
double time_b = ((double)b)/CLOCKS_PER_SEC;
if (timelog != NULL)
{
fprintf(timelog ,"isPartitionEncyptFormatted() took %f seconds to execute \n", time_t);
fprintf(timelog ,"isPartitionPrivacyFormatted() took %f seconds to execute \n", time_a);
fprintf(timelog ,"activate_and_mount() took %f seconds to execute \n", time_b);
fclose(timelog);
timelog = NULL;
}
return retStatus;
}
int main(void)
{
char clientName[Client_Size] = FMPCLIENTNAME;
SECCRYPT_HANDLE handle = NULL;
char *path = TEE_PATH;
char *user_name = USER_NAME;
char *group_name = GROUP_NAME;
struct group *grp;
struct passwd *pwd;
uid_t uid;
gid_t gid;
pwd = getpwnam(user_name);
if (pwd == NULL) {
dprintf(LOG_CRITICAL,"Failed to get uid\n");
return EXIT_FAILURE;
}
uid = pwd->pw_uid;
grp = getgrnam(group_name);
if (grp != NULL) {
gid = grp->gr_gid;
if (chown(path, uid, gid) == ERROR_CODE) {
dprintf(LOG_CRITICAL,"chown failed\n");
return EXIT_FAILURE;
}
if (chmod(path, 0770) != SUCCESS_CODE) {
dprintf(LOG_CRITICAL,"Unable to reset permissions\n");
return EXIT_FAILURE;
}
}
handle = secCryptoInitClntSrvc(clientName);
if ( NULL == handle) {
dprintf(LOG_CRITICAL,"error:client init failed\n");
#if defined(DLT_ENABLED)
DLT_UNREGISTER_APP();
#endif
return EXIT_FAILURE;
}
if(checkAndMount(handle) != SECCRYPTO_OK) {
dprintf(LOG_CRITICAL,"Mounting failed\n");
secCryptoCtrlCloseDiagSrvc(handle);
return EXIT_FAILURE;
}
secCryptoCtrlCloseDiagSrvc(handle);
return 0;
}
To embed this program on your website, copy the following code and paste it into your website's HTML: