This commit was manufactured by cvs2svn to create branch 'RELENG_6'.

This commit is contained in:
cvs2svn 2005-07-29 10:06:58 +00:00
parent d8ee659609
commit ec43e58941
20 changed files with 4790 additions and 0 deletions

View File

@ -0,0 +1,18 @@
# $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
WARNS?= 3
CFLAGS+=-I${.CURDIR}/../../../../sys
.include <bsd.lib.mk>

File diff suppressed because it is too large Load Diff

1170
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
View 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
View 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
View 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
View 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
View 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
View 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_ */

113
sys/geom/zero/g_zero.c Normal file
View File

@ -0,0 +1,113 @@
/*-
* 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$
*/
#include <sys/param.h>
#include <sys/bio.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <geom/geom.h>
#define G_ZERO_CLASS_NAME "ZERO"
SYSCTL_DECL(_kern_geom);
SYSCTL_NODE(_kern_geom, OID_AUTO, zero, CTLFLAG_RW, 0, "GEOM_ZERO stuff");
static u_int g_zero_clear = 1;
SYSCTL_UINT(_kern_geom_zero, OID_AUTO, clear, CTLFLAG_RW, &g_zero_clear, 0,
"Zero-fill bio_data.");
static void
g_zero_start(struct bio *bp)
{
int error = ENXIO;
switch (bp->bio_cmd) {
case BIO_READ:
if (g_zero_clear)
bzero(bp->bio_data, bp->bio_length);
/* FALLTHROUGH */
case BIO_DELETE:
case BIO_WRITE:
bp->bio_completed = bp->bio_length;
error = 0;
break;
case BIO_GETATTR:
default:
error = EOPNOTSUPP;
break;
}
g_io_deliver(bp, error);
}
static void
g_zero_init(struct g_class *mp)
{
struct g_geom *gp;
struct g_provider *pp;
g_topology_assert();
gp = g_new_geomf(mp, "gzero");
gp->start = g_zero_start;
gp->access = g_std_access;
pp = g_new_providerf(gp, "%s", gp->name);
pp->mediasize = 1152921504606846976LLU;
pp->sectorsize = 512;
g_error_provider(pp, 0);
}
static int
g_zero_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused,
struct g_geom *gp)
{
struct g_provider *pp;
g_topology_assert();
if (gp == NULL)
return (0);
pp = LIST_FIRST(&gp->provider);
if (pp == NULL)
return (0);
if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)
return (EBUSY);
g_wither_geom(gp, ENXIO);
return (EBUSY);
}
static struct g_class g_zero_class = {
.name = G_ZERO_CLASS_NAME,
.version = G_VERSION,
.init = g_zero_init,
.destroy_geom = g_zero_destroy_geom
};
DECLARE_GEOM_CLASS(g_zero_class, g_zero);

View 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>

View File

@ -0,0 +1,8 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../geom/zero
KMOD= geom_zero
SRCS= g_zero.c
.include <bsd.kmod.mk>

View File

@ -0,0 +1,38 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
keyfile=`mktemp /tmp/$base.XXXXXX` || exit 1
mdconfig -a -t malloc -s `expr $sectors + 1` -u $no || exit 1
echo "1..3"
dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1
geli init -P -K $keyfile md${no}
geli attach -d -p -k $keyfile md${no}
if [ -c /dev/md${no}.eli ]; then
echo "ok 1"
else
echo "not ok 1"
fi
# Be sure it doesn't detach on read.
dd if=/dev/md${no}.eli of=/dev/null 2>/dev/null
sleep 1
if [ -c /dev/md${no}.eli ]; then
echo "ok 2"
else
echo "not ok 2"
fi
true > /dev/md${no}.eli
sleep 1
if [ ! -c /dev/md${no}.eli ]; then
echo "ok 3"
else
echo "not ok 3"
fi
mdconfig -d -u $no
rm -f $keyfile

View File

