Add GEOM_ELI class which provides GEOM providers encryption.
For features list and usage see manual page: geli(8). Sponsored by: Wheel Sp. z o.o. http://www.wheel.pl MFC after: 1 week
This commit is contained in:
parent
52bcb6f38c
commit
57922fa5cc
17
sbin/geom/class/eli/Makefile
Normal file
17
sbin/geom/class/eli/Makefile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/../../misc ${.CURDIR}/../../../../sys/geom/eli ${.CURDIR}/../../../../sys/crypto/sha2
|
||||||
|
|
||||||
|
CLASS= eli
|
||||||
|
SRCS= g_eli_crypto.c
|
||||||
|
SRCS+= g_eli_key.c
|
||||||
|
SRCS+= pkcs5v2.c
|
||||||
|
SRCS+= sha2.c
|
||||||
|
|
||||||
|
DPADD= ${LIBMD} ${LIBCRYPTO}
|
||||||
|
LDADD= -lmd -lcrypto
|
||||||
|
|
||||||
|
NO_MAN=
|
||||||
|
CFLAGS+=-I${.CURDIR}/../../../../sys
|
||||||
|
|
||||||
|
.include <bsd.lib.mk>
|
511
sbin/geom/class/eli/geli.8
Normal file
511
sbin/geom/class/eli/geli.8
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
.\" Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||||
|
.\" All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" $FreeBSD$
|
||||||
|
.\"
|
||||||
|
.Dd April 11, 2005
|
||||||
|
.Dt GELI 8
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm geli
|
||||||
|
.Nd "control utility for cryptographic GEOM class"
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
To compile GEOM_ELI into your kernel, place the following lines in your kernel
|
||||||
|
configuration file:
|
||||||
|
.Bd -ragged -offset indent
|
||||||
|
.Cd "device crypto"
|
||||||
|
.Cd "device cryptodev"
|
||||||
|
.Cd "options GEOM_ELI"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Alternately, to load the GEOM_ELI module at boot time, place the following line
|
||||||
|
in your
|
||||||
|
.Xr loader.conf 5 :
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
geom_eli_load="YES"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Usage of the
|
||||||
|
.Xr geli 8
|
||||||
|
utility:
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
.Cm init
|
||||||
|
.Op Fl bPv
|
||||||
|
.Op Fl a Ar algo
|
||||||
|
.Op Fl i Ar iterations
|
||||||
|
.Op Fl K Ar newkeyfile
|
||||||
|
.Op Fl l Ar keylen
|
||||||
|
.Op Fl s Ar sectorsize
|
||||||
|
.Ar prov
|
||||||
|
.Nm
|
||||||
|
.Cm label - an alias for
|
||||||
|
.Cm init
|
||||||
|
.Nm
|
||||||
|
.Cm attach
|
||||||
|
.Op Fl dpv
|
||||||
|
.Op Fl k Ar keyfile
|
||||||
|
.Ar prov
|
||||||
|
.Nm
|
||||||
|
.Cm detach
|
||||||
|
.Op Fl fl
|
||||||
|
.Ar prov ...
|
||||||
|
.Nm
|
||||||
|
.Cm stop - an alias for
|
||||||
|
.Cm detach
|
||||||
|
.Nm
|
||||||
|
.Cm onetime
|
||||||
|
.Op Fl d
|
||||||
|
.Op Fl a Ar algo
|
||||||
|
.Op Fl l Ar keylen
|
||||||
|
.Op Fl s Ar sectorsize
|
||||||
|
.Ar prov ...
|
||||||
|
.Nm
|
||||||
|
.Cm setkey
|
||||||
|
.Op Fl pPv
|
||||||
|
.Op Fl k Ar keyfile
|
||||||
|
.Op Fl K Ar newkeyfile
|
||||||
|
.Op Fl n Ar keyno
|
||||||
|
.Ar prov
|
||||||
|
.Nm
|
||||||
|
.Cm delkey
|
||||||
|
.Op Fl afv
|
||||||
|
.Op Fl n Ar keyno
|
||||||
|
.Ar prov
|
||||||
|
.Nm
|
||||||
|
.Cm kill
|
||||||
|
.Op Fl av
|
||||||
|
.Op Ar prov ...
|
||||||
|
.Nm
|
||||||
|
.Cm backup
|
||||||
|
.Op Fl v
|
||||||
|
.Ar prov
|
||||||
|
.Ar file
|
||||||
|
.Nm
|
||||||
|
.Cm restore
|
||||||
|
.Op Fl v
|
||||||
|
.Ar file
|
||||||
|
.Ar prov
|
||||||
|
.Nm
|
||||||
|
.Cm clear
|
||||||
|
.Op Fl v
|
||||||
|
.Ar prov ...
|
||||||
|
.Nm
|
||||||
|
.Cm dump
|
||||||
|
.Op Fl v
|
||||||
|
.Ar prov ...
|
||||||
|
.Nm
|
||||||
|
.Cm list
|
||||||
|
.Nm
|
||||||
|
.Cm status
|
||||||
|
.Nm
|
||||||
|
.Cm load
|
||||||
|
.Nm
|
||||||
|
.Cm unload
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is used to configure encryption on GEOM providers.
|
||||||
|
.Pp
|
||||||
|
Here is the list of the most important features:
|
||||||
|
.Pp
|
||||||
|
.Bl -bullet -offset indent -compact
|
||||||
|
.It
|
||||||
|
Utilize the
|
||||||
|
.Xr crypto 9
|
||||||
|
framework, so when there is a crypto hardware available,
|
||||||
|
.Nm
|
||||||
|
will make use of it automatically.
|
||||||
|
If cryptography needs to be done in software,
|
||||||
|
a dedicated kernel thread will be started to do the crypto work in there.
|
||||||
|
.It
|
||||||
|
Supports many cryptographic algorithms (currently
|
||||||
|
.Nm AES ,
|
||||||
|
.Nm Blowfish
|
||||||
|
and
|
||||||
|
.Nm 3DES ) .
|
||||||
|
.It
|
||||||
|
Can create a key from a couple of components (user entered passphrase, random
|
||||||
|
bits from a file, etc.).
|
||||||
|
.It
|
||||||
|
Allows to encrypt root partition - user will be asked for the passphrase before
|
||||||
|
root file system is mounted.
|
||||||
|
.It
|
||||||
|
User's passphrase is strengthen with:
|
||||||
|
.Rs
|
||||||
|
.%A B. Kaliski
|
||||||
|
.%T "PKCS #5: Password-Based Cryptography Specification, Version 2.0."
|
||||||
|
.%R RFC
|
||||||
|
.%N 2898
|
||||||
|
.Re
|
||||||
|
.It
|
||||||
|
Allows to use two independent keys (e.g.
|
||||||
|
.Qq "user key"
|
||||||
|
and
|
||||||
|
.Qq "company key" ) .
|
||||||
|
.It
|
||||||
|
It is fast -
|
||||||
|
.Nm
|
||||||
|
performs simple sector-to-sector encryption.
|
||||||
|
.It
|
||||||
|
Allows to backup/restore Master Keys, so when user have to quickly destroy keys,
|
||||||
|
it is able to get the data back by restoring keys from the backup.
|
||||||
|
.It
|
||||||
|
Provider can be configured to automatically detach on last close (so user don't
|
||||||
|
have to remember to detach provider after unmounting file system).
|
||||||
|
.It
|
||||||
|
Allows to attach provider with a random, one-time keys - useful for swap
|
||||||
|
partitions and temporary file systems.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The first argument to
|
||||||
|
.Nm
|
||||||
|
indicates an action to be performed:
|
||||||
|
.Bl -tag -width ".Cm onetime"
|
||||||
|
.It Cm init
|
||||||
|
Initialize provider which needs to be encrypted.
|
||||||
|
Here you can setup 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
|
||||||
|
Encryption algorithm to use.
|
||||||
|
Currently supported algorithms are:
|
||||||
|
.Nm AES ,
|
||||||
|
.Nm Blowfish
|
||||||
|
and
|
||||||
|
.Nm 3DES .
|
||||||
|
The default is
|
||||||
|
.Nm AES .
|
||||||
|
.It Fl b
|
||||||
|
Ask for the passphrase on boot, before root partition is mounted.
|
||||||
|
This allows to use encrypted root partition.
|
||||||
|
One will still need bootable unencrypted storage with
|
||||||
|
.Pa /boot/
|
||||||
|
directory, which can be a CD-ROM disc or USB pen-drive, which can be removed
|
||||||
|
after boot.
|
||||||
|
.It Fl i Ar iterations
|
||||||
|
Number of iterations to use with PKCS#5v2.
|
||||||
|
If this option is not specified
|
||||||
|
.Nm
|
||||||
|
will find the number of iterations which is equal to 2 seconds of crypto work.
|
||||||
|
If 0 is given, PKCS#5v2 will not be used.
|
||||||
|
.It Fl K Ar newkeyfile
|
||||||
|
Specifies a file which contains part of the key.
|
||||||
|
If
|
||||||
|
.Ar newkeyfile
|
||||||
|
is given as -, standard input will be used.
|
||||||
|
Here is how more than one file with the key component can be used:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# cat key1 key2 key3 | geli init -K - /dev/da0
|
||||||
|
.Ed
|
||||||
|
.It Fl l Ar keylen
|
||||||
|
Key length to use with the given cryptographic algorithm.
|
||||||
|
If not given, the default key length for the given algorithm is used, which is:
|
||||||
|
128 for
|
||||||
|
.Nm AES ,
|
||||||
|
128 for
|
||||||
|
.Nm Blowfish
|
||||||
|
and 192 for
|
||||||
|
.Nm 3DES .
|
||||||
|
.It Fl s Ar sectorsize
|
||||||
|
Change decrypted provider's sector size.
|
||||||
|
Increasing sector size allows to increase performance, because we need to
|
||||||
|
generate IV and do encrypt/decrypt for every single sector - less number
|
||||||
|
of sectors means less work to do.
|
||||||
|
.It Fl P
|
||||||
|
Do not use passphrase as the key component.
|
||||||
|
.El
|
||||||
|
.It Cm attach
|
||||||
|
Attach the given provider. The master key will be decrypted using the given
|
||||||
|
passphrase/keyfile and a new GEOM provider will be created using the given
|
||||||
|
provider's name with an
|
||||||
|
.Qq .eli
|
||||||
|
suffix.
|
||||||
|
.Pp
|
||||||
|
Additional options include:
|
||||||
|
.Bl -tag -width ".Fl a Ar algo"
|
||||||
|
.It Fl d
|
||||||
|
If specified, decrypted provider will be detached automatically on last close.
|
||||||
|
This can help with short memory - user doesn't have to remember to detach
|
||||||
|
provider after unmounting file system.
|
||||||
|
It only works when provider was opened for writing, so it will not work if
|
||||||
|
file system on the provider is mounted read-only.
|
||||||
|
Probably better choice is the
|
||||||
|
.Fl l
|
||||||
|
option for the
|
||||||
|
.Cm detach
|
||||||
|
subcommand.
|
||||||
|
.It Fl k Ar keyfile
|
||||||
|
Specifies a file which contains part of the key.
|
||||||
|
For more information see description of
|
||||||
|
.Fl K
|
||||||
|
option for the
|
||||||
|
.Cm init
|
||||||
|
subcommand.
|
||||||
|
.It Fl p
|
||||||
|
Do not use passphrase as the key component.
|
||||||
|
.El
|
||||||
|
.It Cm detach
|
||||||
|
Detach the given providers, which means remove devfs entry and clear the keys
|
||||||
|
from memory.
|
||||||
|
.Pp
|
||||||
|
Additional options include:
|
||||||
|
.Bl -tag -width ".Fl a Ar algo"
|
||||||
|
.It Fl f
|
||||||
|
Force detach - detach even if provider is open.
|
||||||
|
.It Fl l
|
||||||
|
Mark provider to detach on last close.
|
||||||
|
If this option is specified provider will not be detached until it is open,
|
||||||
|
but when it will be closed last time, it will be automatically detached (even
|
||||||
|
if it was only opened for reading).
|
||||||
|
.El
|
||||||
|
.It Cm onetime
|
||||||
|
Attach the given providers with a 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
|
||||||
|
Encryption algorithm to use.
|
||||||
|
For more information see description of the
|
||||||
|
.Cm init
|
||||||
|
subcommand.
|
||||||
|
.It Fl d
|
||||||
|
Detach on last close.
|
||||||
|
Note, the option is not usable for temporary file system, because provider will
|
||||||
|
be detached after creating file system on it.
|
||||||
|
It still can (and should be) used for swap partitions.
|
||||||
|
For more information see description of the
|
||||||
|
.Cm attach
|
||||||
|
subcommand.
|
||||||
|
.It Fl l Ar keylen
|
||||||
|
Key length to use with the given cryptographic algorithm.
|
||||||
|
For more information see description of the
|
||||||
|
.Cm init
|
||||||
|
subcommand.
|
||||||
|
.It Fl s Ar sectorsize
|
||||||
|
Change decrypted provider's sector size.
|
||||||
|
For more information see description of the
|
||||||
|
.Cm init
|
||||||
|
subcommand.
|
||||||
|
.El
|
||||||
|
.It Cm setkey
|
||||||
|
Change or setup (if not yet initialized) selected key.
|
||||||
|
There is one master key, which can be encrypted with two independent user keys.
|
||||||
|
With the
|
||||||
|
.Cm init
|
||||||
|
subcommand only key number 0 is initialized.
|
||||||
|
The key can be always changed: for attached provider, for detached provider or
|
||||||
|
on the backup file.
|
||||||
|
When provider is attached, user don't have to provide an old passphrase/keyfile.
|
||||||
|
.Pp
|
||||||
|
Additional options include:
|
||||||
|
.Bl -tag -width ".Fl a Ar algo"
|
||||||
|
.It Fl k Ar keyfile
|
||||||
|
Specifies a file which contains part of the old key.
|
||||||
|
.It Fl K Ar newkeyfile
|
||||||
|
Specifies a file which contains part of the new key.
|
||||||
|
.It Fl n Ar keyno
|
||||||
|
Specifies number of the key to change (could be 0 or 1).
|
||||||
|
If provider is attached and no key number is given, the key used for attaching
|
||||||
|
provider will be changed.
|
||||||
|
If provider is detached (or we're operating on a backup file) and no key number
|
||||||
|
is given, the key decrypted with passphrase/keyfile will be changed.
|
||||||
|
.It Fl p
|
||||||
|
Do not use passphrase as the old key component.
|
||||||
|
.It Fl P
|
||||||
|
Do not use passphrase as the new key component.
|
||||||
|
.El
|
||||||
|
.It Cm delkey
|
||||||
|
Destroy (overwrite with random data) selected key.
|
||||||
|
If one is destroying keys for an attached provider, provider won't be detached
|
||||||
|
even if all keys will be destroyed.
|
||||||
|
It can be even rescued with the
|
||||||
|
.Cm setkey
|
||||||
|
subcommand.
|
||||||
|
.Bl -tag -width ".Fl a Ar algo"
|
||||||
|
.It Fl a
|
||||||
|
Destroy all keys (doesn't need
|
||||||
|
.Fl f
|
||||||
|
option).
|
||||||
|
.It Fl f
|
||||||
|
Force key destruction. This option is needed to destroy the last key.
|
||||||
|
.It Fl n Ar keyno
|
||||||
|
Specifies the key number.
|
||||||
|
If provider is attached and no key number is given, the key used for attaching
|
||||||
|
provider will be destroyed.
|
||||||
|
If provider is detached (or we're operating on a backup file) the key number
|
||||||
|
has to be given.
|
||||||
|
.El
|
||||||
|
.It Cm kill
|
||||||
|
The command should be used in emergency situations.
|
||||||
|
It will destroy all keys on the given provider and will detach it forcibly
|
||||||
|
(if it is attached).
|
||||||
|
This is absolutely one-way command - if you don't have metadata backup, your data
|
||||||
|
is gone for good.
|
||||||
|
.Bl -tag -width ".Fl a Ar algo"
|
||||||
|
.It Fl a
|
||||||
|
If specified, all currently attached providers will be killed.
|
||||||
|
.El
|
||||||
|
.It Cm backup
|
||||||
|
Backup metadata from the given provider to the given file.
|
||||||
|
.It Cm restore
|
||||||
|
Restore metadata from the given file to the given provider.
|
||||||
|
.It Cm clear
|
||||||
|
Clear metadata from the given providers.
|
||||||
|
.It Cm dump
|
||||||
|
Dump metadata stored on the given providers.
|
||||||
|
.It Cm list
|
||||||
|
See
|
||||||
|
.Xr geom 8 .
|
||||||
|
.It Cm status
|
||||||
|
See
|
||||||
|
.Xr geom 8 .
|
||||||
|
.It Cm load
|
||||||
|
See
|
||||||
|
.Xr geom 8 .
|
||||||
|
.It Cm unload
|
||||||
|
See
|
||||||
|
.Xr geom 8 .
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Additional options include:
|
||||||
|
.Bl -tag -width ".Fl v"
|
||||||
|
.It Fl v
|
||||||
|
Be more verbose.
|
||||||
|
.El
|
||||||
|
.Sh SYSCTL VARIABLES
|
||||||
|
The following
|
||||||
|
.Xr sysctl 8
|
||||||
|
variables can be used to control the behavior of the
|
||||||
|
.Nm ELI
|
||||||
|
GEOM class.
|
||||||
|
The default value is shown next to each variable.
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Va kern.geom.eli.debug : No 0
|
||||||
|
Debug level of the
|
||||||
|
.Nm ELI
|
||||||
|
GEOM class.
|
||||||
|
This can be set to a number between 0 and 3 inclusive.
|
||||||
|
If set to 0 minimal debug information is printed, and 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 user is asked for the passphrase.
|
||||||
|
This is only used for providers which should be attached on boot (before root
|
||||||
|
file system is mounted).
|
||||||
|
If set to 0, attaching providers on boot will be disabled.
|
||||||
|
This variable should be set in
|
||||||
|
.Pa /boot/loader.conf .
|
||||||
|
.It Va kern.geom.eli.overwrites : No 5
|
||||||
|
Specifies how many times Master-Key will be overwriten with random values when
|
||||||
|
it is destroyed. After this operation it is filled with zeros.
|
||||||
|
.It Va kern.geom.eli.visible_passphrase : No 0
|
||||||
|
If set to 1, passphrase entered on boot (before root file system is mounted)
|
||||||
|
will be visible.
|
||||||
|
This possibility should be used with caution as entered passphrase can be logged
|
||||||
|
and exposed via
|
||||||
|
.Xr dmesg 8 .
|
||||||
|
This variable should be set in
|
||||||
|
.Pa /boot/loader.conf .
|
||||||
|
.It Va kern.geom.eli.threads : No 1
|
||||||
|
Specifies how many kernel threads should be used for doing software
|
||||||
|
cryptography.
|
||||||
|
It's purpose is to increase performance on SMP systems.
|
||||||
|
This variable could be set in
|
||||||
|
.Pa /boot/loader.conf .
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
Exit status is 0 on success, and 1 if the command fails.
|
||||||
|
.Sh EXAMPLES
|
||||||
|
Initialize provider which is going to be encrypted with a passphrase and random
|
||||||
|
data from a file on the user's pen drive.
|
||||||
|
Use 4kB sector size.
|
||||||
|
Attach the provider, create a file system and mount it.
|
||||||
|
Do the work.
|
||||||
|
Unmount provider and detach it:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# dd if=/dev/random of=/mnt/pendrive/da2.key bs=64 count=1
|
||||||
|
# geli init -s 4096 -K /mnt/pendrive/da2.key /dev/da2
|
||||||
|
Enter new passphrase:
|
||||||
|
Reenter new passphrase:
|
||||||
|
# geli attach -k /mnt/pendrive/da2.key /dev/da2
|
||||||
|
Enter passphrase:
|
||||||
|
# dd if=/dev/random of=/dev/da2.eli bs=1m
|
||||||
|
# newfs /dev/da2.eli
|
||||||
|
# mount /dev/da2.eli /mnt/secret
|
||||||
|
\&...
|
||||||
|
# umount /mnt/secret
|
||||||
|
# geli detach da2.eli
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Create encrypted provider, but use two key: one for your girlfriend and one for
|
||||||
|
you (so there will be no tragedy if she forget her passphrase):
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# geli init /dev/da2
|
||||||
|
Enter new passphrase: (enter your passphrase)
|
||||||
|
Reenter new passphrase:
|
||||||
|
# geli setkey -n 1 /dev/da2
|
||||||
|
Enter passphrase: (enter your passphrase)
|
||||||
|
Enter new passphrase: (let your girlfriend to enter her passphrase ...)
|
||||||
|
Reenter new passphrase: (... twice)
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
You are security-person in your company.
|
||||||
|
Create encrypted provider for use by the user, but remember that users forget
|
||||||
|
their passphrases, so backup Master Key with your own random key:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# dd if=/dev/random of=/mnt/pendrive/keys/`hostname` bs=64 count=1
|
||||||
|
# geli init -P -K /mnt/pendrive/keys/`hostname` /dev/ad0s1e
|
||||||
|
# geli backup /dev/ad0s1e /mnt/pendrive/backups/`hostname`
|
||||||
|
(use key number 0, so encrypted Master Key by you will be overwriten)
|
||||||
|
# geli setkey -n 0 -k /mnt/pendrive/keys/`hostname` /dev/ad0s1e
|
||||||
|
(allow the user to enter his passphrase)
|
||||||
|
Enter new passphrase:
|
||||||
|
Reenter new passphrase:
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Encrypted swap partition setup:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# dd if=/dev/random of=/dev/ad0s1b bs=1m
|
||||||
|
# geli onetime -d -a 3des ad0s1b
|
||||||
|
# swapon /dev/ad0s1b.eli
|
||||||
|
.Ed
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr crypto 4 ,
|
||||||
|
.Xr crypto 9 ,
|
||||||
|
.Xr gbde 4 ,
|
||||||
|
.Xr gbde 8 ,
|
||||||
|
.Xr geom 4 ,
|
||||||
|
.Xr geom 8
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility appeared in
|
||||||
|
.Fx 5.5 .
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org
|
1246
sbin/geom/class/eli/geom_eli.c
Normal file
1246
sbin/geom/class/eli/geom_eli.c
Normal file
File diff suppressed because it is too large
Load Diff
1138
sys/geom/eli/g_eli.c
Normal file
1138
sys/geom/eli/g_eli.c
Normal file
File diff suppressed because it is too large
Load Diff
366
sys/geom/eli/g_eli.h
Normal file
366
sys/geom/eli/g_eli.h
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _G_ELI_H_
|
||||||
|
#define _G_ELI_H_
|
||||||
|
|
||||||
|
#include <sys/endian.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <crypto/sha2/sha2.h>
|
||||||
|
#include <opencrypto/cryptodev.h>
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <sys/bio.h>
|
||||||
|
#include <sys/libkern.h>
|
||||||
|
#include <geom/geom.h>
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
#ifndef _OpenSSL_
|
||||||
|
#include <sys/md5.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define G_ELI_CLASS_NAME "ELI"
|
||||||
|
#define G_ELI_MAGIC "GEOM::ELI"
|
||||||
|
#define G_ELI_SUFFIX ".eli"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version history:
|
||||||
|
* 0 - Initial version number.
|
||||||
|
*/
|
||||||
|
#define G_ELI_VERSION 0
|
||||||
|
|
||||||
|
/* Use random, onetime keys. */
|
||||||
|
#define G_ELI_FLAG_ONETIME 0x00000001
|
||||||
|
/* Ask for the passphrase from the kernel, before mounting root. */
|
||||||
|
#define G_ELI_FLAG_BOOT 0x00000002
|
||||||
|
/* Detach on last close, if we were open for writing. */
|
||||||
|
#define G_ELI_FLAG_WO_DETACH 0x00000004
|
||||||
|
/* Detach on last close. */
|
||||||
|
#define G_ELI_FLAG_RW_DETACH 0x00000008
|
||||||
|
/* Provider was open for writing. */
|
||||||
|
#define G_ELI_FLAG_WOPEN 0x00010000
|
||||||
|
/* Destroy device. */
|
||||||
|
#define G_ELI_FLAG_DESTROY 0x00020000
|
||||||
|
|
||||||
|
#define SHA512_MDLEN 64
|
||||||
|
|
||||||
|
#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_IVKEYLEN G_ELI_MAXKEYLEN
|
||||||
|
#define G_ELI_SALTLEN 64
|
||||||
|
#define G_ELI_DATAIVKEYLEN (G_ELI_DATAKEYLEN + G_ELI_IVKEYLEN)
|
||||||
|
/* Data-Key, IV-Key, HMAC_SHA512(Derived-Key, Data-Key+IV-Key) */
|
||||||
|
#define G_ELI_MKEYLEN (G_ELI_DATAIVKEYLEN + SHA512_MDLEN)
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
extern u_int g_eli_debug;
|
||||||
|
extern u_int g_eli_overwrites;
|
||||||
|
|
||||||
|
#define G_ELI_CRYPTO_HW 1
|
||||||
|
#define G_ELI_CRYPTO_SW 2
|
||||||
|
|
||||||
|
#define G_ELI_DEBUG(lvl, ...) do { \
|
||||||
|
if (g_eli_debug >= (lvl)) { \
|
||||||
|
printf("GEOM_ELI"); \
|
||||||
|
if (g_eli_debug > 0) \
|
||||||
|
printf("[%u]", lvl); \
|
||||||
|
printf(": "); \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
printf("\n"); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define G_ELI_LOGREQ(lvl, bp, ...) do { \
|
||||||
|
if (g_eli_debug >= (lvl)) { \
|
||||||
|
printf("GEOM_ELI"); \
|
||||||
|
if (g_eli_debug > 0) \
|
||||||
|
printf("[%u]", lvl); \
|
||||||
|
printf(": "); \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
printf(" "); \
|
||||||
|
g_print_bio(bp); \
|
||||||
|
printf("\n"); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
struct g_eli_worker {
|
||||||
|
struct g_eli_softc *w_softc;
|
||||||
|
struct proc *w_proc;
|
||||||
|
u_int w_number;
|
||||||
|
uint64_t w_sid;
|
||||||
|
LIST_ENTRY(g_eli_worker) w_next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct g_eli_softc {
|
||||||
|
struct g_geom *sc_geom;
|
||||||
|
u_int sc_crypto;
|
||||||
|
uint8_t sc_datakey[G_ELI_DATAKEYLEN];
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Only for software cryptography. */
|
||||||
|
struct bio_queue_head sc_queue;
|
||||||
|
struct mtx sc_queue_mtx;
|
||||||
|
LIST_HEAD(, g_eli_worker) sc_workers;
|
||||||
|
};
|
||||||
|
#define sc_name sc_geom->name
|
||||||
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
|
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_keylen; /* Key length. */
|
||||||
|
uint64_t md_provsize; /* Provider's size. */
|
||||||
|
uint32_t md_sectorsize; /* Sector size. */
|
||||||
|
uint8_t md_keys; /* Available keys. */
|
||||||
|
int32_t md_iterations; /* Number of iterations for PKCS#5v2 */
|
||||||
|
uint8_t md_salt[G_ELI_SALTLEN]; /* Salt. */
|
||||||
|
/* Encrypted master key (IV-key, Data-key, HMAC). */
|
||||||
|
uint8_t md_mkeys[G_ELI_MAXMKEYS * G_ELI_MKEYLEN];
|
||||||
|
u_char md_hash[16]; /* MD5 hash. */
|
||||||
|
};
|
||||||
|
#ifndef _OpenSSL_
|
||||||
|
static __inline void
|
||||||
|
eli_metadata_encode(struct g_eli_metadata *md, u_char *data)
|
||||||
|
{
|
||||||
|
MD5_CTX ctx;
|
||||||
|
u_char *p;
|
||||||
|
|
||||||
|
p = 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_keylen); p += sizeof(md->md_keylen);
|
||||||
|
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);
|
||||||
|
le32enc(p, md->md_iterations); p += sizeof(md->md_iterations);
|
||||||
|
bcopy(md->md_salt, p, sizeof(md->md_salt)); p += sizeof(md->md_salt);
|
||||||
|
bcopy(md->md_mkeys, p, sizeof(md->md_mkeys)); p += sizeof(md->md_mkeys);
|
||||||
|
MD5Init(&ctx);
|
||||||
|
MD5Update(&ctx, data, p - data);
|
||||||
|
MD5Final(md->md_hash, &ctx);
|
||||||
|
bcopy(md->md_hash, p, sizeof(md->md_hash));
|
||||||
|
}
|
||||||
|
static __inline int
|
||||||
|
eli_metadata_decode_v0(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_algo = le16dec(p); p += sizeof(md->md_algo);
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
|
||||||
|
bcopy(data, md->md_magic, sizeof(md->md_magic));
|
||||||
|
md->md_version = le32dec(data + sizeof(md->md_magic));
|
||||||
|
switch (md->md_version) {
|
||||||
|
case 0:
|
||||||
|
error = eli_metadata_decode_v0(data, md);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
#endif /* !_OpenSSL */
|
||||||
|
|
||||||
|
static __inline u_int
|
||||||
|
g_eli_str2algo(const char *name)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (strcmp("null", name) == 0)
|
||||||
|
return (CRYPTO_NULL_CBC);
|
||||||
|
if (strcmp("aes", name) == 0)
|
||||||
|
return (CRYPTO_AES_CBC);
|
||||||
|
else if (strcmp("blowfish", name) == 0)
|
||||||
|
return (CRYPTO_BLF_CBC);
|
||||||
|
else if (strcmp("3des", name) == 0)
|
||||||
|
return (CRYPTO_3DES_CBC);
|
||||||
|
return (CRYPTO_ALGORITHM_MIN - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline const char *
|
||||||
|
g_eli_algo2str(u_int algo)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (algo) {
|
||||||
|
case CRYPTO_NULL_CBC:
|
||||||
|
return ("NULL");
|
||||||
|
case CRYPTO_AES_CBC:
|
||||||
|
return ("AES");
|
||||||
|
case CRYPTO_BLF_CBC:
|
||||||
|
return ("Blowfish");
|
||||||
|
case CRYPTO_3DES_CBC:
|
||||||
|
return ("3DES");
|
||||||
|
}
|
||||||
|
return ("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void
|
||||||
|
eli_metadata_dump(const struct g_eli_metadata *md)
|
||||||
|
{
|
||||||
|
static const char hex[] = "0123456789abcdef";
|
||||||
|
char str[sizeof(md->md_mkeys) * 2 + 1];
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
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(" keylen: %u\n", (u_int)md->md_keylen);
|
||||||
|
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);
|
||||||
|
printf("iterations: %u\n", (u_int)md->md_iterations);
|
||||||
|
bzero(str, sizeof(str));
|
||||||
|
for (i = 0; i < sizeof(md->md_salt); i++) {
|
||||||
|
str[i * 2] = hex[md->md_salt[i] >> 4];
|
||||||
|
str[i * 2 + 1] = hex[md->md_salt[i] & 0x0f];
|
||||||
|
}
|
||||||
|
printf(" Salt: %s\n", str);
|
||||||
|
bzero(str, sizeof(str));
|
||||||
|
for (i = 0; i < sizeof(md->md_mkeys); i++) {
|
||||||
|
str[i * 2] = hex[md->md_mkeys[i] >> 4];
|
||||||
|
str[i * 2 + 1] = hex[md->md_mkeys[i] & 0x0f];
|
||||||
|
}
|
||||||
|
printf("Master Key: %s\n", str);
|
||||||
|
bzero(str, sizeof(str));
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
str[i * 2] = hex[md->md_hash[i] >> 4];
|
||||||
|
str[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
|
||||||
|
}
|
||||||
|
printf(" MD5 hash: %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline u_int
|
||||||
|
g_eli_keylen(u_int algo, u_int keylen)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (algo) {
|
||||||
|
case CRYPTO_NULL_CBC:
|
||||||
|
if (keylen == 0)
|
||||||
|
keylen = 64 * 8;
|
||||||
|
else {
|
||||||
|
if (keylen > 64 * 8)
|
||||||
|
keylen = 0;
|
||||||
|
}
|
||||||
|
return (keylen);
|
||||||
|
case CRYPTO_AES_CBC:
|
||||||
|
switch (keylen) {
|
||||||
|
case 0:
|
||||||
|
return (128);
|
||||||
|
case 128:
|
||||||
|
case 192:
|
||||||
|
case 256:
|
||||||
|
return (keylen);
|
||||||
|
default:
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
case CRYPTO_BLF_CBC:
|
||||||
|
if (keylen == 0)
|
||||||
|
return (128);
|
||||||
|
if (keylen < 128 || keylen > 448)
|
||||||
|
return (0);
|
||||||
|
if ((keylen % 32) != 0)
|
||||||
|
return (0);
|
||||||
|
return (keylen);
|
||||||
|
case CRYPTO_3DES_CBC:
|
||||||
|
if (keylen == 0 || keylen == 192)
|
||||||
|
return (192);
|
||||||
|
return (0);
|
||||||
|
default:
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
int g_eli_read_metadata(struct g_class *mp, struct g_provider *pp,
|
||||||
|
struct g_eli_metadata *md);
|
||||||
|
struct g_geom *g_eli_create(struct gctl_req *req, struct g_class *mp,
|
||||||
|
struct g_provider *bpp, const struct g_eli_metadata *md,
|
||||||
|
const u_char *mkey, int nkey);
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void g_eli_mkey_hmac(unsigned char *mkey, const unsigned char *key);
|
||||||
|
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);
|
||||||
|
|
||||||
|
int g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
|
||||||
|
const u_char *key, size_t keysize);
|
||||||
|
int g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
|
||||||
|
const u_char *key, size_t keysize);
|
||||||
|
|
||||||
|
struct hmac_ctx {
|
||||||
|
SHA512_CTX shactx;
|
||||||
|
u_char k_opad[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
void g_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey,
|
||||||
|
size_t hkeylen);
|
||||||
|
void g_eli_crypto_hmac_update(struct hmac_ctx *ctx, const uint8_t *data,
|
||||||
|
size_t datasize);
|
||||||
|
void g_eli_crypto_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize);
|
||||||
|
void g_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize,
|
||||||
|
const uint8_t *data, size_t datasize, uint8_t *md, size_t mdsize);
|
||||||
|
#endif /* !_G_ELI_H_ */
|
276
sys/geom/eli/g_eli_crypto.c
Normal file
276
sys/geom/eli/g_eli_crypto.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#define _OpenSSL_
|
||||||
|
#endif
|
||||||
|
#include <geom/eli/g_eli.h>
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
MALLOC_DECLARE(M_ELI);
|
||||||
|
|
||||||
|
static int
|
||||||
|
g_eli_crypto_done(struct cryptop *crp)
|
||||||
|
{
|
||||||
|
|
||||||
|
crp->crp_opaque = (void *)crp;
|
||||||
|
wakeup(crp);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
|
||||||
|
const u_char *key, size_t keysize)
|
||||||
|
{
|
||||||
|
struct cryptoini cri;
|
||||||
|
struct cryptop *crp;
|
||||||
|
struct cryptodesc *crd;
|
||||||
|
struct uio *uio;
|
||||||
|
struct iovec *iov;
|
||||||
|
uint64_t sid;
|
||||||
|
u_char *p;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
bzero(&cri, sizeof(cri));
|
||||||
|
cri.cri_alg = algo;
|
||||||
|
cri.cri_key = __DECONST(void *, key);
|
||||||
|
cri.cri_klen = keysize;
|
||||||
|
error = crypto_newsession(&sid, &cri, 0);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
p = malloc(sizeof(*crp) + sizeof(*crd) + sizeof(*uio) + sizeof(*iov),
|
||||||
|
M_ELI, M_NOWAIT | M_ZERO);
|
||||||
|
if (p == NULL) {
|
||||||
|
crypto_freesession(sid);
|
||||||
|
return (ENOMEM);
|
||||||
|
}
|
||||||
|
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 = datasize;
|
||||||
|
iov->iov_base = data;
|
||||||
|
|
||||||
|
uio->uio_iov = iov;
|
||||||
|
uio->uio_iovcnt = 1;
|
||||||
|
uio->uio_segflg = UIO_SYSSPACE;
|
||||||
|
uio->uio_resid = datasize;
|
||||||
|
|
||||||
|
crd->crd_skip = 0;
|
||||||
|
crd->crd_len = datasize;
|
||||||
|
crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT | CRD_F_KEY_EXPLICIT;
|
||||||
|
if (enc)
|
||||||
|
crd->crd_flags |= CRD_F_ENCRYPT;
|
||||||
|
crd->crd_alg = algo;
|
||||||
|
crd->crd_key = __DECONST(void *, key);
|
||||||
|
crd->crd_klen = keysize;
|
||||||
|
bzero(crd->crd_iv, sizeof(crd->crd_iv));
|
||||||
|
crd->crd_next = NULL;
|
||||||
|
|
||||||
|
crp->crp_sid = sid;
|
||||||
|
crp->crp_ilen = datasize;
|
||||||
|
crp->crp_olen = datasize;
|
||||||
|
crp->crp_opaque = NULL;
|
||||||
|
crp->crp_callback = g_eli_crypto_done;
|
||||||
|
crp->crp_buf = (void *)uio;
|
||||||
|
crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIFSYNC | CRYPTO_F_REL;
|
||||||
|
crp->crp_desc = crd;
|
||||||
|
|
||||||
|
error = crypto_dispatch(crp);
|
||||||
|
if (error == 0) {
|
||||||
|
while (crp->crp_opaque == NULL)
|
||||||
|
tsleep(crp, PRIBIO, "geli", hz / 5);
|
||||||
|
error = crp->crp_etype;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(crp, M_ELI);
|
||||||
|
crypto_freesession(sid);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
#else /* !_KERNEL */
|
||||||
|
static int
|
||||||
|
g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
|
||||||
|
const u_char *key, size_t keysize)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX ctx;
|
||||||
|
const EVP_CIPHER *type;
|
||||||
|
u_char iv[keysize];
|
||||||
|
int outsize;
|
||||||
|
|
||||||
|
switch (algo) {
|
||||||
|
case CRYPTO_NULL_CBC:
|
||||||
|
type = EVP_enc_null();
|
||||||
|
break;
|
||||||
|
case CRYPTO_AES_CBC:
|
||||||
|
switch (keysize) {
|
||||||
|
case 128:
|
||||||
|
type = EVP_aes_128_cbc();
|
||||||
|
break;
|
||||||
|
case 192:
|
||||||
|
type = EVP_aes_192_cbc();
|
||||||
|
break;
|
||||||
|
case 256:
|
||||||
|
type = EVP_aes_256_cbc();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CRYPTO_BLF_CBC:
|
||||||
|
type = EVP_bf_cbc();
|
||||||
|
break;
|
||||||
|
case CRYPTO_3DES_CBC:
|
||||||
|
type = EVP_des_ede3_cbc();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX_init(&ctx);
|
||||||
|
|
||||||
|
EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc);
|
||||||
|
EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8);
|
||||||
|
EVP_CIPHER_CTX_set_padding(&ctx, 0);
|
||||||
|
bzero(iv, sizeof(iv));
|
||||||
|
EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc);
|
||||||
|
|
||||||
|
if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) {
|
||||||
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
assert(outsize == (int)datasize);
|
||||||
|
|
||||||
|
if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) {
|
||||||
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
assert(outsize == 0);
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
#endif /* !_KERNEL */
|
||||||
|
|
||||||
|
int
|
||||||
|
g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
|
||||||
|
const u_char *key, size_t keysize)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
|
||||||
|
const u_char *key, size_t keysize)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey,
|
||||||
|
size_t hkeylen)
|
||||||
|
{
|
||||||
|
u_char k_ipad[128], key[128];
|
||||||
|
SHA512_CTX lctx;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
bzero(key, sizeof(key));
|
||||||
|
if (hkeylen == 0)
|
||||||
|
; /* do nothing */
|
||||||
|
else if (hkeylen <= 128)
|
||||||
|
bcopy(hkey, key, hkeylen);
|
||||||
|
else {
|
||||||
|
/* If key is longer than 128 bytes reset it to key = SHA512(key). */
|
||||||
|
SHA512_Init(&lctx);
|
||||||
|
SHA512_Update(&lctx, hkey, hkeylen);
|
||||||
|
SHA512_Final(key, &lctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XOR key with ipad and opad values. */
|
||||||
|
for (i = 0; i < sizeof(key); i++) {
|
||||||
|
k_ipad[i] = key[i] ^ 0x36;
|
||||||
|
ctx->k_opad[i] = key[i] ^ 0x5c;
|
||||||
|
}
|
||||||
|
bzero(key, sizeof(key));
|
||||||
|
/* Perform inner SHA512. */
|
||||||
|
SHA512_Init(&ctx->shactx);
|
||||||
|
SHA512_Update(&ctx->shactx, k_ipad, sizeof(k_ipad));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_eli_crypto_hmac_update(struct hmac_ctx *ctx, const uint8_t *data,
|
||||||
|
size_t datasize)
|
||||||
|
{
|
||||||
|
|
||||||
|
SHA512_Update(&ctx->shactx, data, datasize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_eli_crypto_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize)
|
||||||
|
{
|
||||||
|
u_char digest[SHA512_MDLEN];
|
||||||
|
SHA512_CTX lctx;
|
||||||
|
|
||||||
|
SHA512_Final(digest, &ctx->shactx);
|
||||||
|
/* Perform outer SHA512. */
|
||||||
|
SHA512_Init(&lctx);
|
||||||
|
SHA512_Update(&lctx, ctx->k_opad, sizeof(ctx->k_opad));
|
||||||
|
bzero(ctx, sizeof(*ctx));
|
||||||
|
SHA512_Update(&lctx, digest, sizeof(digest));
|
||||||
|
SHA512_Final(digest, &lctx);
|
||||||
|
/* mdsize == 0 means "Give me the whole hash!" */
|
||||||
|
if (mdsize == 0)
|
||||||
|
mdsize = SHA512_MDLEN;
|
||||||
|
bcopy(digest, md, mdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data,
|
||||||
|
size_t datasize, uint8_t *md, size_t mdsize)
|
||||||
|
{
|
||||||
|
struct hmac_ctx ctx;
|
||||||
|
|
||||||
|
g_eli_crypto_hmac_init(&ctx, hkey, hkeysize);
|
||||||
|
g_eli_crypto_hmac_update(&ctx, data, datasize);
|
||||||
|
g_eli_crypto_hmac_final(&ctx, md, mdsize);
|
||||||
|
}
|
639
sys/geom/eli/g_eli_ctl.c
Normal file
639
sys/geom/eli/g_eli_ctl.c
Normal file
@ -0,0 +1,639 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/bio.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/kthread.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/sched.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#include <vm/uma.h>
|
||||||
|
|
||||||
|
#include <geom/geom.h>
|
||||||
|
#include <geom/eli/g_eli.h>
|
||||||
|
|
||||||
|
|
||||||
|
MALLOC_DECLARE(M_ELI);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
|
||||||
|
{
|
||||||
|
struct g_eli_metadata md;
|
||||||
|
struct g_provider *pp;
|
||||||
|
const char *name;
|
||||||
|
u_char *key, mkey[G_ELI_DATAIVKEYLEN];
|
||||||
|
int *nargs, *detach;
|
||||||
|
int keysize, error;
|
||||||
|
u_int nkey;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
|
||||||
|
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
|
||||||
|
if (nargs == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "nargs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*nargs != 1) {
|
||||||
|
gctl_error(req, "Invalid number of arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
detach = gctl_get_paraml(req, "detach", sizeof(*detach));
|
||||||
|
if (detach == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "detach");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = gctl_get_asciiparam(req, "arg0");
|
||||||
|
if (name == NULL) {
|
||||||
|
gctl_error(req, "No 'arg%u' argument.", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
|
||||||
|
name += strlen("/dev/");
|
||||||
|
pp = g_provider_by_name(name);
|
||||||
|
if (pp == NULL) {
|
||||||
|
gctl_error(req, "Provider %s is invalid.", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
error = g_eli_read_metadata(mp, pp, &md);
|
||||||
|
if (error != 0) {
|
||||||
|
gctl_error(req, "Cannot read metadata from %s (error=%d).",
|
||||||
|
name, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (md.md_keys == 0x00) {
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
gctl_error(req, "No valid keys on %s.", pp->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = gctl_get_param(req, "key", &keysize);
|
||||||
|
if (key == NULL || keysize != G_ELI_USERKEYLEN) {
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
gctl_error(req, "No '%s' argument.", "key");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
|
||||||
|
bzero(key, keysize);
|
||||||
|
if (error == -1) {
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
gctl_error(req, "Wrong key for %s.", pp->name);
|
||||||
|
return;
|
||||||
|
} else if (error > 0) {
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
|
||||||
|
pp->name, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
|
||||||
|
|
||||||
|
if (*detach)
|
||||||
|
md.md_flags |= G_ELI_FLAG_WO_DETACH;
|
||||||
|
g_eli_create(req, mp, pp, &md, mkey, nkey);
|
||||||
|
bzero(mkey, sizeof(mkey));
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct g_eli_softc *
|
||||||
|
g_eli_find_device(struct g_class *mp, const char *prov)
|
||||||
|
{
|
||||||
|
struct g_eli_softc *sc;
|
||||||
|
struct g_geom *gp;
|
||||||
|
struct g_provider *pp;
|
||||||
|
struct g_consumer *cp;
|
||||||
|
|
||||||
|
if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
|
||||||
|
prov += strlen("/dev/");
|
||||||
|
LIST_FOREACH(gp, &mp->geom, geom) {
|
||||||
|
sc = gp->softc;
|
||||||
|
if (sc == NULL)
|
||||||
|
continue;
|
||||||
|
pp = LIST_FIRST(&gp->provider);
|
||||||
|
if (pp != NULL && strcmp(pp->name, prov) == 0)
|
||||||
|
return (sc);
|
||||||
|
cp = LIST_FIRST(&gp->consumer);
|
||||||
|
if (cp != NULL && cp->provider != NULL &&
|
||||||
|
strcmp(cp->provider->name, prov) == 0) {
|
||||||
|
return (sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
|
||||||
|
{
|
||||||
|
struct g_eli_softc *sc;
|
||||||
|
int *force, *last, *nargs, error;
|
||||||
|
const char *prov;
|
||||||
|
char param[16];
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
|
||||||
|
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
|
||||||
|
if (nargs == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "nargs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*nargs <= 0) {
|
||||||
|
gctl_error(req, "Missing device(s).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
force = gctl_get_paraml(req, "force", sizeof(*force));
|
||||||
|
if (force == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "force");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
last = gctl_get_paraml(req, "last", sizeof(*last));
|
||||||
|
if (last == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "last");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (u_int)*nargs; i++) {
|
||||||
|
snprintf(param, sizeof(param), "arg%u", i);
|
||||||
|
prov = gctl_get_asciiparam(req, param);
|
||||||
|
if (prov == NULL) {
|
||||||
|
gctl_error(req, "No 'arg%u' argument.", i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sc = g_eli_find_device(mp, prov);
|
||||||
|
if (sc == NULL) {
|
||||||
|
gctl_error(req, "No such device: %s.", prov);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*last) {
|
||||||
|
sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
|
||||||
|
sc->sc_geom->access = g_eli_access;
|
||||||
|
} else {
|
||||||
|
error = g_eli_destroy(sc, *force);
|
||||||
|
if (error != 0) {
|
||||||
|
gctl_error(req,
|
||||||
|
"Cannot destroy device %s (error=%d).",
|
||||||
|
sc->sc_name, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
|
||||||
|
{
|
||||||
|
struct g_eli_metadata md;
|
||||||
|
struct g_provider *pp;
|
||||||
|
const char *name;
|
||||||
|
intmax_t *keylen, *sectorsize;
|
||||||
|
u_char mkey[G_ELI_DATAIVKEYLEN];
|
||||||
|
int *nargs, *detach;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
|
||||||
|
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
|
||||||
|
if (nargs == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "nargs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*nargs != 1) {
|
||||||
|
gctl_error(req, "Invalid number of arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
detach = gctl_get_paraml(req, "detach", sizeof(*detach));
|
||||||
|
if (detach == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "detach");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
|
||||||
|
md.md_version = G_ELI_VERSION;
|
||||||
|
md.md_flags |= G_ELI_FLAG_ONETIME;
|
||||||
|
if (*detach)
|
||||||
|
md.md_flags |= G_ELI_FLAG_WO_DETACH;
|
||||||
|
|
||||||
|
name = gctl_get_asciiparam(req, "algo");
|
||||||
|
if (name == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "algo");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
|
||||||
|
if (keylen == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "keylen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
md.md_keylen = g_eli_keylen(md.md_algo, *keylen);
|
||||||
|
if (md.md_keylen == 0) {
|
||||||
|
gctl_error(req, "Invalid '%s' argument.", "keylen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not important here. */
|
||||||
|
md.md_provsize = 0;
|
||||||
|
/* Not important here. */
|
||||||
|
bzero(md.md_salt, sizeof(md.md_salt));
|
||||||
|
|
||||||
|
md.md_keys = 0x01;
|
||||||
|
arc4rand(mkey, sizeof(mkey), 0);
|
||||||
|
|
||||||
|
/* Not important here. */
|
||||||
|
bzero(md.md_hash, sizeof(md.md_hash));
|
||||||
|
|
||||||
|
name = gctl_get_asciiparam(req, "arg0");
|
||||||
|
if (name == NULL) {
|
||||||
|
gctl_error(req, "No 'arg%u' argument.", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
|
||||||
|
name += strlen("/dev/");
|
||||||
|
pp = g_provider_by_name(name);
|
||||||
|
if (pp == NULL) {
|
||||||
|
gctl_error(req, "Provider %s is invalid.", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
|
||||||
|
if (sectorsize == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "sectorsize");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*sectorsize == 0)
|
||||||
|
md.md_sectorsize = pp->sectorsize;
|
||||||
|
else {
|
||||||
|
if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
|
||||||
|
gctl_error(req, "Invalid sector size.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
md.md_sectorsize = *sectorsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_eli_create(req, mp, pp, &md, mkey, -1);
|
||||||
|
bzero(mkey, sizeof(mkey));
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
|
||||||
|
{
|
||||||
|
struct g_eli_softc *sc;
|
||||||
|
struct g_eli_metadata md;
|
||||||
|
struct g_provider *pp;
|
||||||
|
struct g_consumer *cp;
|
||||||
|
const char *name;
|
||||||
|
u_char *key, *mkeydst, *sector;
|
||||||
|
intmax_t *valp;
|
||||||
|
int nkey;
|
||||||
|
int keysize, error;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
|
||||||
|
name = gctl_get_asciiparam(req, "arg0");
|
||||||
|
if (name == NULL) {
|
||||||
|
gctl_error(req, "No 'arg%u' argument.", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sc = g_eli_find_device(mp, name);
|
||||||
|
if (sc == NULL) {
|
||||||
|
gctl_error(req, "Provider %s is invalid.", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||||
|
pp = cp->provider;
|
||||||
|
|
||||||
|
error = g_eli_read_metadata(mp, pp, &md);
|
||||||
|
if (error != 0) {
|
||||||
|
gctl_error(req, "Cannot read metadata from %s (error=%d).",
|
||||||
|
name, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
|
||||||
|
if (valp == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "keyno");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*valp != -1)
|
||||||
|
nkey = *valp;
|
||||||
|
else
|
||||||
|
nkey = sc->sc_nkey;
|
||||||
|
if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
|
||||||
|
gctl_error(req, "Invalid '%s' argument.", "keyno");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = gctl_get_param(req, "key", &keysize);
|
||||||
|
if (key == NULL || keysize != G_ELI_USERKEYLEN) {
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
gctl_error(req, "No '%s' argument.", "key");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* Encrypt Master Key with the new key. */
|
||||||
|
error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst);
|
||||||
|
bzero(key, sizeof(key));
|
||||||
|
if (error != 0) {
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
|
||||||
|
/* Store metadata with fresh key. */
|
||||||
|
eli_metadata_encode(&md, sector);
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
|
||||||
|
pp->sectorsize);
|
||||||
|
bzero(sector, sizeof(sector));
|
||||||
|
free(sector, M_ELI);
|
||||||
|
if (error != 0) {
|
||||||
|
gctl_error(req, "Cannot store metadata on %s (error=%d).",
|
||||||
|
pp->name, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
|
||||||
|
{
|
||||||
|
struct g_eli_softc *sc;
|
||||||
|
struct g_eli_metadata md;
|
||||||
|
struct g_provider *pp;
|
||||||
|
struct g_consumer *cp;
|
||||||
|
const char *name;
|
||||||
|
u_char *mkeydst, *sector;
|
||||||
|
intmax_t *valp;
|
||||||
|
size_t keysize;
|
||||||
|
int error, nkey, *all, *force;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
|
||||||
|
nkey = 0; /* fixes causeless gcc warning */
|
||||||
|
|
||||||
|
name = gctl_get_asciiparam(req, "arg0");
|
||||||
|
if (name == NULL) {
|
||||||
|
gctl_error(req, "No 'arg%u' argument.", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sc = g_eli_find_device(mp, name);
|
||||||
|
if (sc == NULL) {
|
||||||
|
gctl_error(req, "Provider %s is invalid.", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cp = LIST_FIRST(&sc->sc_geom->consumer);
|
||||||
|
pp = cp->provider;
|
||||||
|
|
||||||
|
error = g_eli_read_metadata(mp, pp, &md);
|
||||||
|
if (error != 0) {
|
||||||
|
gctl_error(req, "Cannot read metadata from %s (error=%d).",
|
||||||
|
name, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
all = gctl_get_paraml(req, "all", sizeof(*all));
|
||||||
|
if (all == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "all");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*all) {
|
||||||
|
mkeydst = md.md_mkeys;
|
||||||
|
keysize = sizeof(md.md_mkeys);
|
||||||
|
} else {
|
||||||
|
force = gctl_get_paraml(req, "force", sizeof(*force));
|
||||||
|
if (force == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "force");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
|
||||||
|
if (valp == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "keyno");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*valp != -1)
|
||||||
|
nkey = *valp;
|
||||||
|
else
|
||||||
|
nkey = sc->sc_nkey;
|
||||||
|
if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
|
||||||
|
gctl_error(req, "Invalid '%s' argument.", "keyno");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(md.md_keys & (1 << nkey)) && !*force) {
|
||||||
|
gctl_error(req, "Master Key %u is not set.", nkey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
md.md_keys &= ~(1 << nkey);
|
||||||
|
if (md.md_keys == 0 && !*force) {
|
||||||
|
gctl_error(req, "This is the last Master Key. Use '-f' "
|
||||||
|
"flag if you really want to remove it.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
|
||||||
|
keysize = G_ELI_MKEYLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
|
||||||
|
for (i = 0; i <= g_eli_overwrites; i++) {
|
||||||
|
if (i == g_eli_overwrites)
|
||||||
|
bzero(mkeydst, keysize);
|
||||||
|
else
|
||||||
|
arc4rand(mkeydst, keysize, 0);
|
||||||
|
/* Store metadata with destroyed key. */
|
||||||
|
eli_metadata_encode(&md, sector);
|
||||||
|
error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
|
||||||
|
pp->sectorsize);
|
||||||
|
if (error != 0) {
|
||||||
|
G_ELI_DEBUG(0, "Cannot store metadata on %s "
|
||||||
|
"(error=%d).", pp->name, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bzero(&md, sizeof(md));
|
||||||
|
bzero(sector, sizeof(sector));
|
||||||
|
free(sector, M_ELI);
|
||||||
|
if (*all)
|
||||||
|
G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
|
||||||
|
else
|
||||||
|
G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
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;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
|
||||||
|
if (sc == NULL)
|
||||||
|
return (ENOENT);
|
||||||
|
|
||||||
|
pp = LIST_FIRST(&sc->sc_geom->provider);
|
||||||
|
g_error_provider(pp, ENXIO);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(sector, M_ELI);
|
||||||
|
if (error == 0)
|
||||||
|
G_ELI_DEBUG(0, "%s has been killed.", pp->name);
|
||||||
|
g_eli_destroy(sc, 1);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
|
||||||
|
{
|
||||||
|
int *all, *nargs;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
|
||||||
|
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
|
||||||
|
if (nargs == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "nargs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
all = gctl_get_paraml(req, "all", sizeof(*all));
|
||||||
|
if (all == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "all");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!*all && *nargs == 0) {
|
||||||
|
gctl_error(req, "Too few arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*all) {
|
||||||
|
struct g_geom *gp, *gp2;
|
||||||
|
|
||||||
|
LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
|
||||||
|
error = g_eli_kill_one(gp->softc);
|
||||||
|
if (error != 0)
|
||||||
|
gctl_error(req, "Not fully done.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct g_eli_softc *sc;
|
||||||
|
const char *prov;
|
||||||
|
char param[16];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < *nargs; i++) {
|
||||||
|
snprintf(param, sizeof(param), "arg%u", i);
|
||||||
|
prov = gctl_get_asciiparam(req, param);
|
||||||
|
|
||||||
|
sc = g_eli_find_device(mp, prov);
|
||||||
|
if (sc == NULL) {
|
||||||
|
G_ELI_DEBUG(1, "No such provider: %s.", prov);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
error = g_eli_kill_one(sc);
|
||||||
|
if (error != 0)
|
||||||
|
gctl_error(req, "Not fully done.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
|
||||||
|
{
|
||||||
|
uint32_t *version;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
|
||||||
|
version = gctl_get_paraml(req, "version", sizeof(*version));
|
||||||
|
if (version == NULL) {
|
||||||
|
gctl_error(req, "No '%s' argument.", "version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*version != G_ELI_VERSION) {
|
||||||
|
gctl_error(req, "Userland and kernel parts are out of sync.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(verb, "attach") == 0)
|
||||||
|
g_eli_ctl_attach(req, mp);
|
||||||
|
else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
|
||||||
|
g_eli_ctl_detach(req, mp);
|
||||||
|
else if (strcmp(verb, "onetime") == 0)
|
||||||
|
g_eli_ctl_onetime(req, mp);
|
||||||
|
else if (strcmp(verb, "setkey") == 0)
|
||||||
|
g_eli_ctl_setkey(req, mp);
|
||||||
|
else if (strcmp(verb, "delkey") == 0)
|
||||||
|
g_eli_ctl_delkey(req, mp);
|
||||||
|
else if (strcmp(verb, "kill") == 0)
|
||||||
|
g_eli_ctl_kill(req, mp);
|
||||||
|
else
|
||||||
|
gctl_error(req, "Unknown verb.");
|
||||||
|
}
|
179
sys/geom/eli/g_eli_key.c
Normal file
179
sys/geom/eli/g_eli_key.c
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <geom/geom.h>
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <geom/eli/g_eli.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify if the given 'key' is correct.
|
||||||
|
* Return 1 if it is correct and 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
g_eli_mkey_verify(const unsigned char *mkey, const unsigned char *key)
|
||||||
|
{
|
||||||
|
const unsigned char *odhmac; /* On-disk HMAC. */
|
||||||
|
unsigned char chmac[SHA512_MDLEN]; /* Calculated HMAC. */
|
||||||
|
unsigned char hmkey[SHA512_MDLEN]; /* Key for HMAC. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key for HMAC calculations is: hmkey = HMAC_SHA512(Derived-Key, 0)
|
||||||
|
*/
|
||||||
|
g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x00", 1, hmkey, 0);
|
||||||
|
|
||||||
|
odhmac = mkey + G_ELI_DATAIVKEYLEN;
|
||||||
|
|
||||||
|
/* Calculate HMAC from Data-Key and IV-Key. */
|
||||||
|
g_eli_crypto_hmac(hmkey, sizeof(hmkey), mkey, G_ELI_DATAIVKEYLEN,
|
||||||
|
chmac, 0);
|
||||||
|
|
||||||
|
bzero(hmkey, sizeof(hmkey));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare calculated HMAC with HMAC from metadata.
|
||||||
|
* If two HMACs are equal, 'key' is correct.
|
||||||
|
*/
|
||||||
|
return (!bcmp(odhmac, chmac, SHA512_MDLEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate HMAC from Data-Key and IV-Key.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_eli_mkey_hmac(unsigned char *mkey, const unsigned char *key)
|
||||||
|
{
|
||||||
|
unsigned char hmkey[SHA512_MDLEN]; /* Key for HMAC. */
|
||||||
|
unsigned char *odhmac; /* On-disk HMAC. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key for HMAC calculations is: hmkey = HMAC_SHA512(Derived-Key, 0)
|
||||||
|
*/
|
||||||
|
g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x00", 1, hmkey, 0);
|
||||||
|
|
||||||
|
odhmac = mkey + G_ELI_DATAIVKEYLEN;
|
||||||
|
/* Calculate HMAC from Data-Key and IV-Key. */
|
||||||
|
g_eli_crypto_hmac(hmkey, sizeof(hmkey), mkey, G_ELI_DATAIVKEYLEN,
|
||||||
|
odhmac, 0);
|
||||||
|
|
||||||
|
bzero(hmkey, sizeof(hmkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find and decrypt Master Key encrypted with 'key'.
|
||||||
|
* Return decrypted Master Key number in 'nkeyp' if not NULL.
|
||||||
|
* Return 0 on success, > 0 on failure, -1 on bad key.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
g_eli_mkey_decrypt(const struct g_eli_metadata *md, const unsigned char *key,
|
||||||
|
unsigned char *mkey, unsigned *nkeyp)
|
||||||
|
{
|
||||||
|
unsigned char tmpmkey[G_ELI_MKEYLEN];
|
||||||
|
unsigned char enckey[SHA512_MDLEN]; /* Key for encryption. */
|
||||||
|
const unsigned char *mmkey;
|
||||||
|
int bit, error, nkey;
|
||||||
|
|
||||||
|
if (nkeyp != NULL)
|
||||||
|
*nkeyp = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key for encryption is: enckey = HMAC_SHA512(Derived-Key, 1)
|
||||||
|
*/
|
||||||
|
g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x01", 1, enckey, 0);
|
||||||
|
|
||||||
|
mmkey = md->md_mkeys;
|
||||||
|
nkey = 0;
|
||||||
|
for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++, mmkey += G_ELI_MKEYLEN) {
|
||||||
|
bit = (1 << nkey);
|
||||||
|
if ((md->md_keys & bit) == 0)
|
||||||
|
continue;
|
||||||
|
bcopy(mmkey, tmpmkey, G_ELI_MKEYLEN);
|
||||||
|
error = g_eli_crypto_decrypt(md->md_algo, tmpmkey,
|
||||||
|
G_ELI_MKEYLEN, enckey, md->md_keylen);
|
||||||
|
if (error != 0) {
|
||||||
|
bzero(tmpmkey, sizeof(tmpmkey));
|
||||||
|
bzero(enckey, sizeof(enckey));
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
if (g_eli_mkey_verify(tmpmkey, key)) {
|
||||||
|
bcopy(tmpmkey, mkey, G_ELI_DATAIVKEYLEN);
|
||||||
|
bzero(tmpmkey, sizeof(tmpmkey));
|
||||||
|
bzero(enckey, sizeof(enckey));
|
||||||
|
if (nkeyp != NULL)
|
||||||
|
*nkeyp = nkey;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bzero(enckey, sizeof(enckey));
|
||||||
|
bzero(tmpmkey, sizeof(tmpmkey));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encrypt the Master-Key and calculate HMAC to be able to verify it in the
|
||||||
|
* future.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
|
||||||
|
unsigned char *mkey)
|
||||||
|
{
|
||||||
|
unsigned char enckey[SHA512_MDLEN]; /* Key for encryption. */
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To calculate HMAC, the whole key (G_ELI_USERKEYLEN bytes long) will
|
||||||
|
* be used.
|
||||||
|
*/
|
||||||
|
g_eli_mkey_hmac(mkey, key);
|
||||||
|
/*
|
||||||
|
* The key for encryption is: enckey = HMAC_SHA512(Derived-Key, 1)
|
||||||
|
*/
|
||||||
|
g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x01", 1, enckey, 0);
|
||||||
|
/*
|
||||||
|
* Encrypt the Master-Key and HMAC() result with the given key (this
|
||||||
|
* time only 'keylen' bits from the key are used).
|
||||||
|
*/
|
||||||
|
error = g_eli_crypto_encrypt(algo, mkey, G_ELI_MKEYLEN, enckey, keylen);
|
||||||
|
|
||||||
|
bzero(enckey, sizeof(enckey));
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
123
sys/geom/eli/pkcs5v2.c
Normal file
123
sys/geom/eli/pkcs5v2.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#else
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <geom/eli/g_eli.h>
|
||||||
|
#include <geom/eli/pkcs5v2.h>
|
||||||
|
|
||||||
|
static __inline void
|
||||||
|
xor(uint8_t *dst, const uint8_t *src, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (; size > 0; size--)
|
||||||
|
*dst++ ^= *src++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pkcs5v2_genkey(uint8_t *key, unsigned keylen, const uint8_t *salt,
|
||||||
|
size_t saltsize, const char *passphrase, u_int iterations)
|
||||||
|
{
|
||||||
|
uint8_t md[SHA512_MDLEN], saltcount[saltsize + sizeof(uint32_t)];
|
||||||
|
uint8_t *counter, *keyp;
|
||||||
|
u_int i, bsize, passlen;
|
||||||
|
uint32_t count;
|
||||||
|
|
||||||
|
passlen = strlen(passphrase);
|
||||||
|
bzero(key, keylen);
|
||||||
|
bcopy(salt, saltcount, saltsize);
|
||||||
|
counter = saltcount + saltsize;
|
||||||
|
|
||||||
|
keyp = key;
|
||||||
|
for (count = 1; keylen > 0; count++, keylen -= bsize, keyp += bsize) {
|
||||||
|
bsize = MIN(keylen, sizeof(md));
|
||||||
|
|
||||||
|
counter[0] = (count >> 24) & 0xff;
|
||||||
|
counter[1] = (count >> 16) & 0xff;
|
||||||
|
counter[2] = (count >> 8) & 0xff;
|
||||||
|
counter[3] = count & 0xff;
|
||||||
|
g_eli_crypto_hmac(passphrase, passlen, saltcount,
|
||||||
|
sizeof(saltcount), md, 0);
|
||||||
|
xor(keyp, md, bsize);
|
||||||
|
|
||||||
|
for(i = 1; i < iterations; i++) {
|
||||||
|
g_eli_crypto_hmac(passphrase, passlen, md, sizeof(md),
|
||||||
|
md, 0);
|
||||||
|
xor(keyp, md, bsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _KERNEL
|
||||||
|
/*
|
||||||
|
* Return the number of microseconds needed for 'interations' iterations.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
pkcs5v2_probe(int iterations)
|
||||||
|
{
|
||||||
|
uint8_t key[G_ELI_USERKEYLEN], salt[G_ELI_SALTLEN];
|
||||||
|
uint8_t passphrase[] = "passphrase";
|
||||||
|
struct rusage start, end;
|
||||||
|
int usecs;
|
||||||
|
|
||||||
|
getrusage(RUSAGE_SELF, &start);
|
||||||
|
pkcs5v2_genkey(key, sizeof(key), salt, sizeof(salt), passphrase,
|
||||||
|
iterations);
|
||||||
|
getrusage(RUSAGE_SELF, &end);
|
||||||
|
|
||||||
|
usecs = end.ru_utime.tv_sec - start.ru_utime.tv_sec;
|
||||||
|
usecs *= 1000000;
|
||||||
|
usecs += end.ru_utime.tv_usec - start.ru_utime.tv_usec;
|
||||||
|
return (usecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the number of iterations which takes 'usecs' microseconds.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
pkcs5v2_calculate(int usecs)
|
||||||
|
{
|
||||||
|
int iterations, v;
|
||||||
|
|
||||||
|
for (iterations = 1; ; iterations <<= 1) {
|
||||||
|
v = pkcs5v2_probe(iterations);
|
||||||
|
if (v > 2000000)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (((intmax_t)iterations * (intmax_t)usecs) / v);
|
||||||
|
}
|
||||||
|
#endif /* !_KERNEL */
|
36
sys/geom/eli/pkcs5v2.h
Normal file
36
sys/geom/eli/pkcs5v2.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PKCS5V2_H_
|
||||||
|
#define _PKCS5V2_H_
|
||||||
|
void pkcs5v2_genkey(uint8_t *key, unsigned keylen, const uint8_t *salt,
|
||||||
|
size_t saltsize, const char *passphrase, u_int iterations);
|
||||||
|
#ifndef _KERNEL
|
||||||
|
int pkcs5v2_calculate(int usecs);
|
||||||
|
#endif
|
||||||
|
#endif /* !_PKCS5V2_H_ */
|
9
sys/modules/geom/geom_eli/Makefile
Normal file
9
sys/modules/geom/geom_eli/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
.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
|
||||||
|
WARNS?= 2
|
||||||
|
|
||||||
|
.include <bsd.kmod.mk>
|
Loading…
x
Reference in New Issue
Block a user