Line data Source code
1 : /* $OpenBSD: uvm_swap_encrypt.c,v 1.22 2015/05/06 04:00:10 dlg 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 <crypto/rijndael.h>
40 :
41 : #include <uvm/uvm.h>
42 : #include <uvm/uvm_swap_encrypt.h>
43 :
44 : struct swap_key *kcur = NULL;
45 : rijndael_ctx swap_ctxt;
46 :
47 : int uvm_doswapencrypt = 1;
48 : u_int uvm_swpkeyscreated = 0;
49 : u_int uvm_swpkeysdeleted = 0;
50 :
51 : int swap_encrypt_initialized = 0;
52 :
53 : int
54 0 : swap_encrypt_ctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
55 : void *newp, size_t newlen, struct proc *p)
56 : {
57 : /* all sysctl names at this level are terminal */
58 0 : if (namelen != 1)
59 0 : return (ENOTDIR); /* overloaded */
60 :
61 0 : switch (name[0]) {
62 : case SWPENC_ENABLE: {
63 0 : int doencrypt = uvm_doswapencrypt;
64 : int result;
65 :
66 0 : result = sysctl_int(oldp, oldlenp, newp, newlen, &doencrypt);
67 0 : if (result)
68 0 : return result;
69 :
70 : /*
71 : * Swap Encryption has been turned on, we need to
72 : * initialize state for swap devices that have been
73 : * added.
74 : */
75 0 : if (doencrypt)
76 0 : uvm_swap_initcrypt_all();
77 0 : uvm_doswapencrypt = doencrypt;
78 0 : return (0);
79 0 : }
80 : case SWPENC_CREATED:
81 0 : return (sysctl_rdint(oldp, oldlenp, newp, uvm_swpkeyscreated));
82 : case SWPENC_DELETED:
83 0 : return (sysctl_rdint(oldp, oldlenp, newp, uvm_swpkeysdeleted));
84 : default:
85 0 : return (EOPNOTSUPP);
86 : }
87 : /* NOTREACHED */
88 0 : }
89 :
90 : void
91 0 : swap_key_create(struct swap_key *key)
92 : {
93 0 : arc4random_buf(key->key, sizeof(key->key));
94 0 : uvm_swpkeyscreated++;
95 0 : }
96 :
97 : void
98 0 : swap_key_delete(struct swap_key *key)
99 : {
100 : /* Make sure that this key gets removed if we just used it */
101 0 : swap_key_cleanup(key);
102 :
103 0 : explicit_bzero(key, sizeof(*key));
104 0 : uvm_swpkeysdeleted++;
105 0 : }
106 :
107 : /*
108 : * Encrypt the data before it goes to swap, the size should be 64-bit
109 : * aligned.
110 : */
111 :
112 : void
113 0 : swap_encrypt(struct swap_key *key, caddr_t src, caddr_t dst, u_int64_t block,
114 : size_t count)
115 : {
116 0 : u_int32_t *dsrc = (u_int32_t *)src;
117 0 : u_int32_t *ddst = (u_int32_t *)dst;
118 0 : u_int32_t iv[4];
119 : u_int32_t iv1, iv2, iv3, iv4;
120 :
121 0 : if (!swap_encrypt_initialized)
122 0 : swap_encrypt_initialized = 1;
123 :
124 0 : swap_key_prepare(key, 1);
125 :
126 0 : count /= sizeof(u_int32_t);
127 :
128 0 : iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
129 0 : rijndael_encrypt(&swap_ctxt, (u_char *)iv, (u_char *)iv);
130 0 : iv1 = iv[0]; iv2 = iv[1]; iv3 = iv[2]; iv4 = iv[3];
131 :
132 0 : for (; count > 0; count -= 4) {
133 0 : ddst[0] = dsrc[0] ^ iv1;
134 0 : ddst[1] = dsrc[1] ^ iv2;
135 0 : ddst[2] = dsrc[2] ^ iv3;
136 0 : ddst[3] = dsrc[3] ^ iv4;
137 : /*
138 : * Do not worry about endianess, it only needs to decrypt
139 : * on this machine.
140 : */
141 0 : rijndael_encrypt(&swap_ctxt, (u_char *)ddst, (u_char *)ddst);
142 0 : iv1 = ddst[0];
143 0 : iv2 = ddst[1];
144 0 : iv3 = ddst[2];
145 0 : iv4 = ddst[3];
146 :
147 0 : dsrc += 4;
148 0 : ddst += 4;
149 : }
150 0 : }
151 :
152 : /*
153 : * Decrypt the data after we retrieved it from swap, the size should be 64-bit
154 : * aligned.
155 : */
156 :
157 : void
158 0 : swap_decrypt(struct swap_key *key, caddr_t src, caddr_t dst, u_int64_t block,
159 : size_t count)
160 : {
161 0 : u_int32_t *dsrc = (u_int32_t *)src;
162 0 : u_int32_t *ddst = (u_int32_t *)dst;
163 0 : u_int32_t iv[4];
164 : u_int32_t iv1, iv2, iv3, iv4, niv1, niv2, niv3, niv4;
165 :
166 0 : if (!swap_encrypt_initialized)
167 0 : panic("swap_decrypt: key not initialized");
168 :
169 0 : swap_key_prepare(key, 0);
170 :
171 0 : count /= sizeof(u_int32_t);
172 :
173 0 : iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
174 0 : rijndael_encrypt(&swap_ctxt, (u_char *)iv, (u_char *)iv);
175 0 : iv1 = iv[0]; iv2 = iv[1]; iv3 = iv[2]; iv4 = iv[3];
176 :
177 0 : for (; count > 0; count -= 4) {
178 0 : ddst[0] = niv1 = dsrc[0];
179 0 : ddst[1] = niv2 = dsrc[1];
180 0 : ddst[2] = niv3 = dsrc[2];
181 0 : ddst[3] = niv4 = dsrc[3];
182 0 : rijndael_decrypt(&swap_ctxt, (u_char *)ddst, (u_char *)ddst);
183 0 : ddst[0] ^= iv1;
184 0 : ddst[1] ^= iv2;
185 0 : ddst[2] ^= iv3;
186 0 : ddst[3] ^= iv4;
187 :
188 : iv1 = niv1;
189 : iv2 = niv2;
190 : iv3 = niv3;
191 : iv4 = niv4;
192 :
193 0 : dsrc += 4;
194 0 : ddst += 4;
195 : }
196 0 : }
197 :
198 : void
199 0 : swap_key_prepare(struct swap_key *key, int encrypt)
200 : {
201 : /*
202 : * Check if we have prepared for this key already,
203 : * if we only have the encryption schedule, we have
204 : * to recompute and get the decryption schedule also.
205 : */
206 0 : if (kcur == key && (encrypt || !swap_ctxt.enc_only))
207 : return;
208 :
209 0 : if (encrypt)
210 0 : rijndael_set_key_enc_only(&swap_ctxt, (u_char *)key->key,
211 : sizeof(key->key) * 8);
212 : else
213 0 : rijndael_set_key(&swap_ctxt, (u_char *)key->key,
214 : sizeof(key->key) * 8);
215 :
216 0 : kcur = key;
217 0 : }
218 :
219 : /*
220 : * Make sure that a specific key is no longer available.
221 : */
222 :
223 : void
224 0 : swap_key_cleanup(struct swap_key *key)
225 : {
226 : /* Check if we have a key */
227 0 : if (kcur == NULL || kcur != key)
228 : return;
229 :
230 : /* Zero out the subkeys */
231 0 : explicit_bzero(&swap_ctxt, sizeof(swap_ctxt));
232 :
233 0 : kcur = NULL;
234 0 : }
|