#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: crypto.c,v 1.2 2004/03/30 01:21:23 jtownsen Exp $";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/crypto.h"
int
__crypto_region_init(dbenv)
DB_ENV *dbenv;
{
REGENV *renv;
REGINFO *infop;
CIPHER *cipher;
DB_CIPHER *db_cipher;
char *sh_passwd;
int ret;
db_cipher = dbenv->crypto_handle;
ret = 0;
infop = dbenv->reginfo;
renv = infop->primary;
MUTEX_LOCK(dbenv, &renv->mutex);
if (renv->cipher_off == INVALID_ROFF) {
if (!CRYPTO_ON(dbenv))
goto out;
if (!F_ISSET(infop, REGION_CREATE)) {
__db_err(dbenv,
"Joining non-encrypted environment with encryption key");
ret = EINVAL;
goto out;
}
if (F_ISSET(db_cipher, CIPHER_ANY)) {
__db_err(dbenv, "Encryption algorithm not supplied");
ret = EINVAL;
goto out;
}
if ((ret = __db_shalloc(infop->addr,
sizeof(CIPHER), MUTEX_ALIGN, &cipher)) != 0)
goto out;
memset(cipher, 0, sizeof(*cipher));
if ((ret = __db_shalloc(infop->addr,
dbenv->passwd_len, 0, &sh_passwd)) != 0) {
__db_shalloc_free(infop->addr, cipher);
goto out;
}
memset(sh_passwd, 0, dbenv->passwd_len);
cipher->passwd = R_OFFSET(infop, sh_passwd);
cipher->passwd_len = dbenv->passwd_len;
cipher->flags = db_cipher->alg;
memcpy(sh_passwd, dbenv->passwd, cipher->passwd_len);
renv->cipher_off = R_OFFSET(infop, cipher);
} else {
if (!CRYPTO_ON(dbenv)) {
__db_err(dbenv,
"Encrypted environment: no encryption key supplied");
ret = EINVAL;
goto out;
}
cipher = R_ADDR(infop, renv->cipher_off);
sh_passwd = R_ADDR(infop, cipher->passwd);
if ((cipher->passwd_len != dbenv->passwd_len) ||
memcmp(dbenv->passwd, sh_passwd, cipher->passwd_len) != 0) {
__db_err(dbenv, "Invalid password");
ret = EPERM;
goto out;
}
if (!F_ISSET(db_cipher, CIPHER_ANY) &&
db_cipher->alg != cipher->flags) {
__db_err(dbenv,
"Environment encrypted using a different algorithm");
ret = EINVAL;
goto out;
}
if (F_ISSET(db_cipher, CIPHER_ANY))
if ((ret = __crypto_algsetup(dbenv, db_cipher,
cipher->flags, 0)) != 0)
goto out;
}
MUTEX_UNLOCK(dbenv, &renv->mutex);
ret = db_cipher->init(dbenv, db_cipher);
memset(dbenv->passwd, 0xff, dbenv->passwd_len-1);
__os_free(dbenv, dbenv->passwd);
dbenv->passwd = NULL;
dbenv->passwd_len = 0;
if (0) {
out: MUTEX_UNLOCK(dbenv, &renv->mutex);
}
return (ret);
}
int
__crypto_dbenv_close(dbenv)
DB_ENV *dbenv;
{
DB_CIPHER *db_cipher;
int ret;
ret = 0;
db_cipher = dbenv->crypto_handle;
if (dbenv->passwd != NULL) {
memset(dbenv->passwd, 0xff, dbenv->passwd_len-1);
__os_free(dbenv, dbenv->passwd);
dbenv->passwd = NULL;
}
if (!CRYPTO_ON(dbenv))
return (0);
if (!F_ISSET(db_cipher, CIPHER_ANY))
ret = db_cipher->close(dbenv, db_cipher->data);
__os_free(dbenv, db_cipher);
return (ret);
}
int
__crypto_algsetup(dbenv, db_cipher, alg, do_init)
DB_ENV *dbenv;
DB_CIPHER *db_cipher;
u_int32_t alg;
int do_init;
{
int ret;
ret = 0;
if (!CRYPTO_ON(dbenv)) {
__db_err(dbenv, "No cipher structure given");
return (EINVAL);
}
F_CLR(db_cipher, CIPHER_ANY);
switch (alg) {
case CIPHER_AES:
db_cipher->alg = CIPHER_AES;
ret = __aes_setup(dbenv, db_cipher);
break;
default:
__db_panic(dbenv, EINVAL);
}
if (do_init)
ret = db_cipher->init(dbenv, db_cipher);
return (ret);
}
int
__crypto_decrypt_meta(dbenv, dbp, mbuf, do_metachk)
DB_ENV *dbenv;
DB *dbp;
u_int8_t *mbuf;
int do_metachk;
{
DB_CIPHER *db_cipher;
DB dummydb;
DBMETA *meta;
size_t pg_off;
int ret;
u_int8_t *iv;
if (dbp == NULL) {
memset(&dummydb, 0, sizeof(DB));
dbp = &dummydb;
}
ret = 0;
meta = (DBMETA *)mbuf;
if (meta->encrypt_alg != 0) {
db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
if (!F_ISSET(dbp, DB_AM_ENCRYPT)) {
if (!CRYPTO_ON(dbenv)) {
__db_err(dbenv,
"Encrypted database: no encryption flag specified");
return (EINVAL);
}
F_SET(dbp, DB_AM_ENCRYPT|DB_AM_CHKSUM);
}
DB_ASSERT(CRYPTO_ON(dbenv));
if (!F_ISSET(db_cipher, CIPHER_ANY) &&
meta->encrypt_alg != db_cipher->alg) {
__db_err(dbenv,
"Database encrypted using a different algorithm");
return (EINVAL);
}
DB_ASSERT(F_ISSET(dbp, DB_AM_CHKSUM));
iv = ((BTMETA *)mbuf)->iv;
pg_off = P_OVERHEAD(dbp);
alg_retry:
if (!F_ISSET(db_cipher, CIPHER_ANY)) {
if (do_metachk && (ret = db_cipher->decrypt(dbenv,
db_cipher->data, iv, mbuf + pg_off,
DBMETASIZE - pg_off)))
return (ret);
if (((BTMETA *)meta)->crypto_magic !=
meta->magic) {
__db_err(dbenv, "Invalid password");
return (EINVAL);
}
return (0);
}
ret = __crypto_algsetup(dbenv, db_cipher, meta->encrypt_alg, 1);
goto alg_retry;
} else if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
__db_err(dbenv,
"Unencrypted database with a supplied encryption key");
return (EINVAL);
}
return (ret);
}
int
__crypto_set_passwd(dbenv_src, dbenv_dest)
DB_ENV *dbenv_src, *dbenv_dest;
{
CIPHER *cipher;
REGENV *renv;
REGINFO *infop;
char *sh_passwd;
int ret;
ret = 0;
infop = dbenv_src->reginfo;
renv = infop->primary;
DB_ASSERT(CRYPTO_ON(dbenv_src));
cipher = R_ADDR(infop, renv->cipher_off);
sh_passwd = R_ADDR(infop, cipher->passwd);
return (__dbenv_set_encrypt(dbenv_dest, sh_passwd, DB_ENCRYPT_AES));
}