@ -0,0 +1,140 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
keyfile1=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile2=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile3=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile4=`mktemp /tmp/$base.XXXXXX` || exit 1
mdconfig -a -t malloc -s `expr $sectors + 1` -u $no || exit 1
echo "1..14"
dd if=/dev/random of=${keyfile1} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile2} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile3} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile4} bs=512 count=16 >/dev/null 2>&1
geli init -P -K $keyfile1 md${no}
geli attach -p -k $keyfile1 md${no}
geli setkey -n 1 -P -K $keyfile2 md${no}
# Remove key 0 for attached provider.
geli delkey -n 0 md${no}
if [ $? -eq 0 ]; then
echo "ok 1"
else
echo "not ok 1"
fi
geli detach md${no}
# We cannot use keyfile1 anymore.
geli attach -p -k $keyfile1 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 2"
else
echo "not ok 2"
fi
# Attach with key 1.
geli attach -p -k $keyfile2 md${no}
if [ $? -eq 0 ]; then
echo "ok 3"
else
echo "not ok 3"
fi
# We cannot remove last key without -f option (for attached provider).
geli delkey -n 1 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 4"
else
echo "not ok 4"
fi
# Remove last key for attached provider.
geli delkey -f -n 1 md${no}
if [ $? -eq 0 ]; then
echo "ok 5"
else
echo "not ok 5"
fi
# If there are no valid keys, but provider is attached, we can save situation.
geli setkey -n 0 -P -K $keyfile3 md${no}
if [ $? -eq 0 ]; then
echo "ok 6"
else
echo "not ok 6"
fi
geli detach md${no}
# We cannot use keyfile2 anymore.
geli attach -p -k $keyfile2 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 7"
else
echo "not ok 7"
fi
# Attach with key 0.
geli attach -p -k $keyfile3 md${no}
if [ $? -eq 0 ]; then
echo "ok 8"
else
echo "not ok 8"
fi
# Setup key 1.
geli setkey -n 1 -P -K $keyfile4 md${no}
if [ $? -eq 0 ]; then
echo "ok 9"
else
echo "not ok 9"
fi
geli detach md${no}
# Remove key 1 for detached provider.
geli delkey -n 1 md${no}
if [ $? -eq 0 ]; then
echo "ok 10"
else
echo "not ok 10"
fi
# We cannot use keyfile4 anymore.
geli attach -p -k $keyfile4 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 11"
else
echo "not ok 11"
fi
# We cannot remove last key without -f option (for detached provider).
geli delkey -n 0 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 12"
else
echo "not ok 12"
fi
# Remove last key for detached provider.
geli delkey -f -n 0 md${no}
if [ $? -eq 0 ]; then
echo "ok 13"
else
echo "not ok 13"
fi
# We cannot use keyfile3 anymore.
geli attach -p -k $keyfile3 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 14"
else
echo "not ok 14"
fi
mdconfig -d -u $no
rm -f $keyfile1 $keyfile2 $keyfile3 $keyfile4

View File

@ -0,0 +1,44 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
keyfile=`mktemp /tmp/$base.XXXXXX` || exit 1
mdconfig -a -t malloc -s `expr $sectors + 1` -u $no || exit 1
echo "1..4"
dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1
geli init -P -K $keyfile md${no}
geli attach -p -k $keyfile md${no}
if [ -c /dev/md${no}.eli ]; then
echo "ok 1"
else
echo "not ok 1"
fi
# Be sure it doesn't detach before 'detach -l'.
dd if=/dev/md${no}.eli of=/dev/null 2>/dev/null
sleep 1
if [ -c /dev/md${no}.eli ]; then
echo "ok 2"
else
echo "not ok 2"
fi
geli detach -l md${no}
if [ -c /dev/md${no}.eli ]; then
echo "ok 3"
else
echo "not ok 3"
fi
dd if=/dev/md${no}.eli of=/dev/null 2>/dev/null
sleep 1
if [ ! -c /dev/md${no}.eli ]; then
echo "ok 4"
else
echo "not ok 4"
fi
mdconfig -d -u $no
rm -f $keyfile

View File

