/****************************************************************
 * 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;
}

Embed on website

To embed this program on your website, copy the following code and paste it into your website's HTML: