MFC: Synchronize geli(8) with HEAD version.
This commit is contained in:
parent
9cb7cb37ab
commit
6fb52e4447
@ -24,7 +24,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 11, 2006
|
||||
.Dd August 9, 2006
|
||||
.Dt GELI 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -52,7 +52,8 @@ utility:
|
||||
.Nm
|
||||
.Cm init
|
||||
.Op Fl bPv
|
||||
.Op Fl a Ar algo
|
||||
.Op Fl a Ar aalgo
|
||||
.Op Fl e Ar ealgo
|
||||
.Op Fl i Ar iterations
|
||||
.Op Fl K Ar newkeyfile
|
||||
.Op Fl l Ar keylen
|
||||
@ -63,7 +64,7 @@ utility:
|
||||
.Cm init
|
||||
.Nm
|
||||
.Cm attach
|
||||
.Op Fl dpv
|
||||
.Op Fl dprv
|
||||
.Op Fl k Ar keyfile
|
||||
.Ar prov
|
||||
.Nm
|
||||
@ -76,7 +77,8 @@ utility:
|
||||
.Nm
|
||||
.Cm onetime
|
||||
.Op Fl d
|
||||
.Op Fl a Ar algo
|
||||
.Op Fl a Ar aalgo
|
||||
.Op Fl e Ar ealgo
|
||||
.Op Fl l Ar keylen
|
||||
.Op Fl s Ar sectorsize
|
||||
.Ar prov ...
|
||||
@ -144,6 +146,16 @@ Supports many cryptographic algorithms (currently
|
||||
and
|
||||
.Nm 3DES ) .
|
||||
.It
|
||||
Can optionally perform data authentication (integrity verification) utilizing
|
||||
one of the following algorithms:
|
||||
.Nm HMAC/MD5 ,
|
||||
.Nm HMAC/SHA1 ,
|
||||
.Nm HMAC/RIPEMD160 ,
|
||||
.Nm HMAC/SHA256 ,
|
||||
.Nm HMAC/SHA384
|
||||
or
|
||||
.Nm HMAC/SHA512 .
|
||||
.It
|
||||
Can create a key from a couple of components (user entered passphrase, random
|
||||
bits from a file, etc.).
|
||||
.It
|
||||
@ -151,7 +163,7 @@ Allows to encrypt the root partition - the user will be asked for the
|
||||
passphrase before the root file system is mounted.
|
||||
.It
|
||||
The passphrase of the user is strengthened with:
|
||||
.Rs
|
||||
.Rs
|
||||
.%A B. Kaliski
|
||||
.%T "PKCS #5: Password-Based Cryptography Specification, Version 2.0."
|
||||
.%R RFC
|
||||
@ -163,7 +175,7 @@ Allows to use two independent keys (e.g.
|
||||
and
|
||||
.Qq "company key" ) .
|
||||
.It
|
||||
It is fast -
|
||||
It is fast -
|
||||
.Nm
|
||||
performs simple sector-to-sector encryption.
|
||||
.It
|
||||
@ -177,6 +189,8 @@ the file systems).
|
||||
.It
|
||||
Allows to attach a provider with a random, one-time key - useful for swap
|
||||
partitions and temporary file systems.
|
||||
.It
|
||||
Allows to verify data integrity (data authentication).
|
||||
.El
|
||||
.Pp
|
||||
The first argument to
|
||||
@ -189,8 +203,23 @@ Here you can set up the cryptographic algorithm to use, key length, etc.
|
||||
The last provider's sector is used to store metadata.
|
||||
.Pp
|
||||
Additional options include:
|
||||
.Bl -tag -width ".Fl a Ar algo"
|
||||
.It Fl a Ar algo
|
||||
.Bl -tag -width ".Fl a Ar aalgo"
|
||||
.It Fl a Ar aalgo
|
||||
Enable data integrity verification (authentication) using the given algorithm.
|
||||
This will reduce size of available storage and also reduce speed.
|
||||
For example, when using 4096 bytes sector and
|
||||
.Nm HMAC/SHA256
|
||||
algorithm, 89% of the original provider storage will be available for use.
|
||||
Currently supported algorithms are:
|
||||
.Nm HMAC/MD5 ,
|
||||
.Nm HMAC/SHA1 ,
|
||||
.Nm HMAC/RIPEMD160 ,
|
||||
.Nm HMAC/SHA256 ,
|
||||
.Nm HMAC/SHA384
|
||||
and
|
||||
.Nm HMAC/SHA512 .
|
||||
If the option is not given, there will be no authentication, only encryption.
|
||||
.It Fl e Ar ealgo
|
||||
Encryption algorithm to use.
|
||||
Currently supported algorithms are:
|
||||
.Nm AES ,
|
||||
@ -259,6 +288,9 @@ Probably a better choice is the
|
||||
option for the
|
||||
.Cm detach
|
||||
subcommand.
|
||||
.It Fl r
|
||||
Attach read-only provider.
|
||||
It will not be opened for writing.
|
||||
.It Fl k Ar keyfile
|
||||
Specifies a file which contains part of the key.
|
||||
For more information see the description of the
|
||||
@ -289,8 +321,13 @@ Attach the given providers with random, one-time keys.
|
||||
The command can be used to encrypt swap partitions or temporary file systems.
|
||||
.Pp
|
||||
Additional options include:
|
||||
.Bl -tag -width ".Fl a Ar algo"
|
||||
.It Fl a Ar algo
|
||||
.Bl -tag -width ".Fl a Ar aalgo"
|
||||
.It Fl a Ar aalgo
|
||||
Enable data integrity verification (authentication).
|
||||
For more information, see the description of the
|
||||
.Cm init
|
||||
subcommand.
|
||||
.It Fl e Ar ealgo
|
||||
Encryption algorithm to use.
|
||||
For more information, see the description of the
|
||||
.Cm init
|
||||
@ -415,6 +452,8 @@ variables can be used to control the behavior of the
|
||||
.Nm ELI
|
||||
GEOM class.
|
||||
The default value is shown next to each variable.
|
||||
All variables can also be set in
|
||||
.Pa /boot/loader.conf .
|
||||
.Bl -tag -width indent
|
||||
.It Va kern.geom.eli.debug : No 0
|
||||
Debug level of the
|
||||
@ -424,8 +463,6 @@ This can be set to a number between 0 and 3 inclusive.
|
||||
If set to 0, minimal debug information is printed.
|
||||
If set to 3, the
|
||||
maximum amount of debug information is printed.
|
||||
This variable could be set in
|
||||
.Pa /boot/loader.conf .
|
||||
.It Va kern.geom.eli.tries : No 3
|
||||
Number of times a user is asked for the passphrase.
|
||||
This is only used for providers which should be attached on boot
|
||||
@ -451,8 +488,11 @@ cryptography.
|
||||
Its purpose is to increase performance on SMP systems.
|
||||
If hardware acceleration is available, only one thread will be started.
|
||||
If set to 0, CPU-bound thread will be started for every active CPU.
|
||||
This variable could be set in
|
||||
.Pa /boot/loader.conf .
|
||||
.It Va kern.geom.eli.batch : No 0
|
||||
When set to 1, can speed-up crypto operations by using batching.
|
||||
Batching allows to reduce number of interrupts by responding on a group of
|
||||
crypto requests with one interrupt.
|
||||
The crypto card and the driver has to support this feature.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
Exit status is 0 on success, and 1 if the command fails.
|
||||
@ -508,7 +548,7 @@ Reenter new passphrase:
|
||||
Encrypted swap partition setup:
|
||||
.Bd -literal -offset indent
|
||||
# dd if=/dev/random of=/dev/ad0s1b bs=1m
|
||||
# geli onetime -d -a 3des ad0s1b
|
||||
# geli onetime -d -e 3des ad0s1b
|
||||
# swapon /dev/ad0s1b.eli
|
||||
.Ed
|
||||
.Pp
|
||||
@ -546,6 +586,38 @@ geli_da1s3a_keyfile0_load="YES"
|
||||
geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0"
|
||||
geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key"
|
||||
.Ed
|
||||
.Pp
|
||||
Not only configure encryption, but also data integrity verification using
|
||||
.Nm HMAC/SHA256 .
|
||||
.Bd -literal -offset indent
|
||||
# geli init -a hmac/sha256 -s 4096 /dev/da0
|
||||
Enter new passphrase:
|
||||
Reenter new passphrase:
|
||||
# geli attach /dev/da0
|
||||
Enter passphrase:
|
||||
# dd if=/dev/random of=/dev/da0.eli bs=1m
|
||||
# newfs /dev/da0.eli
|
||||
# mount /dev/da0.eli /mnt/secret
|
||||
.Ed
|
||||
.Sh DATA AUTHENTICATION
|
||||
.Nm
|
||||
can verify data integrity when an authentication algorithm is specified.
|
||||
When data corruption/modification is detected,
|
||||
.Nm
|
||||
will not return any data, but instead will return an error
|
||||
.Pq Er EINVAL .
|
||||
The offset and size of the corrupted data will be printed on the console.
|
||||
It is important to know against which attacks
|
||||
.Nm
|
||||
provides protection for your data.
|
||||
If data is modified or copied from one place on the disk
|
||||
to another,
|
||||
.Nm
|
||||
should be able to detect such a modification.
|
||||
If an attacker can remember the encrypted data, modify them and write them
|
||||
back to the same place, the modification will not be detected.
|
||||
.Nm
|
||||
will not protect your data against replay attacks.
|
||||
.Sh SEE ALSO
|
||||
.Xr crypto 4 ,
|
||||
.Xr gbde 4 ,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -54,7 +54,8 @@ __FBSDID("$FreeBSD$");
|
||||
uint32_t lib_version = G_LIB_VERSION;
|
||||
uint32_t version = G_ELI_VERSION;
|
||||
|
||||
static char algo[] = "aes";
|
||||
static char aalgo[] = "none";
|
||||
static char ealgo[] = "aes";
|
||||
static intmax_t keylen = 0;
|
||||
static intmax_t keyno = -1;
|
||||
static intmax_t iterations = -1;
|
||||
@ -75,12 +76,12 @@ static void eli_dump(struct gctl_req *req);
|
||||
/*
|
||||
* Available commands:
|
||||
*
|
||||
* init [-bhPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] prov
|
||||
* init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
|
||||
* label - alias for 'init'
|
||||
* attach [-dpv] [-k keyfile] prov
|
||||
* attach [-dprv] [-k keyfile] prov
|
||||
* detach [-fl] prov ...
|
||||
* stop - alias for 'detach'
|
||||
* onetime [-d] [-a algo] [-l keylen] prov ...
|
||||
* onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
|
||||
* setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
|
||||
* delkey [-afv] [-n keyno] prov
|
||||
* kill [-av] [prov ...]
|
||||
@ -92,8 +93,9 @@ static void eli_dump(struct gctl_req *req);
|
||||
struct g_command class_commands[] = {
|
||||
{ "init", G_FLAG_VERBOSE, eli_main,
|
||||
{
|
||||
{ 'a', "algo", algo, G_TYPE_STRING },
|
||||
{ 'a', "aalgo", aalgo, G_TYPE_STRING },
|
||||
{ 'b', "boot", NULL, G_TYPE_NONE },
|
||||
{ 'e', "ealgo", ealgo, G_TYPE_STRING },
|
||||
{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
|
||||
{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
|
||||
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
||||
@ -101,12 +103,13 @@ struct g_command class_commands[] = {
|
||||
{ 's', "sectorsize", §orsize, G_TYPE_NUMBER },
|
||||
G_OPT_SENTINEL
|
||||
},
|
||||
"[-bPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
|
||||
"[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
|
||||
},
|
||||
{ "label", G_FLAG_VERBOSE, eli_main,
|
||||
{
|
||||
{ 'a', "algo", algo, G_TYPE_STRING },
|
||||
{ 'a', "aalgo", aalgo, G_TYPE_STRING },
|
||||
{ 'b', "boot", NULL, G_TYPE_NONE },
|
||||
{ 'e', "ealgo", ealgo, G_TYPE_STRING },
|
||||
{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
|
||||
{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
|
||||
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
||||
@ -121,9 +124,10 @@ struct g_command class_commands[] = {
|
||||
{ 'd', "detach", NULL, G_TYPE_NONE },
|
||||
{ 'k', "keyfile", keyfile, G_TYPE_STRING },
|
||||
{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
|
||||
{ 'r', "readonly", NULL, G_TYPE_NONE },
|
||||
G_OPT_SENTINEL
|
||||
},
|
||||
"[-dpv] [-k keyfile] prov"
|
||||
"[-dprv] [-k keyfile] prov"
|
||||
},
|
||||
{ "detach", 0, NULL,
|
||||
{
|
||||
@ -143,13 +147,14 @@ struct g_command class_commands[] = {
|
||||
},
|
||||
{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
|
||||
{
|
||||
{ 'a', "algo", algo, G_TYPE_STRING },
|
||||
{ 'a', "aalgo", aalgo, G_TYPE_STRING },
|
||||
{ 'd', "detach", NULL, G_TYPE_NONE },
|
||||
{ 'e', "ealgo", ealgo, G_TYPE_STRING },
|
||||
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
||||
{ 's', "sectorsize", §orsize, G_TYPE_NUMBER },
|
||||
G_OPT_SENTINEL
|
||||
},
|
||||
"[-d] [-a algo] [-l keylen] [-s sectorsize] prov ..."
|
||||
"[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..."
|
||||
},
|
||||
{ "setkey", G_FLAG_VERBOSE, eli_main,
|
||||
{
|
||||
@ -389,7 +394,7 @@ eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If md_iterations is equal to 0, user don't want PKCS5v2.
|
||||
* If md_iterations is equal to 0, user don't want PKCS#5v2.
|
||||
*/
|
||||
if (md->md_iterations == 0) {
|
||||
g_eli_crypto_hmac_update(&ctx, md->md_salt,
|
||||
@ -523,16 +528,44 @@ eli_init(struct gctl_req *req)
|
||||
md.md_flags = 0;
|
||||
if (gctl_get_int(req, "boot"))
|
||||
md.md_flags |= G_ELI_FLAG_BOOT;
|
||||
str = gctl_get_ascii(req, "algo");
|
||||
md.md_algo = g_eli_str2algo(str);
|
||||
if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_algo > CRYPTO_ALGORITHM_MAX) {
|
||||
gctl_error(req, "Invalid encryption algorithm.");
|
||||
return;
|
||||
md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
|
||||
str = gctl_get_ascii(req, "aalgo");
|
||||
if (strcmp(str, "none") != 0) {
|
||||
md.md_aalgo = g_eli_str2aalgo(str);
|
||||
if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
|
||||
md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
|
||||
md.md_flags |= G_ELI_FLAG_AUTH;
|
||||
} else {
|
||||
/*
|
||||
* For backward compatibility, check if the -a option
|
||||
* was used to provide encryption algorithm.
|
||||
*/
|
||||
md.md_ealgo = g_eli_str2ealgo(str);
|
||||
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
|
||||
gctl_error(req,
|
||||
"Invalid authentication algorithm.");
|
||||
return;
|
||||
} else {
|
||||
fprintf(stderr, "warning: The -e option, not "
|
||||
"the -a option is now used to specify "
|
||||
"encryption algorithm to use.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
|
||||
str = gctl_get_ascii(req, "ealgo");
|
||||
md.md_ealgo = g_eli_str2ealgo(str);
|
||||
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
|
||||
gctl_error(req, "Invalid encryption algorithm.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
val = gctl_get_intmax(req, "keylen");
|
||||
md.md_keylen = val;
|
||||
md.md_keylen = g_eli_keylen(md.md_algo, md.md_keylen);
|
||||
md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
|
||||
if (md.md_keylen == 0) {
|
||||
gctl_error(req, "Invalid key length.");
|
||||
return;
|
||||
@ -579,7 +612,7 @@ eli_init(struct gctl_req *req)
|
||||
}
|
||||
|
||||
/* Encrypt the first and the only Master Key. */
|
||||
error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, md.md_mkeys);
|
||||
error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
|
||||
bzero(key, sizeof(key));
|
||||
if (error != 0) {
|
||||
bzero(&md, sizeof(md));
|
||||
@ -733,7 +766,7 @@ eli_setkey_detached(struct gctl_req *req, const char *prov,
|
||||
}
|
||||
|
||||
/* Encrypt the Master-Key with the new key. */
|
||||
error = g_eli_mkey_encrypt(md->md_algo, key, md->md_keylen, mkeydst);
|
||||
error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
|
||||
bzero(key, sizeof(key));
|
||||
if (error != 0) {
|
||||
bzero(md, sizeof(*md));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -69,16 +69,20 @@ SYSCTL_UINT(_kern_geom_eli, OID_AUTO, visible_passphrase, CTLFLAG_RW,
|
||||
&g_eli_visible_passphrase, 0,
|
||||
"Turn on echo when entering the passphrase (for debug purposes only!!)");
|
||||
u_int g_eli_overwrites = 5;
|
||||
TUNABLE_INT("kern.geom.eli.overwrites", &g_eli_overwrites);
|
||||
SYSCTL_UINT(_kern_geom_eli, OID_AUTO, overwrites, CTLFLAG_RW, &g_eli_overwrites,
|
||||
0, "Number of times on-disk keys should be overwritten when destroying them");
|
||||
static u_int g_eli_threads = 0;
|
||||
TUNABLE_INT("kern.geom.eli.threads", &g_eli_threads);
|
||||
SYSCTL_UINT(_kern_geom_eli, OID_AUTO, threads, CTLFLAG_RW, &g_eli_threads, 0,
|
||||
"Number of threads doing crypto work");
|
||||
u_int g_eli_batch = 0;
|
||||
TUNABLE_INT("kern.geom.eli.batch", &g_eli_batch);
|
||||
SYSCTL_UINT(_kern_geom_eli, OID_AUTO, batch, CTLFLAG_RW, &g_eli_batch, 0,
|
||||
"Use crypto operations batching");
|
||||
|
||||
static int g_eli_destroy_geom(struct gctl_req *req, struct g_class *mp,
|
||||
struct g_geom *gp);
|
||||
static void g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp);
|
||||
|
||||
static g_taste_t g_eli_taste;
|
||||
static g_dumpconf_t g_eli_dumpconf;
|
||||
@ -106,7 +110,7 @@ struct g_class g_eli_class = {
|
||||
* accelerator or something like this.
|
||||
* The function updates the SID and rerun the operation.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
g_eli_crypto_rerun(struct cryptop *crp)
|
||||
{
|
||||
struct g_eli_softc *sc;
|
||||
@ -139,7 +143,7 @@ g_eli_crypto_rerun(struct cryptop *crp)
|
||||
*
|
||||
* g_eli_start -> g_io_request -> G_ELI_READ_DONE -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver
|
||||
*/
|
||||
static void
|
||||
void
|
||||
g_eli_read_done(struct bio *bp)
|
||||
{
|
||||
struct g_eli_softc *sc;
|
||||
@ -149,10 +153,20 @@ g_eli_read_done(struct bio *bp)
|
||||
pbp = bp->bio_parent;
|
||||
if (pbp->bio_error == 0)
|
||||
pbp->bio_error = bp->bio_error;
|
||||
/*
|
||||
* Do we have all sectors already?
|
||||
*/
|
||||
pbp->bio_inbed++;
|
||||
if (pbp->bio_inbed < pbp->bio_children)
|
||||
return;
|
||||
g_destroy_bio(bp);
|
||||
if (pbp->bio_error != 0) {
|
||||
G_ELI_LOGREQ(0, pbp, "%s() failed", __func__);
|
||||
pbp->bio_completed = 0;
|
||||
if (pbp->bio_driver2 != NULL) {
|
||||
free(pbp->bio_driver2, M_ELI);
|
||||
pbp->bio_driver2 = NULL;
|
||||
}
|
||||
g_io_deliver(pbp, pbp->bio_error);
|
||||
return;
|
||||
}
|
||||
@ -163,70 +177,31 @@ g_eli_read_done(struct bio *bp)
|
||||
wakeup(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* The function is called after we read and decrypt data.
|
||||
*
|
||||
* g_eli_start -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> G_ELI_CRYPTO_READ_DONE -> g_io_deliver
|
||||
*/
|
||||
static int
|
||||
g_eli_crypto_read_done(struct cryptop *crp)
|
||||
{
|
||||
struct bio *bp;
|
||||
|
||||
if (crp->crp_etype == EAGAIN) {
|
||||
if (g_eli_crypto_rerun(crp) == 0)
|
||||
return (0);
|
||||
}
|
||||
bp = (struct bio *)crp->crp_opaque;
|
||||
bp->bio_inbed++;
|
||||
if (crp->crp_etype == 0) {
|
||||
G_ELI_DEBUG(3, "Crypto READ request done (%d/%d).",
|
||||
bp->bio_inbed, bp->bio_children);
|
||||
bp->bio_completed += crp->crp_olen;
|
||||
} else {
|
||||
G_ELI_DEBUG(1, "Crypto READ request failed (%d/%d) error=%d.",
|
||||
bp->bio_inbed, bp->bio_children, crp->crp_etype);
|
||||
if (bp->bio_error == 0)
|
||||
bp->bio_error = crp->crp_etype;
|
||||
}
|
||||
/*
|
||||
* Do we have all sectors already?
|
||||
*/
|
||||
if (bp->bio_inbed < bp->bio_children)
|
||||
return (0);
|
||||
free(bp->bio_driver2, M_ELI);
|
||||
bp->bio_driver2 = NULL;
|
||||
if (bp->bio_error != 0) {
|
||||
G_ELI_LOGREQ(0, bp, "Crypto READ request failed (error=%d).",
|
||||
bp->bio_error);
|
||||
bp->bio_completed = 0;
|
||||
}
|
||||
/*
|
||||
* Read is finished, send it up.
|
||||
*/
|
||||
g_io_deliver(bp, bp->bio_error);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The function is called after we encrypt and write data.
|
||||
*
|
||||
* g_eli_start -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> G_ELI_WRITE_DONE -> g_io_deliver
|
||||
*/
|
||||
static void
|
||||
void
|
||||
g_eli_write_done(struct bio *bp)
|
||||
{
|
||||
struct bio *pbp;
|
||||
|
||||
G_ELI_LOGREQ(2, bp, "Request done.");
|
||||
pbp = bp->bio_parent;
|
||||
if (pbp->bio_error == 0)
|
||||
pbp->bio_error = bp->bio_error;
|
||||
if (pbp->bio_error == 0) {
|
||||
if (bp->bio_error != 0)
|
||||
pbp->bio_error = bp->bio_error;
|
||||
}
|
||||
/*
|
||||
* Do we have all sectors already?
|
||||
*/
|
||||
pbp->bio_inbed++;
|
||||
if (pbp->bio_inbed < pbp->bio_children)
|
||||
return;
|
||||
free(pbp->bio_driver2, M_ELI);
|
||||
pbp->bio_driver2 = NULL;
|
||||
if (pbp->bio_error == 0)
|
||||
pbp->bio_completed = pbp->bio_length;
|
||||
else {
|
||||
if (pbp->bio_error != 0) {
|
||||
G_ELI_LOGREQ(0, pbp, "Crypto WRITE request failed (error=%d).",
|
||||
pbp->bio_error);
|
||||
pbp->bio_completed = 0;
|
||||
@ -235,67 +210,10 @@ g_eli_write_done(struct bio *bp)
|
||||
/*
|
||||
* Write is finished, send it up.
|
||||
*/
|
||||
pbp->bio_completed = pbp->bio_length;
|
||||
g_io_deliver(pbp, pbp->bio_error);
|
||||
}
|
||||
|
||||
/*
|
||||
* The function is called after data encryption.
|
||||
*
|
||||
* g_eli_start -> g_eli_crypto_run -> G_ELI_CRYPTO_WRITE_DONE -> g_io_request -> g_eli_write_done -> g_io_deliver
|
||||
*/
|
||||
static int
|
||||
g_eli_crypto_write_done(struct cryptop *crp)
|
||||
{
|
||||
struct g_geom *gp;
|
||||
struct g_consumer *cp;
|
||||
struct bio *bp, *cbp;
|
||||
|
||||
if (crp->crp_etype == EAGAIN) {
|
||||
if (g_eli_crypto_rerun(crp) == 0)
|
||||
return (0);
|
||||
}
|
||||
bp = (struct bio *)crp->crp_opaque;
|
||||
bp->bio_inbed++;
|
||||
if (crp->crp_etype == 0) {
|
||||
G_ELI_DEBUG(3, "Crypto WRITE request done (%d/%d).",
|
||||
bp->bio_inbed, bp->bio_children);
|
||||
} else {
|
||||
G_ELI_DEBUG(1, "Crypto WRITE request failed (%d/%d) error=%d.",
|
||||
bp->bio_inbed, bp->bio_children, crp->crp_etype);
|
||||
if (bp->bio_error == 0)
|
||||
bp->bio_error = crp->crp_etype;
|
||||
}
|
||||
/*
|
||||
* All sectors are already encrypted?
|
||||
*/
|
||||
if (bp->bio_inbed < bp->bio_children)
|
||||
return (0);
|
||||
bp->bio_inbed = 0;
|
||||
bp->bio_children = 1;
|
||||
cbp = bp->bio_driver1;
|
||||
bp->bio_driver1 = NULL;
|
||||
if (bp->bio_error != 0) {
|
||||
G_ELI_LOGREQ(0, bp, "Crypto WRITE request failed (error=%d).",
|
||||
bp->bio_error);
|
||||
free(bp->bio_driver2, M_ELI);
|
||||
bp->bio_driver2 = NULL;
|
||||
g_destroy_bio(cbp);
|
||||
g_io_deliver(bp, bp->bio_error);
|
||||
return (0);
|
||||
}
|
||||
cbp->bio_data = bp->bio_driver2;
|
||||
cbp->bio_done = g_eli_write_done;
|
||||
gp = bp->bio_to->geom;
|
||||
cp = LIST_FIRST(&gp->consumer);
|
||||
cbp->bio_to = cp->provider;
|
||||
G_ELI_LOGREQ(2, cbp, "Sending request.");
|
||||
/*
|
||||
* Send encrypted data to the provider.
|
||||
*/
|
||||
g_io_request(cbp, cp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function should never be called, but GEOM made as it set ->orphan()
|
||||
* method for every geom.
|
||||
@ -358,15 +276,20 @@ g_eli_start(struct bio *bp)
|
||||
}
|
||||
switch (bp->bio_cmd) {
|
||||
case BIO_READ:
|
||||
cbp->bio_done = g_eli_read_done;
|
||||
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||
cbp->bio_to = cp->provider;
|
||||
G_ELI_LOGREQ(2, cbp, "Sending request.");
|
||||
/*
|
||||
* Read encrypted data from provider.
|
||||
*/
|
||||
g_io_request(cbp, cp);
|
||||
break;
|
||||
if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) {
|
||||
bp->bio_driver2 = NULL;
|
||||
cbp->bio_done = g_eli_read_done;
|
||||
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||
cbp->bio_to = cp->provider;
|
||||
G_ELI_LOGREQ(2, cbp, "Sending request.");
|
||||
/*
|
||||
* Read encrypted data from provider.
|
||||
*/
|
||||
g_io_request(cbp, cp);
|
||||
break;
|
||||
}
|
||||
bp->bio_pflags = 255;
|
||||
/* FALLTHROUGH */
|
||||
case BIO_WRITE:
|
||||
bp->bio_driver1 = cbp;
|
||||
mtx_lock(&sc->sc_queue_mtx);
|
||||
@ -411,7 +334,7 @@ g_eli_worker(void *arg)
|
||||
mtx_lock(&sc->sc_queue_mtx);
|
||||
bp = bioq_takefirst(&sc->sc_queue);
|
||||
if (bp == NULL) {
|
||||
if ((sc->sc_flags & G_ELI_FLAG_DESTROY) != 0) {
|
||||
if (sc->sc_flags & G_ELI_FLAG_DESTROY) {
|
||||
LIST_REMOVE(wr, w_next);
|
||||
crypto_freesession(wr->w_sid);
|
||||
free(wr, M_ELI);
|
||||
@ -426,20 +349,27 @@ g_eli_worker(void *arg)
|
||||
continue;
|
||||
}
|
||||
mtx_unlock(&sc->sc_queue_mtx);
|
||||
g_eli_crypto_run(wr, bp);
|
||||
if (bp->bio_cmd == BIO_READ && bp->bio_pflags == 255)
|
||||
g_eli_auth_read(sc, bp);
|
||||
else if (sc->sc_flags & G_ELI_FLAG_AUTH)
|
||||
g_eli_auth_run(wr, bp);
|
||||
else
|
||||
g_eli_crypto_run(wr, bp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we generate IV. It is unique for every sector.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv,
|
||||
size_t size)
|
||||
{
|
||||
u_char hash[SHA256_DIGEST_LENGTH];
|
||||
u_char off[8], hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256_CTX ctx;
|
||||
|
||||
if (!(sc->sc_flags & G_ELI_FLAG_NATIVE_BYTE_ORDER))
|
||||
le64enc(off, (uint64_t)offset);
|
||||
/* Copy precalculated SHA256 context for IV-Key. */
|
||||
bcopy(&sc->sc_ivctx, &ctx, sizeof(ctx));
|
||||
SHA256_Update(&ctx, (uint8_t *)&offset, sizeof(offset));
|
||||
@ -447,110 +377,6 @@ g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv,
|
||||
bcopy(hash, iv, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main function responsible for cryptography (ie. communication
|
||||
* with crypto(9) subsystem).
|
||||
*/
|
||||
static void
|
||||
g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp)
|
||||
{
|
||||
struct g_eli_softc *sc;
|
||||
struct cryptop *crp;
|
||||
struct cryptodesc *crd;
|
||||
struct uio *uio;
|
||||
struct iovec *iov;
|
||||
u_int i, nsec, add, secsize;
|
||||
int err, error;
|
||||
size_t size;
|
||||
u_char *p, *data;
|
||||
|
||||
G_ELI_LOGREQ(3, bp, "%s", __func__);
|
||||
|
||||
bp->bio_pflags = wr->w_number;
|
||||
sc = wr->w_softc;
|
||||
secsize = LIST_FIRST(&sc->sc_geom->provider)->sectorsize;
|
||||
nsec = bp->bio_length / secsize;
|
||||
|
||||
/*
|
||||
* Calculate how much memory do we need.
|
||||
* We need separate crypto operation for every single sector.
|
||||
* It is much faster to calculate total amount of needed memory here and
|
||||
* do the allocation once instead of allocating memory in pieces (many,
|
||||
* many pieces).
|
||||
*/
|
||||
size = sizeof(*crp) * nsec;
|
||||
size += sizeof(*crd) * nsec;
|
||||
size += sizeof(*uio) * nsec;
|
||||
size += sizeof(*iov) * nsec;
|
||||
/*
|
||||
* If we write the data we cannot destroy current bio_data content,
|
||||
* so we need to allocate more memory for encrypted data.
|
||||
*/
|
||||
if (bp->bio_cmd == BIO_WRITE)
|
||||
size += bp->bio_length;
|
||||
p = malloc(size, M_ELI, M_WAITOK);
|
||||
|
||||
bp->bio_inbed = 0;
|
||||
bp->bio_children = nsec;
|
||||
bp->bio_driver2 = p;
|
||||
|
||||
if (bp->bio_cmd == BIO_READ)
|
||||
data = bp->bio_data;
|
||||
else {
|
||||
data = p;
|
||||
p += bp->bio_length;
|
||||
bcopy(bp->bio_data, data, bp->bio_length);
|
||||
}
|
||||
|
||||
error = 0;
|
||||
for (i = 0, add = 0; i < nsec; i++, add += secsize) {
|
||||
crp = (struct cryptop *)p; p += sizeof(*crp);
|
||||
crd = (struct cryptodesc *)p; p += sizeof(*crd);
|
||||
uio = (struct uio *)p; p += sizeof(*uio);
|
||||
iov = (struct iovec *)p; p += sizeof(*iov);
|
||||
|
||||
iov->iov_len = secsize;
|
||||
iov->iov_base = data;
|
||||
data += secsize;
|
||||
|
||||
uio->uio_iov = iov;
|
||||
uio->uio_iovcnt = 1;
|
||||
uio->uio_segflg = UIO_SYSSPACE;
|
||||
uio->uio_resid = secsize;
|
||||
|
||||
crp->crp_sid = wr->w_sid;
|
||||
crp->crp_ilen = secsize;
|
||||
crp->crp_olen = secsize;
|
||||
crp->crp_opaque = (void *)bp;
|
||||
crp->crp_buf = (void *)uio;
|
||||
if (bp->bio_cmd == BIO_WRITE)
|
||||
crp->crp_callback = g_eli_crypto_write_done;
|
||||
else /* if (bp->bio_cmd == BIO_READ) */
|
||||
crp->crp_callback = g_eli_crypto_read_done;
|
||||
crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIFSYNC | CRYPTO_F_REL;
|
||||
crp->crp_desc = crd;
|
||||
|
||||
crd->crd_skip = 0;
|
||||
crd->crd_len = secsize;
|
||||
crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
|
||||
if (bp->bio_cmd == BIO_WRITE)
|
||||
crd->crd_flags |= CRD_F_ENCRYPT;
|
||||
crd->crd_alg = sc->sc_algo;
|
||||
crd->crd_key = sc->sc_datakey;
|
||||
crd->crd_klen = sc->sc_keylen;
|
||||
g_eli_crypto_ivgen(sc, bp->bio_offset + add, crd->crd_iv,
|
||||
sizeof(crd->crd_iv));
|
||||
crd->crd_next = NULL;
|
||||
|
||||
crp->crp_etype = 0;
|
||||
err = crypto_dispatch(crp);
|
||||
if (error == 0)
|
||||
error = err;
|
||||
}
|
||||
if (bp->bio_error == 0)
|
||||
bp->bio_error = error;
|
||||
}
|
||||
|
||||
int
|
||||
g_eli_read_metadata(struct g_class *mp, struct g_provider *pp,
|
||||
struct g_eli_metadata *md)
|
||||
@ -631,6 +457,10 @@ g_eli_access(struct g_provider *pp, int dr, int dw, int de)
|
||||
sc = gp->softc;
|
||||
|
||||
if (dw > 0) {
|
||||
if (sc->sc_flags & G_ELI_FLAG_RO) {
|
||||
/* Deny write attempts. */
|
||||
return (EROFS);
|
||||
}
|
||||
/* Someone is opening us for write, we need to remember that. */
|
||||
sc->sc_flags |= G_ELI_FLAG_WOPEN;
|
||||
return (0);
|
||||
@ -658,7 +488,7 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
|
||||
struct g_geom *gp;
|
||||
struct g_provider *pp;
|
||||
struct g_consumer *cp;
|
||||
struct cryptoini cri;
|
||||
struct cryptoini crie, cria;
|
||||
u_int i, threads;
|
||||
int error;
|
||||
|
||||
@ -671,31 +501,60 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
|
||||
gp->start = g_eli_start;
|
||||
/*
|
||||
* Spoiling cannot happen actually, because we keep provider open for
|
||||
* writing all the time.
|
||||
* writing all the time or provider is read-only.
|
||||
*/
|
||||
gp->spoiled = g_eli_orphan_spoil_assert;
|
||||
gp->orphan = g_eli_orphan;
|
||||
gp->dumpconf = g_eli_dumpconf;
|
||||
/*
|
||||
* If detach-on-last-close feature is not enabled, we can simply use
|
||||
* g_std_access().
|
||||
* If detach-on-last-close feature is not enabled and we don't operate
|
||||
* on read-only provider, we can simply use g_std_access().
|
||||
*/
|
||||
if (md->md_flags & G_ELI_FLAG_WO_DETACH)
|
||||
if (md->md_flags & (G_ELI_FLAG_WO_DETACH | G_ELI_FLAG_RO))
|
||||
gp->access = g_eli_access;
|
||||
else
|
||||
gp->access = g_std_access;
|
||||
gp->dumpconf = g_eli_dumpconf;
|
||||
|
||||
sc->sc_crypto = G_ELI_CRYPTO_SW;
|
||||
sc->sc_flags = md->md_flags;
|
||||
sc->sc_algo = md->md_algo;
|
||||
/* Backward compatibility. */
|
||||
if (md->md_version < 2)
|
||||
sc->sc_flags |= G_ELI_FLAG_NATIVE_BYTE_ORDER;
|
||||
sc->sc_ealgo = md->md_ealgo;
|
||||
sc->sc_nkey = nkey;
|
||||
/*
|
||||
* Remember the keys in our softc structure.
|
||||
*/
|
||||
bcopy(mkey, sc->sc_ivkey, sizeof(sc->sc_ivkey));
|
||||
mkey += sizeof(sc->sc_ivkey);
|
||||
bcopy(mkey, sc->sc_datakey, sizeof(sc->sc_datakey));
|
||||
sc->sc_keylen = md->md_keylen;
|
||||
g_eli_mkey_propagate(sc, mkey);
|
||||
sc->sc_ekeylen = md->md_keylen;
|
||||
|
||||
if (sc->sc_flags & G_ELI_FLAG_AUTH) {
|
||||
sc->sc_akeylen = sizeof(sc->sc_akey) * 8;
|
||||
sc->sc_aalgo = md->md_aalgo;
|
||||
sc->sc_alen = g_eli_hashlen(sc->sc_aalgo);
|
||||
|
||||
sc->sc_data_per_sector = bpp->sectorsize - sc->sc_alen;
|
||||
/*
|
||||
* Some hash functions (like SHA1 and RIPEMD160) generates hash
|
||||
* which length is not multiple of 128 bits, but we want data
|
||||
* length to be multiple of 128, so we can encrypt without
|
||||
* padding. The line below rounds down data length to multiple
|
||||
* of 128 bits.
|
||||
*/
|
||||
sc->sc_data_per_sector -= sc->sc_data_per_sector % 16;
|
||||
|
||||
sc->sc_bytes_per_sector =
|
||||
(md->md_sectorsize - 1) / sc->sc_data_per_sector + 1;
|
||||
sc->sc_bytes_per_sector *= bpp->sectorsize;
|
||||
/*
|
||||
* Precalculate SHA256 for HMAC key generation.
|
||||
* This is expensive operation and we can do it only once now or
|
||||
* for every access to sector, so now will be much better.
|
||||
*/
|
||||
SHA256_Init(&sc->sc_akeyctx);
|
||||
SHA256_Update(&sc->sc_akeyctx, sc->sc_akey,
|
||||
sizeof(sc->sc_akey));
|
||||
}
|
||||
|
||||
/*
|
||||
* Precalculate SHA256 for IV generation.
|
||||
@ -728,8 +587,13 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
|
||||
* Keep provider open all the time, so we can run critical tasks,
|
||||
* like Master Keys deletion, without wondering if we can open
|
||||
* provider or not.
|
||||
* We don't open provider for writing only when user requested read-only
|
||||
* access.
|
||||
*/
|
||||
error = g_access(cp, 1, 1, 1);
|
||||
if (sc->sc_flags & G_ELI_FLAG_RO)
|
||||
error = g_access(cp, 1, 0, 1);
|
||||
else
|
||||
error = g_access(cp, 1, 1, 1);
|
||||
if (error != 0) {
|
||||
if (req != NULL) {
|
||||
gctl_error(req, "Cannot access %s (error=%d).",
|
||||
@ -743,10 +607,17 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
|
||||
|
||||
LIST_INIT(&sc->sc_workers);
|
||||
|
||||
bzero(&cri, sizeof(cri));
|
||||
cri.cri_alg = sc->sc_algo;
|
||||
cri.cri_klen = sc->sc_keylen;
|
||||
cri.cri_key = sc->sc_datakey;
|
||||
bzero(&crie, sizeof(crie));
|
||||
crie.cri_alg = sc->sc_ealgo;
|
||||
crie.cri_klen = sc->sc_ekeylen;
|
||||
crie.cri_key = sc->sc_ekey;
|
||||
if (sc->sc_flags & G_ELI_FLAG_AUTH) {
|
||||
bzero(&cria, sizeof(cria));
|
||||
cria.cri_alg = sc->sc_aalgo;
|
||||
cria.cri_klen = sc->sc_akeylen;
|
||||
cria.cri_key = sc->sc_akey;
|
||||
crie.cri_next = &cria;
|
||||
}
|
||||
|
||||
threads = g_eli_threads;
|
||||
if (threads == 0)
|
||||
@ -766,12 +637,12 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
|
||||
* Use software cryptography, if we cannot get it.
|
||||
*/
|
||||
if (i == 0) {
|
||||
error = crypto_newsession(&wr->w_sid, &cri, 1);
|
||||
error = crypto_newsession(&wr->w_sid, &crie, 1);
|
||||
if (error == 0)
|
||||
sc->sc_crypto = G_ELI_CRYPTO_HW;
|
||||
}
|
||||
if (sc->sc_crypto == G_ELI_CRYPTO_SW)
|
||||
error = crypto_newsession(&wr->w_sid, &cri, 0);
|
||||
error = crypto_newsession(&wr->w_sid, &crie, 0);
|
||||
if (error != 0) {
|
||||
free(wr, M_ELI);
|
||||
if (req != NULL) {
|
||||
@ -810,14 +681,22 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
|
||||
pp = g_new_providerf(gp, "%s%s", bpp->name, G_ELI_SUFFIX);
|
||||
pp->sectorsize = md->md_sectorsize;
|
||||
pp->mediasize = bpp->mediasize;
|
||||
if ((sc->sc_flags & G_ELI_FLAG_ONETIME) == 0)
|
||||
if (!(sc->sc_flags & G_ELI_FLAG_ONETIME))
|
||||
pp->mediasize -= bpp->sectorsize;
|
||||
pp->mediasize -= (pp->mediasize % pp->sectorsize);
|
||||
if (!(sc->sc_flags & G_ELI_FLAG_AUTH))
|
||||
pp->mediasize -= (pp->mediasize % pp->sectorsize);
|
||||
else {
|
||||
pp->mediasize /= sc->sc_bytes_per_sector;
|
||||
pp->mediasize *= pp->sectorsize;
|
||||
}
|
||||
|
||||
g_error_provider(pp, 0);
|
||||
|
||||
G_ELI_DEBUG(0, "Device %s created.", pp->name);
|
||||
G_ELI_DEBUG(0, " Cipher: %s", g_eli_algo2str(sc->sc_algo));
|
||||
G_ELI_DEBUG(0, "Key length: %u", sc->sc_keylen);
|
||||
G_ELI_DEBUG(0, "Encryption: %s %u", g_eli_algo2str(sc->sc_ealgo),
|
||||
sc->sc_ekeylen);
|
||||
if (sc->sc_flags & G_ELI_FLAG_AUTH)
|
||||
G_ELI_DEBUG(0, " Integrity: %s", g_eli_algo2str(sc->sc_aalgo));
|
||||
G_ELI_DEBUG(0, " Crypto: %s",
|
||||
sc->sc_crypto == G_ELI_CRYPTO_SW ? "software" : "hardware");
|
||||
return (gp);
|
||||
@ -995,7 +874,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
|
||||
if (md.md_provsize != pp->mediasize)
|
||||
return (NULL);
|
||||
/* Should we attach it on boot? */
|
||||
if ((md.md_flags & G_ELI_FLAG_BOOT) == 0)
|
||||
if (!(md.md_flags & G_ELI_FLAG_BOOT))
|
||||
return (NULL);
|
||||
if (md.md_keys == 0x00) {
|
||||
G_ELI_DEBUG(0, "No valid keys on %s.", pp->name);
|
||||
@ -1117,7 +996,7 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
|
||||
int first = 1;
|
||||
|
||||
#define ADD_FLAG(flag, name) do { \
|
||||
if ((sc->sc_flags & (flag)) != 0) { \
|
||||
if (sc->sc_flags & (flag)) { \
|
||||
if (!first) \
|
||||
sbuf_printf(sb, ", "); \
|
||||
else \
|
||||
@ -1125,17 +1004,20 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
|
||||
sbuf_printf(sb, name); \
|
||||
} \
|
||||
} while (0)
|
||||
ADD_FLAG(G_ELI_FLAG_NATIVE_BYTE_ORDER, "NATIVE-BYTE-ORDER");
|
||||
ADD_FLAG(G_ELI_FLAG_ONETIME, "ONETIME");
|
||||
ADD_FLAG(G_ELI_FLAG_BOOT, "BOOT");
|
||||
ADD_FLAG(G_ELI_FLAG_WO_DETACH, "W-DETACH");
|
||||
ADD_FLAG(G_ELI_FLAG_RW_DETACH, "RW-DETACH");
|
||||
ADD_FLAG(G_ELI_FLAG_AUTH, "AUTH");
|
||||
ADD_FLAG(G_ELI_FLAG_WOPEN, "W-OPEN");
|
||||
ADD_FLAG(G_ELI_FLAG_DESTROY, "DESTROY");
|
||||
ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY");
|
||||
#undef ADD_FLAG
|
||||
}
|
||||
sbuf_printf(sb, "</Flags>\n");
|
||||
|
||||
if ((sc->sc_flags & G_ELI_FLAG_ONETIME) == 0) {
|
||||
if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
|
||||
sbuf_printf(sb, "%s<UsedKey>%u</UsedKey>\n", indent,
|
||||
sc->sc_nkey);
|
||||
}
|
||||
@ -1152,9 +1034,15 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
|
||||
break;
|
||||
}
|
||||
sbuf_printf(sb, "</Crypto>\n");
|
||||
sbuf_printf(sb, "%s<KeyLength>%u</KeyLength>\n", indent, sc->sc_keylen);
|
||||
sbuf_printf(sb, "%s<Cipher>%s</Cipher>\n", indent,
|
||||
g_eli_algo2str(sc->sc_algo));
|
||||
if (sc->sc_flags & G_ELI_FLAG_AUTH) {
|
||||
sbuf_printf(sb,
|
||||
"%s<AuthenticationAlgorithm>%s</AuthenticationAlgorithm>\n",
|
||||
indent, g_eli_algo2str(sc->sc_aalgo));
|
||||
}
|
||||
sbuf_printf(sb, "%s<KeyLength>%u</KeyLength>\n", indent,
|
||||
sc->sc_ekeylen);
|
||||
sbuf_printf(sb, "%s<EncryptionAlgorithm>%s</EncryptionAlgorithm>\n", indent,
|
||||
g_eli_algo2str(sc->sc_ealgo));
|
||||
}
|
||||
|
||||
DECLARE_GEOM_CLASS(g_eli_class, g_eli);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -54,28 +54,43 @@
|
||||
/*
|
||||
* Version history:
|
||||
* 0 - Initial version number.
|
||||
* 1 - Added data authentication support (md_aalgo field and
|
||||
* G_ELI_FLAG_AUTH flag).
|
||||
* 2 - Added G_ELI_FLAG_READONLY.
|
||||
* - IV is generated from offset converted to little-endian
|
||||
* (flag G_ELI_FLAG_NATIVE_BYTE_ORDER will be set for older versions).
|
||||
*/
|
||||
#define G_ELI_VERSION 0
|
||||
#define G_ELI_VERSION 2
|
||||
|
||||
/* ON DISK FLAGS. */
|
||||
/* Use random, onetime keys. */
|
||||
#define G_ELI_FLAG_ONETIME 0x00000001
|
||||
#define G_ELI_FLAG_ONETIME 0x00000001
|
||||
/* Ask for the passphrase from the kernel, before mounting root. */
|
||||
#define G_ELI_FLAG_BOOT 0x00000002
|
||||
#define G_ELI_FLAG_BOOT 0x00000002
|
||||
/* Detach on last close, if we were open for writing. */
|
||||
#define G_ELI_FLAG_WO_DETACH 0x00000004
|
||||
#define G_ELI_FLAG_WO_DETACH 0x00000004
|
||||
/* Detach on last close. */
|
||||
#define G_ELI_FLAG_RW_DETACH 0x00000008
|
||||
#define G_ELI_FLAG_RW_DETACH 0x00000008
|
||||
/* Provide data authentication. */
|
||||
#define G_ELI_FLAG_AUTH 0x00000010
|
||||
/* Provider is read-only, we should deny all write attempts. */
|
||||
#define G_ELI_FLAG_RO 0x00000020
|
||||
/* RUNTIME FLAGS. */
|
||||
/* Provider was open for writing. */
|
||||
#define G_ELI_FLAG_WOPEN 0x00010000
|
||||
#define G_ELI_FLAG_WOPEN 0x00010000
|
||||
/* Destroy device. */
|
||||
#define G_ELI_FLAG_DESTROY 0x00020000
|
||||
#define G_ELI_FLAG_DESTROY 0x00020000
|
||||
/* Provider uses native byte-order for IV generation. */
|
||||
#define G_ELI_FLAG_NATIVE_BYTE_ORDER 0x00040000
|
||||
|
||||
#define SHA512_MDLEN 64
|
||||
#define G_ELI_AUTH_SECKEYLEN SHA256_DIGEST_LENGTH
|
||||
|
||||
#define G_ELI_MAXMKEYS 2
|
||||
#define G_ELI_MAXKEYLEN 64
|
||||
#define G_ELI_USERKEYLEN G_ELI_MAXKEYLEN
|
||||
#define G_ELI_DATAKEYLEN G_ELI_MAXKEYLEN
|
||||
#define G_ELI_AUTHKEYLEN G_ELI_MAXKEYLEN
|
||||
#define G_ELI_IVKEYLEN G_ELI_MAXKEYLEN
|
||||
#define G_ELI_SALTLEN 64
|
||||
#define G_ELI_DATAIVKEYLEN (G_ELI_DATAKEYLEN + G_ELI_IVKEYLEN)
|
||||
@ -85,6 +100,7 @@
|
||||
#ifdef _KERNEL
|
||||
extern u_int g_eli_debug;
|
||||
extern u_int g_eli_overwrites;
|
||||
extern u_int g_eli_batch;
|
||||
|
||||
#define G_ELI_CRYPTO_HW 1
|
||||
#define G_ELI_CRYPTO_SW 2
|
||||
@ -123,13 +139,21 @@ struct g_eli_worker {
|
||||
struct g_eli_softc {
|
||||
struct g_geom *sc_geom;
|
||||
u_int sc_crypto;
|
||||
uint8_t sc_datakey[G_ELI_DATAKEYLEN];
|
||||
uint8_t sc_mkey[G_ELI_DATAIVKEYLEN];
|
||||
uint8_t sc_ekey[G_ELI_DATAKEYLEN];
|
||||
u_int sc_ealgo;
|
||||
u_int sc_ekeylen;
|
||||
uint8_t sc_akey[G_ELI_AUTHKEYLEN];
|
||||
u_int sc_aalgo;
|
||||
u_int sc_akeylen;
|
||||
u_int sc_alen;
|
||||
SHA256_CTX sc_akeyctx;
|
||||
uint8_t sc_ivkey[G_ELI_IVKEYLEN];
|
||||
SHA256_CTX sc_ivctx;
|
||||
u_int sc_algo;
|
||||
u_int sc_keylen;
|
||||
int sc_nkey;
|
||||
uint32_t sc_flags;
|
||||
u_int sc_bytes_per_sector;
|
||||
u_int sc_data_per_sector;
|
||||
|
||||
/* Only for software cryptography. */
|
||||
struct bio_queue_head sc_queue;
|
||||
@ -143,8 +167,9 @@ struct g_eli_metadata {
|
||||
char md_magic[16]; /* Magic value. */
|
||||
uint32_t md_version; /* Version number. */
|
||||
uint32_t md_flags; /* Additional flags. */
|
||||
uint16_t md_algo; /* Encryption algorithm. */
|
||||
uint16_t md_ealgo; /* Encryption algorithm. */
|
||||
uint16_t md_keylen; /* Key length. */
|
||||
uint16_t md_aalgo; /* Authentication algorithm. */
|
||||
uint64_t md_provsize; /* Provider's size. */
|
||||
uint32_t md_sectorsize; /* Sector size. */
|
||||
uint8_t md_keys; /* Available keys. */
|
||||
@ -165,8 +190,9 @@ eli_metadata_encode(struct g_eli_metadata *md, u_char *data)
|
||||
bcopy(md->md_magic, p, sizeof(md->md_magic)); p += sizeof(md->md_magic);
|
||||
le32enc(p, md->md_version); p += sizeof(md->md_version);
|
||||
le32enc(p, md->md_flags); p += sizeof(md->md_flags);
|
||||
le16enc(p, md->md_algo); p += sizeof(md->md_algo);
|
||||
le16enc(p, md->md_ealgo); p += sizeof(md->md_ealgo);
|
||||
le16enc(p, md->md_keylen); p += sizeof(md->md_keylen);
|
||||
le16enc(p, md->md_aalgo); p += sizeof(md->md_aalgo);
|
||||
le64enc(p, md->md_provsize); p += sizeof(md->md_provsize);
|
||||
le32enc(p, md->md_sectorsize); p += sizeof(md->md_sectorsize);
|
||||
*p = md->md_keys; p += sizeof(md->md_keys);
|
||||
@ -186,7 +212,7 @@ eli_metadata_decode_v0(const u_char *data, struct g_eli_metadata *md)
|
||||
|
||||
p = data + sizeof(md->md_magic) + sizeof(md->md_version);
|
||||
md->md_flags = le32dec(p); p += sizeof(md->md_flags);
|
||||
md->md_algo = le16dec(p); p += sizeof(md->md_algo);
|
||||
md->md_ealgo = le16dec(p); p += sizeof(md->md_ealgo);
|
||||
md->md_keylen = le16dec(p); p += sizeof(md->md_keylen);
|
||||
md->md_provsize = le64dec(p); p += sizeof(md->md_provsize);
|
||||
md->md_sectorsize = le32dec(p); p += sizeof(md->md_sectorsize);
|
||||
@ -202,6 +228,30 @@ eli_metadata_decode_v0(const u_char *data, struct g_eli_metadata *md)
|
||||
return (0);
|
||||
}
|
||||
static __inline int
|
||||
eli_metadata_decode_v1v2(const u_char *data, struct g_eli_metadata *md)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
const u_char *p;
|
||||
|
||||
p = data + sizeof(md->md_magic) + sizeof(md->md_version);
|
||||
md->md_flags = le32dec(p); p += sizeof(md->md_flags);
|
||||
md->md_ealgo = le16dec(p); p += sizeof(md->md_ealgo);
|
||||
md->md_keylen = le16dec(p); p += sizeof(md->md_keylen);
|
||||
md->md_aalgo = le16dec(p); p += sizeof(md->md_aalgo);
|
||||
md->md_provsize = le64dec(p); p += sizeof(md->md_provsize);
|
||||
md->md_sectorsize = le32dec(p); p += sizeof(md->md_sectorsize);
|
||||
md->md_keys = *p; p += sizeof(md->md_keys);
|
||||
md->md_iterations = le32dec(p); p += sizeof(md->md_iterations);
|
||||
bcopy(p, md->md_salt, sizeof(md->md_salt)); p += sizeof(md->md_salt);
|
||||
bcopy(p, md->md_mkeys, sizeof(md->md_mkeys)); p += sizeof(md->md_mkeys);
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, data, p - data);
|
||||
MD5Final(md->md_hash, &ctx);
|
||||
if (bcmp(md->md_hash, p, 16) != 0)
|
||||
return (EINVAL);
|
||||
return (0);
|
||||
}
|
||||
static __inline int
|
||||
eli_metadata_decode(const u_char *data, struct g_eli_metadata *md)
|
||||
{
|
||||
int error;
|
||||
@ -212,6 +262,10 @@ eli_metadata_decode(const u_char *data, struct g_eli_metadata *md)
|
||||
case 0:
|
||||
error = eli_metadata_decode_v0(data, md);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
error = eli_metadata_decode_v1v2(data, md);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
@ -221,7 +275,7 @@ eli_metadata_decode(const u_char *data, struct g_eli_metadata *md)
|
||||
#endif /* !_OpenSSL */
|
||||
|
||||
static __inline u_int
|
||||
g_eli_str2algo(const char *name)
|
||||
g_eli_str2ealgo(const char *name)
|
||||
{
|
||||
|
||||
if (strcasecmp("null", name) == 0)
|
||||
@ -235,6 +289,25 @@ g_eli_str2algo(const char *name)
|
||||
return (CRYPTO_ALGORITHM_MIN - 1);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
g_eli_str2aalgo(const char *name)
|
||||
{
|
||||
|
||||
if (strcasecmp("hmac/md5", name) == 0)
|
||||
return (CRYPTO_MD5_HMAC);
|
||||
else if (strcasecmp("hmac/sha1", name) == 0)
|
||||
return (CRYPTO_SHA1_HMAC);
|
||||
else if (strcasecmp("hmac/ripemd160", name) == 0)
|
||||
return (CRYPTO_RIPEMD160_HMAC);
|
||||
else if (strcasecmp("hmac/sha256", name) == 0)
|
||||
return (CRYPTO_SHA2_256_HMAC);
|
||||
else if (strcasecmp("hmac/sha384", name) == 0)
|
||||
return (CRYPTO_SHA2_384_HMAC);
|
||||
else if (strcasecmp("hmac/sha512", name) == 0)
|
||||
return (CRYPTO_SHA2_512_HMAC);
|
||||
return (CRYPTO_ALGORITHM_MIN - 1);
|
||||
}
|
||||
|
||||
static __inline const char *
|
||||
g_eli_algo2str(u_int algo)
|
||||
{
|
||||
@ -243,11 +316,23 @@ g_eli_algo2str(u_int algo)
|
||||
case CRYPTO_NULL_CBC:
|
||||
return ("NULL");
|
||||
case CRYPTO_AES_CBC:
|
||||
return ("AES");
|
||||
return ("AES-CBC");
|
||||
case CRYPTO_BLF_CBC:
|
||||
return ("Blowfish");
|
||||
return ("Blowfish-CBC");
|
||||
case CRYPTO_3DES_CBC:
|
||||
return ("3DES");
|
||||
return ("3DES-CBC");
|
||||
case CRYPTO_MD5_HMAC:
|
||||
return ("HMAC/MD5");
|
||||
case CRYPTO_SHA1_HMAC:
|
||||
return ("HMAC/SHA1");
|
||||
case CRYPTO_RIPEMD160_HMAC:
|
||||
return ("HMAC/RIPEMD160");
|
||||
case CRYPTO_SHA2_256_HMAC:
|
||||
return ("HMAC/SHA256");
|
||||
case CRYPTO_SHA2_384_HMAC:
|
||||
return ("HMAC/SHA384");
|
||||
case CRYPTO_SHA2_512_HMAC:
|
||||
return ("HMAC/SHA512");
|
||||
}
|
||||
return ("unknown");
|
||||
}
|
||||
@ -262,8 +347,10 @@ eli_metadata_dump(const struct g_eli_metadata *md)
|
||||
printf(" magic: %s\n", md->md_magic);
|
||||
printf(" version: %u\n", (u_int)md->md_version);
|
||||
printf(" flags: 0x%x\n", (u_int)md->md_flags);
|
||||
printf(" algo: %s\n", g_eli_algo2str(md->md_algo));
|
||||
printf(" ealgo: %s\n", g_eli_algo2str(md->md_ealgo));
|
||||
printf(" keylen: %u\n", (u_int)md->md_keylen);
|
||||
if (md->md_flags & G_ELI_FLAG_AUTH)
|
||||
printf(" aalgo: %s\n", g_eli_algo2str(md->md_aalgo));
|
||||
printf(" provsize: %ju\n", (uintmax_t)md->md_provsize);
|
||||
printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
|
||||
printf(" keys: 0x%02x\n", (u_int)md->md_keys);
|
||||
@ -329,6 +416,27 @@ g_eli_keylen(u_int algo, u_int keylen)
|
||||
}
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
g_eli_hashlen(u_int algo)
|
||||
{
|
||||
|
||||
switch (algo) {
|
||||
case CRYPTO_MD5_HMAC:
|
||||
return (16);
|
||||
case CRYPTO_SHA1_HMAC:
|
||||
return (20);
|
||||
case CRYPTO_RIPEMD160_HMAC:
|
||||
return (20);
|
||||
case CRYPTO_SHA2_256_HMAC:
|
||||
return (32);
|
||||
case CRYPTO_SHA2_384_HMAC:
|
||||
return (48);
|
||||
case CRYPTO_SHA2_512_HMAC:
|
||||
return (64);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef _KERNEL
|
||||
int g_eli_read_metadata(struct g_class *mp, struct g_provider *pp,
|
||||
struct g_eli_metadata *md);
|
||||
@ -339,6 +447,17 @@ int g_eli_destroy(struct g_eli_softc *sc, boolean_t force);
|
||||
|
||||
int g_eli_access(struct g_provider *pp, int dr, int dw, int de);
|
||||
void g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb);
|
||||
|
||||
void g_eli_read_done(struct bio *bp);
|
||||
void g_eli_write_done(struct bio *bp);
|
||||
int g_eli_crypto_rerun(struct cryptop *crp);
|
||||
void g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv,
|
||||
size_t size);
|
||||
|
||||
void g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp);
|
||||
|
||||
void g_eli_auth_read(struct g_eli_softc *sc, struct bio *bp);
|
||||
void g_eli_auth_run(struct g_eli_worker *wr, struct bio *bp);
|
||||
#endif
|
||||
|
||||
void g_eli_mkey_hmac(unsigned char *mkey, const unsigned char *key);
|
||||
@ -346,6 +465,9 @@ int g_eli_mkey_decrypt(const struct g_eli_metadata *md,
|
||||
const unsigned char *key, unsigned char *mkey, unsigned *nkeyp);
|
||||
int g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
|
||||
unsigned char *mkey);
|
||||
#ifdef _KERNEL
|
||||
void g_eli_mkey_propagate(struct g_eli_softc *sc, const unsigned char *mkey);
|
||||
#endif
|
||||
|
||||
int g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
|
||||
const u_char *key, size_t keysize);
|
||||
|
@ -57,7 +57,7 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
|
||||
struct g_provider *pp;
|
||||
const char *name;
|
||||
u_char *key, mkey[G_ELI_DATAIVKEYLEN];
|
||||
int *nargs, *detach;
|
||||
int *nargs, *detach, *readonly;
|
||||
int keysize, error;
|
||||
u_int nkey;
|
||||
|
||||
@ -79,6 +79,12 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
|
||||
return;
|
||||
}
|
||||
|
||||
readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
|
||||
if (readonly == NULL) {
|
||||
gctl_error(req, "No '%s' argument.", "readonly");
|
||||
return;
|
||||
}
|
||||
|
||||
name = gctl_get_asciiparam(req, "arg0");
|
||||
if (name == NULL) {
|
||||
gctl_error(req, "No 'arg%u' argument.", 0);
|
||||
@ -124,8 +130,16 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
|
||||
}
|
||||
G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
|
||||
|
||||
if (*detach && *readonly) {
|
||||
bzero(&md, sizeof(md));
|
||||
gctl_error(req, "Options -d and -r are mutually exclusive.",
|
||||
pp->name, error);
|
||||
return;
|
||||
}
|
||||
if (*detach)
|
||||
md.md_flags |= G_ELI_FLAG_WO_DETACH;
|
||||
if (*readonly)
|
||||
md.md_flags |= G_ELI_FLAG_RO;
|
||||
g_eli_create(req, mp, pp, &md, mkey, nkey);
|
||||
bzero(mkey, sizeof(mkey));
|
||||
bzero(&md, sizeof(md));
|
||||
@ -250,16 +264,49 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
|
||||
if (*detach)
|
||||
md.md_flags |= G_ELI_FLAG_WO_DETACH;
|
||||
|
||||
name = gctl_get_asciiparam(req, "algo");
|
||||
md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
|
||||
name = gctl_get_asciiparam(req, "aalgo");
|
||||
if (name == NULL) {
|
||||
gctl_error(req, "No '%s' argument.", "algo");
|
||||
gctl_error(req, "No '%s' argument.", "aalgo");
|
||||
return;
|
||||
}
|
||||
md.md_algo = g_eli_str2algo(name);
|
||||
if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_algo > CRYPTO_ALGORITHM_MAX) {
|
||||
gctl_error(req, "Invalid '%s' argument.", "algo");
|
||||
return;
|
||||
if (strcmp(name, "none") != 0) {
|
||||
md.md_aalgo = g_eli_str2aalgo(name);
|
||||
if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
|
||||
md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
|
||||
md.md_flags |= G_ELI_FLAG_AUTH;
|
||||
} else {
|
||||
/*
|
||||
* For backward compatibility, check if the -a option
|
||||
* was used to provide encryption algorithm.
|
||||
*/
|
||||
md.md_ealgo = g_eli_str2ealgo(name);
|
||||
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
|
||||
gctl_error(req,
|
||||
"Invalid authentication algorithm.");
|
||||
return;
|
||||
} else {
|
||||
gctl_error(req, "warning: The -e option, not "
|
||||
"the -a option is now used to specify "
|
||||
"encryption algorithm to use.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
|
||||
name = gctl_get_asciiparam(req, "ealgo");
|
||||
if (name == NULL) {
|
||||
gctl_error(req, "No '%s' argument.", "ealgo");
|
||||
return;
|
||||
}
|
||||
md.md_ealgo = g_eli_str2ealgo(name);
|
||||
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
|
||||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
|
||||
gctl_error(req, "Invalid encryption algorithm.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
|
||||
@ -267,7 +314,7 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
|
||||
gctl_error(req, "No '%s' argument.", "keylen");
|
||||
return;
|
||||
}
|
||||
md.md_keylen = g_eli_keylen(md.md_algo, *keylen);
|
||||
md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
|
||||
if (md.md_keylen == 0) {
|
||||
gctl_error(req, "Invalid '%s' argument.", "keylen");
|
||||
return;
|
||||
@ -341,6 +388,10 @@ g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
|
||||
gctl_error(req, "Provider %s is invalid.", name);
|
||||
return;
|
||||
}
|
||||
if (sc->sc_flags & G_ELI_FLAG_RO) {
|
||||
gctl_error(req, "Cannot change keys for read-only provider.");
|
||||
return;
|
||||
}
|
||||
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||
pp = cp->provider;
|
||||
|
||||
@ -395,12 +446,10 @@ g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
|
||||
mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
|
||||
md.md_keys |= (1 << nkey);
|
||||
|
||||
bcopy(sc->sc_ivkey, mkeydst, sizeof(sc->sc_ivkey));
|
||||
bcopy(sc->sc_datakey, mkeydst + sizeof(sc->sc_ivkey),
|
||||
sizeof(sc->sc_datakey));
|
||||
bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
|
||||
|
||||
/* Encrypt Master Key with the new key. */
|
||||
error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst);
|
||||
error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
|
||||
bzero(key, sizeof(key));
|
||||
if (error != 0) {
|
||||
bzero(&md, sizeof(md));
|
||||
@ -452,6 +501,10 @@ g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
|
||||
gctl_error(req, "Provider %s is invalid.", name);
|
||||
return;
|
||||
}
|
||||
if (sc->sc_flags & G_ELI_FLAG_RO) {
|
||||
gctl_error(req, "Cannot delete keys for read-only provider.");
|
||||
return;
|
||||
}
|
||||
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||
pp = cp->provider;
|
||||
|
||||
@ -534,9 +587,7 @@ g_eli_kill_one(struct g_eli_softc *sc)
|
||||
{
|
||||
struct g_provider *pp;
|
||||
struct g_consumer *cp;
|
||||
u_char *sector;
|
||||
int err, error = 0;
|
||||
u_int i;
|
||||
int error = 0;
|
||||
|
||||
g_topology_assert();
|
||||
|
||||
@ -549,22 +600,31 @@ g_eli_kill_one(struct g_eli_softc *sc)
|
||||
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||
pp = cp->provider;
|
||||
|
||||
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
|
||||
for (i = 0; i <= g_eli_overwrites; i++) {
|
||||
if (i == g_eli_overwrites)
|
||||
bzero(sector, pp->sectorsize);
|
||||
else
|
||||
arc4rand(sector, pp->sectorsize, 0);
|
||||
err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
|
||||
pp->sectorsize);
|
||||
if (err != 0) {
|
||||
G_ELI_DEBUG(0, "Cannot erase metadata on %s "
|
||||
"(error=%d).", pp->name, err);
|
||||
if (error == 0)
|
||||
error = err;
|
||||
if (sc->sc_flags & G_ELI_FLAG_RO) {
|
||||
G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
|
||||
"provider: %s.", pp->name);
|
||||
} else {
|
||||
u_char *sector;
|
||||
u_int i;
|
||||
int err;
|
||||
|
||||
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
|
||||
for (i = 0; i <= g_eli_overwrites; i++) {
|
||||
if (i == g_eli_overwrites)
|
||||
bzero(sector, pp->sectorsize);
|
||||
else
|
||||
arc4rand(sector, pp->sectorsize, 0);
|
||||
err = g_write_data(cp, pp->mediasize - pp->sectorsize,
|
||||
sector, pp->sectorsize);
|
||||
if (err != 0) {
|
||||
G_ELI_DEBUG(0, "Cannot erase metadata on %s "
|
||||
"(error=%d).", pp->name, err);
|
||||
if (error == 0)
|
||||
error = err;
|
||||
}
|
||||
}
|
||||
free(sector, M_ELI);
|
||||
}
|
||||
free(sector, M_ELI);
|
||||
if (error == 0)
|
||||
G_ELI_DEBUG(0, "%s has been killed.", pp->name);
|
||||
g_eli_destroy(sc, 1);
|
||||
|
@ -123,10 +123,10 @@ g_eli_mkey_decrypt(const struct g_eli_metadata *md, const unsigned char *key,
|
||||
nkey = 0;
|
||||
for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++, mmkey += G_ELI_MKEYLEN) {
|
||||
bit = (1 << nkey);
|
||||
if ((md->md_keys & bit) == 0)
|
||||
if (!(md->md_keys & bit))
|
||||
continue;
|
||||
bcopy(mmkey, tmpmkey, G_ELI_MKEYLEN);
|
||||
error = g_eli_crypto_decrypt(md->md_algo, tmpmkey,
|
||||
error = g_eli_crypto_decrypt(md->md_ealgo, tmpmkey,
|
||||
G_ELI_MKEYLEN, enckey, md->md_keylen);
|
||||
if (error != 0) {
|
||||
bzero(tmpmkey, sizeof(tmpmkey));
|
||||
@ -177,3 +177,33 @@ g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* When doing encryption only, copy IV key and encryption key.
|
||||
* When doing encryption and authentication, copy IV key, generate encryption
|
||||
* key and generate authentication key.
|
||||
*/
|
||||
void
|
||||
g_eli_mkey_propagate(struct g_eli_softc *sc, const unsigned char *mkey)
|
||||
{
|
||||
|
||||
/* Remember the Master Key. */
|
||||
bcopy(mkey, sc->sc_mkey, sizeof(sc->sc_mkey));
|
||||
|
||||
bcopy(mkey, sc->sc_ivkey, sizeof(sc->sc_ivkey));
|
||||
mkey += sizeof(sc->sc_ivkey);
|
||||
|
||||
if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) {
|
||||
bcopy(mkey, sc->sc_ekey, sizeof(sc->sc_ekey));
|
||||
} else {
|
||||
/*
|
||||
* The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10)
|
||||
* The authentication key is: akey = HMAC_SHA512(Master-Key, 0x11)
|
||||
*/
|
||||
g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, sc->sc_ekey, 0);
|
||||
g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x11", 1, sc->sc_akey, 0);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@ -3,7 +3,14 @@
|
||||
.PATH: ${.CURDIR}/../../../geom/eli
|
||||
|
||||
KMOD= geom_eli
|
||||
SRCS= g_eli.c g_eli_crypto.c g_eli_ctl.c g_eli_key.c pkcs5v2.c vnode_if.h
|
||||
SRCS= g_eli.c
|
||||
SRCS+= g_eli_crypto.c
|
||||
SRCS+= g_eli_ctl.c
|
||||
SRCS+= g_eli_integrity.c
|
||||
SRCS+= g_eli_key.c
|
||||
SRCS+= g_eli_privacy.c
|
||||
SRCS+= pkcs5v2.c
|
||||
SRCS+= vnode_if.h
|
||||
WARNS?= 2
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
@ -4,11 +4,9 @@
|
||||
base=`basename $0`
|
||||
no=45
|
||||
sectors=100
|
||||
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
|
||||
keyfile=`mktemp /tmp/$base.XXXXXX` || exit 1
|
||||
mdconfig -a -t malloc -s `expr $sectors + 1` -u $no || exit 1
|
||||
|
||||
echo "1..36"
|
||||
echo "1..180"
|
||||
|
||||
i=1
|
||||
for cipher in aes:0 aes:128 aes:192 aes:256 \
|
||||
@ -16,36 +14,43 @@ for cipher in aes:0 aes:128 aes:192 aes:256 \
|
||||
blowfish:0 blowfish:128 blowfish:160 blowfish:192 blowfish:224 \
|
||||
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
|
||||
blowfish:416 blowfish:448; do
|
||||
algo=${cipher%%:*}
|
||||
ealgo=${cipher%%:*}
|
||||
keylen=${cipher##*:}
|
||||
for secsize in 512 1024 2048 4096 8192; do
|
||||
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
|
||||
mdconfig -a -t malloc -s `expr $secsize \* $sectors + 512`b -u $no || exit 1
|
||||
|
||||
dd if=/dev/random of=${rnd} bs=512 count=${sectors} >/dev/null 2>&1
|
||||
dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1
|
||||
dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1
|
||||
|
||||
geli init -a $algo -l $keylen -P -K $keyfile md${no}
|
||||
geli attach -p -k $keyfile md${no}
|
||||
geli init -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no}
|
||||
geli attach -p -k $keyfile md${no}
|
||||
|
||||
dd if=${rnd} of=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null
|
||||
secs=`diskinfo /dev/md${no}.eli | awk '{print $4}'`
|
||||
|
||||
md_rnd=`dd if=${rnd} bs=512 count=${sectors} 2>/dev/null | md5`
|
||||
md_ddev=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
|
||||
md_edev=`dd if=/dev/md${no} bs=512 count=${sectors} 2>/dev/null | md5`
|
||||
dd if=/dev/random of=${rnd} bs=${secsize} count=${secs} >/dev/null 2>&1
|
||||
dd if=${rnd} of=/dev/md${no}.eli bs=${secsize} count=${secs} 2>/dev/null
|
||||
|
||||
if [ ${md_rnd} = ${md_ddev} ]; then
|
||||
echo "ok $i - ${cipher}"
|
||||
else
|
||||
echo "not ok $i - ${cipher}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
if [ ${md_rnd} != ${md_edev} ]; then
|
||||
echo "ok $i - ${cipher}"
|
||||
else
|
||||
echo "not ok $i - ${cipher}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
md_rnd=`dd if=${rnd} bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||
md_ddev=`dd if=/dev/md${no}.eli bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||
md_edev=`dd if=/dev/md${no} bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||
|
||||
geli detach md${no}
|
||||
if [ ${md_rnd} = ${md_ddev} ]; then
|
||||
echo "ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
else
|
||||
echo "not ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
if [ ${md_rnd} != ${md_edev} ]; then
|
||||
echo "ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
else
|
||||
echo "not ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
|
||||
geli detach md${no}
|
||||
rm -f $rnd
|
||||
mdconfig -d -u $no
|
||||
done
|
||||
done
|
||||
|
||||
mdconfig -d -u $no
|
||||
rm -f $rnd $keyfile
|
||||
rm -f $keyfile
|
||||
|
@ -4,10 +4,8 @@
|
||||
base=`basename $0`
|
||||
no=45
|
||||
sectors=100
|
||||
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
|
||||
mdconfig -a -t malloc -s $sectors -u $no || exit 1
|
||||
|
||||
echo "1..36"
|
||||
echo "1..180"
|
||||
|
||||
i=1
|
||||
for cipher in aes:0 aes:128 aes:192 aes:256 \
|
||||
@ -15,34 +13,38 @@ for cipher in aes:0 aes:128 aes:192 aes:256 \
|
||||
blowfish:0 blowfish:128 blowfish:160 blowfish:192 blowfish:224 \
|
||||
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
|
||||
blowfish:416 blowfish:448; do
|
||||
algo=${cipher%%:*}
|
||||
ealgo=${cipher%%:*}
|
||||
keylen=${cipher##*:}
|
||||
for secsize in 512 1024 2048 4096 8192; do
|
||||
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
|
||||
mdconfig -a -t malloc -s `expr $secsize \* $sectors`b -u $no || exit 1
|
||||
|
||||
dd if=/dev/random of=${rnd} bs=512 count=${sectors} >/dev/null 2>&1
|
||||
geli onetime -e $ealgo -l $keylen -s $secsize md${no}
|
||||
|
||||
geli onetime -a $algo -l $keylen md${no}
|
||||
secs=`diskinfo /dev/md${no}.eli | awk '{print $4}'`
|
||||
|
||||
dd if=${rnd} of=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null
|
||||
dd if=/dev/random of=${rnd} bs=${secsize} count=${secs} >/dev/null 2>&1
|
||||
dd if=${rnd} of=/dev/md${no}.eli bs=${secsize} count=${secs} 2>/dev/null
|
||||
|
||||
md_rnd=`dd if=${rnd} bs=512 count=${sectors} 2>/dev/null | md5`
|
||||
md_ddev=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
|
||||
md_edev=`dd if=/dev/md${no} bs=512 count=${sectors} 2>/dev/null | md5`
|
||||
md_rnd=`dd if=${rnd} bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||
md_ddev=`dd if=/dev/md${no}.eli bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||
md_edev=`dd if=/dev/md${no} bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||
|
||||
if [ ${md_rnd} = ${md_ddev} ]; then
|
||||
echo "ok $i - ${cipher}"
|
||||
else
|
||||
echo "not ok $i - ${cipher}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
if [ ${md_rnd} != ${md_edev} ]; then
|
||||
echo "ok $i - ${cipher}"
|
||||
else
|
||||
echo "not ok $i - ${cipher}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
if [ ${md_rnd} = ${md_ddev} ]; then
|
||||
echo "ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
else
|
||||
echo "not ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
if [ ${md_rnd} != ${md_edev} ]; then
|
||||
echo "ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
else
|
||||
echo "not ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
|
||||
geli detach md${no}
|
||||
geli detach md${no}
|
||||
rm -f $rnd
|
||||
mdconfig -d -u $no
|
||||
done
|
||||
done
|
||||
|
||||
mdconfig -d -u $no
|
||||
rm -f $rnd
|
||||
|
Loading…
x
Reference in New Issue
Block a user