MFC: Synchronize geli(8) with HEAD version.
This commit is contained in:
parent
9cb7cb37ab
commit
6fb52e4447
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd February 11, 2006
|
.Dd August 9, 2006
|
||||||
.Dt GELI 8
|
.Dt GELI 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -52,7 +52,8 @@ utility:
|
|||||||
.Nm
|
.Nm
|
||||||
.Cm init
|
.Cm init
|
||||||
.Op Fl bPv
|
.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 i Ar iterations
|
||||||
.Op Fl K Ar newkeyfile
|
.Op Fl K Ar newkeyfile
|
||||||
.Op Fl l Ar keylen
|
.Op Fl l Ar keylen
|
||||||
@ -63,7 +64,7 @@ utility:
|
|||||||
.Cm init
|
.Cm init
|
||||||
.Nm
|
.Nm
|
||||||
.Cm attach
|
.Cm attach
|
||||||
.Op Fl dpv
|
.Op Fl dprv
|
||||||
.Op Fl k Ar keyfile
|
.Op Fl k Ar keyfile
|
||||||
.Ar prov
|
.Ar prov
|
||||||
.Nm
|
.Nm
|
||||||
@ -76,7 +77,8 @@ utility:
|
|||||||
.Nm
|
.Nm
|
||||||
.Cm onetime
|
.Cm onetime
|
||||||
.Op Fl d
|
.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 l Ar keylen
|
||||||
.Op Fl s Ar sectorsize
|
.Op Fl s Ar sectorsize
|
||||||
.Ar prov ...
|
.Ar prov ...
|
||||||
@ -144,6 +146,16 @@ Supports many cryptographic algorithms (currently
|
|||||||
and
|
and
|
||||||
.Nm 3DES ) .
|
.Nm 3DES ) .
|
||||||
.It
|
.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
|
Can create a key from a couple of components (user entered passphrase, random
|
||||||
bits from a file, etc.).
|
bits from a file, etc.).
|
||||||
.It
|
.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.
|
passphrase before the root file system is mounted.
|
||||||
.It
|
.It
|
||||||
The passphrase of the user is strengthened with:
|
The passphrase of the user is strengthened with:
|
||||||
.Rs
|
.Rs
|
||||||
.%A B. Kaliski
|
.%A B. Kaliski
|
||||||
.%T "PKCS #5: Password-Based Cryptography Specification, Version 2.0."
|
.%T "PKCS #5: Password-Based Cryptography Specification, Version 2.0."
|
||||||
.%R RFC
|
.%R RFC
|
||||||
@ -163,7 +175,7 @@ Allows to use two independent keys (e.g.
|
|||||||
and
|
and
|
||||||
.Qq "company key" ) .
|
.Qq "company key" ) .
|
||||||
.It
|
.It
|
||||||
It is fast -
|
It is fast -
|
||||||
.Nm
|
.Nm
|
||||||
performs simple sector-to-sector encryption.
|
performs simple sector-to-sector encryption.
|
||||||
.It
|
.It
|
||||||
@ -177,6 +189,8 @@ the file systems).
|
|||||||
.It
|
.It
|
||||||
Allows to attach a provider with a random, one-time key - useful for swap
|
Allows to attach a provider with a random, one-time key - useful for swap
|
||||||
partitions and temporary file systems.
|
partitions and temporary file systems.
|
||||||
|
.It
|
||||||
|
Allows to verify data integrity (data authentication).
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The first argument to
|
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.
|
The last provider's sector is used to store metadata.
|
||||||
.Pp
|
.Pp
|
||||||
Additional options include:
|
Additional options include:
|
||||||
.Bl -tag -width ".Fl a Ar algo"
|
.Bl -tag -width ".Fl a Ar aalgo"
|
||||||
.It Fl a Ar algo
|
.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.
|
Encryption algorithm to use.
|
||||||
Currently supported algorithms are:
|
Currently supported algorithms are:
|
||||||
.Nm AES ,
|
.Nm AES ,
|
||||||
@ -259,6 +288,9 @@ Probably a better choice is the
|
|||||||
option for the
|
option for the
|
||||||
.Cm detach
|
.Cm detach
|
||||||
subcommand.
|
subcommand.
|
||||||
|
.It Fl r
|
||||||
|
Attach read-only provider.
|
||||||
|
It will not be opened for writing.
|
||||||
.It Fl k Ar keyfile
|
.It Fl k Ar keyfile
|
||||||
Specifies a file which contains part of the key.
|
Specifies a file which contains part of the key.
|
||||||
For more information see the description of the
|
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.
|
The command can be used to encrypt swap partitions or temporary file systems.
|
||||||
.Pp
|
.Pp
|
||||||
Additional options include:
|
Additional options include:
|
||||||
.Bl -tag -width ".Fl a Ar algo"
|
.Bl -tag -width ".Fl a Ar aalgo"
|
||||||
.It Fl a Ar algo
|
.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.
|
Encryption algorithm to use.
|
||||||
For more information, see the description of the
|
For more information, see the description of the
|
||||||
.Cm init
|
.Cm init
|
||||||
@ -415,6 +452,8 @@ variables can be used to control the behavior of the
|
|||||||
.Nm ELI
|
.Nm ELI
|
||||||
GEOM class.
|
GEOM class.
|
||||||
The default value is shown next to each variable.
|
The default value is shown next to each variable.
|
||||||
|
All variables can also be set in
|
||||||
|
.Pa /boot/loader.conf .
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
.It Va kern.geom.eli.debug : No 0
|
.It Va kern.geom.eli.debug : No 0
|
||||||
Debug level of the
|
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 0, minimal debug information is printed.
|
||||||
If set to 3, the
|
If set to 3, the
|
||||||
maximum amount of debug information is printed.
|
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
|
.It Va kern.geom.eli.tries : No 3
|
||||||
Number of times a user is asked for the passphrase.
|
Number of times a user is asked for the passphrase.
|
||||||
This is only used for providers which should be attached on boot
|
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.
|
Its purpose is to increase performance on SMP systems.
|
||||||
If hardware acceleration is available, only one thread will be started.
|
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.
|
If set to 0, CPU-bound thread will be started for every active CPU.
|
||||||
This variable could be set in
|
.It Va kern.geom.eli.batch : No 0
|
||||||
.Pa /boot/loader.conf .
|
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
|
.El
|
||||||
.Sh EXIT STATUS
|
.Sh EXIT STATUS
|
||||||
Exit status is 0 on success, and 1 if the command fails.
|
Exit status is 0 on success, and 1 if the command fails.
|
||||||
@ -508,7 +548,7 @@ Reenter new passphrase:
|
|||||||
Encrypted swap partition setup:
|
Encrypted swap partition setup:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
# dd if=/dev/random of=/dev/ad0s1b bs=1m
|
# 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
|
# swapon /dev/ad0s1b.eli
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@ -546,6 +586,38 @@ geli_da1s3a_keyfile0_load="YES"
|
|||||||
geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0"
|
geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0"
|
||||||
geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key"
|
geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key"
|
||||||
.Ed
|
.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
|
.Sh SEE ALSO
|
||||||
.Xr crypto 4 ,
|
.Xr crypto 4 ,
|
||||||
.Xr gbde 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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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 lib_version = G_LIB_VERSION;
|
||||||
uint32_t version = G_ELI_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 keylen = 0;
|
||||||
static intmax_t keyno = -1;
|
static intmax_t keyno = -1;
|
||||||
static intmax_t iterations = -1;
|
static intmax_t iterations = -1;
|
||||||
@ -75,12 +76,12 @@ static void eli_dump(struct gctl_req *req);
|
|||||||
/*
|
/*
|
||||||
* Available commands:
|
* 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'
|
* label - alias for 'init'
|
||||||
* attach [-dpv] [-k keyfile] prov
|
* attach [-dprv] [-k keyfile] prov
|
||||||
* detach [-fl] prov ...
|
* detach [-fl] prov ...
|
||||||
* stop - alias for 'detach'
|
* 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
|
* setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
|
||||||
* delkey [-afv] [-n keyno] prov
|
* delkey [-afv] [-n keyno] prov
|
||||||
* kill [-av] [prov ...]
|
* kill [-av] [prov ...]
|
||||||
@ -92,8 +93,9 @@ static void eli_dump(struct gctl_req *req);
|
|||||||
struct g_command class_commands[] = {
|
struct g_command class_commands[] = {
|
||||||
{ "init", G_FLAG_VERBOSE, eli_main,
|
{ "init", G_FLAG_VERBOSE, eli_main,
|
||||||
{
|
{
|
||||||
{ 'a', "algo", algo, G_TYPE_STRING },
|
{ 'a', "aalgo", aalgo, G_TYPE_STRING },
|
||||||
{ 'b', "boot", NULL, G_TYPE_NONE },
|
{ 'b', "boot", NULL, G_TYPE_NONE },
|
||||||
|
{ 'e', "ealgo", ealgo, G_TYPE_STRING },
|
||||||
{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
|
{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
|
||||||
{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
|
{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
|
||||||
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
||||||
@ -101,12 +103,13 @@ struct g_command class_commands[] = {
|
|||||||
{ 's', "sectorsize", §orsize, G_TYPE_NUMBER },
|
{ 's', "sectorsize", §orsize, G_TYPE_NUMBER },
|
||||||
G_OPT_SENTINEL
|
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,
|
{ "label", G_FLAG_VERBOSE, eli_main,
|
||||||
{
|
{
|
||||||
{ 'a', "algo", algo, G_TYPE_STRING },
|
{ 'a', "aalgo", aalgo, G_TYPE_STRING },
|
||||||
{ 'b', "boot", NULL, G_TYPE_NONE },
|
{ 'b', "boot", NULL, G_TYPE_NONE },
|
||||||
|
{ 'e', "ealgo", ealgo, G_TYPE_STRING },
|
||||||
{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
|
{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
|
||||||
{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
|
{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
|
||||||
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
||||||
@ -121,9 +124,10 @@ struct g_command class_commands[] = {
|
|||||||
{ 'd', "detach", NULL, G_TYPE_NONE },
|
{ 'd', "detach", NULL, G_TYPE_NONE },
|
||||||
{ 'k', "keyfile", keyfile, G_TYPE_STRING },
|
{ 'k', "keyfile", keyfile, G_TYPE_STRING },
|
||||||
{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
|
{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
|
||||||
|
{ 'r', "readonly", NULL, G_TYPE_NONE },
|
||||||
G_OPT_SENTINEL
|
G_OPT_SENTINEL
|
||||||
},
|
},
|
||||||
"[-dpv] [-k keyfile] prov"
|
"[-dprv] [-k keyfile] prov"
|
||||||
},
|
},
|
||||||
{ "detach", 0, NULL,
|
{ "detach", 0, NULL,
|
||||||
{
|
{
|
||||||
@ -143,13 +147,14 @@ struct g_command class_commands[] = {
|
|||||||
},
|
},
|
||||||
{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
|
{ "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 },
|
{ 'd', "detach", NULL, G_TYPE_NONE },
|
||||||
|
{ 'e', "ealgo", ealgo, G_TYPE_STRING },
|
||||||
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
|
||||||
{ 's', "sectorsize", §orsize, G_TYPE_NUMBER },
|
{ 's', "sectorsize", §orsize, G_TYPE_NUMBER },
|
||||||
G_OPT_SENTINEL
|
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,
|
{ "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) {
|
if (md->md_iterations == 0) {
|
||||||
g_eli_crypto_hmac_update(&ctx, md->md_salt,
|
g_eli_crypto_hmac_update(&ctx, md->md_salt,
|
||||||
@ -523,16 +528,44 @@ eli_init(struct gctl_req *req)
|
|||||||
md.md_flags = 0;
|
md.md_flags = 0;
|
||||||
if (gctl_get_int(req, "boot"))
|
if (gctl_get_int(req, "boot"))
|
||||||
md.md_flags |= G_ELI_FLAG_BOOT;
|
md.md_flags |= G_ELI_FLAG_BOOT;
|
||||||
str = gctl_get_ascii(req, "algo");
|
md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
|
||||||
md.md_algo = g_eli_str2algo(str);
|
str = gctl_get_ascii(req, "aalgo");
|
||||||
if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
|
if (strcmp(str, "none") != 0) {
|
||||||
md.md_algo > CRYPTO_ALGORITHM_MAX) {
|
md.md_aalgo = g_eli_str2aalgo(str);
|
||||||
gctl_error(req, "Invalid encryption algorithm.");
|
if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
|
||||||
return;
|
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");
|
val = gctl_get_intmax(req, "keylen");
|
||||||
md.md_keylen = val;
|
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) {
|
if (md.md_keylen == 0) {
|
||||||
gctl_error(req, "Invalid key length.");
|
gctl_error(req, "Invalid key length.");
|
||||||
return;
|
return;
|
||||||
@ -579,7 +612,7 @@ eli_init(struct gctl_req *req)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Encrypt the first and the only Master Key. */
|
/* 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));
|
bzero(key, sizeof(key));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
bzero(&md, sizeof(md));
|
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. */
|
/* 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));
|
bzero(key, sizeof(key));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
bzero(md, sizeof(*md));
|
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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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,
|
&g_eli_visible_passphrase, 0,
|
||||||
"Turn on echo when entering the passphrase (for debug purposes only!!)");
|
"Turn on echo when entering the passphrase (for debug purposes only!!)");
|
||||||
u_int g_eli_overwrites = 5;
|
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,
|
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");
|
0, "Number of times on-disk keys should be overwritten when destroying them");
|
||||||
static u_int g_eli_threads = 0;
|
static u_int g_eli_threads = 0;
|
||||||
TUNABLE_INT("kern.geom.eli.threads", &g_eli_threads);
|
TUNABLE_INT("kern.geom.eli.threads", &g_eli_threads);
|
||||||
SYSCTL_UINT(_kern_geom_eli, OID_AUTO, threads, CTLFLAG_RW, &g_eli_threads, 0,
|
SYSCTL_UINT(_kern_geom_eli, OID_AUTO, threads, CTLFLAG_RW, &g_eli_threads, 0,
|
||||||
"Number of threads doing crypto work");
|
"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,
|
static int g_eli_destroy_geom(struct gctl_req *req, struct g_class *mp,
|
||||||
struct g_geom *gp);
|
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_taste_t g_eli_taste;
|
||||||
static g_dumpconf_t g_eli_dumpconf;
|
static g_dumpconf_t g_eli_dumpconf;
|
||||||
@ -106,7 +110,7 @@ struct g_class g_eli_class = {
|
|||||||
* accelerator or something like this.
|
* accelerator or something like this.
|
||||||
* The function updates the SID and rerun the operation.
|
* The function updates the SID and rerun the operation.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
g_eli_crypto_rerun(struct cryptop *crp)
|
g_eli_crypto_rerun(struct cryptop *crp)
|
||||||
{
|
{
|
||||||
struct g_eli_softc *sc;
|
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
|
* 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)
|
g_eli_read_done(struct bio *bp)
|
||||||
{
|
{
|
||||||
struct g_eli_softc *sc;
|
struct g_eli_softc *sc;
|
||||||
@ -149,10 +153,20 @@ g_eli_read_done(struct bio *bp)
|
|||||||
pbp = bp->bio_parent;
|
pbp = bp->bio_parent;
|
||||||
if (pbp->bio_error == 0)
|
if (pbp->bio_error == 0)
|
||||||
pbp->bio_error = bp->bio_error;
|
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);
|
g_destroy_bio(bp);
|
||||||
if (pbp->bio_error != 0) {
|
if (pbp->bio_error != 0) {
|
||||||
G_ELI_LOGREQ(0, pbp, "%s() failed", __func__);
|
G_ELI_LOGREQ(0, pbp, "%s() failed", __func__);
|
||||||
pbp->bio_completed = 0;
|
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);
|
g_io_deliver(pbp, pbp->bio_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -163,70 +177,31 @@ g_eli_read_done(struct bio *bp)
|
|||||||
wakeup(sc);
|
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.
|
* 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
|
* 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)
|
g_eli_write_done(struct bio *bp)
|
||||||
{
|
{
|
||||||
struct bio *pbp;
|
struct bio *pbp;
|
||||||
|
|
||||||
G_ELI_LOGREQ(2, bp, "Request done.");
|
G_ELI_LOGREQ(2, bp, "Request done.");
|
||||||
pbp = bp->bio_parent;
|
pbp = bp->bio_parent;
|
||||||
if (pbp->bio_error == 0)
|
if (pbp->bio_error == 0) {
|
||||||
pbp->bio_error = bp->bio_error;
|
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);
|
free(pbp->bio_driver2, M_ELI);
|
||||||
pbp->bio_driver2 = NULL;
|
pbp->bio_driver2 = NULL;
|
||||||
if (pbp->bio_error == 0)
|
if (pbp->bio_error != 0) {
|
||||||
pbp->bio_completed = pbp->bio_length;
|
|
||||||
else {
|
|
||||||
G_ELI_LOGREQ(0, pbp, "Crypto WRITE request failed (error=%d).",
|
G_ELI_LOGREQ(0, pbp, "Crypto WRITE request failed (error=%d).",
|
||||||
pbp->bio_error);
|
pbp->bio_error);
|
||||||
pbp->bio_completed = 0;
|
pbp->bio_completed = 0;
|
||||||
@ -235,67 +210,10 @@ g_eli_write_done(struct bio *bp)
|
|||||||
/*
|
/*
|
||||||
* Write is finished, send it up.
|
* Write is finished, send it up.
|
||||||
*/
|
*/
|
||||||
|
pbp->bio_completed = pbp->bio_length;
|
||||||
g_io_deliver(pbp, pbp->bio_error);
|
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()
|
* This function should never be called, but GEOM made as it set ->orphan()
|
||||||
* method for every geom.
|
* method for every geom.
|
||||||
@ -358,15 +276,20 @@ g_eli_start(struct bio *bp)
|
|||||||
}
|
}
|
||||||
switch (bp->bio_cmd) {
|
switch (bp->bio_cmd) {
|
||||||
case BIO_READ:
|
case BIO_READ:
|
||||||
cbp->bio_done = g_eli_read_done;
|
if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) {
|
||||||
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
bp->bio_driver2 = NULL;
|
||||||
cbp->bio_to = cp->provider;
|
cbp->bio_done = g_eli_read_done;
|
||||||
G_ELI_LOGREQ(2, cbp, "Sending request.");
|
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||||
/*
|
cbp->bio_to = cp->provider;
|
||||||
* Read encrypted data from provider.
|
G_ELI_LOGREQ(2, cbp, "Sending request.");
|
||||||
*/
|
/*
|
||||||
g_io_request(cbp, cp);
|
* Read encrypted data from provider.
|
||||||
break;
|
*/
|
||||||
|
g_io_request(cbp, cp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bp->bio_pflags = 255;
|
||||||
|
/* FALLTHROUGH */
|
||||||
case BIO_WRITE:
|
case BIO_WRITE:
|
||||||
bp->bio_driver1 = cbp;
|
bp->bio_driver1 = cbp;
|
||||||
mtx_lock(&sc->sc_queue_mtx);
|
mtx_lock(&sc->sc_queue_mtx);
|
||||||
@ -411,7 +334,7 @@ g_eli_worker(void *arg)
|
|||||||
mtx_lock(&sc->sc_queue_mtx);
|
mtx_lock(&sc->sc_queue_mtx);
|
||||||
bp = bioq_takefirst(&sc->sc_queue);
|
bp = bioq_takefirst(&sc->sc_queue);
|
||||||
if (bp == NULL) {
|
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);
|
LIST_REMOVE(wr, w_next);
|
||||||
crypto_freesession(wr->w_sid);
|
crypto_freesession(wr->w_sid);
|
||||||
free(wr, M_ELI);
|
free(wr, M_ELI);
|
||||||
@ -426,20 +349,27 @@ g_eli_worker(void *arg)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mtx_unlock(&sc->sc_queue_mtx);
|
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.
|
* 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,
|
g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
u_char hash[SHA256_DIGEST_LENGTH];
|
u_char off[8], hash[SHA256_DIGEST_LENGTH];
|
||||||
SHA256_CTX ctx;
|
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. */
|
/* Copy precalculated SHA256 context for IV-Key. */
|
||||||
bcopy(&sc->sc_ivctx, &ctx, sizeof(ctx));
|
bcopy(&sc->sc_ivctx, &ctx, sizeof(ctx));
|
||||||
SHA256_Update(&ctx, (uint8_t *)&offset, sizeof(offset));
|
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);
|
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
|
int
|
||||||
g_eli_read_metadata(struct g_class *mp, struct g_provider *pp,
|
g_eli_read_metadata(struct g_class *mp, struct g_provider *pp,
|
||||||
struct g_eli_metadata *md)
|
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;
|
sc = gp->softc;
|
||||||
|
|
||||||
if (dw > 0) {
|
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. */
|
/* Someone is opening us for write, we need to remember that. */
|
||||||
sc->sc_flags |= G_ELI_FLAG_WOPEN;
|
sc->sc_flags |= G_ELI_FLAG_WOPEN;
|
||||||
return (0);
|
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_geom *gp;
|
||||||
struct g_provider *pp;
|
struct g_provider *pp;
|
||||||
struct g_consumer *cp;
|
struct g_consumer *cp;
|
||||||
struct cryptoini cri;
|
struct cryptoini crie, cria;
|
||||||
u_int i, threads;
|
u_int i, threads;
|
||||||
int error;
|
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;
|
gp->start = g_eli_start;
|
||||||
/*
|
/*
|
||||||
* Spoiling cannot happen actually, because we keep provider open for
|
* 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->spoiled = g_eli_orphan_spoil_assert;
|
||||||
gp->orphan = g_eli_orphan;
|
gp->orphan = g_eli_orphan;
|
||||||
|
gp->dumpconf = g_eli_dumpconf;
|
||||||
/*
|
/*
|
||||||
* If detach-on-last-close feature is not enabled, we can simply use
|
* If detach-on-last-close feature is not enabled and we don't operate
|
||||||
* g_std_access().
|
* 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;
|
gp->access = g_eli_access;
|
||||||
else
|
else
|
||||||
gp->access = g_std_access;
|
gp->access = g_std_access;
|
||||||
gp->dumpconf = g_eli_dumpconf;
|
|
||||||
|
|
||||||
sc->sc_crypto = G_ELI_CRYPTO_SW;
|
sc->sc_crypto = G_ELI_CRYPTO_SW;
|
||||||
sc->sc_flags = md->md_flags;
|
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;
|
sc->sc_nkey = nkey;
|
||||||
/*
|
/*
|
||||||
* Remember the keys in our softc structure.
|
* Remember the keys in our softc structure.
|
||||||
*/
|
*/
|
||||||
bcopy(mkey, sc->sc_ivkey, sizeof(sc->sc_ivkey));
|
g_eli_mkey_propagate(sc, mkey);
|
||||||
mkey += sizeof(sc->sc_ivkey);
|
sc->sc_ekeylen = md->md_keylen;
|
||||||
bcopy(mkey, sc->sc_datakey, sizeof(sc->sc_datakey));
|
|
||||||
sc->sc_keylen = 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.
|
* 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,
|
* Keep provider open all the time, so we can run critical tasks,
|
||||||
* like Master Keys deletion, without wondering if we can open
|
* like Master Keys deletion, without wondering if we can open
|
||||||
* provider or not.
|
* 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 (error != 0) {
|
||||||
if (req != NULL) {
|
if (req != NULL) {
|
||||||
gctl_error(req, "Cannot access %s (error=%d).",
|
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);
|
LIST_INIT(&sc->sc_workers);
|
||||||
|
|
||||||
bzero(&cri, sizeof(cri));
|
bzero(&crie, sizeof(crie));
|
||||||
cri.cri_alg = sc->sc_algo;
|
crie.cri_alg = sc->sc_ealgo;
|
||||||
cri.cri_klen = sc->sc_keylen;
|
crie.cri_klen = sc->sc_ekeylen;
|
||||||
cri.cri_key = sc->sc_datakey;
|
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;
|
threads = g_eli_threads;
|
||||||
if (threads == 0)
|
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.
|
* Use software cryptography, if we cannot get it.
|
||||||
*/
|
*/
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
error = crypto_newsession(&wr->w_sid, &cri, 1);
|
error = crypto_newsession(&wr->w_sid, &crie, 1);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
sc->sc_crypto = G_ELI_CRYPTO_HW;
|
sc->sc_crypto = G_ELI_CRYPTO_HW;
|
||||||
}
|
}
|
||||||
if (sc->sc_crypto == G_ELI_CRYPTO_SW)
|
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) {
|
if (error != 0) {
|
||||||
free(wr, M_ELI);
|
free(wr, M_ELI);
|
||||||
if (req != NULL) {
|
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 = g_new_providerf(gp, "%s%s", bpp->name, G_ELI_SUFFIX);
|
||||||
pp->sectorsize = md->md_sectorsize;
|
pp->sectorsize = md->md_sectorsize;
|
||||||
pp->mediasize = bpp->mediasize;
|
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 -= 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_error_provider(pp, 0);
|
||||||
|
|
||||||
G_ELI_DEBUG(0, "Device %s created.", pp->name);
|
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, "Encryption: %s %u", g_eli_algo2str(sc->sc_ealgo),
|
||||||
G_ELI_DEBUG(0, "Key length: %u", sc->sc_keylen);
|
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",
|
G_ELI_DEBUG(0, " Crypto: %s",
|
||||||
sc->sc_crypto == G_ELI_CRYPTO_SW ? "software" : "hardware");
|
sc->sc_crypto == G_ELI_CRYPTO_SW ? "software" : "hardware");
|
||||||
return (gp);
|
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)
|
if (md.md_provsize != pp->mediasize)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
/* Should we attach it on boot? */
|
/* 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);
|
return (NULL);
|
||||||
if (md.md_keys == 0x00) {
|
if (md.md_keys == 0x00) {
|
||||||
G_ELI_DEBUG(0, "No valid keys on %s.", pp->name);
|
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;
|
int first = 1;
|
||||||
|
|
||||||
#define ADD_FLAG(flag, name) do { \
|
#define ADD_FLAG(flag, name) do { \
|
||||||
if ((sc->sc_flags & (flag)) != 0) { \
|
if (sc->sc_flags & (flag)) { \
|
||||||
if (!first) \
|
if (!first) \
|
||||||
sbuf_printf(sb, ", "); \
|
sbuf_printf(sb, ", "); \
|
||||||
else \
|
else \
|
||||||
@ -1125,17 +1004,20 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
|
|||||||
sbuf_printf(sb, name); \
|
sbuf_printf(sb, name); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} 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_ONETIME, "ONETIME");
|
||||||
ADD_FLAG(G_ELI_FLAG_BOOT, "BOOT");
|
ADD_FLAG(G_ELI_FLAG_BOOT, "BOOT");
|
||||||
ADD_FLAG(G_ELI_FLAG_WO_DETACH, "W-DETACH");
|
ADD_FLAG(G_ELI_FLAG_WO_DETACH, "W-DETACH");
|
||||||
ADD_FLAG(G_ELI_FLAG_RW_DETACH, "RW-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_WOPEN, "W-OPEN");
|
||||||
ADD_FLAG(G_ELI_FLAG_DESTROY, "DESTROY");
|
ADD_FLAG(G_ELI_FLAG_DESTROY, "DESTROY");
|
||||||
|
ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY");
|
||||||
#undef ADD_FLAG
|
#undef ADD_FLAG
|
||||||
}
|
}
|
||||||
sbuf_printf(sb, "</Flags>\n");
|
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,
|
sbuf_printf(sb, "%s<UsedKey>%u</UsedKey>\n", indent,
|
||||||
sc->sc_nkey);
|
sc->sc_nkey);
|
||||||
}
|
}
|
||||||
@ -1152,9 +1034,15 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sbuf_printf(sb, "</Crypto>\n");
|
sbuf_printf(sb, "</Crypto>\n");
|
||||||
sbuf_printf(sb, "%s<KeyLength>%u</KeyLength>\n", indent, sc->sc_keylen);
|
if (sc->sc_flags & G_ELI_FLAG_AUTH) {
|
||||||
sbuf_printf(sb, "%s<Cipher>%s</Cipher>\n", indent,
|
sbuf_printf(sb,
|
||||||
g_eli_algo2str(sc->sc_algo));
|
"%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);
|
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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -54,28 +54,43 @@
|
|||||||
/*
|
/*
|
||||||
* Version history:
|
* Version history:
|
||||||
* 0 - Initial version number.
|
* 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. */
|
/* 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. */
|
/* 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. */
|
/* 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. */
|
/* 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. */
|
/* Provider was open for writing. */
|
||||||
#define G_ELI_FLAG_WOPEN 0x00010000
|
#define G_ELI_FLAG_WOPEN 0x00010000
|
||||||
/* Destroy device. */
|
/* 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 SHA512_MDLEN 64
|
||||||
|
#define G_ELI_AUTH_SECKEYLEN SHA256_DIGEST_LENGTH
|
||||||
|
|
||||||
#define G_ELI_MAXMKEYS 2
|
#define G_ELI_MAXMKEYS 2
|
||||||
#define G_ELI_MAXKEYLEN 64
|
#define G_ELI_MAXKEYLEN 64
|
||||||
#define G_ELI_USERKEYLEN G_ELI_MAXKEYLEN
|
#define G_ELI_USERKEYLEN G_ELI_MAXKEYLEN
|
||||||
#define G_ELI_DATAKEYLEN 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_IVKEYLEN G_ELI_MAXKEYLEN
|
||||||
#define G_ELI_SALTLEN 64
|
#define G_ELI_SALTLEN 64
|
||||||
#define G_ELI_DATAIVKEYLEN (G_ELI_DATAKEYLEN + G_ELI_IVKEYLEN)
|
#define G_ELI_DATAIVKEYLEN (G_ELI_DATAKEYLEN + G_ELI_IVKEYLEN)
|
||||||
@ -85,6 +100,7 @@
|
|||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
extern u_int g_eli_debug;
|
extern u_int g_eli_debug;
|
||||||
extern u_int g_eli_overwrites;
|
extern u_int g_eli_overwrites;
|
||||||
|
extern u_int g_eli_batch;
|
||||||
|
|
||||||
#define G_ELI_CRYPTO_HW 1
|
#define G_ELI_CRYPTO_HW 1
|
||||||
#define G_ELI_CRYPTO_SW 2
|
#define G_ELI_CRYPTO_SW 2
|
||||||
@ -123,13 +139,21 @@ struct g_eli_worker {
|
|||||||
struct g_eli_softc {
|
struct g_eli_softc {
|
||||||
struct g_geom *sc_geom;
|
struct g_geom *sc_geom;
|
||||||
u_int sc_crypto;
|
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];
|
uint8_t sc_ivkey[G_ELI_IVKEYLEN];
|
||||||
SHA256_CTX sc_ivctx;
|
SHA256_CTX sc_ivctx;
|
||||||
u_int sc_algo;
|
|
||||||
u_int sc_keylen;
|
|
||||||
int sc_nkey;
|
int sc_nkey;
|
||||||
uint32_t sc_flags;
|
uint32_t sc_flags;
|
||||||
|
u_int sc_bytes_per_sector;
|
||||||
|
u_int sc_data_per_sector;
|
||||||
|
|
||||||
/* Only for software cryptography. */
|
/* Only for software cryptography. */
|
||||||
struct bio_queue_head sc_queue;
|
struct bio_queue_head sc_queue;
|
||||||
@ -143,8 +167,9 @@ struct g_eli_metadata {
|
|||||||
char md_magic[16]; /* Magic value. */
|
char md_magic[16]; /* Magic value. */
|
||||||
uint32_t md_version; /* Version number. */
|
uint32_t md_version; /* Version number. */
|
||||||
uint32_t md_flags; /* Additional flags. */
|
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_keylen; /* Key length. */
|
||||||
|
uint16_t md_aalgo; /* Authentication algorithm. */
|
||||||
uint64_t md_provsize; /* Provider's size. */
|
uint64_t md_provsize; /* Provider's size. */
|
||||||
uint32_t md_sectorsize; /* Sector size. */
|
uint32_t md_sectorsize; /* Sector size. */
|
||||||
uint8_t md_keys; /* Available keys. */
|
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);
|
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_version); p += sizeof(md->md_version);
|
||||||
le32enc(p, md->md_flags); p += sizeof(md->md_flags);
|
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_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);
|
le64enc(p, md->md_provsize); p += sizeof(md->md_provsize);
|
||||||
le32enc(p, md->md_sectorsize); p += sizeof(md->md_sectorsize);
|
le32enc(p, md->md_sectorsize); p += sizeof(md->md_sectorsize);
|
||||||
*p = md->md_keys; p += sizeof(md->md_keys);
|
*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);
|
p = data + sizeof(md->md_magic) + sizeof(md->md_version);
|
||||||
md->md_flags = le32dec(p); p += sizeof(md->md_flags);
|
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_keylen = le16dec(p); p += sizeof(md->md_keylen);
|
||||||
md->md_provsize = le64dec(p); p += sizeof(md->md_provsize);
|
md->md_provsize = le64dec(p); p += sizeof(md->md_provsize);
|
||||||
md->md_sectorsize = le32dec(p); p += sizeof(md->md_sectorsize);
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
static __inline int
|
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)
|
eli_metadata_decode(const u_char *data, struct g_eli_metadata *md)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
@ -212,6 +262,10 @@ eli_metadata_decode(const u_char *data, struct g_eli_metadata *md)
|
|||||||
case 0:
|
case 0:
|
||||||
error = eli_metadata_decode_v0(data, md);
|
error = eli_metadata_decode_v0(data, md);
|
||||||
break;
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
error = eli_metadata_decode_v1v2(data, md);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
break;
|
break;
|
||||||
@ -221,7 +275,7 @@ eli_metadata_decode(const u_char *data, struct g_eli_metadata *md)
|
|||||||
#endif /* !_OpenSSL */
|
#endif /* !_OpenSSL */
|
||||||
|
|
||||||
static __inline u_int
|
static __inline u_int
|
||||||
g_eli_str2algo(const char *name)
|
g_eli_str2ealgo(const char *name)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (strcasecmp("null", name) == 0)
|
if (strcasecmp("null", name) == 0)
|
||||||
@ -235,6 +289,25 @@ g_eli_str2algo(const char *name)
|
|||||||
return (CRYPTO_ALGORITHM_MIN - 1);
|
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 *
|
static __inline const char *
|
||||||
g_eli_algo2str(u_int algo)
|
g_eli_algo2str(u_int algo)
|
||||||
{
|
{
|
||||||
@ -243,11 +316,23 @@ g_eli_algo2str(u_int algo)
|
|||||||
case CRYPTO_NULL_CBC:
|
case CRYPTO_NULL_CBC:
|
||||||
return ("NULL");
|
return ("NULL");
|
||||||
case CRYPTO_AES_CBC:
|
case CRYPTO_AES_CBC:
|
||||||
return ("AES");
|
return ("AES-CBC");
|
||||||
case CRYPTO_BLF_CBC:
|
case CRYPTO_BLF_CBC:
|
||||||
return ("Blowfish");
|
return ("Blowfish-CBC");
|
||||||
case CRYPTO_3DES_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");
|
return ("unknown");
|
||||||
}
|
}
|
||||||
@ -262,8 +347,10 @@ eli_metadata_dump(const struct g_eli_metadata *md)
|
|||||||
printf(" magic: %s\n", md->md_magic);
|
printf(" magic: %s\n", md->md_magic);
|
||||||
printf(" version: %u\n", (u_int)md->md_version);
|
printf(" version: %u\n", (u_int)md->md_version);
|
||||||
printf(" flags: 0x%x\n", (u_int)md->md_flags);
|
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);
|
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(" provsize: %ju\n", (uintmax_t)md->md_provsize);
|
||||||
printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
|
printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
|
||||||
printf(" keys: 0x%02x\n", (u_int)md->md_keys);
|
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
|
#ifdef _KERNEL
|
||||||
int g_eli_read_metadata(struct g_class *mp, struct g_provider *pp,
|
int g_eli_read_metadata(struct g_class *mp, struct g_provider *pp,
|
||||||
struct g_eli_metadata *md);
|
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);
|
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_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
|
#endif
|
||||||
|
|
||||||
void g_eli_mkey_hmac(unsigned char *mkey, const unsigned char *key);
|
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);
|
const unsigned char *key, unsigned char *mkey, unsigned *nkeyp);
|
||||||
int g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
|
int g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
|
||||||
unsigned char *mkey);
|
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,
|
int 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);
|
||||||
|
@ -57,7 +57,7 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
|
|||||||
struct g_provider *pp;
|
struct g_provider *pp;
|
||||||
const char *name;
|
const char *name;
|
||||||
u_char *key, mkey[G_ELI_DATAIVKEYLEN];
|
u_char *key, mkey[G_ELI_DATAIVKEYLEN];
|
||||||
int *nargs, *detach;
|
int *nargs, *detach, *readonly;
|
||||||
int keysize, error;
|
int keysize, error;
|
||||||
u_int nkey;
|
u_int nkey;
|
||||||
|
|
||||||
@ -79,6 +79,12 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
|
|||||||
return;
|
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");
|
name = gctl_get_asciiparam(req, "arg0");
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
gctl_error(req, "No 'arg%u' argument.", 0);
|
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);
|
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)
|
if (*detach)
|
||||||
md.md_flags |= G_ELI_FLAG_WO_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);
|
g_eli_create(req, mp, pp, &md, mkey, nkey);
|
||||||
bzero(mkey, sizeof(mkey));
|
bzero(mkey, sizeof(mkey));
|
||||||
bzero(&md, sizeof(md));
|
bzero(&md, sizeof(md));
|
||||||
@ -250,16 +264,49 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
|
|||||||
if (*detach)
|
if (*detach)
|
||||||
md.md_flags |= G_ELI_FLAG_WO_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) {
|
if (name == NULL) {
|
||||||
gctl_error(req, "No '%s' argument.", "algo");
|
gctl_error(req, "No '%s' argument.", "aalgo");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
md.md_algo = g_eli_str2algo(name);
|
if (strcmp(name, "none") != 0) {
|
||||||
if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
|
md.md_aalgo = g_eli_str2aalgo(name);
|
||||||
md.md_algo > CRYPTO_ALGORITHM_MAX) {
|
if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
|
||||||
gctl_error(req, "Invalid '%s' argument.", "algo");
|
md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
|
||||||
return;
|
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));
|
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");
|
gctl_error(req, "No '%s' argument.", "keylen");
|
||||||
return;
|
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) {
|
if (md.md_keylen == 0) {
|
||||||
gctl_error(req, "Invalid '%s' argument.", "keylen");
|
gctl_error(req, "Invalid '%s' argument.", "keylen");
|
||||||
return;
|
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);
|
gctl_error(req, "Provider %s is invalid.", name);
|
||||||
return;
|
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);
|
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||||
pp = cp->provider;
|
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;
|
mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
|
||||||
md.md_keys |= (1 << nkey);
|
md.md_keys |= (1 << nkey);
|
||||||
|
|
||||||
bcopy(sc->sc_ivkey, mkeydst, sizeof(sc->sc_ivkey));
|
bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
|
||||||
bcopy(sc->sc_datakey, mkeydst + sizeof(sc->sc_ivkey),
|
|
||||||
sizeof(sc->sc_datakey));
|
|
||||||
|
|
||||||
/* Encrypt Master Key with the new key. */
|
/* 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));
|
bzero(key, sizeof(key));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
bzero(&md, sizeof(md));
|
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);
|
gctl_error(req, "Provider %s is invalid.", name);
|
||||||
return;
|
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);
|
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||||
pp = cp->provider;
|
pp = cp->provider;
|
||||||
|
|
||||||
@ -534,9 +587,7 @@ g_eli_kill_one(struct g_eli_softc *sc)
|
|||||||
{
|
{
|
||||||
struct g_provider *pp;
|
struct g_provider *pp;
|
||||||
struct g_consumer *cp;
|
struct g_consumer *cp;
|
||||||
u_char *sector;
|
int error = 0;
|
||||||
int err, error = 0;
|
|
||||||
u_int i;
|
|
||||||
|
|
||||||
g_topology_assert();
|
g_topology_assert();
|
||||||
|
|
||||||
@ -549,22 +600,31 @@ g_eli_kill_one(struct g_eli_softc *sc)
|
|||||||
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||||
pp = cp->provider;
|
pp = cp->provider;
|
||||||
|
|
||||||
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
|
if (sc->sc_flags & G_ELI_FLAG_RO) {
|
||||||
for (i = 0; i <= g_eli_overwrites; i++) {
|
G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
|
||||||
if (i == g_eli_overwrites)
|
"provider: %s.", pp->name);
|
||||||
bzero(sector, pp->sectorsize);
|
} else {
|
||||||
else
|
u_char *sector;
|
||||||
arc4rand(sector, pp->sectorsize, 0);
|
u_int i;
|
||||||
err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
|
int err;
|
||||||
pp->sectorsize);
|
|
||||||
if (err != 0) {
|
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
|
||||||
G_ELI_DEBUG(0, "Cannot erase metadata on %s "
|
for (i = 0; i <= g_eli_overwrites; i++) {
|
||||||
"(error=%d).", pp->name, err);
|
if (i == g_eli_overwrites)
|
||||||
if (error == 0)
|
bzero(sector, pp->sectorsize);
|
||||||
error = err;
|
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)
|
if (error == 0)
|
||||||
G_ELI_DEBUG(0, "%s has been killed.", pp->name);
|
G_ELI_DEBUG(0, "%s has been killed.", pp->name);
|
||||||
g_eli_destroy(sc, 1);
|
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;
|
nkey = 0;
|
||||||
for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++, mmkey += G_ELI_MKEYLEN) {
|
for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++, mmkey += G_ELI_MKEYLEN) {
|
||||||
bit = (1 << nkey);
|
bit = (1 << nkey);
|
||||||
if ((md->md_keys & bit) == 0)
|
if (!(md->md_keys & bit))
|
||||||
continue;
|
continue;
|
||||||
bcopy(mmkey, tmpmkey, G_ELI_MKEYLEN);
|
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);
|
G_ELI_MKEYLEN, enckey, md->md_keylen);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
bzero(tmpmkey, sizeof(tmpmkey));
|
bzero(tmpmkey, sizeof(tmpmkey));
|
||||||
@ -177,3 +177,33 @@ g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
|
|||||||
|
|
||||||
return (error);
|
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
|
.PATH: ${.CURDIR}/../../../geom/eli
|
||||||
|
|
||||||
KMOD= 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
|
WARNS?= 2
|
||||||
|
|
||||||
.include <bsd.kmod.mk>
|
.include <bsd.kmod.mk>
|
||||||
|
@ -4,11 +4,9 @@
|
|||||||
base=`basename $0`
|
base=`basename $0`
|
||||||
no=45
|
no=45
|
||||||
sectors=100
|
sectors=100
|
||||||
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
|
|
||||||
keyfile=`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
|
i=1
|
||||||
for cipher in aes:0 aes:128 aes:192 aes:256 \
|
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:0 blowfish:128 blowfish:160 blowfish:192 blowfish:224 \
|
||||||
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
|
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
|
||||||
blowfish:416 blowfish:448; do
|
blowfish:416 blowfish:448; do
|
||||||
algo=${cipher%%:*}
|
ealgo=${cipher%%:*}
|
||||||
keylen=${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 init -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no}
|
||||||
geli attach -p -k $keyfile 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`
|
dd if=/dev/random of=${rnd} bs=${secsize} count=${secs} >/dev/null 2>&1
|
||||||
md_ddev=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
|
dd if=${rnd} of=/dev/md${no}.eli bs=${secsize} count=${secs} 2>/dev/null
|
||||||
md_edev=`dd if=/dev/md${no} bs=512 count=${sectors} 2>/dev/null | md5`
|
|
||||||
|
|
||||||
if [ ${md_rnd} = ${md_ddev} ]; then
|
md_rnd=`dd if=${rnd} bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||||
echo "ok $i - ${cipher}"
|
md_ddev=`dd if=/dev/md${no}.eli bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||||
else
|
md_edev=`dd if=/dev/md${no} bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||||
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))
|
|
||||||
|
|
||||||
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
|
done
|
||||||
|
|
||||||
mdconfig -d -u $no
|
rm -f $keyfile
|
||||||
rm -f $rnd $keyfile
|
|
||||||
|
@ -4,10 +4,8 @@
|
|||||||
base=`basename $0`
|
base=`basename $0`
|
||||||
no=45
|
no=45
|
||||||
sectors=100
|
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
|
i=1
|
||||||
for cipher in aes:0 aes:128 aes:192 aes:256 \
|
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:0 blowfish:128 blowfish:160 blowfish:192 blowfish:224 \
|
||||||
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
|
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
|
||||||
blowfish:416 blowfish:448; do
|
blowfish:416 blowfish:448; do
|
||||||
algo=${cipher%%:*}
|
ealgo=${cipher%%:*}
|
||||||
keylen=${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_rnd=`dd if=${rnd} bs=${secsize} count=${secs} 2>/dev/null | md5`
|
||||||
md_ddev=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 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=512 count=${sectors} 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
|
if [ ${md_rnd} = ${md_ddev} ]; then
|
||||||
echo "ok $i - ${cipher}"
|
echo "ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||||
else
|
else
|
||||||
echo "not ok $i - ${cipher}"
|
echo "not ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||||
fi
|
fi
|
||||||
i=$((i+1))
|
i=$((i+1))
|
||||||
if [ ${md_rnd} != ${md_edev} ]; then
|
if [ ${md_rnd} != ${md_edev} ]; then
|
||||||
echo "ok $i - ${cipher}"
|
echo "ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||||
else
|
else
|
||||||
echo "not ok $i - ${cipher}"
|
echo "not ok $i - ealgo=${ealgo} keylen=${keylen} sec=${secsize}"
|
||||||
fi
|
fi
|
||||||
i=$((i+1))
|
i=$((i+1))
|
||||||
|
|
||||||
geli detach md${no}
|
geli detach md${no}
|
||||||
|
rm -f $rnd
|
||||||
|
mdconfig -d -u $no
|
||||||
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
mdconfig -d -u $no
|
|
||||||
rm -f $rnd
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user