uvm_swap_encrypt.c revision 1.8
1/*	$OpenBSD: uvm_swap_encrypt.c,v 1.8 2001/08/06 22:34:44 mickey Exp $	*/
2
3/*
4 * Copyright 1999 Niels Provos <provos@citi.umich.edu>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed by Niels Provos.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/sysctl.h>
38#include <sys/time.h>
39#include <sys/conf.h>
40#include <dev/rndvar.h>
41#include <crypto/rijndael.h>
42
43#include <vm/vm.h>
44
45#include <uvm/uvm.h>
46
47struct swap_key *kcur = NULL;
48rijndael_ctx swap_key;
49
50int uvm_doswapencrypt = 0;
51u_int uvm_swpkeyscreated = 0;
52u_int uvm_swpkeysdeleted = 0;
53
54int swap_encrypt_initalized = 0;
55
56int
57swap_encrypt_ctl(name, namelen, oldp, oldlenp, newp, newlen, p)
58	int *name;
59	u_int namelen;
60	void *oldp;
61	size_t *oldlenp;
62	void *newp;
63	size_t newlen;
64	struct proc *p;
65{
66	/* all sysctl names at this level are terminal */
67	if (namelen != 1)
68		return (ENOTDIR);		/* overloaded */
69
70	switch (name[0]) {
71	case SWPENC_ENABLE: {
72		int doencrypt = uvm_doswapencrypt;
73		int result;
74
75		result = sysctl_int(oldp, oldlenp, newp, newlen, &doencrypt);
76		if (result)
77			return result;
78
79		/* Swap Encryption has been turned on, we need to
80		 * initalize state for swap devices that have been
81		 * added
82		 */
83		if (doencrypt)
84			uvm_swap_initcrypt_all();
85		uvm_doswapencrypt = doencrypt;
86		return (0);
87	}
88	case SWPENC_CREATED:
89		return (sysctl_rdint(oldp, oldlenp, newp, uvm_swpkeyscreated));
90	case SWPENC_DELETED:
91		return (sysctl_rdint(oldp, oldlenp, newp, uvm_swpkeysdeleted));
92	default:
93		return (EOPNOTSUPP);
94	}
95	/* NOTREACHED */
96}
97
98void
99swap_key_create(struct swap_key *key)
100{
101	int i;
102	u_int32_t *p = key->key;
103
104	key->refcount = 0;
105	for (i = 0; i < sizeof(key->key) / sizeof(u_int32_t); i++)
106		*p++ = arc4random();
107
108	uvm_swpkeyscreated++;
109}
110
111void
112swap_key_delete(struct swap_key *key)
113{
114	/* Make sure that this key gets removed if we just used it */
115	swap_key_cleanup(key);
116
117	memset(key, 0, sizeof(*key));
118	uvm_swpkeysdeleted++;
119}
120
121/*
122 * Encrypt the data before it goes to swap, the size should be 64-bit
123 * aligned.
124 */
125
126void
127swap_encrypt(struct swap_key *key, caddr_t src, caddr_t dst,
128	     u_int64_t block, size_t count)
129{
130	u_int32_t *dsrc = (u_int32_t *)src;
131	u_int32_t *ddst = (u_int32_t *)dst;
132	u_int32_t iv[4];
133	u_int32_t iv1, iv2, iv3, iv4;
134
135	if (!swap_encrypt_initalized)
136		swap_encrypt_initalized = 1;
137
138	swap_key_prepare(key, 1);
139
140	count /= sizeof(u_int32_t);
141
142	iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
143	rijndael_encrypt(&swap_key, iv, iv);
144	iv1 = iv[0]; iv2 = iv[1]; iv3 = iv[2]; iv4 = iv[3];
145
146	for (; count > 0; count -= 4) {
147		ddst[0] = dsrc[0] ^ iv1;
148		ddst[1] = dsrc[1] ^ iv2;
149		ddst[2] = dsrc[2] ^ iv3;
150		ddst[3] = dsrc[3] ^ iv4;
151		/*
152		 * Do not worry about endianess, it only needs to decrypt
153		 * on this machine
154		 */
155		rijndael_encrypt(&swap_key, ddst, ddst);
156		iv1 = ddst[0];
157		iv2 = ddst[1];
158		iv3 = ddst[2];
159		iv4 = ddst[3];
160
161		dsrc += 4;
162		ddst += 4;
163	}
164}
165
166/*
167 * Decrypt the data after we retrieved it from swap, the size should be 64-bit
168 * aligned.
169 */
170
171void
172swap_decrypt(struct swap_key *key, caddr_t src, caddr_t dst,
173	     u_int64_t block, size_t count)
174{
175	u_int32_t *dsrc = (u_int32_t *)src;
176	u_int32_t *ddst = (u_int32_t *)dst;
177	u_int32_t iv[4];
178	u_int32_t iv1, iv2, iv3, iv4, niv1, niv2, niv3, niv4;
179
180	if (!swap_encrypt_initalized)
181		panic("swap_decrypt: key not initalized");
182
183	swap_key_prepare(key, 0);
184
185	count /= sizeof(u_int32_t);
186
187	iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
188	rijndael_encrypt(&swap_key, iv, iv);
189	iv1 = iv[0]; iv2 = iv[1]; iv3 = iv[2]; iv4 = iv[3];
190
191	for (; count > 0; count -= 4) {
192		ddst[0] = niv1 = dsrc[0];
193		ddst[1] = niv2 = dsrc[1];
194		ddst[2] = niv3 = dsrc[2];
195		ddst[3] = niv4 = dsrc[3];
196		rijndael_decrypt(&swap_key, ddst, ddst);
197		ddst[0] ^= iv1;
198		ddst[1] ^= iv2;
199		ddst[2] ^= iv3;
200		ddst[3] ^= iv4;
201
202		iv1 = niv1;
203		iv2 = niv2;
204		iv3 = niv3;
205		iv4 = niv4;
206
207		dsrc += 4;
208		ddst += 4;
209	}
210}
211
212void
213swap_key_prepare(struct swap_key *key, int encrypt)
214{
215	/* Check if we have prepared for this key already,
216	 * if we only have the encryption schedule, we have
217	 * to recompute ang get the decryption schedule also
218	 */
219	if (kcur == key && (encrypt || swap_key.decrypt))
220		return;
221
222	rijndael_set_key(&swap_key, key->key,
223			 sizeof(key->key) * 8,
224			 encrypt);
225
226	kcur = key;
227}
228
229/*
230 * Make sure that a specific key is no longer available.
231 */
232
233void
234swap_key_cleanup(struct swap_key *key)
235{
236	/* Check if we have a key */
237	if (kcur == NULL || kcur != key)
238		return;
239
240	/* Zero out the subkeys */
241       	memset(&swap_key, 0, sizeof(swap_key));
242
243	kcur = NULL;
244}
245