1*4af3577fSjsg /* $OpenBSD: uvm_swap_encrypt.c,v 1.24 2021/03/12 14:15:49 jsg Exp $ */
2133306f0Sniklas
308914706Sprovos /*
408914706Sprovos * Copyright 1999 Niels Provos <provos@citi.umich.edu>
508914706Sprovos * All rights reserved.
608914706Sprovos *
708914706Sprovos * Redistribution and use in source and binary forms, with or without
808914706Sprovos * modification, are permitted provided that the following conditions
908914706Sprovos * are met:
1008914706Sprovos * 1. Redistributions of source code must retain the above copyright
1108914706Sprovos * notice, this list of conditions and the following disclaimer.
1208914706Sprovos * 2. Redistributions in binary form must reproduce the above copyright
1308914706Sprovos * notice, this list of conditions and the following disclaimer in the
1408914706Sprovos * documentation and/or other materials provided with the distribution.
1508914706Sprovos * 3. All advertising materials mentioning features or use of this software
1608914706Sprovos * must display the following acknowledgement:
1708914706Sprovos * This product includes software developed by Niels Provos.
1808914706Sprovos * 4. The name of the author may not be used to endorse or promote products
1908914706Sprovos * derived from this software without specific prior written permission.
2008914706Sprovos *
2108914706Sprovos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2208914706Sprovos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2308914706Sprovos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2408914706Sprovos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2508914706Sprovos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2608914706Sprovos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2708914706Sprovos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2808914706Sprovos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2908914706Sprovos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3008914706Sprovos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3108914706Sprovos */
3208914706Sprovos
3308914706Sprovos #include <sys/param.h>
3408914706Sprovos #include <sys/systm.h>
356b24b8a0Sprovos #include <sys/kernel.h>
366b24b8a0Sprovos #include <sys/malloc.h>
378a1f2f9eSprovos #include <sys/sysctl.h>
386b24b8a0Sprovos #include <sys/time.h>
396b24b8a0Sprovos #include <crypto/rijndael.h>
4008914706Sprovos
416b24b8a0Sprovos #include <uvm/uvm.h>
4289602861Sdlg #include <uvm/uvm_swap_encrypt.h>
436b24b8a0Sprovos
446b24b8a0Sprovos struct swap_key *kcur = NULL;
455076b47dSmarkus rijndael_ctx swap_ctxt;
4608914706Sprovos
47c4c74878Sderaadt int uvm_doswapencrypt = 1;
486b24b8a0Sprovos u_int uvm_swpkeyscreated = 0;
496b24b8a0Sprovos u_int uvm_swpkeysdeleted = 0;
506b24b8a0Sprovos
51f92e66c2Snate int swap_encrypt_initialized = 0;
5208914706Sprovos
538a1f2f9eSprovos int
swap_encrypt_ctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)542670cea8Shshoexer swap_encrypt_ctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
552670cea8Shshoexer void *newp, size_t newlen, struct proc *p)
568a1f2f9eSprovos {
578a1f2f9eSprovos /* all sysctl names at this level are terminal */
588a1f2f9eSprovos if (namelen != 1)
598a1f2f9eSprovos return (ENOTDIR); /* overloaded */
608a1f2f9eSprovos
618a1f2f9eSprovos switch (name[0]) {
628a1f2f9eSprovos case SWPENC_ENABLE: {
638a1f2f9eSprovos int doencrypt = uvm_doswapencrypt;
648a1f2f9eSprovos int result;
658a1f2f9eSprovos
660b905610Sgnezdo result = sysctl_int_bounded(oldp, oldlenp, newp, newlen,
670b905610Sgnezdo &doencrypt, 0, 1);
688a1f2f9eSprovos if (result)
698a1f2f9eSprovos return result;
708a1f2f9eSprovos
712670cea8Shshoexer /*
722670cea8Shshoexer * Swap Encryption has been turned on, we need to
73f92e66c2Snate * initialize state for swap devices that have been
742670cea8Shshoexer * added.
758a1f2f9eSprovos */
768a1f2f9eSprovos if (doencrypt)
778a1f2f9eSprovos uvm_swap_initcrypt_all();
788a1f2f9eSprovos uvm_doswapencrypt = doencrypt;
798a1f2f9eSprovos return (0);
808a1f2f9eSprovos }
818a1f2f9eSprovos case SWPENC_CREATED:
828a1f2f9eSprovos return (sysctl_rdint(oldp, oldlenp, newp, uvm_swpkeyscreated));
838a1f2f9eSprovos case SWPENC_DELETED:
848a1f2f9eSprovos return (sysctl_rdint(oldp, oldlenp, newp, uvm_swpkeysdeleted));
858a1f2f9eSprovos default:
868a1f2f9eSprovos return (EOPNOTSUPP);
878a1f2f9eSprovos }
888a1f2f9eSprovos /* NOTREACHED */
898a1f2f9eSprovos }
908a1f2f9eSprovos
9108914706Sprovos void
swap_key_create(struct swap_key * key)9205db9060Sdlg swap_key_create(struct swap_key *key)
9305db9060Sdlg {
9405db9060Sdlg arc4random_buf(key->key, sizeof(key->key));
9505db9060Sdlg uvm_swpkeyscreated++;
9605db9060Sdlg }
9705db9060Sdlg
9805db9060Sdlg void
swap_key_delete(struct swap_key * key)996b24b8a0Sprovos swap_key_delete(struct swap_key *key)
1006b24b8a0Sprovos {
1016b24b8a0Sprovos /* Make sure that this key gets removed if we just used it */
1026b24b8a0Sprovos swap_key_cleanup(key);
1036b24b8a0Sprovos
104fa2d22afSderaadt explicit_bzero(key, sizeof(*key));
1056b24b8a0Sprovos uvm_swpkeysdeleted++;
10608914706Sprovos }
10708914706Sprovos
10808914706Sprovos /*
10908914706Sprovos * Encrypt the data before it goes to swap, the size should be 64-bit
11008914706Sprovos * aligned.
11108914706Sprovos */
11208914706Sprovos
11308914706Sprovos void
swap_encrypt(struct swap_key * key,caddr_t src,caddr_t dst,u_int64_t block,size_t count)1142670cea8Shshoexer swap_encrypt(struct swap_key *key, caddr_t src, caddr_t dst, u_int64_t block,
1152670cea8Shshoexer size_t count)
11608914706Sprovos {
11708914706Sprovos u_int32_t *dsrc = (u_int32_t *)src;
11808914706Sprovos u_int32_t *ddst = (u_int32_t *)dst;
1196b24b8a0Sprovos u_int32_t iv[4];
1206b24b8a0Sprovos u_int32_t iv1, iv2, iv3, iv4;
12108914706Sprovos
122f92e66c2Snate if (!swap_encrypt_initialized)
123f92e66c2Snate swap_encrypt_initialized = 1;
1246b24b8a0Sprovos
1256b24b8a0Sprovos swap_key_prepare(key, 1);
12608914706Sprovos
12708914706Sprovos count /= sizeof(u_int32_t);
12808914706Sprovos
1296b24b8a0Sprovos iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
1305076b47dSmarkus rijndael_encrypt(&swap_ctxt, (u_char *)iv, (u_char *)iv);
1316b24b8a0Sprovos iv1 = iv[0]; iv2 = iv[1]; iv3 = iv[2]; iv4 = iv[3];
1326b24b8a0Sprovos
1336b24b8a0Sprovos for (; count > 0; count -= 4) {
13408914706Sprovos ddst[0] = dsrc[0] ^ iv1;
13508914706Sprovos ddst[1] = dsrc[1] ^ iv2;
1366b24b8a0Sprovos ddst[2] = dsrc[2] ^ iv3;
1376b24b8a0Sprovos ddst[3] = dsrc[3] ^ iv4;
13808914706Sprovos /*
139*4af3577fSjsg * Do not worry about endianness, it only needs to decrypt
1402670cea8Shshoexer * on this machine.
14108914706Sprovos */
1425076b47dSmarkus rijndael_encrypt(&swap_ctxt, (u_char *)ddst, (u_char *)ddst);
14308914706Sprovos iv1 = ddst[0];
14408914706Sprovos iv2 = ddst[1];
1456b24b8a0Sprovos iv3 = ddst[2];
1466b24b8a0Sprovos iv4 = ddst[3];
14708914706Sprovos
1486b24b8a0Sprovos dsrc += 4;
1496b24b8a0Sprovos ddst += 4;
15008914706Sprovos }
15108914706Sprovos }
15208914706Sprovos
15308914706Sprovos /*
15408914706Sprovos * Decrypt the data after we retrieved it from swap, the size should be 64-bit
15508914706Sprovos * aligned.
15608914706Sprovos */
15708914706Sprovos
15808914706Sprovos void
swap_decrypt(struct swap_key * key,caddr_t src,caddr_t dst,u_int64_t block,size_t count)1592670cea8Shshoexer swap_decrypt(struct swap_key *key, caddr_t src, caddr_t dst, u_int64_t block,
1602670cea8Shshoexer size_t count)
16108914706Sprovos {
16208914706Sprovos u_int32_t *dsrc = (u_int32_t *)src;
16308914706Sprovos u_int32_t *ddst = (u_int32_t *)dst;
1646b24b8a0Sprovos u_int32_t iv[4];
1656b24b8a0Sprovos u_int32_t iv1, iv2, iv3, iv4, niv1, niv2, niv3, niv4;
16608914706Sprovos
167f92e66c2Snate if (!swap_encrypt_initialized)
168f92e66c2Snate panic("swap_decrypt: key not initialized");
16908914706Sprovos
1706b24b8a0Sprovos swap_key_prepare(key, 0);
1716b24b8a0Sprovos
17208914706Sprovos count /= sizeof(u_int32_t);
17308914706Sprovos
1746b24b8a0Sprovos iv[0] = block >> 32; iv[1] = block; iv[2] = ~iv[0]; iv[3] = ~iv[1];
1755076b47dSmarkus rijndael_encrypt(&swap_ctxt, (u_char *)iv, (u_char *)iv);
1766b24b8a0Sprovos iv1 = iv[0]; iv2 = iv[1]; iv3 = iv[2]; iv4 = iv[3];
1776b24b8a0Sprovos
1786b24b8a0Sprovos for (; count > 0; count -= 4) {
17908914706Sprovos ddst[0] = niv1 = dsrc[0];
18008914706Sprovos ddst[1] = niv2 = dsrc[1];
1816b24b8a0Sprovos ddst[2] = niv3 = dsrc[2];
1826b24b8a0Sprovos ddst[3] = niv4 = dsrc[3];
1835076b47dSmarkus rijndael_decrypt(&swap_ctxt, (u_char *)ddst, (u_char *)ddst);
18408914706Sprovos ddst[0] ^= iv1;
18508914706Sprovos ddst[1] ^= iv2;
1866b24b8a0Sprovos ddst[2] ^= iv3;
1876b24b8a0Sprovos ddst[3] ^= iv4;
18808914706Sprovos
18908914706Sprovos iv1 = niv1;
19008914706Sprovos iv2 = niv2;
1916b24b8a0Sprovos iv3 = niv3;
1926b24b8a0Sprovos iv4 = niv4;
19308914706Sprovos
1946b24b8a0Sprovos dsrc += 4;
1956b24b8a0Sprovos ddst += 4;
19608914706Sprovos }
19708914706Sprovos }
1986b24b8a0Sprovos
1996b24b8a0Sprovos void
swap_key_prepare(struct swap_key * key,int encrypt)2006b24b8a0Sprovos swap_key_prepare(struct swap_key *key, int encrypt)
2016b24b8a0Sprovos {
2022670cea8Shshoexer /*
2032670cea8Shshoexer * Check if we have prepared for this key already,
2046b24b8a0Sprovos * if we only have the encryption schedule, we have
2052670cea8Shshoexer * to recompute and get the decryption schedule also.
2066b24b8a0Sprovos */
2075076b47dSmarkus if (kcur == key && (encrypt || !swap_ctxt.enc_only))
2086b24b8a0Sprovos return;
2096b24b8a0Sprovos
2105076b47dSmarkus if (encrypt)
2115076b47dSmarkus rijndael_set_key_enc_only(&swap_ctxt, (u_char *)key->key,
2125076b47dSmarkus sizeof(key->key) * 8);
2135076b47dSmarkus else
2145076b47dSmarkus rijndael_set_key(&swap_ctxt, (u_char *)key->key,
2155076b47dSmarkus sizeof(key->key) * 8);
2166b24b8a0Sprovos
2176b24b8a0Sprovos kcur = key;
2186b24b8a0Sprovos }
2196b24b8a0Sprovos
2206b24b8a0Sprovos /*
2216b24b8a0Sprovos * Make sure that a specific key is no longer available.
2226b24b8a0Sprovos */
2236b24b8a0Sprovos
2246b24b8a0Sprovos void
swap_key_cleanup(struct swap_key * key)2256b24b8a0Sprovos swap_key_cleanup(struct swap_key *key)
2266b24b8a0Sprovos {
2276b24b8a0Sprovos /* Check if we have a key */
2286b24b8a0Sprovos if (kcur == NULL || kcur != key)
2296b24b8a0Sprovos return;
2306b24b8a0Sprovos
2316b24b8a0Sprovos /* Zero out the subkeys */
232fa2d22afSderaadt explicit_bzero(&swap_ctxt, sizeof(swap_ctxt));
2336b24b8a0Sprovos
2346b24b8a0Sprovos kcur = NULL;
2356b24b8a0Sprovos }
236