@ -0,0 +1,51 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile=`mktemp /tmp/$base.XXXXXX` || exit 1
mdconfig -a -t malloc -s `expr $sectors + 1` -u $no || exit 1
echo "1..36"
i=1
for cipher in aes:0 aes:128 aes:192 aes:256 \
3des:0 3des:192 \
blowfish:0 blowfish:128 blowfish:160 blowfish:192 blowfish:224 \
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
blowfish:416 blowfish:448; do
algo=${cipher%%:*}
keylen=${cipher##*:}
dd if=/dev/random of=${rnd} bs=512 count=${sectors} >/dev/null 2>&1
dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1
geli init -a $algo -l $keylen -P -K $keyfile md${no}
geli attach -p -k $keyfile md${no}
dd if=${rnd} of=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null
md_rnd=`dd if=${rnd} bs=512 count=${sectors} 2>/dev/null | md5`
md_ddev=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
md_edev=`dd if=/dev/md${no} bs=512 count=${sectors} 2>/dev/null | md5`
if [ ${md_rnd} = ${md_ddev} ]; then
echo "ok $i - ${cipher}"
else
echo "not ok $i - ${cipher}"
fi
i=$((i+1))
if [ ${md_rnd} != ${md_edev} ]; then
echo "ok $i - ${cipher}"
else
echo "not ok $i - ${cipher}"
fi
i=$((i+1))
geli detach md${no}
done
mdconfig -d -u $no
rm -f $rnd $keyfile

View File

@ -0,0 +1,97 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
keyfile1=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile2=`mktemp /tmp/$base.XXXXXX` || exit 1
mdconfig -a -t malloc -s `expr $sectors + 1` -u $no || exit 1
echo "1..9"
dd if=/dev/random of=${keyfile1} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile2} bs=512 count=16 >/dev/null 2>&1
geli init -P -K $keyfile1 md${no}
geli attach -p -k $keyfile1 md${no}
geli setkey -n 1 -P -K $keyfile2 md${no}
# Kill attached provider.
geli kill md${no}
if [ $? -eq 0 ]; then
echo "ok 1"
else
echo "not ok 1"
fi
sleep 1
# Provider should be automatically detached.
if [ ! -c /dev/md{$no}.eli ]; then
echo "ok 2"
else
echo "not ok 2"
fi
# We cannot use keyfile1 anymore.
geli attach -p -k $keyfile1 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 3"
else
echo "not ok 3"
fi
# We cannot use keyfile2 anymore.
geli attach -p -k $keyfile2 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 4"
else
echo "not ok 4"
fi
geli init -P -K $keyfile1 md${no}
geli setkey -n 1 -p -k $keyfile1 -P -K $keyfile2 md${no}
# Should be possible to attach with keyfile1.
geli attach -p -k $keyfile1 md${no}
if [ $? -eq 0 ]; then
echo "ok 5"
else
echo "not ok 5"
fi
geli detach md${no}
# Should be possible to attach with keyfile2.
geli attach -p -k $keyfile2 md${no}
if [ $? -eq 0 ]; then
echo "ok 6"
else
echo "not ok 6"
fi
geli detach md${no}
# Kill detached provider.
geli kill md${no}
if [ $? -eq 0 ]; then
echo "ok 7"
else
echo "not ok 7"
fi
# We cannot use keyfile1 anymore.
geli attach -p -k $keyfile1 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 8"
else
echo "not ok 8"
fi
# We cannot use keyfile2 anymore.
geli attach -p -k $keyfile2 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 9"
else
echo "not ok 9"
fi
mdconfig -d -u $no
rm -f $keyfile1 $keyfile2

View File

@ -0,0 +1,33 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
mdconfig -a -t malloc -s $sectors -u $no || exit 1
echo "1..3"
geli onetime -d md${no}
if [ -c /dev/md${no}.eli ]; then
echo "ok 1"
else
echo "not ok 1"
fi
# Be sure it doesn't detach on read.
dd if=/dev/md${no}.eli of=/dev/null 2>/dev/null
sleep 1
if [ -c /dev/md${no}.eli ]; then
echo "ok 2"
else
echo "not ok 2"
fi
true > /dev/md${no}.eli
sleep 1
if [ ! -c /dev/md${no}.eli ]; then
echo "ok 3"
else
echo "not ok 3"
fi
mdconfig -d -u $no

View File

