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