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
95e4208ebf
commit
c58794debd
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…
Reference in New Issue
Block a user