xref: /dflybsd-src/lib/libtcplay/hdr.c (revision 7b1e1c8e1e00f6479eba04708b37a13383f7e197)
10d9ba1e1SAlex Hornung /*
20d9ba1e1SAlex Hornung  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
30d9ba1e1SAlex Hornung  * All rights reserved.
40d9ba1e1SAlex Hornung  *
50d9ba1e1SAlex Hornung  * Redistribution and use in source and binary forms, with or without
60d9ba1e1SAlex Hornung  * modification, are permitted provided that the following conditions
70d9ba1e1SAlex Hornung  * are met:
80d9ba1e1SAlex Hornung  *
90d9ba1e1SAlex Hornung  * 1. Redistributions of source code must retain the above copyright
100d9ba1e1SAlex Hornung  *    notice, this list of conditions and the following disclaimer.
110d9ba1e1SAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
120d9ba1e1SAlex Hornung  *    notice, this list of conditions and the following disclaimer in
130d9ba1e1SAlex Hornung  *    the documentation and/or other materials provided with the
140d9ba1e1SAlex Hornung  *    distribution.
150d9ba1e1SAlex Hornung  *
160d9ba1e1SAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
170d9ba1e1SAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
180d9ba1e1SAlex Hornung  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
190d9ba1e1SAlex Hornung  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
200d9ba1e1SAlex Hornung  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
210d9ba1e1SAlex Hornung  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
220d9ba1e1SAlex Hornung  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
230d9ba1e1SAlex Hornung  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
240d9ba1e1SAlex Hornung  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
250d9ba1e1SAlex Hornung  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
260d9ba1e1SAlex Hornung  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270d9ba1e1SAlex Hornung  * SUCH DAMAGE.
280d9ba1e1SAlex Hornung  */
2981b79547SAlex Hornung 
300d9ba1e1SAlex Hornung #include <sys/types.h>
3181b79547SAlex Hornung 
3281b79547SAlex Hornung #if defined(__DragonFly__)
330d9ba1e1SAlex Hornung #include <sys/endian.h>
3481b79547SAlex Hornung #elif defined(__linux__)
3581b79547SAlex Hornung #include <endian.h>
3681b79547SAlex Hornung #endif
370d9ba1e1SAlex Hornung #include <errno.h>
380d9ba1e1SAlex Hornung #include <stdio.h>
390d9ba1e1SAlex Hornung #include <stdlib.h>
4081b79547SAlex Hornung #include <inttypes.h>
410d9ba1e1SAlex Hornung #include <string.h>
420d9ba1e1SAlex Hornung 
430d9ba1e1SAlex Hornung #include "crc32.h"
440d9ba1e1SAlex Hornung #include "tcplay.h"
450d9ba1e1SAlex Hornung 
460d9ba1e1SAlex Hornung /* Endianess macros */
470d9ba1e1SAlex Hornung #define BE_TO_HOST(n, v) v = be ## n ## toh(v)
480d9ba1e1SAlex Hornung #define LE_TO_HOST(n, v) v = le ## n ## toh(v)
490d9ba1e1SAlex Hornung #define HOST_TO_BE(n, v) v = htobe ## n (v)
500d9ba1e1SAlex Hornung #define HOST_TO_LE(n, v) v = htole ## n (v)
510d9ba1e1SAlex Hornung 
52*7b1e1c8eSDaniel Fojt struct sig_hdr_cfg {
53*7b1e1c8eSDaniel Fojt 	const char	*sig;
54*7b1e1c8eSDaniel Fojt 	uint16_t	min_ver;
55*7b1e1c8eSDaniel Fojt };
56*7b1e1c8eSDaniel Fojt 
57*7b1e1c8eSDaniel Fojt struct sig_hdr_cfg sig_hdr_cfgs[] = {
58*7b1e1c8eSDaniel Fojt 	{ TC_SIG,	0x0007 },
59*7b1e1c8eSDaniel Fojt 	{ VC_SIG,	0x0b01 },
60*7b1e1c8eSDaniel Fojt 	{ NULL,		0x0000 }
61*7b1e1c8eSDaniel Fojt };
62*7b1e1c8eSDaniel Fojt 
63*7b1e1c8eSDaniel Fojt static
64*7b1e1c8eSDaniel Fojt const
hdr_cfg_from_sig(const char * sig)65*7b1e1c8eSDaniel Fojt struct sig_hdr_cfg *hdr_cfg_from_sig(const char *sig)
66*7b1e1c8eSDaniel Fojt {
67*7b1e1c8eSDaniel Fojt 	const struct sig_hdr_cfg *cfg;
68*7b1e1c8eSDaniel Fojt 
69*7b1e1c8eSDaniel Fojt 	for (cfg = &sig_hdr_cfgs[0]; cfg->sig != NULL; cfg++) {
70*7b1e1c8eSDaniel Fojt 		if (strcmp(cfg->sig, sig) == 0)
71*7b1e1c8eSDaniel Fojt 			return cfg;
72*7b1e1c8eSDaniel Fojt 	}
73*7b1e1c8eSDaniel Fojt 
74*7b1e1c8eSDaniel Fojt 	return NULL;
75*7b1e1c8eSDaniel Fojt }
76*7b1e1c8eSDaniel Fojt 
770d9ba1e1SAlex Hornung struct tchdr_dec *
decrypt_hdr(struct tchdr_enc * ehdr,struct tc_cipher_chain * cipher_chain,unsigned char * key)780d9ba1e1SAlex Hornung decrypt_hdr(struct tchdr_enc *ehdr, struct tc_cipher_chain *cipher_chain,
790d9ba1e1SAlex Hornung     unsigned char *key)
800d9ba1e1SAlex Hornung {
810d9ba1e1SAlex Hornung 	struct tchdr_dec *dhdr;
820d9ba1e1SAlex Hornung 	unsigned char iv[128];
830d9ba1e1SAlex Hornung 	int error;
840d9ba1e1SAlex Hornung 
850d9ba1e1SAlex Hornung 	if ((dhdr = alloc_safe_mem(sizeof(struct tchdr_dec))) == NULL) {
860d9ba1e1SAlex Hornung 		tc_log(1, "Error allocating safe tchdr_dec memory\n");
870d9ba1e1SAlex Hornung 		return NULL;
880d9ba1e1SAlex Hornung 	}
890d9ba1e1SAlex Hornung 
900d9ba1e1SAlex Hornung 	memset(iv, 0, sizeof(iv));
910d9ba1e1SAlex Hornung 
920d9ba1e1SAlex Hornung 	error = tc_decrypt(cipher_chain, key, iv, ehdr->enc,
930d9ba1e1SAlex Hornung 	    sizeof(struct tchdr_dec), (unsigned char *)dhdr);
940d9ba1e1SAlex Hornung 	if (error) {
950d9ba1e1SAlex Hornung 		tc_log(1, "Header decryption failed\n");
960d9ba1e1SAlex Hornung 		free_safe_mem(dhdr);
970d9ba1e1SAlex Hornung 		return NULL;
980d9ba1e1SAlex Hornung 	}
990d9ba1e1SAlex Hornung 
1000d9ba1e1SAlex Hornung 	BE_TO_HOST(16, dhdr->tc_ver);
1010d9ba1e1SAlex Hornung 	LE_TO_HOST(16, dhdr->tc_min_ver);
1020d9ba1e1SAlex Hornung 	BE_TO_HOST(32, dhdr->crc_keys);
1030d9ba1e1SAlex Hornung 	BE_TO_HOST(64, dhdr->vol_ctime);
1040d9ba1e1SAlex Hornung 	BE_TO_HOST(64, dhdr->hdr_ctime);
1050d9ba1e1SAlex Hornung 	BE_TO_HOST(64, dhdr->sz_hidvol);
1060d9ba1e1SAlex Hornung 	BE_TO_HOST(64, dhdr->sz_vol);
1070d9ba1e1SAlex Hornung 	BE_TO_HOST(64, dhdr->off_mk_scope);
1080d9ba1e1SAlex Hornung 	BE_TO_HOST(64, dhdr->sz_mk_scope);
1090d9ba1e1SAlex Hornung 	BE_TO_HOST(32, dhdr->flags);
1100d9ba1e1SAlex Hornung 	BE_TO_HOST(32, dhdr->sec_sz);
1110d9ba1e1SAlex Hornung 	BE_TO_HOST(32, dhdr->crc_dhdr);
1120d9ba1e1SAlex Hornung 
1130d9ba1e1SAlex Hornung 	return dhdr;
1140d9ba1e1SAlex Hornung }
1150d9ba1e1SAlex Hornung 
1160d9ba1e1SAlex Hornung int
verify_hdr(struct tchdr_dec * hdr,struct pbkdf_prf_algo * prf_algo)117*7b1e1c8eSDaniel Fojt verify_hdr(struct tchdr_dec *hdr, struct pbkdf_prf_algo *prf_algo)
1180d9ba1e1SAlex Hornung {
1190d9ba1e1SAlex Hornung 	uint32_t crc;
1200d9ba1e1SAlex Hornung 
121*7b1e1c8eSDaniel Fojt 	if (memcmp(hdr->tc_str, prf_algo->sig, sizeof(hdr->tc_str)) != 0) {
1220d9ba1e1SAlex Hornung #ifdef DEBUG
1230d9ba1e1SAlex Hornung 		fprintf(stderr, "Signature mismatch\n");
1240d9ba1e1SAlex Hornung #endif
1250d9ba1e1SAlex Hornung 		return 0;
1260d9ba1e1SAlex Hornung 	}
1270d9ba1e1SAlex Hornung 
128c833cfcfSAlex Hornung 	crc = crc32((void *)&hdr->keys, 256);
1290d9ba1e1SAlex Hornung 	if (crc != hdr->crc_keys) {
1300d9ba1e1SAlex Hornung #ifdef DEBUG
1310d9ba1e1SAlex Hornung 		fprintf(stderr, "CRC32 mismatch (crc_keys)\n");
1320d9ba1e1SAlex Hornung #endif
1330d9ba1e1SAlex Hornung 		return 0;
1340d9ba1e1SAlex Hornung 	}
1350d9ba1e1SAlex Hornung 
1360d9ba1e1SAlex Hornung 	switch(hdr->tc_ver) {
1370d9ba1e1SAlex Hornung 	case 1:
1380d9ba1e1SAlex Hornung 	case 2:
1390d9ba1e1SAlex Hornung 		/* Unsupported header version */
1400d9ba1e1SAlex Hornung 		tc_log(1, "Header version %d unsupported\n", hdr->tc_ver);
1410d9ba1e1SAlex Hornung 		return 0;
1420d9ba1e1SAlex Hornung 
1430d9ba1e1SAlex Hornung 	case 3:
1440d9ba1e1SAlex Hornung 	case 4:
1450d9ba1e1SAlex Hornung 		hdr->sec_sz = 512;
1460d9ba1e1SAlex Hornung 		break;
1470d9ba1e1SAlex Hornung 	}
1480d9ba1e1SAlex Hornung 
1490d9ba1e1SAlex Hornung 	return 1;
1500d9ba1e1SAlex Hornung }
1510d9ba1e1SAlex Hornung 
1520d9ba1e1SAlex Hornung struct tchdr_enc *
create_hdr(unsigned char * pass,int passlen,struct pbkdf_prf_algo * prf_algo,struct tc_cipher_chain * cipher_chain,size_t sec_sz,disksz_t total_blocks __unused,off_t offset,disksz_t blocks,int hidden,int weak,struct tchdr_enc ** backup_hdr)1530d9ba1e1SAlex Hornung create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
1540d9ba1e1SAlex Hornung     struct tc_cipher_chain *cipher_chain, size_t sec_sz,
155c833cfcfSAlex Hornung     disksz_t total_blocks __unused,
156c833cfcfSAlex Hornung     off_t offset, disksz_t blocks, int hidden, int weak, struct tchdr_enc **backup_hdr)
1570d9ba1e1SAlex Hornung {
15881b79547SAlex Hornung 	struct tchdr_enc *ehdr, *ehdr_backup;
1590d9ba1e1SAlex Hornung 	struct tchdr_dec *dhdr;
16081b79547SAlex Hornung 	unsigned char *key, *key_backup;
1610d9ba1e1SAlex Hornung 	unsigned char iv[128];
162*7b1e1c8eSDaniel Fojt 	const struct sig_hdr_cfg *hdr_cfg;
1630d9ba1e1SAlex Hornung 	int error;
1640d9ba1e1SAlex Hornung 
16581b79547SAlex Hornung 	key = key_backup = NULL;
16681b79547SAlex Hornung 	dhdr = NULL;
16781b79547SAlex Hornung 	ehdr = ehdr_backup = NULL;
16881b79547SAlex Hornung 
16981b79547SAlex Hornung 	if (backup_hdr != NULL)
17081b79547SAlex Hornung 		*backup_hdr = NULL;
17181b79547SAlex Hornung 
1720d9ba1e1SAlex Hornung 	if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) {
1730d9ba1e1SAlex Hornung 		tc_log(1, "could not allocate safe dhdr memory\n");
17481b79547SAlex Hornung 		goto error;
1750d9ba1e1SAlex Hornung 	}
1760d9ba1e1SAlex Hornung 
1770d9ba1e1SAlex Hornung 	if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) {
1780d9ba1e1SAlex Hornung 		tc_log(1, "could not allocate safe ehdr memory\n");
17981b79547SAlex Hornung 		goto error;
18081b79547SAlex Hornung 	}
18181b79547SAlex Hornung 
18281b79547SAlex Hornung 	if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem
18381b79547SAlex Hornung 	    (sizeof(*ehdr_backup))) == NULL) {
18481b79547SAlex Hornung 		tc_log(1, "could not allocate safe ehdr_backup memory\n");
18581b79547SAlex Hornung 		goto error;
1860d9ba1e1SAlex Hornung 	}
1870d9ba1e1SAlex Hornung 
1880d9ba1e1SAlex Hornung 	if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
1890d9ba1e1SAlex Hornung 		tc_log(1, "could not allocate safe key memory\n");
19081b79547SAlex Hornung 		goto error;
19181b79547SAlex Hornung 	}
19281b79547SAlex Hornung 
19381b79547SAlex Hornung 	if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
19481b79547SAlex Hornung 		tc_log(1, "could not allocate safe backup key memory\n");
19581b79547SAlex Hornung 		goto error;
1960d9ba1e1SAlex Hornung 	}
1970d9ba1e1SAlex Hornung 
198c833cfcfSAlex Hornung 	if ((error = get_random(ehdr->salt, sizeof(ehdr->salt), weak)) != 0) {
1990d9ba1e1SAlex Hornung 		tc_log(1, "could not get salt\n");
20081b79547SAlex Hornung 		goto error;
2010d9ba1e1SAlex Hornung 	}
2020d9ba1e1SAlex Hornung 
203c833cfcfSAlex Hornung 	if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt), weak))
20481b79547SAlex Hornung 	    != 0) {
20581b79547SAlex Hornung 		tc_log(1, "could not get salt for backup header\n");
20681b79547SAlex Hornung 		goto error;
20781b79547SAlex Hornung 	}
20881b79547SAlex Hornung 
20981b79547SAlex Hornung 	error = pbkdf2(prf_algo, (char *)pass, passlen,
2100d9ba1e1SAlex Hornung 	    ehdr->salt, sizeof(ehdr->salt),
21181b79547SAlex Hornung 	    MAX_KEYSZ, key);
2120d9ba1e1SAlex Hornung 	if (error) {
2130d9ba1e1SAlex Hornung 		tc_log(1, "could not derive key\n");
21481b79547SAlex Hornung 		goto error;
21581b79547SAlex Hornung 	}
21681b79547SAlex Hornung 
21781b79547SAlex Hornung 	error = pbkdf2(prf_algo, (char *)pass, passlen,
21881b79547SAlex Hornung 	    ehdr_backup->salt, sizeof(ehdr_backup->salt),
21981b79547SAlex Hornung 	    MAX_KEYSZ, key_backup);
22081b79547SAlex Hornung 	if (error) {
22181b79547SAlex Hornung 		tc_log(1, "could not derive backup key\n");
22281b79547SAlex Hornung 		goto error;
2230d9ba1e1SAlex Hornung 	}
2240d9ba1e1SAlex Hornung 
2250d9ba1e1SAlex Hornung 	memset(dhdr, 0, sizeof(*dhdr));
2260d9ba1e1SAlex Hornung 
227c833cfcfSAlex Hornung 	if ((error = get_random(dhdr->keys, sizeof(dhdr->keys), weak)) != 0) {
2280d9ba1e1SAlex Hornung 		tc_log(1, "could not get key random bits\n");
22981b79547SAlex Hornung 		goto error;
2300d9ba1e1SAlex Hornung 	}
2310d9ba1e1SAlex Hornung 
232*7b1e1c8eSDaniel Fojt 	if ((hdr_cfg = hdr_cfg_from_sig(prf_algo->sig)) == NULL) {
233*7b1e1c8eSDaniel Fojt 		tc_log(1, "could not find internal header configuration\n");
234*7b1e1c8eSDaniel Fojt 		goto error;
235*7b1e1c8eSDaniel Fojt 	}
236*7b1e1c8eSDaniel Fojt 
237*7b1e1c8eSDaniel Fojt 	memcpy(dhdr->tc_str, prf_algo->sig, 4);
2380d9ba1e1SAlex Hornung 	dhdr->tc_ver = 5;
239*7b1e1c8eSDaniel Fojt 	dhdr->tc_min_ver = hdr_cfg->min_ver;
2400d9ba1e1SAlex Hornung 	dhdr->crc_keys = crc32((void *)&dhdr->keys, 256);
2410d9ba1e1SAlex Hornung 	dhdr->sz_vol = blocks * sec_sz;
2420d9ba1e1SAlex Hornung 	if (hidden)
2430d9ba1e1SAlex Hornung 		dhdr->sz_hidvol = dhdr->sz_vol;
2440d9ba1e1SAlex Hornung 	dhdr->off_mk_scope = offset * sec_sz;
2450d9ba1e1SAlex Hornung 	dhdr->sz_mk_scope = blocks * sec_sz;
2460d9ba1e1SAlex Hornung 	dhdr->sec_sz = sec_sz;
2470d9ba1e1SAlex Hornung 	dhdr->flags = 0;
2480d9ba1e1SAlex Hornung 
2490d9ba1e1SAlex Hornung 	HOST_TO_BE(16, dhdr->tc_ver);
2500d9ba1e1SAlex Hornung 	HOST_TO_LE(16, dhdr->tc_min_ver);
2510d9ba1e1SAlex Hornung 	HOST_TO_BE(32, dhdr->crc_keys);
2520d9ba1e1SAlex Hornung 	HOST_TO_BE(64, dhdr->sz_vol);
2530d9ba1e1SAlex Hornung 	HOST_TO_BE(64, dhdr->sz_hidvol);
2540d9ba1e1SAlex Hornung 	HOST_TO_BE(64, dhdr->off_mk_scope);
2550d9ba1e1SAlex Hornung 	HOST_TO_BE(64, dhdr->sz_mk_scope);
2560d9ba1e1SAlex Hornung 	HOST_TO_BE(32, dhdr->sec_sz);
2570d9ba1e1SAlex Hornung 	HOST_TO_BE(32, dhdr->flags);
2580d9ba1e1SAlex Hornung 
2590d9ba1e1SAlex Hornung 	dhdr->crc_dhdr = crc32((void *)dhdr, 188);
2600d9ba1e1SAlex Hornung 	HOST_TO_BE(32, dhdr->crc_dhdr);
2610d9ba1e1SAlex Hornung 
2620d9ba1e1SAlex Hornung 	memset(iv, 0, sizeof(iv));
2630d9ba1e1SAlex Hornung 	error = tc_encrypt(cipher_chain, key, iv, (unsigned char *)dhdr,
2640d9ba1e1SAlex Hornung 	    sizeof(struct tchdr_dec), ehdr->enc);
2650d9ba1e1SAlex Hornung 	if (error) {
2660d9ba1e1SAlex Hornung 		tc_log(1, "Header encryption failed\n");
26781b79547SAlex Hornung 		goto error;
2680d9ba1e1SAlex Hornung 	}
2690d9ba1e1SAlex Hornung 
27081b79547SAlex Hornung 	memset(iv, 0, sizeof(iv));
27181b79547SAlex Hornung 	error = tc_encrypt(cipher_chain, key_backup, iv,
27281b79547SAlex Hornung 	    (unsigned char *)dhdr,
27381b79547SAlex Hornung 	    sizeof(struct tchdr_dec), ehdr_backup->enc);
27481b79547SAlex Hornung 	if (error) {
27581b79547SAlex Hornung 		tc_log(1, "Backup header encryption failed\n");
27681b79547SAlex Hornung 		goto error;
27781b79547SAlex Hornung 	}
27881b79547SAlex Hornung 
27981b79547SAlex Hornung 	free_safe_mem(key);
28081b79547SAlex Hornung 	free_safe_mem(key_backup);
2810d9ba1e1SAlex Hornung 	free_safe_mem(dhdr);
28281b79547SAlex Hornung 
28381b79547SAlex Hornung 	if (backup_hdr != NULL)
28481b79547SAlex Hornung 		*backup_hdr = ehdr_backup;
28581b79547SAlex Hornung 	else
28681b79547SAlex Hornung 		free_safe_mem(ehdr_backup);
28781b79547SAlex Hornung 
2880d9ba1e1SAlex Hornung 	return ehdr;
28981b79547SAlex Hornung 	/* NOT REACHED */
29081b79547SAlex Hornung 
29181b79547SAlex Hornung error:
29281b79547SAlex Hornung 	if (key)
29381b79547SAlex Hornung 		free_safe_mem(key);
29481b79547SAlex Hornung 	if (key_backup)
29581b79547SAlex Hornung 		free_safe_mem(key_backup);
29681b79547SAlex Hornung 	if (dhdr)
29781b79547SAlex Hornung 		free_safe_mem(dhdr);
29881b79547SAlex Hornung 	if (ehdr)
29981b79547SAlex Hornung 		free_safe_mem(ehdr);
30081b79547SAlex Hornung 	if (ehdr_backup)
30181b79547SAlex Hornung 		free_safe_mem(ehdr_backup);
30281b79547SAlex Hornung 
30381b79547SAlex Hornung 	return NULL;
3040d9ba1e1SAlex Hornung }
305c833cfcfSAlex Hornung 
copy_reencrypt_hdr(unsigned char * pass,int passlen,struct pbkdf_prf_algo * prf_algo,int weak,struct tcplay_info * info,struct tchdr_enc ** backup_hdr)306c833cfcfSAlex Hornung struct tchdr_enc *copy_reencrypt_hdr(unsigned char *pass, int passlen,
307c833cfcfSAlex Hornung     struct pbkdf_prf_algo *prf_algo, int weak, struct tcplay_info *info,
308c833cfcfSAlex Hornung     struct tchdr_enc **backup_hdr)
309c833cfcfSAlex Hornung {
310c833cfcfSAlex Hornung 	struct tchdr_enc *ehdr, *ehdr_backup;
311c833cfcfSAlex Hornung 	unsigned char *key, *key_backup;
312c833cfcfSAlex Hornung 	unsigned char iv[128];
313*7b1e1c8eSDaniel Fojt 	const struct sig_hdr_cfg *hdr_cfg;
314c833cfcfSAlex Hornung 	int error;
315c833cfcfSAlex Hornung 
316c833cfcfSAlex Hornung 	key = key_backup = NULL;
317c833cfcfSAlex Hornung 	ehdr = ehdr_backup = NULL;
318c833cfcfSAlex Hornung 
319c833cfcfSAlex Hornung 	/* By default stick to current PRF algo */
320c833cfcfSAlex Hornung 	if (prf_algo == NULL)
321c833cfcfSAlex Hornung 		prf_algo = info->pbkdf_prf;
322c833cfcfSAlex Hornung 
323c833cfcfSAlex Hornung 	if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) {
324c833cfcfSAlex Hornung 		tc_log(1, "could not allocate safe ehdr memory\n");
325c833cfcfSAlex Hornung 		goto error;
326c833cfcfSAlex Hornung 	}
327c833cfcfSAlex Hornung 
328c833cfcfSAlex Hornung 	if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem
329c833cfcfSAlex Hornung 	    (sizeof(*ehdr_backup))) == NULL) {
330c833cfcfSAlex Hornung 		tc_log(1, "could not allocate safe ehdr_backup memory\n");
331c833cfcfSAlex Hornung 		goto error;
332c833cfcfSAlex Hornung 	}
333c833cfcfSAlex Hornung 
334c833cfcfSAlex Hornung 	if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
335c833cfcfSAlex Hornung 		tc_log(1, "could not allocate safe key memory\n");
336c833cfcfSAlex Hornung 		goto error;
337c833cfcfSAlex Hornung 	}
338c833cfcfSAlex Hornung 
339c833cfcfSAlex Hornung 	if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
340c833cfcfSAlex Hornung 		tc_log(1, "could not allocate safe backup key memory\n");
341c833cfcfSAlex Hornung 		goto error;
342c833cfcfSAlex Hornung 	}
343c833cfcfSAlex Hornung 
344c833cfcfSAlex Hornung 	if ((error = get_random(ehdr->salt, sizeof(ehdr->salt), weak)) != 0) {
345c833cfcfSAlex Hornung 		tc_log(1, "could not get salt\n");
346c833cfcfSAlex Hornung 		goto error;
347c833cfcfSAlex Hornung 	}
348c833cfcfSAlex Hornung 
349c833cfcfSAlex Hornung 	if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt), weak))
350c833cfcfSAlex Hornung 	    != 0) {
351c833cfcfSAlex Hornung 		tc_log(1, "could not get salt for backup header\n");
352c833cfcfSAlex Hornung 		goto error;
353c833cfcfSAlex Hornung 	}
354c833cfcfSAlex Hornung 
355c833cfcfSAlex Hornung 	error = pbkdf2(prf_algo, (char *)pass, passlen,
356c833cfcfSAlex Hornung 	    ehdr->salt, sizeof(ehdr->salt),
357c833cfcfSAlex Hornung 	    MAX_KEYSZ, key);
358c833cfcfSAlex Hornung 	if (error) {
359c833cfcfSAlex Hornung 		tc_log(1, "could not derive key\n");
360c833cfcfSAlex Hornung 		goto error;
361c833cfcfSAlex Hornung 	}
362c833cfcfSAlex Hornung 
363c833cfcfSAlex Hornung 	error = pbkdf2(prf_algo, (char *)pass, passlen,
364c833cfcfSAlex Hornung 	    ehdr_backup->salt, sizeof(ehdr_backup->salt),
365c833cfcfSAlex Hornung 	    MAX_KEYSZ, key_backup);
366c833cfcfSAlex Hornung 	if (error) {
367c833cfcfSAlex Hornung 		tc_log(1, "could not derive backup key\n");
368c833cfcfSAlex Hornung 		goto error;
369c833cfcfSAlex Hornung 	}
370c833cfcfSAlex Hornung 
371*7b1e1c8eSDaniel Fojt 	if ((hdr_cfg = hdr_cfg_from_sig(prf_algo->sig)) == NULL) {
372*7b1e1c8eSDaniel Fojt 		tc_log(1, "could not find internal header configuration\n");
373*7b1e1c8eSDaniel Fojt 		goto error;
374*7b1e1c8eSDaniel Fojt 	}
375*7b1e1c8eSDaniel Fojt 
376*7b1e1c8eSDaniel Fojt 	/* Update signature and min_ver depending on selected PBKDF2 PRF algo */
377*7b1e1c8eSDaniel Fojt 	memcpy(info->hdr->tc_str, prf_algo->sig, 4);
378*7b1e1c8eSDaniel Fojt 	info->hdr->tc_min_ver = hdr_cfg->min_ver;
379*7b1e1c8eSDaniel Fojt 
380c833cfcfSAlex Hornung 	HOST_TO_BE(16, info->hdr->tc_ver);
381c833cfcfSAlex Hornung 	HOST_TO_LE(16, info->hdr->tc_min_ver);
382c833cfcfSAlex Hornung 	HOST_TO_BE(32, info->hdr->crc_keys);
383c833cfcfSAlex Hornung 	HOST_TO_BE(64, info->hdr->vol_ctime);
384c833cfcfSAlex Hornung 	HOST_TO_BE(64, info->hdr->hdr_ctime);
385c833cfcfSAlex Hornung 	HOST_TO_BE(64, info->hdr->sz_vol);
386c833cfcfSAlex Hornung 	HOST_TO_BE(64, info->hdr->sz_hidvol);
387c833cfcfSAlex Hornung 	HOST_TO_BE(64, info->hdr->off_mk_scope);
388c833cfcfSAlex Hornung 	HOST_TO_BE(64, info->hdr->sz_mk_scope);
389c833cfcfSAlex Hornung 	HOST_TO_BE(32, info->hdr->sec_sz);
390c833cfcfSAlex Hornung 	HOST_TO_BE(32, info->hdr->flags);
391c833cfcfSAlex Hornung 	HOST_TO_BE(32, info->hdr->crc_dhdr);
392c833cfcfSAlex Hornung 
393c833cfcfSAlex Hornung 	memset(iv, 0, sizeof(iv));
394c833cfcfSAlex Hornung 	error = tc_encrypt(info->cipher_chain, key, iv,
395c833cfcfSAlex Hornung 	    (unsigned char *)info->hdr, sizeof(struct tchdr_dec), ehdr->enc);
396c833cfcfSAlex Hornung 	if (error) {
397c833cfcfSAlex Hornung 		tc_log(1, "Header encryption failed\n");
398c833cfcfSAlex Hornung 		goto error;
399c833cfcfSAlex Hornung 	}
400c833cfcfSAlex Hornung 
401c833cfcfSAlex Hornung 	memset(iv, 0, sizeof(iv));
402c833cfcfSAlex Hornung 	error = tc_encrypt(info->cipher_chain, key_backup, iv,
403c833cfcfSAlex Hornung 	    (unsigned char *)info->hdr,
404c833cfcfSAlex Hornung 	    sizeof(struct tchdr_dec), ehdr_backup->enc);
405c833cfcfSAlex Hornung 	if (error) {
406c833cfcfSAlex Hornung 		tc_log(1, "Backup header encryption failed\n");
407c833cfcfSAlex Hornung 		goto error;
408c833cfcfSAlex Hornung 	}
409c833cfcfSAlex Hornung 
410c833cfcfSAlex Hornung 	free_safe_mem(key);
411c833cfcfSAlex Hornung 	free_safe_mem(key_backup);
412c833cfcfSAlex Hornung 
413c833cfcfSAlex Hornung 	if (backup_hdr != NULL)
414c833cfcfSAlex Hornung 		*backup_hdr = ehdr_backup;
415c833cfcfSAlex Hornung 	else
416c833cfcfSAlex Hornung 		free_safe_mem(ehdr_backup);
417c833cfcfSAlex Hornung 
418c833cfcfSAlex Hornung 	return ehdr;
419c833cfcfSAlex Hornung 	/* NOT REACHED */
420c833cfcfSAlex Hornung 
421c833cfcfSAlex Hornung error:
422c833cfcfSAlex Hornung 	if (key)
423c833cfcfSAlex Hornung 		free_safe_mem(key);
424c833cfcfSAlex Hornung 	if (key_backup)
425c833cfcfSAlex Hornung 		free_safe_mem(key_backup);
426c833cfcfSAlex Hornung 	if (ehdr)
427c833cfcfSAlex Hornung 		free_safe_mem(ehdr);
428c833cfcfSAlex Hornung 	if (ehdr_backup)
429c833cfcfSAlex Hornung 		free_safe_mem(ehdr_backup);
430c833cfcfSAlex Hornung 
431c833cfcfSAlex Hornung 	return NULL;
432c833cfcfSAlex Hornung }
433