Skip to content

Commit

Permalink
major refactoring, bugfixes
Browse files Browse the repository at this point in the history
* Code has now been split up into several different files to improve
  readability.

* The usage() message has been updated.

* Version bumped to 0.5.

* Fixes in the safe_mem purging
  • Loading branch information
bwalex committed May 17, 2011
1 parent 72a5221 commit dedd95c
Show file tree
Hide file tree
Showing 7 changed files with 881 additions and 772 deletions.
2 changes: 1 addition & 1 deletion Makefile
@@ -1,4 +1,4 @@
all: all:
gcc -O0 -Wall -g tc-play.c crc32.c openssl/openssl/libcrypto.a -o tc-play -ldevmapper -lprop -lutil gcc -O0 -Wall -g tc-play.c crc32.c safe_mem.c io.c crypto.c hdr.c openssl/openssl/libcrypto.a -o tc-play -ldevmapper -lprop -lutil
clean: clean:
rm -f tc-play tc-play.core *.o ktrace.out rm -f tc-play tc-play.core *.o ktrace.out
178 changes: 178 additions & 0 deletions crypto.c
@@ -0,0 +1,178 @@
/*
* Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
* 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 COPYRIGHT HOLDERS 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
* COPYRIGHT HOLDERS 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 <errno.h>
#include <string.h>
#include <openssl/evp.h>

#include "crc32.h"
#include "tc-play.h"

int
tc_crypto_init(void)
{
OpenSSL_add_all_algorithms();

return 0;
}

int
tc_encrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out)
{
const EVP_CIPHER *evp;
EVP_CIPHER_CTX ctx;
int outl, tmplen;

evp = EVP_get_cipherbyname(cipher_name);
if (evp == NULL) {
printf("Cipher %s not found\n", cipher_name);
return ENOENT;
}

EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit(&ctx, evp, key, iv);
EVP_EncryptUpdate(&ctx, out, &outl, in, in_len);
EVP_EncryptFinal(&ctx, out + outl, &tmplen);

return 0;
}

int
tc_decrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out)
{
const EVP_CIPHER *evp;
EVP_CIPHER_CTX ctx;
int outl, tmplen;

evp = EVP_get_cipherbyname(cipher_name);
if (evp == NULL) {
printf("Cipher %s not found\n", cipher_name);
return ENOENT;
}

EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit(&ctx, evp, key, iv);
EVP_DecryptUpdate(&ctx, out, &outl, in, in_len);
EVP_DecryptFinal(&ctx, out + outl, &tmplen);

return 0;
}

int
pbkdf2(const char *pass, int passlen, const unsigned char *salt, int saltlen,
int iter, const char *hash_name, int keylen, unsigned char *out)
{
const EVP_MD *md;
int r;

md = EVP_get_digestbyname(hash_name);
if (md == NULL) {
printf("Hash %s not found\n", hash_name);
return ENOENT;
}
r = PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, md,
keylen, out);

if (r == 0) {
printf("Error in PBKDF2\n");
return EINVAL;
}

return 0;
}

int
apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[],
int nkeyfiles)
{
int pl, k;
unsigned char *kpool;
unsigned char *kdata;
int kpool_idx;
size_t i, kdata_sz;
uint32_t crc;

if (pass_memsz < MAX_PASSSZ) {
fprintf(stderr, "Not enough memory for password manipluation\n");
return ENOMEM;
}

pl = strlen(pass);
memset(pass+pl, 0, MAX_PASSSZ-pl);

if ((kpool = alloc_safe_mem(KPOOL_SZ)) == NULL) {
fprintf(stderr, "Error allocating memory for keyfile pool\n");
return ENOMEM;
}

memset(kpool, 0, KPOOL_SZ);

for (k = 0; k < nkeyfiles; k++) {
#ifdef DEBUG
printf("Loading keyfile %s into kpool\n", keyfiles[k]);
#endif
kpool_idx = 0;
crc = ~0U;
kdata_sz = MAX_KFILE_SZ;

if ((kdata = read_to_safe_mem(keyfiles[k], 0, &kdata_sz)) == NULL) {
fprintf(stderr, "Error reading keyfile %s content\n",
keyfiles[k]);
free_safe_mem(kpool);
return EIO;
}

for (i = 0; i < kdata_sz; i++) {
crc = crc32_intermediate(crc, kdata[i]);

kpool[kpool_idx++] += (unsigned char)(crc >> 24);
kpool[kpool_idx++] += (unsigned char)(crc >> 16);
kpool[kpool_idx++] += (unsigned char)(crc >> 8);
kpool[kpool_idx++] += (unsigned char)(crc);

/* Wrap around */
if (kpool_idx == KPOOL_SZ)
kpool_idx = 0;
}

free_safe_mem(kdata);
}

#ifdef DEBUG
printf("Applying kpool to passphrase\n");
#endif
/* Apply keyfile pool to passphrase */
for (i = 0; i < KPOOL_SZ; i++)
pass[i] += kpool[i];

free_safe_mem(kpool);

return 0;
}
202 changes: 202 additions & 0 deletions hdr.c
@@ -0,0 +1,202 @@
/*
* Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
* 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 COPYRIGHT HOLDERS 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
* COPYRIGHT HOLDERS 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/types.h>
#include <sys/endian.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "crc32.h"
#include "tc-play.h"

/* Endianess macros */
#define BE_TO_HOST(n, v) v = be ## n ## toh(v)
#define LE_TO_HOST(n, v) v = le ## n ## toh(v)
#define HOST_TO_BE(n, v) v = htobe ## n (v)
#define HOST_TO_LE(n, v) v = htole ## n (v)

