diff -ru --new-file linux-2.4.20/Documentation/Configure.help linux-2.4.20-evfs/Documentation/Configure.help --- linux-2.4.20/Documentation/Configure.help Fri Nov 29 00:53:08 2002 +++ linux-2.4.20-evfs/Documentation/Configure.help Thu Apr 10 21:25:33 2003 @@ -14996,6 +14996,22 @@ partition (the one containing the directory /) cannot be compiled as a module. +Encrypted Virtual File System (EXPERIMENTAL) +CONFIG_EVFS_FS + EVFS is virtual filesystem hack which can provide run-time encryption + over any existing directory in per-user basis. It encrypts filenames, + file contents and symlink values. It doesn't requiere real block device, + it's file access is based on top of vfs (i.e. accessing mount source by + vfs) and is not currently considered to be SMP safe. You'll need special + utility 'efs' which can mount encrypted directories. + + The cipher used is Rijndael (AES) in with 256 bit key (which is made from + sha256-ed user-supplied password while mount), the cipherblocks is + 128bit in CBC mode for each 4k page. Look into evfs_core.c and aes.c + for more details how is encryption done. + + For more information and user 'efs' wrapper look at http://hysteria.sk/evfs + Reiserfs support CONFIG_REISERFS_FS Stores not just filenames but the files themselves in a balanced diff -ru --new-file linux-2.4.20/fs/Config.in linux-2.4.20-evfs/fs/Config.in --- linux-2.4.20/fs/Config.in Fri Nov 29 00:53:15 2002 +++ linux-2.4.20-evfs/fs/Config.in Thu May 22 00:41:15 2003 @@ -5,6 +5,9 @@ comment 'File systems' bool 'Quota support' CONFIG_QUOTA + +tristate 'Virtual Encrypted File System' CONFIG_EVFS_FS + tristate 'Kernel automounter support' CONFIG_AUTOFS_FS tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS diff -ru --new-file linux-2.4.20/fs/Makefile linux-2.4.20-evfs/fs/Makefile --- linux-2.4.20/fs/Makefile Fri Nov 29 00:53:15 2002 +++ linux-2.4.20-evfs/fs/Makefile Thu Apr 10 19:54:32 2003 @@ -68,6 +68,7 @@ subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs subdir-$(CONFIG_BEFS_FS) += befs subdir-$(CONFIG_JFS_FS) += jfs +subdir-$(CONFIG_EVFS_FS) += evfs obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o diff -ru --new-file linux-2.4.20/fs/evfs/Makefile linux-2.4.20-evfs/fs/evfs/Makefile --- linux-2.4.20/fs/evfs/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/Makefile Thu Apr 10 19:57:45 2003 @@ -0,0 +1,6 @@ +O_TARGET := evfs.o + +obj-y := aes.o sha256.o evfs_core.o base64.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -ru --new-file linux-2.4.20/fs/evfs/aes.c linux-2.4.20-evfs/fs/evfs/aes.c --- linux-2.4.20/fs/evfs/aes.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/aes.c Thu Apr 10 20:06:17 2003 @@ -0,0 +1,324 @@ +/* + * The most believed to be secure cipher today ... ripped from kernel 2.5.66 + * + * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. + * All rights reserved. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +#include "aes.h" +#include + +static u8 pow_tab[256]; +static u8 log_tab[256]; +static u8 sbx_tab[256]; +static u8 isb_tab[256]; +static u32 rco_tab[10]; +static u32 ft_tab[4][256]; +static u32 it_tab[4][256]; + +static u32 fl_tab[4][256]; +static u32 il_tab[4][256]; + +static inline u8 +f_mult (u8 a, u8 b) +{ + u8 aa = log_tab[a], cc = aa + log_tab[b]; + + return pow_tab[cc + (cc < aa ? 1 : 0)]; +} + + +void gen_tabs (void) +{ + u32 i, t; + u8 p, q; + + /* log and power tables for GF(2**8) finite field with + 0x011b as modular polynomial - the simplest prmitive + root is 0x03, used here to generate the tables */ + + for (i = 0, p = 1; i < 256; ++i) { + pow_tab[i] = (u8) p; + log_tab[p] = (u8) i; + + p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + log_tab[1] = 0; + + for (i = 0, p = 1; i < 10; ++i) { + rco_tab[i] = p; + + p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + for (i = 0; i < 256; ++i) { + p = (i ? pow_tab[255 - log_tab[i]] : 0); + q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); + p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); + sbx_tab[i] = p; + isb_tab[p] = (u8) i; + } + + for (i = 0; i < 256; ++i) { + p = sbx_tab[i]; + + t = p; + fl_tab[0][i] = t; + fl_tab[1][i] = rotl (t, 8); + fl_tab[2][i] = rotl (t, 16); + fl_tab[3][i] = rotl (t, 24); + + t = ((u32) ff_mult (2, p)) | + ((u32) p << 8) | + ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); + + ft_tab[0][i] = t; + ft_tab[1][i] = rotl (t, 8); + ft_tab[2][i] = rotl (t, 16); + ft_tab[3][i] = rotl (t, 24); + + p = isb_tab[i]; + + t = p; + il_tab[0][i] = t; + il_tab[1][i] = rotl (t, 8); + il_tab[2][i] = rotl (t, 16); + il_tab[3][i] = rotl (t, 24); + + t = ((u32) ff_mult (14, p)) | + ((u32) ff_mult (9, p) << 8) | + ((u32) ff_mult (13, p) << 16) | + ((u32) ff_mult (11, p) << 24); + + it_tab[0][i] = t; + it_tab[1][i] = rotl (t, 8); + it_tab[2][i] = rotl (t, 16); + it_tab[3][i] = rotl (t, 24); + } +} + +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) + +#define imix_col(y,x) \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= rotr(u ^ t, 8) ^ \ + rotr(v ^ t, 16) ^ \ + rotr(t,24) + +/* initialise the key schedule from the user supplied key */ + +#define loop4(i) \ +{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ + t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ + t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ + t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ +} + +#define loop6(i) \ +{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ + t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ + t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ + t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ + t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ + t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ +} + +#define loop8(i) \ +{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ + t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ + t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ + t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ + t = E_KEY[8 * i + 4] ^ ls_box(t); \ + E_KEY[8 * i + 12] = t; \ + t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ + t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ + t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ +} + +int aes_set_key(void *ctx_arg, const u8 *in_key) +{ + struct aes_ctx *ctx = ctx_arg; + u32 i, t, u, v, w; + + E_KEY[0] = u32_in (in_key); + E_KEY[1] = u32_in (in_key + 4); + E_KEY[2] = u32_in (in_key + 8); + E_KEY[3] = u32_in (in_key + 12); + + E_KEY[4] = u32_in (in_key + 16); + E_KEY[5] = u32_in (in_key + 20); + E_KEY[6] = u32_in (in_key + 24); + t = E_KEY[7] = u32_in (in_key + 28); + for (i = 0; i < 7; ++i) + loop8 (i); + + D_KEY[0] = E_KEY[0]; + D_KEY[1] = E_KEY[1]; + D_KEY[2] = E_KEY[2]; + D_KEY[3] = E_KEY[3]; + + for (i = 4; i < 32 + 24; ++i) { + imix_col (D_KEY[i], E_KEY[i]); + } + + return 0; +} + +/* encrypt a block of text */ + +#define f_nround(bo, bi, k) \ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k += 4 + +#define f_lround(bo, bi, k) \ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k) + +void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in, u8 *salt) +{ + const struct aes_ctx *ctx = ctx_arg; + u32 b0[4], b1[4]; + const u32 *kp = E_KEY + 4; + + b0[0] = u32_in(salt) ^ u32_in (in) ^ E_KEY[0]; + b0[1] = u32_in(salt + 4) ^ u32_in (in + 4) ^ E_KEY[1]; + b0[2] = u32_in(salt + 8) ^ u32_in (in + 8) ^ E_KEY[2]; + b0[3] = u32_in(salt + 12) ^ u32_in (in + 12) ^ E_KEY[3]; + + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_lround (b0, b1, kp); + + u32_out (out, b0[0]); + u32_out (out + 4, b0[1]); + u32_out (out + 8, b0[2]); + u32_out (out + 12, b0[3]); + + u32_out (salt, b0[0]); + u32_out (salt + 4, b0[1]); + u32_out (salt + 8, b0[2]); + u32_out (salt + 12, b0[3]); +} + +/* decrypt a block of text */ + +#define i_nround(bo, bi, k) \ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k -= 4 + +#define i_lround(bo, bi, k) \ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k) + +void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in, u8 *salt) +{ + const struct aes_ctx *ctx = ctx_arg; + u32 b0[4], b1[4], ss[4]; + const u32 *kp = D_KEY + 32 + 20; + + memcpy(ss, in, sizeof(ss)); + + b0[0] = (u32_in (in)) ^ E_KEY[32 + 24]; + b0[1] = (u32_in (in + 4)) ^ E_KEY[32 + 25]; + b0[2] = (u32_in (in + 8)) ^ E_KEY[32 + 26]; + b0[3] = (u32_in (in + 12)) ^ E_KEY[32 + 27]; + + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_lround (b0, b1, kp); + + u32_out (out, b0[0] ^ u32_in(salt)); + u32_out (out + 4, b0[1] ^ u32_in(salt + 4)); + u32_out (out + 8, b0[2] ^ u32_in(salt + 8)); + u32_out (out + 12, b0[3] ^ u32_in(salt + 12)); + + memcpy(salt, ss, sizeof(ss)); +} + +#define AES_BLOCK_SIZE 16 + +void aes_encrypt_str(void *ctx_arg, u8 *out, const u8 *in, int len, u8 *salt) +{ + register int i, l = len / AES_BLOCK_SIZE; + register const u8 *p = in; + register u8 *op = out; + + for (i = 0; i < l; i++, p+=AES_BLOCK_SIZE,op+=AES_BLOCK_SIZE) + aes_encrypt(ctx_arg, op, p, salt); +} + +void aes_decrypt_str(void *ctx_arg, u8 *out, const u8 *in, int len, u8 *salt) +{ + register int i, l = len / AES_BLOCK_SIZE; + register const u8 *p = in; + register u8 *op = out; + + for (i = 0; i < l; i++, p+=AES_BLOCK_SIZE,op+=AES_BLOCK_SIZE) + aes_decrypt(ctx_arg, op, p, salt); +} diff -ru --new-file linux-2.4.20/fs/evfs/aes.h linux-2.4.20-evfs/fs/evfs/aes.h --- linux-2.4.20/fs/evfs/aes.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/aes.h Thu May 22 00:31:12 2003 @@ -0,0 +1,96 @@ +#ifndef AES_H +#define AES_H + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +#include +#include + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define AES_BLOCK_SIZE 16 + +struct aes_ctx { + u32 E[60]; + u32 D[60]; +}; + +static inline +u32 generic_rotr32 (const u32 x, const unsigned bits) +{ + const unsigned n = bits % 32; + return (x >> n) | (x << (32 - n)); +} + +static inline +u32 generic_rotl32 (const u32 x, const unsigned bits) +{ + const unsigned n = bits % 32; + return (x << n) | (x >> (32 - n)); +} + +#define rotl generic_rotl32 +#define rotr generic_rotr32 + +/* + * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) + */ +inline static u8 +byte(const u32 x, const unsigned n) +{ + return x >> (n << 3); +} + +#define u32_in(x) le32_to_cpu(*(const u32 *)(x)) +#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from)) + +#define E_KEY ctx->E +#define D_KEY ctx->D + + +#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) + +#define f_rn(bo, bi, n, k) \ + bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rn(bo, bi, n, k) \ + bo[n] = it_tab[0][byte(bi[n],0)] ^ \ + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#define ls_box(x) \ + ( fl_tab[0][byte(x, 0)] ^ \ + fl_tab[1][byte(x, 1)] ^ \ + fl_tab[2][byte(x, 2)] ^ \ + fl_tab[3][byte(x, 3)] ) + +#define f_rl(bo, bi, n, k) \ + bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] = il_tab[0][byte(bi[n],0)] ^ \ + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + + + +extern void gen_tabs (void); +extern int aes_set_key(void *ctx_arg, const u8 *in_key); +extern void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in, u8 *salt); +extern void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in, u8 *salt); +extern void aes_encrypt_str(void *ctx_arg, u8 *out, const u8 *in, int len, u8 *salt); +extern void aes_decrypt_str(void *ctx_arg, u8 *out, const u8 *in, int len, u8 *salt); + + + +#endif diff -ru --new-file linux-2.4.20/fs/evfs/base64.c linux-2.4.20-evfs/fs/evfs/base64.c --- linux-2.4.20/fs/evfs/base64.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/base64.c Wed Apr 9 16:36:10 2003 @@ -0,0 +1,83 @@ +/* + * $Id: base64.c, base64 codec for filenames + */ + +#include "base64.h" + +/* bin => b64 table */ +static char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"; +/* b64 => bin table */ +static int tab64[256] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00, + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12, + 0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x00,0x00,0x00,0x00,0x3e, + 0x00,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24, + 0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30, + 0x31,0x32,0x33 }; + + +/* encode binary string to base64 */ +int base64_encode(const unsigned char *data, unsigned char *out, int len) +{ + register int i, j, a1 = 0, k; + for (i = 0, j = 0, k = 0; i < len; i++) { + switch (k) { + + case 0: + a1 = b64[(data[i] & 0x3f)]; + break; + case 1: + out[j++] = a1; + out[j++] = b64[(data[i-1] >> 6) | ((data[i] & 0xf) << 2)]; + break; + case 2: + out[j++] = b64[(data[i-1] >> 4 | ((data[i] & 0x3) << 4))]; + out[j++] = b64[(data[i] >> 2)]; + k = 0; + continue; + + } + k++; + + } + if (k == 1) { + out[j++] = a1; + out[j++] = b64[(data[i-1] >> 6)]; + } + if (k == 2) { + out[j++] = b64[(data[i-1] >> 4)]; + } + return j; +} + +int base64_decode(const unsigned char *data, unsigned char *out, int len) +{ + register int i, j; + for (i = j = 0; i < len; i++) { + register int val = (int) tab64[(int)data[i]]; + switch (i & 3) { + case 0: + out[j++] = val; + break; + case 1: + out[j-1] |= (val & 3) << 6; + out[j++] = (val >> 2); + break; + case 2: + out[j-1] |= (val & 0xf) << 4; + out[j++] = (val >> 4); + break; + case 3: + out[j-1] |= val << 2; + break; + } + } + return j; +} + + diff -ru --new-file linux-2.4.20/fs/evfs/base64.h linux-2.4.20-evfs/fs/evfs/base64.h --- linux-2.4.20/fs/evfs/base64.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/base64.h Wed Apr 16 18:48:24 2003 @@ -0,0 +1,15 @@ +/* + * $Id: base64.c, base64 codec for filenames + */ + +#ifndef BASE64_H +#define BASE64_H + +/* approximate lengths you'll get after conversions */ +#define norm2baselen(x) (((x)*8+5)/6) +#define base2normlen(x) ((x)*6/8) + +extern int base64_encode(const unsigned char *data,unsigned char *out, int len); +extern int base64_decode(const unsigned char *data,unsigned char *out, int len); + +#endif diff -ru --new-file linux-2.4.20/fs/evfs/evfs.h linux-2.4.20-evfs/fs/evfs/evfs.h --- linux-2.4.20/fs/evfs/evfs.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/evfs.h Sat Apr 5 21:04:08 2003 @@ -0,0 +1,7 @@ +#ifndef EVFS_H +#define EVFS_H + +#define EVFS_MAGIC 0xdefaced0 +#define EVFS_COOKIE ".evfs" + +#endif diff -ru --new-file linux-2.4.20/fs/evfs/evfs_core.c linux-2.4.20-evfs/fs/evfs/evfs_core.c --- linux-2.4.20/fs/evfs/evfs_core.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/evfs_core.c Thu May 22 00:36:47 2003 @@ -0,0 +1,1205 @@ +/* evfs 0.3 2003 sd */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "evfs.h" +#include "aes.h" +#include "sha256.h" +#include "base64.h" + +/* those is considered to be the fastest */ +#define EVFS_BLK_SIZE PAGE_CACHE_SIZE +#define EVFS_BLK_BITS 12 +/* padlen, all of it's bits must be *always* 1 in line, f.e. : 1,3,7,15,31 ... */ +#define PADLEN (AES_BLOCK_SIZE-1) +#define KBUFSZ (PADLEN+PAGE_CACHE_SIZE) +#define SALTLEN 16 + +//#define track() printk("track: " __func__ "()/%d reached\n", __LINE__) +#define track() + + +extern long sys_readlink(const char * path, char * buf, int bufsiz); +extern long sys_link(const char * oldname, const char * newname); +extern long sys_unlink(const char * pathname); +extern long sys_symlink(const char * oldname, const char * newname); +extern long sys_mkdir(const char * pathname, int mode); +extern long sys_rmdir(const char * pathname); +extern long sys_mknod(const char * filename, int mode, dev_t dev); +extern long sys_rename(const char * oldname, const char * newname); + + +struct evfs_ctx { + struct aes_ctx aes; /* master aes key */ + /* we've 256 salts by 16 bytes, after 1mb it will repeat + - give chance to compress really big files ;)) */ + /* (256*PAGE_CACHE_SIZE) */ + char salts[256][SALTLEN]; + int recursion; +}; + + +static struct super_operations evfs_sbops; +static struct inode_operations evfs_file_iops; +static struct inode_operations evfs_dir_iops; +static struct file_operations evfs_fops; +static struct file_operations evfs_dir_fops; +static struct address_space_operations evfs_aops; +static struct address_space_operations evfs_link_aops; +static struct dentry_operations evfs_dentry_ops; + +/************************************************************************** + General purpose functions + **************************************************************************/ + +#define get_mem() kmalloc(PAGE_CACHE_SIZE + 1024, GFP_KERNEL) +#define put_mem(x) kfree(x) +#define COPY_INODE(i,g) \ + i->i_size = S_ISREG(g->i_mode)?((g->i_size > PADLEN)?g->i_size - PADLEN:0):(S_ISLNK(g->i_mode)?0:g->i_size); \ + i->i_ino = g->i_ino; \ + i->i_mode = g->i_mode; \ + i->i_nlink = g->i_nlink; \ + i->i_uid = g->i_uid; \ + i->i_gid = g->i_gid; \ + i->i_rdev = g->i_rdev; \ + i->i_atime = g->i_atime; \ + i->i_mtime = g->i_mtime; \ + i->i_ctime = g->i_ctime; \ + i->i_blkbits = EVFS_BLK_BITS; \ + i->i_blksize = EVFS_BLK_SIZE; \ + i->i_blocks = (g->i_blocks * (1 << g->i_blkbits)) / EVFS_BLK_SIZE; + + +struct evfs_inode { + char *host_filename; + char *sym; + struct file *fd; +}; +#define evfs_i(x) (*((struct evfs_inode *) &(x)->u.generic_ip)) +#define file_evfs_i(file) (&evfs_i((file)->f_dentry->d_inode)) +#define evfs_key(x) ((struct evfs_ctx *) (x)->u.generic_sbp) +#define gk(i) (evfs_key((i->i_sb))) + +static int my_truncate(struct dentry *dentry, loff_t length) +{ + struct inode *inode = dentry->d_inode; + int error; + struct iattr newattrs; + + down(&inode->i_sem); + newattrs.ia_size = length; + newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; + error = notify_change(dentry, &newattrs); + up(&inode->i_sem); + return error; +} + +static inline char *get_salt(struct evfs_ctx *ctx, u8 index, char *buf) +{ + if (!ctx) + memset(buf, 0, SALTLEN); + else + memcpy(buf, &ctx->salts[index][0], SALTLEN); + return buf; +} + +static inline char *kstrdup(char *s) +{ + char *p = kmalloc(strlen(s) + 1, GFP_KERNEL); + if (!p) + return NULL; + strcpy(p, s); + return p; +} + +static inline int hpath_lookup_dir(char *name, struct nameidata *nd, int flags) +{ + int error = 0; + track(); + if (path_init(name, LOOKUP_POSITIVE|LOOKUP_DIRECTORY|flags, nd)) + error = path_walk(name, nd); + track(); + return error; +} + + +static inline int hpath_lookup(char *name, struct nameidata *nd) +{ + int error = 0; + track(); + if (path_init(name, LOOKUP_POSITIVE, nd)) + error = path_walk(name, nd); + track(); + return error; +} + +static int read_name(struct inode *ino, char *name) +{ + struct nameidata nd; + int error = hpath_lookup(name, &nd); + track(); + if (error) return error; + if (!nd.dentry->d_inode) { + path_release(&nd); + return -ENOENT; + } + COPY_INODE(ino, nd.dentry->d_inode); + path_release(&nd); + return error; +} + +static int file_type(char *name, int *rdev) +{ + struct nameidata nd; + int error = hpath_lookup(name, &nd); + track(); + if (!error) { + if (nd.dentry->d_inode) { + error = nd.dentry->d_inode->i_mode; + if (rdev) + *rdev = nd.dentry->d_inode->i_rdev; + } else { + error = -1024; + } + path_release(&nd); + } + return error; +} + + + +/* translate our virtual path (discovered by traversing + dcache tree) to real encrypted names path */ +static char *dentry_name(struct dentry *dentry, int extra, struct super_block *sb) +{ + struct dentry *parent; + char *name, *root; + int len, rootlen; + char tmp[NAME_MAX + 1]; + + track(); +/* if ((dentry->d_name.len == sizeof(EVFS_COOKIE)-1) && + (!memcmp(dentry->d_name.name, EVFS_COOKIE, sizeof(EVFS_COOKIE)-1))) + return NULL; */ + len = 0; + for (parent = dentry; parent->d_parent != parent; parent = parent->d_parent) + len += norm2baselen((parent->d_name.len + PADLEN) & ~PADLEN) + 1; /* +1 for '/' */ + + track(); + root = evfs_i(parent->d_inode).host_filename; + rootlen = strlen(root); + len += rootlen; + track(); + name = kmalloc(len + extra + 1, GFP_KERNEL); + if (!name) + return NULL; + track(); + memcpy(name, root, rootlen); + name[len] = 0; + + /* count length of whole tree (only approx!) */ + track(); + for (parent = dentry; parent->d_parent != parent; parent = parent->d_parent) { + int alen = (parent->d_name.len + PADLEN) & ~PADLEN; + int elen = norm2baselen(alen); + char salt[SALTLEN]; + + track(); + len -= elen + 1; + name[len] = '/'; + memset(tmp, 0, alen); + memcpy(tmp, parent->d_name.name, parent->d_name.len); + track(); + if (!sb) sb = dentry->d_inode->i_sb; + aes_encrypt_str(&evfs_key(sb)->aes, tmp, tmp, alen, get_salt(NULL, 0, salt)); + track(); + base64_encode(tmp, name + len + 1, alen); + } + return name; +} + +static char *inode_name(struct inode *ino, int extra) +{ + struct dentry *dentry; + + track(); + dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); + return(dentry_name(dentry, extra, ino->i_sb)); +} + +static struct inode *get_inode(struct super_block *sb, struct dentry *dentry, + int *error) +{ + struct inode *inode; + char *name; + int type, err = -ENOMEM, rdev; + + track(); + inode = get_empty_inode(); + if(inode == NULL) + goto out; + + evfs_i(inode).host_filename = NULL; + evfs_i(inode).fd = NULL; + evfs_i(inode).sym = NULL; + insert_inode_hash(inode); + if(dentry){ + name = dentry_name(dentry, 0, sb); + if(name == NULL){ + err = -ENOMEM; + goto out_put; + } + type = file_type(name, &rdev); + if (type == -1024) { + type = S_IFLNK; + } else + if (S_ISLNK(type)) { + int c, n; + char *buf = get_mem(); + mm_segment_t fs = get_fs(); + set_fs(KERNEL_DS); + c = sys_readlink(name, buf, PAGE_CACHE_SIZE-1); + set_fs(fs); + n = base2normlen(c); + if ((c > 0) && !(n & PADLEN)) { + char *tmp = get_mem(); + char salt[SALTLEN]; + /* symlink is ok, decode it */ + base64_decode(buf, tmp, c); + aes_decrypt_str(&evfs_key(sb)->aes, tmp, tmp, n, get_salt(NULL, 0, salt)); + tmp[n] = 0; + evfs_i(inode).sym = tmp; + } + put_mem(buf); + } + kfree(name); + } + else type = S_IFDIR; + inode->i_sb = sb; + + err = 0; + if(S_ISLNK(type)) + inode->i_op = &page_symlink_inode_operations; + else if(S_ISDIR(type)) + inode->i_op = &evfs_dir_iops; + else inode->i_op = &evfs_file_iops; + + if(S_ISDIR(type)) inode->i_fop = &evfs_dir_fops; + else inode->i_fop = &evfs_fops; + + if(S_ISLNK(type)) + inode->i_mapping->a_ops = &evfs_link_aops; + else inode->i_mapping->a_ops = &evfs_aops; + + if (S_ISCHR(type)) + init_special_inode(inode, S_IFCHR, rdev); + else + if (S_ISBLK(type)) + init_special_inode(inode, S_IFBLK, rdev); + else + if (S_ISFIFO(type)) + init_special_inode(inode, S_IFIFO, 0); + else + if (S_ISSOCK(type)) + init_special_inode(inode, S_IFSOCK, 0); + + if(error) *error = err; + return(inode); + out_put: + iput(inode); + out: + if(error) *error = err; + return(NULL); +} + + + +/************************************************************************** + Super operations + **************************************************************************/ +/* purge an evfs inode */ +static void evfs_delete_inode(struct inode *ino) +{ + track(); + if (evfs_i(ino).host_filename) + kfree(evfs_i(ino).host_filename); + evfs_i(ino).host_filename = NULL; + + if(evfs_i(ino).fd) { + /* set real size */ + if (S_ISREG(ino->i_mode)) + my_truncate(evfs_i(ino).fd->f_dentry, ino->i_size + PADLEN); + fput(evfs_i(ino).fd); + evfs_i(ino).fd = NULL; + } + if(evfs_i(ino).sym) { + put_mem(evfs_i(ino).sym); + evfs_i(ino).sym = NULL; + } + clear_inode(ino); +} + + +/* stat a filesystem */ +int evfs_statfs(struct super_block *sb, struct statfs *sf) +{ + struct nameidata nd; + int error; + error = hpath_lookup(evfs_i(sb->s_root->d_inode).host_filename, &nd); + if (!error) { + error = vfs_statfs(nd.dentry->d_inode->i_sb, sf); + path_release(&nd); + } + return error; +} + +static void evfs_putsuper(struct super_block *s) +{ + track(); + kfree(evfs_key(s)); +} + +/* read evfs superblock */ +static struct super_block *evfs_read_super(struct super_block *s, void *d, int silent) +{ + char *data = d; + char *password; + char *name, *to; + struct inode *root_inode; + char buf[32]; + struct sha256_ctx ctx; + struct nameidata nd, ns; + struct dentry *parent; + + int uid = current->fsuid; + int gid = current->fsgid; + + track(); + /* first some basic super ops */ + s->s_blocksize = EVFS_BLK_SIZE; + s->s_blocksize_bits = EVFS_BLK_BITS; + s->s_magic = EVFS_MAGIC; + s->s_op = &evfs_sbops; + + /* and some common checks */ + if (!data || !*data) { + printk("evfs: source mount directory not specified\n"); + return NULL; + } + + /* extract from, to and password */ + for (to = data; *to != ' '; to++) { + if (!*to) { + printk("evfs: invalid number of arguments (destination and password missing)\n"); + return NULL; + } + } + *to++ = 0; + + for (password = to; *password != ' '; password++) + if (!*password) { + printk("evfs: no password supplied while mounting %s\n", data); + return NULL; + } + *password++ = 0; + + if (hpath_lookup_dir(to, &nd, LOOKUP_FOLLOW)) { + printk("evfs: error while looking up mount destination!\n"); + return NULL; + } + + /* check uid ... */ + if (uid) + if ((nd.dentry->d_inode->i_uid != uid) || (nd.dentry->d_inode->i_gid != gid)) { + printk("evfs: *WARNING*, uid %d supplied someone's else directory as destination!\n", uid); + goto out_nd; + } + + /* and absolute path */ + if (data[0] != '/') { + printk("evfs: attempted to mount relative path %s!\n", data); + goto out_nd; + } + + /* create root inode */ + root_inode = get_inode(s, NULL, NULL); + if (!root_inode) + goto out_nd; + name = kstrdup(data); + track(); + s->s_root = d_alloc_root(root_inode); + evfs_i(root_inode).host_filename = name; + track(); + + if (hpath_lookup_dir(name, &ns, 0)) + goto out; + + if (ns.dentry->d_inode->i_sb->s_magic == EVFS_MAGIC) { + printk("evfs: uid %d tried to mount evfs from evfs - not supported yet, to avoid recursion.\n", uid); + goto out_put; + } + + COPY_INODE(root_inode, ns.dentry->d_inode); + + track(); + /* hrmm. comparing whether source is not in destinating directory *is* good idea */ + for (parent = ns.dentry; parent != parent->d_parent; parent = parent->d_parent) { + if (parent == nd.dentry) + goto out_put; + } + track(); + + if (uid) + if ((root_inode->i_uid != uid || root_inode->i_gid != gid) && + ((uid != 0) && (gid != 0))) + goto out_put; + + evfs_key(s) = kmalloc(sizeof(struct evfs_ctx), GFP_KERNEL); + if (!evfs_key(s)) + goto out_put; + sha256_init(&ctx); + sha256_update(&ctx, password, strlen(password)); + sha256_final(&ctx, buf); + memset(&ctx, 0xF8, sizeof(ctx)); + aes_set_key(&evfs_key(s)->aes, buf); + evfs_key(s)->recursion = 0; + memset(evfs_key(s)->salts, buf[0] + buf[31], sizeof(evfs_key(s)->salts)); + /* initialize disk block salts (one for one blocks, 256 total, then repeats */ + aes_encrypt_str(&evfs_key(s)->aes, &evfs_key(s)->salts[0][0], &evfs_key(s)->salts[0][0], sizeof(evfs_key(s)->salts), buf); + memset(buf, 0xF8, 32); + + path_release(&nd); + path_release(&ns); + return s; +out_put: + track(); + path_release(&ns); +out: + iput(root_inode); +out_nd: + track(); + path_release(&nd); + return NULL; +} + +/************************************************************************** + Inode operations + **************************************************************************/ +int evfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + struct inode *inode; + char *name; + struct file *fd; + int error; + + track(); + inode = get_inode(dir->i_sb, dentry, &error); + if (error) return(error); + name = dentry_name(dentry, 0, dir->i_sb); + if(name == NULL){ + iput(inode); + return(-ENOMEM); + } + fd = filp_open(name, O_CREAT | O_EXCL, mode); + error = IS_ERR(fd); + if (!error) { + my_truncate(fd->f_dentry, PADLEN); + fput(fd); + } + else error = PTR_ERR(fd); + if(!error) error = read_name(inode, name); + kfree(name); + if(error) { + iput(inode); + return(error); + } + d_instantiate(dentry, inode); + return(0); +} + +struct dentry *evfs_lookup(struct inode *ino, struct dentry *dentry) +{ + struct inode *inode; + char *name; + int error; + + track(); + inode = get_inode(ino->i_sb, dentry, &error); + if(error != 0) return(ERR_PTR(error)); + name = dentry_name(dentry, 0, ino->i_sb); + if(name == NULL) return(ERR_PTR(-ENOMEM)); + error = read_name(inode, name); + kfree(name); + if(error){ + iput(inode); + if(error == -ENOENT) inode = NULL; + else return(ERR_PTR(error)); + } + d_add(dentry, inode); + dentry->d_op = &evfs_dentry_ops; + return(NULL); +} + +static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) +{ + char *file; + int fl, i; + int alen = (dentry->d_name.len + PADLEN) & ~PADLEN; + int elen = norm2baselen(alen); + char tmp[NAME_MAX + 1]; + char salt[SALTLEN]; + +/* if ((dentry->d_name.len == sizeof(EVFS_COOKIE)-1) && + (!memcmp(dentry->d_name.name, EVFS_COOKIE, sizeof(EVFS_COOKIE)-1))) + return NULL; */ + + track(); + file = inode_name(ino, elen + 1); + if (file == NULL) return(NULL); + fl = strlen(file); + file[fl++] = '/'; + memset(tmp, 0, alen); + memcpy(tmp, dentry->d_name.name, dentry->d_name.len); + aes_encrypt_str(&evfs_key(ino->i_sb)->aes, tmp, tmp, alen, get_salt(NULL, 0, salt)); + i = base64_encode(tmp, file + fl, alen); + file[fl + i] = 0; + return(file); +} + +int evfs_link(struct dentry *to, struct inode *ino, struct dentry *from) +{ + char *from_name, *to_name; + int err; + mm_segment_t fs; + + track(); + if((from_name = inode_dentry_name(ino, from)) == NULL) + return(-ENOMEM); + to_name = dentry_name(to, 0, ino->i_sb); + if(to_name == NULL){ + kfree(from_name); + return(-ENOMEM); + } + fs = get_fs(); set_fs(KERNEL_DS); + err = sys_link(to_name, from_name); + set_fs(fs); + kfree(from_name); + kfree(to_name); + return(err); +} + +int evfs_unlink(struct inode *ino, struct dentry *dentry) +{ + char *file; + int err; + mm_segment_t fs; + + track(); + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + fs = get_fs(); set_fs(KERNEL_DS); + err = sys_unlink(file); + set_fs(fs); + kfree(file); + return(err); +} + +int evfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) +{ + char *file; + int err; + mm_segment_t fs; + char salt[SALTLEN]; + char *buf = get_mem(); + char *buf2 = get_mem(); + + int len = strlen(to); + int alen = (len + PADLEN) & ~PADLEN; + + track(); + if (alen > PAGE_CACHE_SIZE) return -ENOMEM; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + fs = get_fs(); set_fs(KERNEL_DS); + + if (!buf) return -ENOMEM; + if (!buf2) { + put_mem(buf); + return -ENOMEM; + } + + memset(buf, 0, alen); + memcpy(buf, to, len); + + aes_encrypt_str(&gk(ino)->aes, buf, buf, alen, get_salt(NULL, 0, salt)); + buf2[base64_encode(buf, buf2, alen)] = 0; + + err = sys_symlink(buf2, file); + put_mem(buf); + put_mem(buf2); + set_fs(fs); + kfree(file); + return(err); +} + +int evfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) +{ + char *file; + int err; + mm_segment_t fs; + + track(); + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + fs = get_fs(); set_fs(KERNEL_DS); + err = sys_mkdir(file, mode); + set_fs(fs); + kfree(file); + return(err); +} + +int evfs_rmdir(struct inode *ino, struct dentry *dentry) +{ + char *file; + int err; + mm_segment_t fs; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + fs = get_fs(); set_fs(KERNEL_DS); + err = sys_rmdir(file); + set_fs(fs); + kfree(file); + return(err); +} + +int evfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) +{ + struct inode *inode; + char *name; + int error; + mm_segment_t fs; + + track(); + inode = get_inode(dir->i_sb, dentry, &error); + if(error) return(error); + name = dentry_name(dentry, 0, dir->i_sb); + if(name == NULL){ + iput(inode); + return(-ENOMEM); + } + init_special_inode(inode, mode, dev); + fs = get_fs(); set_fs(KERNEL_DS); + error = sys_mknod(name, mode, dev); + set_fs(fs); + if(!error) error = read_name(inode, name); + kfree(name); + if(error){ + iput(inode); + return(error); + } + d_instantiate(dentry, inode); + return(0); +} + +int evfs_rename(struct inode *from_ino, struct dentry *from, + struct inode *to_ino, struct dentry *to) +{ + char *from_name, *to_name; + int err; + mm_segment_t fs; + + if((from_name = inode_dentry_name(from_ino, from)) == NULL) + return(-ENOMEM); + if((to_name = inode_dentry_name(to_ino, to)) == NULL){ + kfree(from_name); + return(-ENOMEM); + } + fs = get_fs(); set_fs(KERNEL_DS); + err = sys_rename(from_name, to_name); + set_fs(fs); + kfree(from_name); + kfree(to_name); + return(err); +} + +void evfs_truncate(struct inode *ino) +{ + return -EINVAL; +} + +int evfs_permission(struct inode *ino, int desired) +{ + int err; + char *name; + struct nameidata nd; + + track(); + name = inode_name(ino, 0); + if(name == NULL) return(-ENOMEM); + + err = hpath_lookup(name, &nd); + kfree(name); + if(!err) { + err = permission(nd.dentry->d_inode, desired); + path_release(&nd); + } + return(err); +} + +int evfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct nameidata nd; + char *name; + int err; + + track(); + name = dentry_name(dentry, 0, NULL); + if(name == NULL) return(-ENOMEM); + err = hpath_lookup(name, &nd); + kfree(name); + if (!err) { + /* handle truncate */ + if (attr->ia_valid & ATTR_SIZE) { + attr->ia_size += PADLEN; + } + err = inode_setattr(nd.dentry->d_inode, attr); + path_release(&nd); + } + return(err); +} + +/************************************************************************** + File operations + **************************************************************************/ + + +int evfs_file_open(struct inode *ino, struct file *file) +{ + char *name; + struct file *fd; + + track(); + if(evfs_i(ino).fd) { + fput(evfs_i(ino).fd); + evfs_i(ino).fd = NULL; + } + name = dentry_name(file->f_dentry, 0, ino->i_sb); + if(name == NULL) + return(-ENOMEM); + + fd = filp_open(name, file->f_flags & ~(O_APPEND | O_EXCL | O_CREAT), file->f_mode); + kfree(name); + if (IS_ERR(fd)) return(PTR_ERR(fd)); + file_evfs_i(file)->fd = fd; + return(0); +} + +int evfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + return(0); +} + +/************************************************************************** + Directory operations + **************************************************************************/ +int evfs_dir_release(struct inode *ino, struct file *file) +{ + track(); + return(0); +} + +struct my_ent { + void *old_filler; + void *old_ent; + struct super_block *sb; +}; + +static int my_filldir(struct my_ent *e, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + filldir_t old_filldir; + int len, nlen; + char buf[NAME_MAX + 1]; + char salt[SALTLEN]; + + old_filldir = e->old_filler; + /* hide magic */ + if ((namlen == sizeof(EVFS_COOKIE)-1) && (!memcmp(name, EVFS_COOKIE, namlen))) + return 0; + /* and do not ever try to decode '.' and '..' */ + if ((name[0] == '.') && ((namlen == 1) || (namlen == 2 && name[1] == '.'))) + return old_filldir(e->old_ent, name, namlen, offset, ino, d_type); + /* the rest will get decrypted */ + len = base2normlen(namlen); + /* unaligned sucks */ + if (len & PADLEN) + return 0; + + base64_decode(name, buf, namlen); + aes_decrypt_str(&evfs_key(e->sb)->aes, buf, buf, len, get_salt(NULL, 0, salt)); + nlen = strnlen(buf, len); + buf[nlen] = 0; + return old_filldir(e->old_ent, buf, nlen, offset, ino, d_type); +} + +int evfs_readdir(struct file *file, void *ent, filldir_t filldir) +{ + struct my_ent e; + track(); + e.old_filler = filldir; + e.old_ent = ent; + e.sb = file->f_dentry->d_inode->i_sb; + return vfs_readdir(file_evfs_i(file)->fd, (void *) my_filldir, (void *) &e); +} + +/************************************************************************** + Address space operations + **************************************************************************/ +int evfs_do_read(struct file *file, long long *start, char *buf, size_t count) +{ + int ret = -EBADF; + mm_segment_t fs = get_fs(); + set_fs(KERNEL_DS); + + ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode, + file, *start, count); + if (!ret) { + ssize_t (*read)(struct file *, char *, size_t, loff_t *); + ret = -EINVAL; + if (file->f_op && (read = file->f_op->read) != NULL) { + ret = read(file, buf, count, start); + } + } + if (ret > 0) + dnotify_parent(file->f_dentry, DN_ACCESS); + set_fs(fs); + return ret; +} + +int evfs_do_write(struct file *file, long long *start, char *buf, size_t count) +{ + int ret = -EBADF; + mm_segment_t fs = get_fs(); + struct inode *inode = file->f_dentry->d_inode; + set_fs(KERNEL_DS); + + track(); + ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, + *start, count); + if (!ret) { + ssize_t (*write)(struct file *, const char *, size_t, loff_t *); + ret = -EINVAL; + if (file->f_op && (write = file->f_op->write) != NULL) { + ret = write(file, buf, count, start); + } + } + if (ret > 0) + dnotify_parent(file->f_dentry, DN_MODIFY); + set_fs(fs); + return ret; +} + + +int evfs_writepage(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + char *buffer; + unsigned long long base; + int count = PAGE_CACHE_SIZE; + int end_index = inode->i_size >> PAGE_CACHE_SHIFT; + int err; + char *kbuf = get_mem(); + char buf[SALTLEN]; + + if (!kbuf) + return -ENOMEM; + + track(); + if (page->index >= end_index) + count = (inode->i_size & (PAGE_CACHE_SIZE-1)); + + buffer = kmap(page); + base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; + + aes_encrypt_str(&gk(inode)->aes, kbuf, buffer, (count+PADLEN) & ~PADLEN, get_salt(gk(inode), page->index, buf)); + err = evfs_do_write(evfs_i(inode).fd, &base, kbuf, (count + PADLEN) & ~PADLEN); + if(err != count){ + ClearPageUptodate(page); + goto out; + } + + if (base > inode->i_size) { + inode->i_size = base; + } + + /* this is just for everyone else using that file, real fs will get + notified by regular do_truncate about real size when we'll fput this + file */ + evfs_i(inode).fd->f_dentry->d_inode->i_size = inode->i_size + PADLEN; + + if (PageError(page)) + ClearPageError(page); + err = 0; + + out: + kunmap(page); + + UnlockPage(page); + put_mem(kbuf); + return err; +} + + +int evfs_readpage(struct file *file, struct page *page) +{ + char *buffer; + long long start, tmp; + int err = 0; + struct inode *inode = file->f_dentry->d_inode; + struct file *f = file_evfs_i(file)->fd; + int end_index = inode->i_size >> PAGE_CACHE_SHIFT; + char buf[SALTLEN]; + + track(); + start = (long long) page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + tmp = start; + err = evfs_do_read(f, &start, buffer, + PAGE_CACHE_SIZE); + if(err < 0) goto out; + + if (err & PADLEN) { + if (!(page->index >= end_index)) + printk("EVFS WARNING: access beyond end of padding of file!\n"); + } + /* yeah ! */ + aes_decrypt_str(&gk(inode)->aes, buffer, buffer, err & ~PADLEN, get_salt(gk(inode), page->index, buf)); + + /* do we've reached padding (i.e. virtual size) ? */ + if (start > inode->i_size) { + /* my dear, we did - round it up to virtual size */ + start = inode->i_size; + err = start - tmp; + if (err < 0) err = 0; + } + + flush_dcache_page(page); + SetPageUptodate(page); + if (PageError(page)) ClearPageError(page); + err = 0; + out: + kunmap(page); + UnlockPage(page); + return(err); +} + + +int evfs_prepare_write(struct file *file, struct page *page, + unsigned int from, unsigned int to) +{ + return 0; +} + +int evfs_commit_write(struct file *file, struct page *page, unsigned from, + unsigned to) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + char *buffer, *kbuf; + long long o, tmp, start; + int err = 0; + int end_index = inode->i_size >> PAGE_CACHE_SHIFT; + char buf[SALTLEN]; + + kbuf = get_mem(); + if (!kbuf) + return -ENOMEM; + + track(); + o = tmp = start = (long long) (page->index << PAGE_CACHE_SHIFT); + buffer = kmap(page); + + memset(kbuf, 0, PAGE_CACHE_SIZE); + + /* we've to get at least partly complete page to do some encryption */ + err = evfs_do_read(file_evfs_i(file)->fd, &tmp, kbuf, PAGE_CACHE_SIZE); + if (err < 0) goto out; + if (err & PADLEN) { + if (!(page->index >= end_index)) + printk("EVFS WARNING: access beyond end of padding of file!\n"); + } + /* oki, we've that bitch, now decrypt it :) */ + aes_decrypt_str(&gk(inode)->aes, kbuf, kbuf, (err + PADLEN) & ~PADLEN, get_salt(gk(inode), page->index, buf)); + /* overwrite it with new data */ + memcpy(kbuf + from, buffer + from, to - from); + if (to > err) err = to; + /* and encrypt whole thingie */ + aes_encrypt_str(&gk(inode)->aes, kbuf, kbuf, (err + PADLEN) & ~PADLEN, get_salt(gk(inode), page->index, buf)); + err = evfs_do_write(file_evfs_i(file)->fd, &start, kbuf, (err + PADLEN) & ~PADLEN); + if (err < to) + err = -EPIPE; + else { + o += to; + if (o > inode->i_size) + inode->i_size = o; + err = 0; + /* this is just for everyone else using that file, real fs will get + notified by regular do_truncate about real size when we'll fput this + file */ + evfs_i(inode).fd->f_dentry->d_inode->i_size = inode->i_size + PADLEN; + } +out: + kunmap(page); + put_mem(kbuf); + return(err); +} + +static __inline__ int +do_revalidate(struct dentry *dentry) +{ + struct inode * inode = dentry->d_inode; + if (inode->i_op && inode->i_op->revalidate) + return inode->i_op->revalidate(dentry); + return 0; +} + + +int evfs_link_readpage(struct file *file, struct page *page) +{ + struct inode *ino; + char *buffer; + long long start; + int err; + + track(); + start = page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + ino = page->mapping->host; + track(); + + err = -EINVAL; + if (ino) { + if ((!evfs_i(ino).sym) || (!ino)) + err = -ENOENT; + else { + strncpy(buffer, evfs_i(ino).sym, PAGE_CACHE_SIZE-1); + buffer[PAGE_CACHE_SIZE-1] = 0; + err = strlen(buffer); + } + } + if(err > 0) { + flush_dcache_page(page); + SetPageUptodate(page); + if (PageError(page)) ClearPageError(page); + err = 0; + } + kunmap(page); + UnlockPage(page); + return(err); +} + + +int evfs_d_delete(struct dentry *dentry) +{ + return(1); +} + + +DECLARE_FSTYPE(evfs_type, "evfs", evfs_read_super, 0); + +static int __init init_evfs(void) +{ + gen_tabs(); + return register_filesystem(&evfs_type); +} + +static void __exit exit_evfs(void) +{ + unregister_filesystem(&evfs_type); +} + +static struct super_operations evfs_sbops = { + put_inode: force_delete, + put_super: evfs_putsuper, + delete_inode: evfs_delete_inode, + statfs: evfs_statfs +}; + +static struct inode_operations evfs_file_iops = { + create: evfs_create, + link: evfs_link, + unlink: evfs_unlink, + symlink: evfs_symlink, + mkdir: evfs_mkdir, + rmdir: evfs_rmdir, + mknod: evfs_mknod, + rename: evfs_rename, + truncate: evfs_truncate, + permission: evfs_permission, + setattr: evfs_setattr +}; + +static struct inode_operations evfs_dir_iops = { + create: evfs_create, + lookup: evfs_lookup, + link: evfs_link, + unlink: evfs_unlink, + symlink: evfs_symlink, + mkdir: evfs_mkdir, + rmdir: evfs_rmdir, + mknod: evfs_mknod, + rename: evfs_rename, + truncate: evfs_truncate, + permission: evfs_permission, + setattr: evfs_setattr +}; + +static struct file_operations evfs_fops = { + owner: NULL, + read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap, + open: evfs_file_open, + release: NULL, + fsync: evfs_fsync, +}; + +static struct file_operations evfs_dir_fops = { + owner: NULL, + readdir: evfs_readdir, + open: evfs_file_open, + release: evfs_dir_release, + fsync: evfs_fsync, +}; + +static struct dentry_operations evfs_dentry_ops = { + d_delete: evfs_d_delete, +}; + +static struct address_space_operations evfs_aops = { + writepage: evfs_writepage, + readpage: evfs_readpage, + prepare_write: evfs_prepare_write, + commit_write: evfs_commit_write +}; + +static struct address_space_operations evfs_link_aops = { + readpage: evfs_link_readpage +}; + +EXPORT_NO_SYMBOLS; + +module_init(init_evfs); +module_exit(exit_evfs); +MODULE_LICENSE("BSD/GPL"); diff -ru --new-file linux-2.4.20/fs/evfs/sha256.c linux-2.4.20-evfs/fs/evfs/sha256.c --- linux-2.4.20/fs/evfs/sha256.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/sha256.c Wed Apr 9 16:45:10 2003 @@ -0,0 +1,272 @@ +/* + * Cryptographic API. + * + * SHA-256, as specified in + * http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf + * + * SHA-256 code by Jean-Luc Cooke . + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include "sha256.h" +#include + +static void sha256_transform(u32 *state, const u8 *input) +{ + u32 a, b, c, d, e, f, g, h, t1, t2; + u32 W[64]; + int i; + + /* load the input */ + for (i = 0; i < 16; i++) + LOAD_OP(i, W, input); + + /* now blend */ + for (i = 16; i < 64; i++) + BLEND_OP(i, W); + + /* load the state into our registers */ + a=state[0]; b=state[1]; c=state[2]; d=state[3]; + e=state[4]; f=state[5]; g=state[6]; h=state[7]; + + /* now iterate */ + t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; + + /* clear any sensitive info... */ + a = b = c = d = e = f = g = h = t1 = t2 = 0; + memset(W, 0, 64 * sizeof(u32)); +} + +void sha256_init(void *ctx) +{ + struct sha256_ctx *sctx = ctx; + sctx->state[0] = H0; + sctx->state[1] = H1; + sctx->state[2] = H2; + sctx->state[3] = H3; + sctx->state[4] = H4; + sctx->state[5] = H5; + sctx->state[6] = H6; + sctx->state[7] = H7; + sctx->count[0] = sctx->count[1] = 0; + memset(sctx->buf, 0, sizeof(sctx->buf)); +} + +void sha256_update(void *ctx, const u8 *data, unsigned int len) +{ + struct sha256_ctx *sctx = ctx; + unsigned int i, index, part_len; + + /* Compute number of bytes mod 128 */ + index = (unsigned int)((sctx->count[0] >> 3) & 0x3f); + + /* Update number of bits */ + if ((sctx->count[0] += (len << 3)) < (len << 3)) { + sctx->count[1]++; + sctx->count[1] += (len >> 29); + } + + part_len = 64 - index; + + /* Transform as many times as possible. */ + if (len >= part_len) { + memcpy(&sctx->buf[index], data, part_len); + sha256_transform(sctx->state, sctx->buf); + + for (i = part_len; i + 63 < len; i += 64) + sha256_transform(sctx->state, &data[i]); + index = 0; + } else { + i = 0; + } + + /* Buffer remaining input */ + memcpy(&sctx->buf[index], &data[i], len-i); +} + +void sha256_final(void* ctx, u8 *out) +{ + struct sha256_ctx *sctx = ctx; + u8 bits[8]; + unsigned int index, pad_len, t; + int i, j; + const u8 padding[64] = { 0x80, }; + + /* Save number of bits */ + t = sctx->count[0]; + bits[7] = t; t >>= 8; + bits[6] = t; t >>= 8; + bits[5] = t; t >>= 8; + bits[4] = t; + t = sctx->count[1]; + bits[3] = t; t >>= 8; + bits[2] = t; t >>= 8; + bits[1] = t; t >>= 8; + bits[0] = t; + + /* Pad out to 56 mod 64. */ + index = (sctx->count[0] >> 3) & 0x3f; + pad_len = (index < 56) ? (56 - index) : ((64+56) - index); + sha256_update(sctx, padding, pad_len); + + /* Append length (before padding) */ + sha256_update(sctx, bits, 8); + + /* Store state in digest */ + for (i = j = 0; i < 8; i++, j += 4) { + t = sctx->state[i]; + out[j+3] = t; t >>= 8; + out[j+2] = t; t >>= 8; + out[j+1] = t; t >>= 8; + out[j ] = t; + } + + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(*sctx)); +} diff -ru --new-file linux-2.4.20/fs/evfs/sha256.h linux-2.4.20-evfs/fs/evfs/sha256.h --- linux-2.4.20/fs/evfs/sha256.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.20-evfs/fs/evfs/sha256.h Thu May 22 00:31:14 2003 @@ -0,0 +1,70 @@ +#ifndef SHA256_H +#define SHA256_H + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +#include +#include + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_HMAC_BLOCK_SIZE 64 + +struct sha256_ctx { + u32 count[2]; + u32 state[8]; + u8 buf[128]; +}; + +static inline u32 Ch(u32 x, u32 y, u32 z) +{ + return ((x & y) ^ (~x & z)); +} + +static inline u32 Maj(u32 x, u32 y, u32 z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} + +static inline u32 RORu32(u32 x, u32 y) +{ + return (x >> y) | (x << (32 - y)); +} + +#define e0(x) (RORu32(x, 2) ^ RORu32(x,13) ^ RORu32(x,22)) +#define e1(x) (RORu32(x, 6) ^ RORu32(x,11) ^ RORu32(x,25)) +#define s0(x) (RORu32(x, 7) ^ RORu32(x,18) ^ (x >> 3)) +#define s1(x) (RORu32(x,17) ^ RORu32(x,19) ^ (x >> 10)) + +#define H0 0x6a09e667 +#define H1 0xbb67ae85 +#define H2 0x3c6ef372 +#define H3 0xa54ff53a +#define H4 0x510e527f +#define H5 0x9b05688c +#define H6 0x1f83d9ab +#define H7 0x5be0cd19 + +static inline void LOAD_OP(int I, u32 *W, const u8 *input) +{ + u32 t1 = input[(4 * I)] & 0xff; + + t1 <<= 8; + t1 |= input[(4 * I) + 1] & 0xff; + t1 <<= 8; + t1 |= input[(4 * I) + 2] & 0xff; + t1 <<= 8; + t1 |= input[(4 * I) + 3] & 0xff; + W[I] = t1; +} + +static inline void BLEND_OP(int I, u32 *W) +{ + W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; +} + +extern void sha256_init(void *ctx); +extern void sha256_update(void *ctx, const u8 *data, unsigned int len); +extern void sha256_final(void* ctx, u8 *out); + +#endif diff -ru --new-file linux-2.4.20/kernel/ksyms.c linux-2.4.20-evfs/kernel/ksyms.c --- linux-2.4.20/kernel/ksyms.c Fri Nov 29 00:53:15 2002 +++ linux-2.4.20-evfs/kernel/ksyms.c Wed Apr 16 18:21:06 2003 @@ -579,3 +579,21 @@ /* debug */ EXPORT_SYMBOL(dump_stack); +/* symbols needed for evfs */ +extern void sys_rename(); +extern void sys_readlink(); +extern void sys_unlink(); +extern void sys_symlink(); +extern void sys_mknod(); +extern void sys_mknod(); +extern void sys_mkdir(); +extern void sys_rmdir(); +extern void sys_link(); +EXPORT_SYMBOL(sys_rename); +EXPORT_SYMBOL(sys_readlink); +EXPORT_SYMBOL(sys_unlink); +EXPORT_SYMBOL(sys_symlink); +EXPORT_SYMBOL(sys_mknod); +EXPORT_SYMBOL(sys_mkdir); +EXPORT_SYMBOL(sys_rmdir); +EXPORT_SYMBOL(sys_link);