The following patch adds the core functionality for the encrypted
suspend image.
--
Andreas Steinmetz SPAMmers use [email protected]
--- linux-2.6.11.2/kernel/power/swsusp.c.ast 2005-04-10 14:08:55.000000000 +0200
+++ linux-2.6.11.2/kernel/power/swsusp.c 2005-04-11 00:50:45.000000000 +0200
@@ -31,6 +31,9 @@
* Alex Badea <[email protected]>:
* Fixed runaway init
*
+ * Andreas Steinmetz <[email protected]>:
+ * Added encrypted suspend option
+ *
* More state savers are welcome. Especially for the scsi layer...
*
* For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
@@ -72,6 +75,16 @@
#include "power.h"
+#ifdef CONFIG_SWSUSP_ENCRYPT
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#endif
+
+#define CIPHER "aes"
+#define MAXKEY 32
+#define MAXIV 32
+
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
@@ -103,15 +116,27 @@
#define SWSUSP_SIG "S1SUSPEND"
-static struct swsusp_header {
- char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
+struct swsusp_header {
+ char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)];
+ u8 key[MAXKEY];
+ u8 iv[MAXIV];
swp_entry_t swsusp_info;
char orig_sig[10];
char sig[10];
-} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static union {
+ struct swsusp_header __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
+ u8 buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+} __attribute__((packed, aligned(PAGE_SIZE))) u;
static struct swsusp_info swsusp_info;
+#ifdef CONFIG_SWSUSP_ENCRYPT
+static u8 key[MAXKEY];
+static u8 iv[MAXIV];
+#endif
+
/*
* XXX: We try to keep some more pages free so that I/O operations succeed
* without paging. Might this be more?
@@ -130,22 +155,72 @@
static unsigned short swapfile_used[MAX_SWAPFILES];
static unsigned short root_swap;
+#ifdef CONFIG_SWSUSP_ENCRYPT
+static struct crypto_tfm *crypto_init(int mode)
+{
+ struct crypto_tfm *tfm;
+ int len;
+
+ tfm = crypto_alloc_tfm(CIPHER, CRYPTO_TFM_MODE_CBC);
+ if(!tfm) {
+ printk(KERN_ERR "swsusp: no tfm, suspend not possible\n");
+ return NULL;
+ }
+
+ if(sizeof(key) < crypto_tfm_alg_min_keysize(tfm)) {
+ printk("swsusp: key buffer too small, suspend not possible\n");
+ crypto_free_tfm(tfm);
+ return NULL;
+ }
+
+ if (sizeof(iv) < crypto_tfm_alg_ivsize(tfm)) {
+ printk("swsusp: iv buffer too small, suspend not possible\n");
+ crypto_free_tfm(tfm);
+ return NULL;
+ }
+
+ if (mode) {
+ get_random_bytes(key, MAXKEY);
+ get_random_bytes(iv, MAXIV);
+ }
+
+ len = crypto_tfm_alg_max_keysize(tfm);
+ if (len > sizeof(key))
+ len = sizeof(key);
+
+ if (crypto_cipher_setkey(tfm, key, len)) {
+ printk(KERN_ERR "swsusp: key setup failure, suspend not possible\n");
+ crypto_free_tfm(tfm);
+ return NULL;
+ }
+
+ len = crypto_tfm_alg_blocksize(tfm);
+ crypto_cipher_set_iv(tfm, iv, len);
+
+ return tfm;
+}
+#endif
+
static int mark_swapfiles(swp_entry_t prev)
{
int error;
rw_swap_page_sync(READ,
swp_entry(root_swap, 0),
- virt_to_page((unsigned long)&swsusp_header));
- if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
- !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
- memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
- memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
- swsusp_header.swsusp_info = prev;
+ virt_to_page((unsigned long)&u.swsusp_header));
+ if (!memcmp("SWAP-SPACE",u.swsusp_header.sig, 10) ||
+ !memcmp("SWAPSPACE2",u.swsusp_header.sig, 10)) {
+ memcpy(u.swsusp_header.orig_sig,u.swsusp_header.sig, 10);
+ memcpy(u.swsusp_header.sig,SWSUSP_SIG, 10);
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ memcpy(u.swsusp_header.key, key, MAXKEY);
+ memcpy(u.swsusp_header.iv, iv, MAXIV);
+#endif
+ u.swsusp_header.swsusp_info = prev;
error = rw_swap_page_sync(WRITE,
swp_entry(root_swap, 0),
virt_to_page((unsigned long)
- &swsusp_header));
+ &u.swsusp_header));
} else {
pr_debug("swsusp: Partition is not swap space.\n");
error = -ENODEV;
@@ -294,6 +369,19 @@
int error = 0;
int i;
unsigned int mod = nr_copy_pages / 100;
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ struct crypto_tfm *tfm;
+ struct scatterlist src, dst;
+
+ if (!(tfm = crypto_init(1)))
+ return -EINVAL;
+
+ src.offset = 0;
+ src.length = PAGE_SIZE;
+ dst.page = virt_to_page(u.buffer);
+ dst.offset = 0;
+ dst.length = PAGE_SIZE;
+#endif
if (!mod)
mod = 1;
@@ -302,10 +390,22 @@
for (i = 0; i < nr_copy_pages && !error; i++) {
if (!(i%mod))
printk( "\b\b\b\b%3d%%", i / mod );
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ src.page = virt_to_page((pagedir_nosave+i)->address);
+ error = crypto_cipher_encrypt_iv(tfm, &dst, &src,
+ PAGE_SIZE, iv);
+ if (!error)
+ error = write_page((unsigned long)u.buffer,
+ &((pagedir_nosave+i)->swap_address));
+#else
error = write_page((pagedir_nosave+i)->address,
&((pagedir_nosave+i)->swap_address));
+#endif
}
printk("\b\b\b\bdone\n");
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ crypto_free_tfm(tfm);
+#endif
return error;
}
@@ -404,6 +504,10 @@
if ((error = close_swap()))
goto FreePagedir;
Done:
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ memset(key, 0, MAXKEY);
+ memset(iv, 0, MAXIV);
+#endif
return error;
FreePagedir:
free_pagedir_entries();
@@ -1101,7 +1205,7 @@
const char * reason = NULL;
int error;
- if ((error = bio_read_page(swp_offset(swsusp_header.swsusp_info), &swsusp_info)))
+ if ((error = bio_read_page(swp_offset(u.swsusp_header.swsusp_info), &swsusp_info)))
return error;
/* Is this same machine? */
@@ -1118,16 +1222,21 @@
{
int error;
- memset(&swsusp_header, 0, sizeof(swsusp_header));
- if ((error = bio_read_page(0, &swsusp_header)))
+ memset(&u.swsusp_header, 0, sizeof(u.swsusp_header));
+ if ((error = bio_read_page(0, &u.swsusp_header)))
return error;
- if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
- memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
-
+ if (!memcmp(SWSUSP_SIG, u.swsusp_header.sig, 10)) {
+ memcpy(u.swsusp_header.sig, u.swsusp_header.orig_sig, 10);
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ memcpy(key, u.swsusp_header.key, MAXKEY);
+ memcpy(iv, u.swsusp_header.iv, MAXIV);
+ memset(u.swsusp_header.key, 0, MAXKEY);
+ memset(u.swsusp_header.iv, 0, MAXIV);
+#endif
/*
* Reset swap signature now.
*/
- error = bio_write_page(0, &swsusp_header);
+ error = bio_write_page(0, &u.swsusp_header);
} else {
pr_debug(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
return -EINVAL;
@@ -1150,6 +1259,18 @@
int error;
int i;
int mod = nr_copy_pages / 100;
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ struct crypto_tfm *tfm;
+ struct scatterlist src, dst;
+
+ if (!(tfm = crypto_init(0)))
+ return -EINVAL;
+
+ src.offset = 0;
+ src.length = PAGE_SIZE;
+ dst.offset = 0;
+ dst.length = PAGE_SIZE;
+#endif
if (!mod)
mod = 1;
@@ -1163,8 +1284,18 @@
printk( "\b\b\b\b%3d%%", i / mod );
error = bio_read_page(swp_offset(p->swap_address),
(void *)p->address);
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ if (!error) {
+ src.page = dst.page = virt_to_page((void *)p->address);
+ error = crypto_cipher_decrypt_iv(tfm, &dst, &src,
+ PAGE_SIZE, iv);
+ }
+#endif
}
printk(" %d done.\n",i);
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ crypto_free_tfm(tfm);
+#endif
return error;
}
@@ -1233,6 +1364,11 @@
} else
error = PTR_ERR(resume_bdev);
+#ifdef CONFIG_SWSUSP_ENCRYPT
+ memset(key, 0, MAXKEY);
+ memset(iv, 0, MAXIV);
+#endif
+
if (!error)
pr_debug("Reading resume file was successful\n");
else
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]