1 /**	$MirOS: src/sys/uvm/uvm_swap_encrypt.c,v 1.6 2010/09/19 20:00:03 tg Exp $ */
2 /*	$OpenBSD: uvm_swap_encrypt.c,v 1.12 2003/12/26 10:04:49 markus Exp $	*/
3 
4 /*-
5  * Copyright 2008 Thorsten Glaser <tg@mirbsd.org>
6  * Copyright 1999 Niels Provos <provos@citi.umich.edu>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Niels Provos.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/sysctl.h>
40 #include <sys/time.h>
41 #include <sys/conf.h>
42 #include <dev/rndvar.h>
43 #include <crypto/rijndael.h>
44 
45 #include <uvm/uvm.h>
46 
47 struct swap_key *kcur = NULL;
48 rijndael_ctx swap_ctxt;
49 
50 int uvm_doswapencrypt = 1;
51 u_int uvm_swpkeyscreated = 0;
52 u_int uvm_swpkeysdeleted = 0;
53 
54 int swap_encrypt_initialized = 0;
55 
56 int
swap_encrypt_ctl(name,namelen,oldp,oldlenp,newp,newlen,p)57 swap_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 		 * initialize 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 
98 void
swap_key_create(struct swap_key * key)99 swap_key_create(struct swap_key *key)
100 {
101 	key->refcount = 0;
102 	arc4random_buf(key->key, sizeof(key->key));
103 
104 	uvm_swpkeyscreated++;
105 }
106 
107 void
swap_key_delete(struct swap_key * key)108 swap_key_delete(struct swap_key *key)
109 {
110 	/* Make sure that this key gets removed if we just used it */
111 	swap_key_cleanup(key);
112 
113 	memset(key, 0, sizeof(*key));
114 	uvm_swpkeysdeleted++;
115 }
116 
117 /*
118  * Encrypt the data before it goes to swap, the size should be 128-bit
119  * aligned.
120  */
121 
122 void
swap_encrypt(struct swap_key * key,caddr_t src,caddr_t dst,u_int64_t block,size_t count)123 swap_encrypt(struct swap_key *key, caddr_t src, caddr_t dst,
124 	     u_int64_t block, size_t count)
125 {
126 	u_int32_t iv[4];
127 
128 	if (!swap_encrypt_initialized)
129 		swap_encrypt_initialized = 1;
130 
131 	swap_key_prepare(key, 1);
132 
133 	iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
134 	(*rijndael_cbc_encrypt_fast)(&swap_ctxt, NULL, (u_char *)iv,
135 	    (u_char *)iv, 1);
136 	(*rijndael_cbc_encrypt_fast)(&swap_ctxt, (u_char *)iv, (u_char *)src,
137 	    (u_char *)dst, count / 16);
138 }
139 
140 /*
141  * Decrypt the data after we retrieved it from swap, the size should be 128-bit
142  * aligned.
143  */
144 
145 void
swap_decrypt(struct swap_key * key,caddr_t src,caddr_t dst,u_int64_t block,size_t count)146 swap_decrypt(struct swap_key *key, caddr_t src, caddr_t dst,
147 	     u_int64_t block, size_t count)
148 {
149 	u_int32_t iv[4];
150 
151 	if (!swap_encrypt_initialized)
152 		panic("swap_decrypt: key not initialized");
153 
154 	swap_key_prepare(key, 0);
155 
156 	iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
157 	(*rijndael_cbc_encrypt_fast)(&swap_ctxt, NULL, (u_char *)iv,
158 	    (u_char *)iv, 1);
159 	(*rijndael_cbc_decrypt_fast)(&swap_ctxt, (u_char *)iv, (u_char *)src,
160 	    (u_char *)dst, count / 16);
161 }
162 
163 void
swap_key_prepare(struct swap_key * key,int encrypt)164 swap_key_prepare(struct swap_key *key, int encrypt)
165 {
166 	/* Check if we have prepared for this key already,
167 	 * if we only have the encryption schedule, we have
168 	 * to recompute and get the decryption schedule also
169 	 */
170 	if (kcur == key && (encrypt || !swap_ctxt.enc_only))
171 		return;
172 
173 	if (encrypt)
174 		(*rijndael_set_key_enc_only_fast)(&swap_ctxt,
175 		    (u_char *)key->key, sizeof (key->key) * 8);
176 	else
177 		(*rijndael_set_key_fast)(&swap_ctxt,
178 		    (u_char *)key->key, sizeof (key->key) * 8);
179 
180 	kcur = key;
181 }
182 
183 /*
184  * Make sure that a specific key is no longer available.
185  */
186 
187 void
swap_key_cleanup(struct swap_key * key)188 swap_key_cleanup(struct swap_key *key)
189 {
190 	/* Check if we have a key */
191 	if (kcur == NULL || kcur != key)
192 		return;
193 
194 	/* Zero out the subkeys */
195        	memset(&swap_ctxt, 0, sizeof(swap_ctxt));
196 
197 	kcur = NULL;
198 }
199