@ -0,0 +1,48 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
mdconfig -a -t malloc -s $sectors -u $no || exit 1
echo "1..36"
i=1
for cipher in aes:0 aes:128 aes:192 aes:256 \
3des:0 3des:192 \
blowfish:0 blowfish:128 blowfish:160 blowfish:192 blowfish:224 \
blowfish:256 blowfish:288 blowfish:320 blowfish:352 blowfish:384 \
blowfish:416 blowfish:448; do
algo=${cipher%%:*}
keylen=${cipher##*:}
dd if=/dev/random of=${rnd} bs=512 count=${sectors} >/dev/null 2>&1
geli onetime -a $algo -l $keylen md${no}
dd if=${rnd} of=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null
md_rnd=`dd if=${rnd} bs=512 count=${sectors} 2>/dev/null | md5`
md_ddev=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
md_edev=`dd if=/dev/md${no} bs=512 count=${sectors} 2>/dev/null | md5`
if [ ${md_rnd} = ${md_ddev} ]; then
echo "ok $i - ${cipher}"
else
echo "not ok $i - ${cipher}"
fi
i=$((i+1))
if [ ${md_rnd} != ${md_edev} ]; then
echo "ok $i - ${cipher}"
else
echo "not ok $i - ${cipher}"
fi
i=$((i+1))
geli detach md${no}
done
mdconfig -d -u $no
rm -f $rnd

View File

@ -0,0 +1,156 @@
#!/bin/sh
# $FreeBSD$
base=`basename $0`
no=45
sectors=100
rnd=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile1=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile2=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile3=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile4=`mktemp /tmp/$base.XXXXXX` || exit 1
keyfile5=`mktemp /tmp/$base.XXXXXX` || exit 1
mdconfig -a -t malloc -s `expr $sectors + 1` -u $no || exit 1
echo "1..16"
dd if=/dev/random of=${rnd} bs=512 count=${sectors} >/dev/null 2>&1
hash1=`dd if=${rnd} bs=512 count=${sectors} 2>/dev/null | md5`
dd if=/dev/random of=${keyfile1} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile2} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile3} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile4} bs=512 count=16 >/dev/null 2>&1
dd if=/dev/random of=${keyfile5} bs=512 count=16 >/dev/null 2>&1
geli init -P -K $keyfile1 md${no}
geli attach -p -k $keyfile1 md${no}
dd if=${rnd} of=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null
rm -f $rnd
hash2=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
# Change current key (0) for attached provider.
geli setkey -P -K $keyfile2 md${no}
if [ $? -eq 0 ]; then
echo "ok 1"
else
echo "not ok 1"
fi
geli detach md${no}
# We cannot use keyfile1 anymore.
geli attach -p -k $keyfile1 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 2"
else
echo "not ok 2"
fi
# Attach with new key.
geli attach -p -k $keyfile2 md${no}
if [ $? -eq 0 ]; then
echo "ok 3"
else
echo "not ok 3"
fi
hash3=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
# Change key 1 for attached provider.
geli setkey -n 1 -P -K $keyfile3 md${no}
if [ $? -eq 0 ]; then
echo "ok 4"
else
echo "not ok 4"
fi
geli detach md${no}
# Attach with key 1.
geli attach -p -k $keyfile3 md${no}
if [ $? -eq 0 ]; then
echo "ok 5"
else
echo "not ok 5"
fi
hash4=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
geli detach md${no}
# Change current (1) key for detached provider.
geli setkey -p -k $keyfile3 -P -K $keyfile4 md${no}
if [ $? -eq 0 ]; then
echo "ok 6"
else
echo "not ok 6"
fi
# We cannot use keyfile3 anymore.
geli attach -p -k $keyfile3 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 7"
else
echo "not ok 7"
fi
# Attach with key 1.
geli attach -p -k $keyfile4 md${no}
if [ $? -eq 0 ]; then
echo "ok 8"
else
echo "not ok 8"
fi
hash5=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
geli detach md${no}
# Change key 0 for detached provider.
geli setkey -n 0 -p -k $keyfile4 -P -K $keyfile5 md${no}
if [ $? -eq 0 ]; then
echo "ok 9"
else
echo "not ok 9"
fi
# We cannot use keyfile2 anymore.
geli attach -p -k $keyfile2 md${no} 2>/dev/null
if [ $? -ne 0 ]; then
echo "ok 10"
else
echo "not ok 10"
fi
# Attach with key 0.
geli attach -p -k $keyfile5 md${no}
if [ $? -eq 0 ]; then
echo "ok 11"
else
echo "not ok 11"
fi
hash6=`dd if=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null | md5`
geli detach md${no}
if [ ${hash1} = ${hash2} ]; then
echo "ok 12"
else
echo "not ok 12"
fi
if [ ${hash1} = ${hash3} ]; then
echo "ok 13"
else
echo "not ok 13"
fi
if [ ${hash1} = ${hash4} ]; then
echo "ok 14"
else
echo "not ok 14"
fi
if [ ${hash1} = ${hash5} ]; then
echo "ok 15"
else
echo "not ok 15"
fi
if [ ${hash1} = ${hash6} ]; then
echo "ok 16"
else
echo "not ok 16"
fi
mdconfig -d -u $no
rm -f $keyfile1 $keyfile2 $keyfile3 $keyfile4 $keyfile5