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