Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/geli/geliboot_crypto.c
Show All 29 Lines | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <strings.h> | #include <strings.h> | ||||
#include "geliboot_internal.h" | #include "geliboot_internal.h" | ||||
#include "geliboot.h" | #include "geliboot.h" | ||||
int | int | ||||
geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize, | geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize, | ||||
const u_char *key, size_t keysize, u_char *iv) | const u_char *key, size_t keysize, u_char *iv) | ||||
{ | { | ||||
keyInstance aeskey; | keyInstance aeskey; | ||||
cipherInstance cipher; | cipherInstance cipher; | ||||
struct aes_xts_ctx xtsctx, *ctxp; | struct aes_xts_ctx xtsctx, *ctxp; | ||||
size_t xts_len; | size_t xts_len; | ||||
int err, blks, i; | int err, blks, i; | ||||
switch (algo) { | switch (algo) { | ||||
case CRYPTO_AES_CBC: | case CRYPTO_AES_CBC: | ||||
err = rijndael_makeKey(&aeskey, !enc, keysize, | err = rijndael_makeKey(&aeskey, !enc, keysize, | ||||
(const char *)key); | (const char *)key); | ||||
if (err < 0) { | if (err < 0) { | ||||
printf("Failed to setup decryption keys: %d\n", err); | printf("Failed to setup crypo keys: %d\n", err); | ||||
return (err); | return (err); | ||||
} | } | ||||
err = rijndael_cipherInit(&cipher, MODE_CBC, iv); | err = rijndael_cipherInit(&cipher, MODE_CBC, iv); | ||||
if (err < 0) { | if (err < 0) { | ||||
printf("Failed to setup IV: %d\n", err); | printf("Failed to setup IV: %d\n", err); | ||||
return (err); | return (err); | ||||
} | } | ||||
if (enc == 0) { | switch (enc) { | ||||
/* decrypt */ | case GELI_DECRYPT: | ||||
blks = rijndael_blockDecrypt(&cipher, &aeskey, data, | blks = rijndael_blockDecrypt(&cipher, &aeskey, data, | ||||
datasize * 8, data); | datasize * 8, data); | ||||
} else { | break; | ||||
/* encrypt */ | case GELI_ENCRYPT: | ||||
blks = rijndael_blockEncrypt(&cipher, &aeskey, data, | blks = rijndael_blockEncrypt(&cipher, &aeskey, data, | ||||
datasize * 8, data); | datasize * 8, data); | ||||
break; | |||||
} | } | ||||
if (datasize != (blks / 8)) { | if (datasize != (blks / 8)) { | ||||
printf("Failed to decrypt the entire input: " | printf("Failed to %s the entire input: %u != %zu\n", | ||||
"%u != %zu\n", blks, datasize); | enc ? "decrypt" : "encrypt", | ||||
blks, datasize); | |||||
return (1); | return (1); | ||||
} | } | ||||
break; | break; | ||||
case CRYPTO_AES_XTS: | case CRYPTO_AES_XTS: | ||||
xts_len = keysize << 1; | xts_len = keysize << 1; | ||||
ctxp = &xtsctx; | ctxp = &xtsctx; | ||||
enc_xform_aes_xts.setkey(ctxp, key, xts_len / 8); | enc_xform_aes_xts.setkey(ctxp, key, xts_len / 8); | ||||
enc_xform_aes_xts.reinit(ctxp, iv); | enc_xform_aes_xts.reinit(ctxp, iv); | ||||
switch (enc) { | switch (enc) { | ||||
case 0: /* decrypt */ | case GELI_DECRYPT: | ||||
for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { | for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { | ||||
enc_xform_aes_xts.decrypt(ctxp, data + i, | enc_xform_aes_xts.decrypt(ctxp, data + i, | ||||
data + i); | data + i); | ||||
} | } | ||||
break; | break; | ||||
case 1: /* encrypt */ | case GELI_ENCRYPT: | ||||
for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { | for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { | ||||
enc_xform_aes_xts.encrypt(ctxp, data + i, | enc_xform_aes_xts.encrypt(ctxp, data + i, | ||||
data + 1); | data + i); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
printf("Unsupported crypto algorithm #%d\n", algo); | printf("Unsupported crypto algorithm #%d\n", algo); | ||||
return (1); | return (1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, | g_eli_crypto_cipher(u_int algo, geli_op_t enc, u_char *data, size_t datasize, | ||||
const u_char *key, size_t keysize) | const u_char *key, size_t keysize) | ||||
{ | { | ||||
u_char iv[keysize]; | u_char iv[keysize]; | ||||
explicit_bzero(iv, sizeof(iv)); | explicit_bzero(iv, sizeof(iv)); | ||||
return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv)); | return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv)); | ||||
} | } | ||||
int | int | ||||
g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, | g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, | ||||
const u_char *key, size_t keysize) | const u_char *key, size_t keysize) | ||||
{ | { | ||||
/* We prefer AES-CBC for metadata protection. */ | /* We prefer AES-CBC for metadata protection. */ | ||||
if (algo == CRYPTO_AES_XTS) | if (algo == CRYPTO_AES_XTS) | ||||
algo = CRYPTO_AES_CBC; | algo = CRYPTO_AES_CBC; | ||||
return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize)); | return (g_eli_crypto_cipher(algo, GELI_ENCRYPT, data, datasize, key, | ||||
keysize)); | |||||
} | } | ||||
int | int | ||||
g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, | g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, | ||||
const u_char *key, size_t keysize) | const u_char *key, size_t keysize) | ||||
{ | { | ||||
/* We prefer AES-CBC for metadata protection. */ | /* We prefer AES-CBC for metadata protection. */ | ||||
if (algo == CRYPTO_AES_XTS) | if (algo == CRYPTO_AES_XTS) | ||||
algo = CRYPTO_AES_CBC; | algo = CRYPTO_AES_CBC; | ||||
return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize)); | return (g_eli_crypto_cipher(algo, GELI_DECRYPT, data, datasize, key, | ||||
keysize)); | |||||
} | } |