1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * LUKS - Linux Unified Key Setup
3*86d7f5d3SJohn Marino  *
4*86d7f5d3SJohn Marino  * Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
5*86d7f5d3SJohn Marino  *
6*86d7f5d3SJohn Marino  * This program is free software; you can redistribute it and/or
7*86d7f5d3SJohn Marino  * modify it under the terms of the GNU General Public License
8*86d7f5d3SJohn Marino  * version 2 as published by the Free Software Foundation.
9*86d7f5d3SJohn Marino  *
10*86d7f5d3SJohn Marino  * This program is distributed in the hope that it will be useful,
11*86d7f5d3SJohn Marino  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*86d7f5d3SJohn Marino  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*86d7f5d3SJohn Marino  * GNU General Public License for more details.
14*86d7f5d3SJohn Marino  *
15*86d7f5d3SJohn Marino  * You should have received a copy of the GNU General Public License
16*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software
17*86d7f5d3SJohn Marino  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18*86d7f5d3SJohn Marino  */
19*86d7f5d3SJohn Marino 
20*86d7f5d3SJohn Marino #include <string.h>
21*86d7f5d3SJohn Marino #include <stdio.h>
22*86d7f5d3SJohn Marino #include <stdlib.h>
23*86d7f5d3SJohn Marino #include <ctype.h>
24*86d7f5d3SJohn Marino #include <inttypes.h>
25*86d7f5d3SJohn Marino #include <sys/types.h>
26*86d7f5d3SJohn Marino #include <sys/stat.h>
27*86d7f5d3SJohn Marino #include <sys/ioctl.h>
28*86d7f5d3SJohn Marino #include <sys/mman.h>
29*86d7f5d3SJohn Marino #include <sys/utsname.h>
30*86d7f5d3SJohn Marino #include <fcntl.h>
31*86d7f5d3SJohn Marino #include <unistd.h>
32*86d7f5d3SJohn Marino #include <errno.h>
33*86d7f5d3SJohn Marino #include <signal.h>
34*86d7f5d3SJohn Marino 
35*86d7f5d3SJohn Marino #include "luks.h"
36*86d7f5d3SJohn Marino //#include "../lib/libcryptsetup.h"
37*86d7f5d3SJohn Marino #include "../lib/internal.h"
38*86d7f5d3SJohn Marino //#include "../lib/blockdev.h"
39*86d7f5d3SJohn Marino 
40*86d7f5d3SJohn Marino #define div_round_up(a,b) ({          \
41*86d7f5d3SJohn Marino 	typeof(a) __a = (a);          \
42*86d7f5d3SJohn Marino 	typeof(b) __b = (b);          \
43*86d7f5d3SJohn Marino 	(__a - 1) / __b + 1;          \
44*86d7f5d3SJohn Marino })
45*86d7f5d3SJohn Marino 
round_up_modulo(int x,int m)46*86d7f5d3SJohn Marino static inline int round_up_modulo(int x, int m) {
47*86d7f5d3SJohn Marino 	return div_round_up(x, m) * m;
48*86d7f5d3SJohn Marino }
49*86d7f5d3SJohn Marino 
50*86d7f5d3SJohn Marino static const char *cleaner_name=NULL;
51*86d7f5d3SJohn Marino static uint64_t cleaner_size = 0;
52*86d7f5d3SJohn Marino static int devfd=-1;
53*86d7f5d3SJohn Marino 
setup_mapping(const char * cipher,const char * name,const char * device,unsigned int payloadOffset,const char * key,size_t keyLength,unsigned int sector,size_t srcLength,int mode,struct crypt_device * ctx)54*86d7f5d3SJohn Marino static int setup_mapping(const char *cipher, const char *name,
55*86d7f5d3SJohn Marino 			 const char *device, unsigned int payloadOffset,
56*86d7f5d3SJohn Marino 			 const char *key, size_t keyLength,
57*86d7f5d3SJohn Marino 			 unsigned int sector, size_t srcLength,
58*86d7f5d3SJohn Marino 			 int mode, struct crypt_device *ctx)
59*86d7f5d3SJohn Marino {
60*86d7f5d3SJohn Marino 	int device_sector_size = sector_size_for_device(device);
61*86d7f5d3SJohn Marino 	uint64_t size;
62*86d7f5d3SJohn Marino 
63*86d7f5d3SJohn Marino 	/*
64*86d7f5d3SJohn Marino 	 * we need to round this to nearest multiple of the underlying
65*86d7f5d3SJohn Marino 	 * device's sector size, otherwise the mapping will be refused.
66*86d7f5d3SJohn Marino 	 */
67*86d7f5d3SJohn Marino 	if(device_sector_size < 0) {
68*86d7f5d3SJohn Marino 		log_err(ctx, _("Unable to obtain sector size for %s"), device);
69*86d7f5d3SJohn Marino 		return -EINVAL;
70*86d7f5d3SJohn Marino 	}
71*86d7f5d3SJohn Marino 	size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE;
72*86d7f5d3SJohn Marino 	cleaner_size = size;
73*86d7f5d3SJohn Marino 
74*86d7f5d3SJohn Marino 	return dm_create_device(name, device, cipher, "TEMP", NULL, size, 0, sector,
75*86d7f5d3SJohn Marino 				keyLength, key, (mode == O_RDONLY), 0);
76*86d7f5d3SJohn Marino }
77*86d7f5d3SJohn Marino 
sigint_handler(int sig)78*86d7f5d3SJohn Marino static void sigint_handler(int sig)
79*86d7f5d3SJohn Marino {
80*86d7f5d3SJohn Marino 	if(devfd >= 0)
81*86d7f5d3SJohn Marino 		close(devfd);
82*86d7f5d3SJohn Marino 	devfd = -1;
83*86d7f5d3SJohn Marino 	if(cleaner_name)
84*86d7f5d3SJohn Marino 		dm_remove_device(cleaner_name, 1, cleaner_size);
85*86d7f5d3SJohn Marino 
86*86d7f5d3SJohn Marino 	signal(SIGINT, SIG_DFL);
87*86d7f5d3SJohn Marino 	kill(getpid(), SIGINT);
88*86d7f5d3SJohn Marino }
89*86d7f5d3SJohn Marino 
_error_hint(char * cipherName,char * cipherMode,size_t keyLength)90*86d7f5d3SJohn Marino static char *_error_hint(char *cipherName, char *cipherMode, size_t keyLength)
91*86d7f5d3SJohn Marino {
92*86d7f5d3SJohn Marino 	char *hint = "";
93*86d7f5d3SJohn Marino #ifdef __linux__
94*86d7f5d3SJohn Marino 	char c, tmp[4] = {0};
95*86d7f5d3SJohn Marino 	struct utsname uts;
96*86d7f5d3SJohn Marino 	int i = 0, kernel_minor;
97*86d7f5d3SJohn Marino 
98*86d7f5d3SJohn Marino 	/* Nothing to suggest here */
99*86d7f5d3SJohn Marino 	if (uname(&uts) || strncmp(uts.release, "2.6.", 4))
100*86d7f5d3SJohn Marino 		return hint;
101*86d7f5d3SJohn Marino 
102*86d7f5d3SJohn Marino 	/* Get kernel minor without suffixes */
103*86d7f5d3SJohn Marino 	while (i < 3 && (c = uts.release[i + 4]))
104*86d7f5d3SJohn Marino 		tmp[i++] = isdigit(c) ? c : '\0';
105*86d7f5d3SJohn Marino 	kernel_minor = atoi(tmp);
106*86d7f5d3SJohn Marino 
107*86d7f5d3SJohn Marino 	if (!strncmp(cipherMode, "xts", 3) && (keyLength != 256 && keyLength != 512))
108*86d7f5d3SJohn Marino 		hint = _("Key size in XTS mode must be 256 or 512 bits.\n");
109*86d7f5d3SJohn Marino 	else if (!strncmp(cipherMode, "xts", 3) && kernel_minor < 24)
110*86d7f5d3SJohn Marino 		hint = _("Block mode XTS is available since kernel 2.6.24.\n");
111*86d7f5d3SJohn Marino 	if (!strncmp(cipherMode, "lrw", 3) && (keyLength != 256 && keyLength != 512))
112*86d7f5d3SJohn Marino 		hint = _("Key size in LRW mode must be 256 or 512 bits.\n");
113*86d7f5d3SJohn Marino 	else if (!strncmp(cipherMode, "lrw", 3) && kernel_minor < 20)
114*86d7f5d3SJohn Marino 		hint = _("Block mode LRW is available since kernel 2.6.20.\n");
115*86d7f5d3SJohn Marino #endif
116*86d7f5d3SJohn Marino 	return hint;
117*86d7f5d3SJohn Marino }
118*86d7f5d3SJohn Marino 
119*86d7f5d3SJohn Marino /* This function is not reentrant safe, as it installs a signal
120*86d7f5d3SJohn Marino    handler and global vars for cleaning */
LUKS_endec_template(char * src,size_t srcLength,struct luks_phdr * hdr,char * key,size_t keyLength,const char * device,unsigned int sector,ssize_t (* func)(int,void *,size_t),int mode,struct crypt_device * ctx)121*86d7f5d3SJohn Marino static int LUKS_endec_template(char *src, size_t srcLength,
122*86d7f5d3SJohn Marino 			       struct luks_phdr *hdr,
123*86d7f5d3SJohn Marino 			       char *key, size_t keyLength,
124*86d7f5d3SJohn Marino 			       const char *device,
125*86d7f5d3SJohn Marino 			       unsigned int sector,
126*86d7f5d3SJohn Marino 			       ssize_t (*func)(int, void *, size_t),
127*86d7f5d3SJohn Marino 			       int mode,
128*86d7f5d3SJohn Marino 			       struct crypt_device *ctx)
129*86d7f5d3SJohn Marino {
130*86d7f5d3SJohn Marino 	char *name = NULL;
131*86d7f5d3SJohn Marino 	char *fullpath = NULL;
132*86d7f5d3SJohn Marino 	char *dmCipherSpec = NULL;
133*86d7f5d3SJohn Marino 	const char *dmDir = dm_get_dir();
134*86d7f5d3SJohn Marino 	int r = -1;
135*86d7f5d3SJohn Marino 
136*86d7f5d3SJohn Marino 	if(dmDir == NULL) {
137*86d7f5d3SJohn Marino 		log_err(ctx, _("Failed to obtain device mapper directory."));
138*86d7f5d3SJohn Marino 		return -1;
139*86d7f5d3SJohn Marino 	}
140*86d7f5d3SJohn Marino 	if(asprintf(&name,"temporary-cryptsetup-%d",getpid())               == -1 ||
141*86d7f5d3SJohn Marino 	   asprintf(&fullpath,"%s/%s",dmDir,name)                           == -1 ||
142*86d7f5d3SJohn Marino 	   asprintf(&dmCipherSpec,"%s-%s",hdr->cipherName, hdr->cipherMode) == -1) {
143*86d7f5d3SJohn Marino 	        r = -ENOMEM;
144*86d7f5d3SJohn Marino 		goto out1;
145*86d7f5d3SJohn Marino         }
146*86d7f5d3SJohn Marino 
147*86d7f5d3SJohn Marino 	signal(SIGINT, sigint_handler);
148*86d7f5d3SJohn Marino 	cleaner_name = name;
149*86d7f5d3SJohn Marino 
150*86d7f5d3SJohn Marino 	r = setup_mapping(dmCipherSpec, name, device, hdr->payloadOffset,
151*86d7f5d3SJohn Marino 			  key, keyLength, sector, srcLength, mode, ctx);
152*86d7f5d3SJohn Marino 	if(r < 0) {
153*86d7f5d3SJohn Marino 		log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
154*86d7f5d3SJohn Marino 			"Check that kernel supports %s cipher (check syslog for more info).\n%s"),
155*86d7f5d3SJohn Marino 			device, dmCipherSpec,
156*86d7f5d3SJohn Marino 			_error_hint(hdr->cipherName, hdr->cipherMode, keyLength * 8));
157*86d7f5d3SJohn Marino 		r = -EIO;
158*86d7f5d3SJohn Marino 		goto out1;
159*86d7f5d3SJohn Marino 	}
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino 	devfd = open(fullpath, mode | O_DIRECT | O_SYNC);  /* devfd is a global var */
162*86d7f5d3SJohn Marino 	if(devfd == -1) {
163*86d7f5d3SJohn Marino 		log_err(ctx, _("Failed to open temporary keystore device.\n"));
164*86d7f5d3SJohn Marino 		r = -EIO;
165*86d7f5d3SJohn Marino 		goto out2;
166*86d7f5d3SJohn Marino 	}
167*86d7f5d3SJohn Marino 
168*86d7f5d3SJohn Marino 	r = func(devfd,src,srcLength);
169*86d7f5d3SJohn Marino 	if(r < 0) {
170*86d7f5d3SJohn Marino 		log_err(ctx, _("Failed to access temporary keystore device.\n"));
171*86d7f5d3SJohn Marino 		r = -EIO;
172*86d7f5d3SJohn Marino 		goto out3;
173*86d7f5d3SJohn Marino 	}
174*86d7f5d3SJohn Marino 
175*86d7f5d3SJohn Marino 	r = 0;
176*86d7f5d3SJohn Marino  out3:
177*86d7f5d3SJohn Marino 	close(devfd);
178*86d7f5d3SJohn Marino 	devfd = -1;
179*86d7f5d3SJohn Marino  out2:
180*86d7f5d3SJohn Marino 	dm_remove_device(cleaner_name, 1, cleaner_size);
181*86d7f5d3SJohn Marino  out1:
182*86d7f5d3SJohn Marino 	signal(SIGINT, SIG_DFL);
183*86d7f5d3SJohn Marino 	cleaner_name = NULL;
184*86d7f5d3SJohn Marino 	cleaner_size = 0;
185*86d7f5d3SJohn Marino 	free(dmCipherSpec);
186*86d7f5d3SJohn Marino 	free(fullpath);
187*86d7f5d3SJohn Marino 	free(name);
188*86d7f5d3SJohn Marino 	return r;
189*86d7f5d3SJohn Marino }
190*86d7f5d3SJohn Marino 
LUKS_encrypt_to_storage(char * src,size_t srcLength,struct luks_phdr * hdr,char * key,size_t keyLength,const char * device,unsigned int sector,struct crypt_device * ctx)191*86d7f5d3SJohn Marino int LUKS_encrypt_to_storage(char *src, size_t srcLength,
192*86d7f5d3SJohn Marino 			    struct luks_phdr *hdr,
193*86d7f5d3SJohn Marino 			    char *key, size_t keyLength,
194*86d7f5d3SJohn Marino 			    const char *device,
195*86d7f5d3SJohn Marino 			    unsigned int sector,
196*86d7f5d3SJohn Marino 			    struct crypt_device *ctx)
197*86d7f5d3SJohn Marino {
198*86d7f5d3SJohn Marino 	return LUKS_endec_template(src,srcLength,hdr,key,keyLength, device, sector,
199*86d7f5d3SJohn Marino 				   (ssize_t (*)(int, void *, size_t)) write_blockwise,
200*86d7f5d3SJohn Marino 				   O_RDWR, ctx);
201*86d7f5d3SJohn Marino }
202*86d7f5d3SJohn Marino 
LUKS_decrypt_from_storage(char * dst,size_t dstLength,struct luks_phdr * hdr,char * key,size_t keyLength,const char * device,unsigned int sector,struct crypt_device * ctx)203*86d7f5d3SJohn Marino int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
204*86d7f5d3SJohn Marino 			      struct luks_phdr *hdr,
205*86d7f5d3SJohn Marino 			      char *key, size_t keyLength,
206*86d7f5d3SJohn Marino 			      const char *device,
207*86d7f5d3SJohn Marino 			      unsigned int sector,
208*86d7f5d3SJohn Marino 			      struct crypt_device *ctx)
209*86d7f5d3SJohn Marino {
210*86d7f5d3SJohn Marino 	return LUKS_endec_template(dst,dstLength,hdr,key,keyLength, device,
211*86d7f5d3SJohn Marino 				   sector, read_blockwise, O_RDONLY, ctx);
212*86d7f5d3SJohn Marino }
213