struct tchdr_dec *
decrypt_hdr(struct tchdr_enc *ehdr, char *algo, unsigned char *key)
{
struct tchdr_dec *dhdr;
unsigned char iv[128];
int error;

if ((dhdr = alloc_safe_mem(sizeof(struct tchdr_dec))) == NULL) {
fprintf(stderr, "Error allocating safe tchdr_dec memory\n");
return NULL;
}

memset(iv, 0, sizeof(iv));

error = tc_decrypt(algo, key, iv, ehdr->enc, sizeof(struct tchdr_dec),
(unsigned char *)dhdr);
if (error) {
fprintf(stderr, "Header decryption failed\n");
free_safe_mem(dhdr);
return NULL;
}

BE_TO_HOST(16, dhdr->tc_ver);
LE_TO_HOST(16, dhdr->tc_min_ver);
BE_TO_HOST(32, dhdr->crc_keys);
BE_TO_HOST(64, dhdr->vol_ctime);
BE_TO_HOST(64, dhdr->hdr_ctime);
BE_TO_HOST(64, dhdr->sz_hidvol);
BE_TO_HOST(64, dhdr->sz_vol);
BE_TO_HOST(64, dhdr->off_mk_scope);
BE_TO_HOST(64, dhdr->sz_mk_scope);
BE_TO_HOST(32, dhdr->flags);
BE_TO_HOST(32, dhdr->sec_sz);
BE_TO_HOST(32, dhdr->crc_dhdr);

return dhdr;
}

int
verify_hdr(struct tchdr_dec *hdr)
{
uint32_t crc;

if (memcmp(hdr->tc_str, TC_SIG, sizeof(hdr->tc_str)) != 0) {
#ifdef DEBUG
fprintf(stderr, "Signature mismatch\n");
#endif
return 0;
}

crc = crc32((void *)&hdr->keys, 256);
if (crc != hdr->crc_keys) {
#ifdef DEBUG
fprintf(stderr, "CRC32 mismatch (crc_keys)\n");
#endif
return 0;
}

switch(hdr->tc_ver) {
case 1:
case 2:
/* Unsupported header version */
fprintf(stderr, "Header version %d unsupported\n", hdr->tc_ver);
return 0;

case 3:
case 4:
hdr->sec_sz = 512;
break;
}

return 1;
}

struct tchdr_enc *
create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
struct tc_crypto_algo *cipher, size_t sec_sz, size_t total_blocks,
off_t offset, size_t blocks, int hidden)
{
struct tchdr_enc *ehdr;
struct tchdr_dec *dhdr;
unsigned char *key;
unsigned char iv[128];
int error;

if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) {
fprintf(stderr, "could not allocate safe dhdr memory\n");
return NULL;
}

if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) {
fprintf(stderr, "could not allocate safe ehdr memory\n");
return NULL;
}

if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
fprintf(stderr, "could not allocate safe key memory\n");
return NULL;
}

if ((error = get_random(ehdr->salt, sizeof(ehdr->salt))) != 0) {
fprintf(stderr, "could not get salt\n");
return NULL;
}

error = pbkdf2(pass, passlen,
ehdr->salt, sizeof(ehdr->salt),
prf_algo->iteration_count,
prf_algo->name, MAX_KEYSZ, key);
if (error) {
fprintf(stderr, "could not derive key\n");
return NULL;
}

memset(dhdr, 0, sizeof(*dhdr));

if ((error = get_random(dhdr->keys, sizeof(dhdr->keys))) != 0) {
fprintf(stderr, "could not get key random bits\n");
return NULL;
}

memcpy(dhdr->tc_str, "TRUE", 4);
dhdr->tc_ver = 5;
dhdr->tc_min_ver = 7;
dhdr->crc_keys = crc32((void *)&dhdr->keys, 256);
dhdr->sz_vol = blocks * sec_sz;
if (hidden)
dhdr->sz_hidvol = dhdr->sz_vol;
dhdr->off_mk_scope = offset * sec_sz;
dhdr->sz_mk_scope = blocks * sec_sz;
dhdr->sec_sz = sec_sz;
dhdr->flags = 0;

HOST_TO_BE(16, dhdr->tc_ver);
HOST_TO_LE(16, dhdr->tc_min_ver);
HOST_TO_BE(32, dhdr->crc_keys);
HOST_TO_BE(64, dhdr->sz_vol);
HOST_TO_BE(64, dhdr->sz_hidvol);
HOST_TO_BE(64, dhdr->off_mk_scope);
HOST_TO_BE(64, dhdr->sz_mk_scope);
HOST_TO_BE(32, dhdr->sec_sz);
HOST_TO_BE(32, dhdr->flags);

dhdr->crc_dhdr = crc32((void *)dhdr, 188);
HOST_TO_BE(32, dhdr->crc_dhdr);

memset(iv, 0, sizeof(iv));
error = tc_encrypt(cipher->name, key, iv, (unsigned char *)dhdr,
sizeof(struct tchdr_dec), ehdr->enc);
if (error) {
fprintf(stderr, "Header encryption failed\n");
free_safe_mem(dhdr);
return NULL;
}

free_safe_mem(dhdr);
return ehdr;
}

0 comments on commit dedd95c

Please sign in to comment.