Commit 7e7c9c17 authored by Milan Broz's avatar Milan Broz

Switch PBKDF2 from internal SHA1 to libgcrypt.

Also make hash algorithm not fixed here.



git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@79 36d66b0a-2a48-0410-832c-cd162a569da5
parent aab7fecd
......@@ -3,6 +3,7 @@
* Print error when getline fails.
* Remove po/cryptsetup-luks.pot, it's autogenerated.
* Return ENOENT for empty keyslots, EINVAL will be used later for other type of error.
* Switch PBKDF2 from internal SHA1 to libgcrypt, make hash algorithm not hardcoded to SHA1 here.
2009-07-28 Milan Broz <mbroz@redhat.com>
* Pad luks header to 512 sector size.
......
/*
* AFsplitter - Anti forensic information splitter
* Copyright 2004, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefor supporting secure data destruction.
......@@ -19,52 +20,57 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>
#include <gcrypt.h>
#include "sha1.h"
#include "XORblock.h"
#include "random.h"
static int hash_buf(char *src, char *dst, uint32_t iv, int len, int hash_id)
{
gcry_md_hd_t hd;
unsigned char *digest;
iv = htonl(iv);
if (gcry_md_open(&hd, hash_id, 0))
return 1;
gcry_md_write(hd, (unsigned char *)&iv, sizeof(iv));
gcry_md_write(hd, src, len);
digest = gcry_md_read(hd, hash_id);
memcpy(dst, digest, len);
gcry_md_close(hd);
return 0;
}
/* diffuse: Information spreading over the whole dataset with
* the help of sha512.
* the help of hash function.
*/
static void diffuse(unsigned char *src, unsigned char *dst, size_t size)
static int diffuse(char *src, char *dst, size_t size, int hash_id)
{
sha1_ctx ctx;
uint32_t i;
uint32_t IV; /* host byte order independend hash IV */
unsigned int fullblocks = size / SHA1_DIGEST_SIZE;
unsigned int padding = size % SHA1_DIGEST_SIZE;
unsigned char final[SHA1_DIGEST_SIZE];
/* hash block the whole data set with different IVs to produce
* more than just a single data block
*/
for (i=0; i < fullblocks; i++) {
sha1_begin(&ctx);
IV = htonl(i);
sha1_hash((const unsigned char *) &IV, sizeof(IV), &ctx);
sha1_hash(src + SHA1_DIGEST_SIZE * i, SHA1_DIGEST_SIZE, &ctx);
sha1_end(dst + SHA1_DIGEST_SIZE * i, &ctx);
}
unsigned int digest_size = gcry_md_get_algo_dlen(hash_id);
unsigned int i, blocks, padding;
if(padding) {
sha1_begin(&ctx);
IV = htonl(i);
sha1_hash((const unsigned char *) &IV, sizeof(IV), &ctx);
sha1_hash(src + SHA1_DIGEST_SIZE * i, padding, &ctx);
sha1_end(final, &ctx);
memcpy(dst + SHA1_DIGEST_SIZE * i, final, padding);
}
blocks = size / digest_size;
padding = size % digest_size;
for (i = 0; i < blocks; i++)
if(hash_buf(src + digest_size * i,
dst + digest_size * i,
i, digest_size, hash_id))
return 1;
if(padding)
if(hash_buf(src + digest_size * i,
dst + digest_size * i,
i, padding, hash_id))
return 1;
return 0;
}
/*
......@@ -73,11 +79,15 @@ static void diffuse(unsigned char *src, unsigned char *dst, size_t size)
* must be supplied to AF_merge to recover information.
*/
int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers)
int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash)
{
unsigned int i;
char *bufblock;
int r = -EINVAL;
int hash_id;
if (!(hash_id = gcry_md_map_name(hash)))
return -EINVAL;
if((bufblock = calloc(blocksize, 1)) == NULL) return -ENOMEM;
......@@ -87,7 +97,8 @@ int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers)
if(r < 0) goto out;
XORblock(dst+(blocksize*i),bufblock,bufblock,blocksize);
diffuse((unsigned char *) bufblock, (unsigned char *) bufblock, blocksize);
if(diffuse(bufblock, bufblock, blocksize, hash_id))
goto out;
}
/* the last block is computed */
XORblock(src,bufblock,dst+(i*blocksize),blocksize);
......@@ -97,20 +108,27 @@ out:
return r;
}
int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers)
int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash)
{
unsigned int i;
char *bufblock;
int r = -EINVAL;
int hash_id;
if (!(hash_id = gcry_md_map_name(hash)))
return -EINVAL;
if((bufblock = calloc(blocksize, 1)) == NULL) return -ENOMEM;
memset(bufblock,0,blocksize);
for(i=0; i<blocknumbers-1; i++) {
XORblock(src+(blocksize*i),bufblock,bufblock,blocksize);
diffuse((unsigned char *) bufblock, (unsigned char *) bufblock, blocksize);
if(diffuse(bufblock, bufblock, blocksize, hash_id))
goto out;
}
XORblock(src + blocksize * i, bufblock, dst, blocksize);
free(bufblock);
r = 0;
out:
free(bufblock);
return 0;
}
......@@ -7,19 +7,19 @@
*/
/*
* AF_split operates on src and produces information splitted data in
* AF_split operates on src and produces information splitted data in
* dst. src is assumed to be of the length blocksize. The data stripe
* dst points to must be captable of storing blocksize*blocknumbers.
* dst points to must be captable of storing blocksize*blocknumbers.
* blocknumbers is the data multiplication factor.
*
* AF_merge does just the opposite: reproduces the information stored in
* src of the length blocksize*blocknumbers into dst of the length
* AF_merge does just the opposite: reproduces the information stored in
* src of the length blocksize*blocknumbers into dst of the length
* blocksize.
*
* On error, both functions return -1, 0 otherwise.
*/
*/
int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers);
int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers);
int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
#endif
......@@ -191,14 +191,21 @@ int LUKS_generate_phdr(struct luks_phdr *header,
header->keyBytes=mk->keyLength;
r = getRandom(header->mkDigestSalt,LUKS_SALTSIZE);
if(r < 0) return r;
if(r < 0) {
set_error( _("Cannot create LUKS header: reading random salt failed."));
return r;
}
/* Compute master key digest */
header->mkDigestIterations = LUKS_MKD_ITER;
PBKDF2_HMAC_SHA1(mk->key,mk->keyLength,
header->mkDigestSalt,LUKS_SALTSIZE,
header->mkDigestIterations,
header->mkDigest,LUKS_DIGESTSIZE);
r = PBKDF2_HMAC(header->hashSpec,mk->key,mk->keyLength,
header->mkDigestSalt,LUKS_SALTSIZE,
header->mkDigestIterations,
header->mkDigest,LUKS_DIGESTSIZE);
if(r < 0) {
set_error( _("Cannot create LUKS header: header digest failed (using hash %s)."), header->hashSpec);
return r;
}
currentSector = round_up_modulo(LUKS_PHDR_SIZE, alignSectors);
for(i = 0; i < LUKS_NUMKEYS; ++i) {
......@@ -241,18 +248,20 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
// assert((mk->keyLength % TWOFISH_BLOCKSIZE) == 0); FIXME
PBKDF2_HMAC_SHA1(password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
hdr->keyblock[keyIndex].passwordIterations,
derivedKey, hdr->keyBytes);
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
hdr->keyblock[keyIndex].passwordIterations,
derivedKey, hdr->keyBytes);
if(r < 0) return r;
/*
* AF splitting, the masterkey stored in mk->key is splitted to AfMK
*/
AFEKSize = hdr->keyblock[keyIndex].stripes*mk->keyLength;
AfKey = (char *)malloc(AFEKSize);
if(AfKey == NULL) return -ENOMEM;
r = AF_split(mk->key,AfKey,mk->keyLength,hdr->keyblock[keyIndex].stripes);
r = AF_split(mk->key,AfKey,mk->keyLength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if(r < 0) goto out;
/* Encryption via dm */
......@@ -305,11 +314,12 @@ int LUKS_open_key(const char *device,
AFEKSize = hdr->keyblock[keyIndex].stripes*mk->keyLength;
AfKey = (char *)malloc(AFEKSize);
if(AfKey == NULL) return -ENOMEM;
PBKDF2_HMAC_SHA1(password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
hdr->keyblock[keyIndex].passwordIterations,
derivedKey, hdr->keyBytes);
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
hdr->keyblock[keyIndex].passwordIterations,
derivedKey, hdr->keyBytes);
if(r < 0) goto out;
r = LUKS_decrypt_from_storage(AfKey,
AFEKSize,
......@@ -319,23 +329,24 @@ int LUKS_open_key(const char *device,
device,
hdr->keyblock[keyIndex].keyMaterialOffset,
backend);
if(r < 0) {
if(!get_error())
set_error("Failed to read from key storage");
goto out;
}
if(r < 0) goto out;
r = AF_merge(AfKey,mk->key,mk->keyLength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if(r < 0) goto out;
r = AF_merge(AfKey,mk->key,mk->keyLength,hdr->keyblock[keyIndex].stripes);
r = PBKDF2_HMAC(hdr->hashSpec,mk->key,mk->keyLength,
hdr->mkDigestSalt,LUKS_SALTSIZE,
hdr->mkDigestIterations,
checkHashBuf,LUKS_DIGESTSIZE);
if(r < 0) goto out;
PBKDF2_HMAC_SHA1(mk->key,mk->keyLength,
hdr->mkDigestSalt,LUKS_SALTSIZE,
hdr->mkDigestIterations,
checkHashBuf,LUKS_DIGESTSIZE);
r = (memcmp(checkHashBuf,hdr->mkDigest, LUKS_DIGESTSIZE) == 0)?0:-EPERM;
out:
free(AfKey);
if( r < 0 && !get_error())
set_error("Failed to read from key storage.");
return r;
}
......@@ -489,7 +500,15 @@ int LUKS_is_last_keyslot(const char *device, unsigned int keyIndex)
int LUKS_benchmarkt_iterations()
{
return PBKDF2_performance_check()/2;
unsigned int count;
char *hash = "sha1";
if (PBKDF2_performance_check(hash, &count) < 0) {
set_error(_("Not compatible options (using hash algorithm %s)."), hash);
return -EINVAL;
}
return count/2;
}
int LUKS_device_ready(const char *device, int mode)
......
This diff is collapsed.
......@@ -5,10 +5,13 @@
/* */
void PBKDF2_HMAC_SHA1(const char *password, size_t passwordLen,
const char *salt, size_t saltLen, unsigned int iterations,
char *dKey, size_t dKeyLen);
int PBKDF2_HMAC(const char *hash,
const char *password, size_t passwordLen,
const char *salt, size_t saltLen, unsigned int iterations,
char *dKey, size_t dKeyLen);
unsigned int PBKDF2_performance_check();
int PBKDF2_performance_check(const char *hash, unsigned int *iter);
int PBKDF2_HMAC_ready(const char *hash);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment