diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 764c5df..31ac22b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -241,6 +241,7 @@ typedef struct { #else u_int32_t partialMD5[4]; #endif + u_int8_t eme_L[16]; #if defined(CONFIG_BLK_DEV_LOOP_PADLOCK) && (defined(CONFIG_X86) || defined(CONFIG_X86_64)) u_int32_t padlock_cw_e; u_int32_t padlock_cw_d; @@ -519,6 +520,131 @@ error_out: return err; } +typedef void (*aes_func)(const aes_context *a, const unsigned char*, unsigned char*); + +static inline void eme_mul_by_two(uint8_t *output, uint8_t *input) +{ + uint64_t tmp1, tmp2; + uint64_t flagadd; + + memcpy(&tmp1, &input[8], 8); + memcpy(&tmp2, &input[0], 8); + flagadd = (tmp2>>63U); + tmp2 <<= 1U; + if (tmp1>>63U) tmp2 ^= 135; + tmp1 <<= 1U; + tmp1 += flagadd; + + memcpy(&output[8], &tmp1, 8); + memcpy(&output[0], &tmp2, 8); +} + +static inline void eme_xor_blocks(void *output, void *input1, void *input2) +{ + uint64_t *o = output; + uint64_t *i1 = input1; + uint64_t *i2 = input2; + + o[0] = i1[0] ^ i2[0]; + o[1] = i1[1] ^ i2[1]; +} + +static void aes_eme_setup(aes_context *a, uint8_t *L_out) +{ + uint8_t zero[16] = {0}; + + aes_encrypt(a, zero, zero); + eme_mul_by_two(L_out, zero); +} + +static void aes_eme_process(uint8_t C[512], uint8_t P[512], uint8_t T[16], + aes_context *a, uint8_t L_in[16], aes_func func) +{ + int j; + uint8_t L[16] __attribute__((aligned(16))); + uint8_t M[16] __attribute__((aligned(16))); + uint8_t MP[16] __attribute__((aligned(16))); + uint8_t MC[16] __attribute__((aligned(16))); + + memcpy(L, L_in, 16); + + for (j = 0; j < 32; j++) { + eme_xor_blocks(&C[j*16], &P[j*16], L); + func(a, &C[j*16], &C[j*16]); + eme_mul_by_two(L, L); + } + + eme_xor_blocks(MP, C, T); + for (j = 1; j < 32; j++) { + eme_xor_blocks(MP, MP, &C[j*16]); + } + func(a, MP, MC); + eme_xor_blocks(M, MP, MC); + + for (j = 1; j < 32; j++) { + eme_mul_by_two(M, M); + eme_xor_blocks(&C[j*16], &C[j*16], M); + } + eme_xor_blocks(C, MC, T); + for (j = 1; j < 32; j++) { + eme_xor_blocks(C, C, &C[j*16]); + } + + memcpy(L, L_in, 16); + for (j = 0; j < 32; j++) { + func(a, &C[j*16], &C[j*16]); + eme_xor_blocks(&C[j*16], &C[j*16], L); + eme_mul_by_two(L, L); + } +} + +static int transfer_eme_32_aes(struct loop_device *lo, int cmd, char *raw_buf, + char *loop_buf, int size, sector_t devSect) +{ + aes_context *a; + AESmultiKey *m; + u8 T[16] = {0}; + + if(!size || (size & 511)) { + return -EINVAL; + } + m = (AESmultiKey *)lo->key_data; + + while(size) { +#ifdef CONFIG_BLK_DEV_LOOP_KEYSCRUB + read_lock(&m->rwlock); +#endif + a = m->keyPtr[0]; + + T[8] = devSect >> 56; + T[9] = devSect >> 48; + T[10] = devSect >> 40; + T[11] = devSect >> 32; + T[12] = devSect >> 24; + T[13] = devSect >> 16; + T[14] = devSect >> 8; + T[15] = devSect; + + if (cmd == READ) { + aes_eme_process(loop_buf, raw_buf, T, a, m->eme_L, aes_decrypt); + } else { + aes_eme_process(raw_buf, loop_buf, T, a, m->eme_L, aes_encrypt); + } + +#ifdef CONFIG_BLK_DEV_LOOP_KEYSCRUB + read_unlock(&m->rwlock); +#endif + size -= 512; + devSect++; + raw_buf += 512; + loop_buf += 512; + + cond_resched(); + } + + return(0); +} + static int keySetup_aes(struct loop_device *lo, struct loop_info64 *info) { AESmultiKey *m; @@ -531,6 +657,9 @@ static int keySetup_aes(struct loop_device *lo, struct loop_info64 *info) if(!m) return(-ENOMEM); memcpy(&un.b[0], &info->lo_encrypt_key[0], 32); aes_set_key(m->keyPtr[0], &un.b[0], info->lo_encrypt_key_size, 0); + if (info->lo_encrypt_type == LO_CRYPT_EME_32_AES) { + aes_eme_setup(m->keyPtr[0], m->eme_L); + } memset(&info->lo_encrypt_key[0], 0, sizeof(info->lo_encrypt_key)); memset(&un.b[0], 0, 32); #if defined(CONFIG_BLK_DEV_LOOP_PADLOCK) && (defined(CONFIG_X86) || defined(CONFIG_X86_64)) @@ -1232,6 +1361,14 @@ static struct loop_func_table funcs_aes = { ioctl: handleIoctl_aes }; +static struct loop_func_table funcs_eme_32_aes = { + number: 19, /* 19 == EME_32_AES */ + transfer: transfer_eme_32_aes, + init: keySetup_aes, + release: keyClean_aes, + ioctl: handleIoctl_aes +}; + #if defined(CONFIG_BLK_DEV_LOOP_PADLOCK) && (defined(CONFIG_X86) || defined(CONFIG_X86_64)) static struct loop_func_table funcs_padlock_aes = { number: 16, /* 16 == AES */ @@ -1281,6 +1418,7 @@ static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { #ifdef CONFIG_BLK_DEV_LOOP_AES [LO_CRYPT_AES] = &funcs_aes, #endif + [LO_CRYPT_EME_32_AES] = &funcs_eme_32_aes, }; /* diff --git a/include/linux/loop.h b/include/linux/loop.h index 0f860f0..64f809b 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -130,6 +130,7 @@ struct loop_info64 { #define LO_CRYPT_SKIPJACK 10 #define LO_CRYPT_AES 16 #define LO_CRYPT_CRYPTOAPI 18 +#define LO_CRYPT_EME_32_AES 19 #define MAX_LO_CRYPT 20 #ifdef __KERNEL__