📄 loop_twofish.c
字号:
{ TwofishMultiKey *m; fish2_key *a; int x, n; m = (TwofishMultiKey *) kmalloc(sizeof(TwofishMultiKey), GFP_KERNEL); if(!m) return 0; memset(m, 0, sizeof(TwofishMultiKey)); n = PAGE_SIZE / sizeof(fish2_key); if(!n) n = 1; a = (fish2_key *) kmalloc(sizeof(fish2_key) * n, GFP_KERNEL); if(!a) { kfree(m); return 0; } x = 0; while((x < 64) && n) { m->keyPtr[x] = a; a++; x++; n--; } return m;}static void clearAndFreeMultiKey(TwofishMultiKey *m){ fish2_key *a; int x, n; n = PAGE_SIZE / sizeof(fish2_key); if(!n) n = 1; x = 0; while(x < 64) { a = m->keyPtr[x]; if(!a) break; memset(a, 0, sizeof(fish2_key) * n); kfree(a); x += n; } memset(m, 0, sizeof(TwofishMultiKey)); kfree(m);}static int multiKeySetup(struct loop_device *lo, unsigned char *k, int version3){ TwofishMultiKey *m; fish2_key *a; int x, y, n; union { u_int32_t w[16]; unsigned char b[64]; } un; extern void md5_transform_CPUbyteorder_C(u_int32_t *, u_int32_t const *);#if LINUX_VERSION_CODE >= 0x20200 if(lo->lo_key_owner != current->uid && !capable(CAP_SYS_ADMIN)) return -EPERM;#endif m = (TwofishMultiKey *)lo->key_data; if(!m) return -ENXIO; n = PAGE_SIZE / sizeof(fish2_key); if(!n) n = 1; x = 0; while(x < 64) { if(!m->keyPtr[x]) { a = (fish2_key *) kmalloc(sizeof(fish2_key) * n, GFP_KERNEL); if(!a) return -ENOMEM; y = x; while((y < (x + n)) && (y < 64)) { m->keyPtr[y] = a; a++; y++; } } if(copy_from_user(&un.b[0], k, 32)) return -EFAULT; a = m->keyPtr[x]; memset(a, 0, sizeof(fish2_key)); a->keyLen = lo->lo_encrypt_key_size << 3; memcpy(a->key, &un.b[0], lo->lo_encrypt_key_size); init_key(a); k += 32; x++; } m->partialMD5[0] = 0x67452301; m->partialMD5[1] = 0xefcdab89; m->partialMD5[2] = 0x98badcfe; m->partialMD5[3] = 0x10325476; if(version3) { /* only first 128 bits of iv-key is used */ if(copy_from_user(&un.b[0], k, 16)) return -EFAULT;#if defined(__BIG_ENDIAN) un.w[0] = cpu_to_le32(un.w[0]); un.w[1] = cpu_to_le32(un.w[1]); un.w[2] = cpu_to_le32(un.w[2]); un.w[3] = cpu_to_le32(un.w[3]);#endif memset(&un.b[16], 0, 48); md5_transform_CPUbyteorder_C(&m->partialMD5[0], &un.w[0]); lo->lo_flags |= 0x080000; /* multi-key-v3 (info exported to user space) */ } m->keyMask = 0x3F; /* range 0...63 */ lo->lo_flags |= 0x100000; /* multi-key (info exported to user space) */ memset(&un.b[0], 0, 32); return 0;}#if defined(__BIG_ENDIAN)/* twofish specific -- returns ivout[] data in CPU byte order */static void twofish_compute_md5_iv_v3(TransferSector_t devSect, u_int32_t *ivout, u_int32_t *data){ int x, y, e; u_int32_t buf[16]; extern void md5_transform_CPUbyteorder(u_int32_t *, u_int32_t const *); y = 7; e = 16; do { if (!y) { e = 12; /* md5_transform_CPUbyteorder wants data in CPU byte order */ /* devSect is already in CPU byte order -- no need to convert */ if(sizeof(TransferSector_t) == 8) { /* use only 56 bits of sector number */ buf[12] = devSect; buf[13] = (((u_int64_t)devSect >> 32) & 0xFFFFFF) | 0x80000000; } else { /* 32 bits of sector number + 24 zero bits */ buf[12] = devSect; buf[13] = 0x80000000; } /* 4024 bits == 31 * 128 bit plaintext blocks + 56 bits of sector number */ buf[14] = 4024; buf[15] = 0; } x = 0; do { buf[x ] = cpu_to_le32(data[0]); buf[x + 1] = cpu_to_le32(data[1]); buf[x + 2] = cpu_to_le32(data[2]); buf[x + 3] = cpu_to_le32(data[3]); x += 4; data += 4; } while (x < e); md5_transform_CPUbyteorder(&ivout[0], &buf[0]); } while (--y >= 0); /* caller wants ivout[] data in CPU byte order -- no conversion needed here */}#else/* on little endian boxes loop_compute_md5_iv_v3() returns ivout[] data in little *//* endian byte order which happens to be same as CPU byte order, so we use that */extern void loop_compute_md5_iv_v3(TransferSector_t, u_int32_t *, u_int32_t *);#define twofish_compute_md5_iv_v3(a,b,c) loop_compute_md5_iv_v3((a),(b),(c))#endif#define roundE_m(x0,x1,x2,x3,rnd) \ t0 = f32_sbox( x0, key->sbox_full ) ; \ t1 = f32_sbox( ROL(x1,8), key->sbox_full ); \ x2 ^= t0 + t1 + key->subKeys[2*rnd+8]; \ x3 = ROL(x3,1); \ x3 ^= t0 + 2*t1 + key->subKeys[2*rnd+9]; \ x2 = ROR(x2,1);static void blockEncrypt_CBC(fish2_key *key,BYTE *src,BYTE *dst,DWORD iv0,DWORD iv1,DWORD iv2,DWORD iv3){ DWORD xx0,xx1,xx2,xx3,t0,t1; int len; for (len=512;len>=16;len-=16) { xx0=Bswap(((DWORD *)src)[0]) ^ key->subKeys[0] ^ iv0; xx1=Bswap(((DWORD *)src)[1]) ^ key->subKeys[1] ^ iv1; xx2=Bswap(((DWORD *)src)[2]) ^ key->subKeys[2] ^ iv2; xx3=Bswap(((DWORD *)src)[3]) ^ key->subKeys[3] ^ iv3; src+=16; roundE_m(xx0,xx1,xx2,xx3,0); roundE_m(xx2,xx3,xx0,xx1,1); roundE_m(xx0,xx1,xx2,xx3,2); roundE_m(xx2,xx3,xx0,xx1,3); roundE_m(xx0,xx1,xx2,xx3,4); roundE_m(xx2,xx3,xx0,xx1,5); roundE_m(xx0,xx1,xx2,xx3,6); roundE_m(xx2,xx3,xx0,xx1,7); roundE_m(xx0,xx1,xx2,xx3,8); roundE_m(xx2,xx3,xx0,xx1,9); roundE_m(xx0,xx1,xx2,xx3,10); roundE_m(xx2,xx3,xx0,xx1,11); roundE_m(xx0,xx1,xx2,xx3,12); roundE_m(xx2,xx3,xx0,xx1,13); roundE_m(xx0,xx1,xx2,xx3,14); roundE_m(xx2,xx3,xx0,xx1,15); iv0=xx2 ^ key->subKeys[4]; iv1=xx3 ^ key->subKeys[5]; iv2=xx0 ^ key->subKeys[6]; iv3=xx1 ^ key->subKeys[7]; ((DWORD *)dst)[0] = Bswap(iv0); ((DWORD *)dst)[1] = Bswap(iv1); ((DWORD *)dst)[2] = Bswap(iv2); ((DWORD *)dst)[3] = Bswap(iv3); dst+=16; }}#define roundD_m(x0,x1,x2,x3,rnd) \ t0 = f32_sbox( x0, key->sbox_full); \ t1 = f32_sbox( ROL(x1,8),key->sbox_full); \ x2 = ROL(x2,1); \ x3 ^= t0 + 2*t1 + key->subKeys[rnd*2+9]; \ x3 = ROR(x3,1); \ x2 ^= t0 + t1 + key->subKeys[rnd*2+8];static void blockDecrypt_CBC(fish2_key *key,BYTE *src,BYTE *dst,int len,DWORD iv0,DWORD iv1,DWORD iv2,DWORD iv3){ DWORD xx0,xx1,xx2,xx3,t0,t1,lx0,lx1,lx2,lx3; for (;len>=16;len-=16) { lx0=iv0;iv0=Bswap(((DWORD *)src)[0]);xx0=iv0 ^ key->subKeys[4]; lx1=iv1;iv1=Bswap(((DWORD *)src)[1]);xx1=iv1 ^ key->subKeys[5]; lx2=iv2;iv2=Bswap(((DWORD *)src)[2]);xx2=iv2 ^ key->subKeys[6]; lx3=iv3;iv3=Bswap(((DWORD *)src)[3]);xx3=iv3 ^ key->subKeys[7]; src+=16; roundD_m(xx0,xx1,xx2,xx3,15); roundD_m(xx2,xx3,xx0,xx1,14); roundD_m(xx0,xx1,xx2,xx3,13); roundD_m(xx2,xx3,xx0,xx1,12); roundD_m(xx0,xx1,xx2,xx3,11); roundD_m(xx2,xx3,xx0,xx1,10); roundD_m(xx0,xx1,xx2,xx3,9); roundD_m(xx2,xx3,xx0,xx1,8); roundD_m(xx0,xx1,xx2,xx3,7); roundD_m(xx2,xx3,xx0,xx1,6); roundD_m(xx0,xx1,xx2,xx3,5); roundD_m(xx2,xx3,xx0,xx1,4); roundD_m(xx0,xx1,xx2,xx3,3); roundD_m(xx2,xx3,xx0,xx1,2); roundD_m(xx0,xx1,xx2,xx3,1); roundD_m(xx2,xx3,xx0,xx1,0); ((DWORD *)dst)[0] = Bswap(xx2 ^ key->subKeys[0] ^ lx0); ((DWORD *)dst)[1] = Bswap(xx3 ^ key->subKeys[1] ^ lx1); ((DWORD *)dst)[2] = Bswap(xx0 ^ key->subKeys[2] ^ lx2); ((DWORD *)dst)[3] = Bswap(xx1 ^ key->subKeys[3] ^ lx3); dst+=16; }}static int transfer_fish2(struct loop_device *lo, int cmd, char *raw_buf, char *loop_buf, int size, TransferSector_t devSect){ TwofishMultiKey *m; fish2_key *a; u_int32_t iv[4]; int sectInc = 1; unsigned y; if (lo->lo_init[0] == 1) sectInc = devSect = 0; /* "-o loinit=1" means SuSE compatible */ if (size & 0x1FF) return -1; m = (TwofishMultiKey *)lo->key_data; y = m->keyMask; if (cmd == READ) { while(size > 0) { a = m->keyPtr[((unsigned)devSect) & y]; if(y) { iv[0] = Bswap(((u_int32_t *)raw_buf)[0]); iv[1] = Bswap(((u_int32_t *)raw_buf)[1]); iv[2] = Bswap(((u_int32_t *)raw_buf)[2]); iv[3] = Bswap(((u_int32_t *)raw_buf)[3]); blockDecrypt_CBC(a, raw_buf+16, loop_buf+16, 496, iv[0], iv[1], iv[2], iv[3]); memcpy(&iv[0], &m->partialMD5[0], 16); twofish_compute_md5_iv_v3(devSect, &iv[0], (u_int32_t *)(&loop_buf[16])); blockDecrypt_CBC(a, raw_buf, loop_buf, 16, iv[0], iv[1], iv[2], iv[3]); } else { if(sizeof(TransferSector_t) == 8) { blockDecrypt_CBC(a, raw_buf, loop_buf, 512, devSect, (__u64)devSect>>32, 0, 0); } else { blockDecrypt_CBC(a, raw_buf, loop_buf, 512, devSect, 0, 0, 0); } }#if LINUX_VERSION_CODE >= 0x20600 cond_resched();#elif LINUX_VERSION_CODE >= 0x20400 if(current->need_resched) {set_current_state(TASK_RUNNING);schedule();}#else if(current->need_resched) {current->state=TASK_RUNNING;schedule();}#endif raw_buf += 512; loop_buf += 512; size -= 512; devSect += sectInc; } } else { while(size > 0) { a = m->keyPtr[((unsigned)devSect) & y]; if(y) {#if LINUX_VERSION_CODE < 0x20400 /* on 2.2 and older kernels, real raw_buf may be doing */ /* writes at any time, so this needs to be stack buffer */ u_int32_t tmp_raw_buf[128]; char *TMP_RAW_BUF = (char *)(&tmp_raw_buf[0]);#else /* on 2.4 and later kernels, real raw_buf is not doing */ /* any writes now so it can be used as temp buffer */# define TMP_RAW_BUF raw_buf#endif memcpy(TMP_RAW_BUF, loop_buf, 512); memcpy(&iv[0], &m->partialMD5[0], 16); twofish_compute_md5_iv_v3(devSect, &iv[0], (u_int32_t *)(&TMP_RAW_BUF[16])); blockEncrypt_CBC(a, TMP_RAW_BUF, raw_buf, iv[0], iv[1], iv[2], iv[3]); } else { if(sizeof(TransferSector_t) == 8) { blockEncrypt_CBC(a, loop_buf, raw_buf, devSect, (__u64)devSect>>32, 0, 0); } else { blockEncrypt_CBC(a, loop_buf, raw_buf, devSect, 0, 0, 0); } }#if LINUX_VERSION_CODE >= 0x20600 cond_resched();#elif LINUX_VERSION_CODE >= 0x20400 if(current->need_resched) {set_current_state(TASK_RUNNING);schedule();}#else if(current->need_resched) {current->state=TASK_RUNNING;schedule();}#endif raw_buf += 512; loop_buf += 512; size -= 512; devSect += sectInc; } } return 0;}static int fish2_init(struct loop_device *lo, LoopInfo_t *info){ TwofishMultiKey *m; fish2_key *a; if (info->lo_encrypt_key_size<16 || info->lo_encrypt_key_size>32) return -EINVAL; lo->key_data = m = allocMultiKey(); if(!m) return(-ENOMEM); a = m->keyPtr[0]; memset(a, 0, sizeof(fish2_key)); a->keyLen = info->lo_encrypt_key_size << 3; memcpy(a->key, info->lo_encrypt_key, info->lo_encrypt_key_size); init_key(a); memset(&info->lo_encrypt_key[0], 0, sizeof(info->lo_encrypt_key)); return 0;}static int fish2_release(struct loop_device *lo){ if(lo->key_data) { clearAndFreeMultiKey((TwofishMultiKey *)lo->key_data); lo->key_data = 0; } return(0);}static int handleIoctl_fish2(struct loop_device *lo, int cmd, unsigned long arg){ int err; switch (cmd) { case LOOP_MULTI_KEY_SETUP: err = multiKeySetup(lo, (unsigned char *)arg, 0); break; case LOOP_MULTI_KEY_SETUP_V3: err = multiKeySetup(lo, (unsigned char *)arg, 1); break; default: err = -EINVAL; } return err;}#if LINUX_VERSION_CODE < 0x20600static void fish2_lock(struct loop_device *lo){ MOD_INC_USE_COUNT;}static void fish2_unlock(struct loop_device *lo){ MOD_DEC_USE_COUNT;} #endifstatic struct loop_func_table fish2_funcs = { number: 3, /* 3 == LO_CRYPT_FISH2 */ transfer: (void *) transfer_fish2, init: (void *) fish2_init, release: fish2_release,#if LINUX_VERSION_CODE >= 0x20600 owner: THIS_MODULE,#else lock: fish2_lock, unlock: fish2_unlock,#endif ioctl: (void *) handleIoctl_fish2};#if LINUX_VERSION_CODE >= 0x20600# define loop_twofish_init __init loop_twofish_initfn# define loop_twofish_exit loop_twofish_exitfn#else# define loop_twofish_init init_module# define loop_twofish_exit cleanup_module#endifint loop_twofish_init(void){ if (loop_register_transfer(&fish2_funcs)) { printk(KERN_WARNING "loop: unable to register twofish transfer\n"); return -EIO; } printk(KERN_INFO "loop: registered twofish encryption\n"); return 0;}void loop_twofish_exit(void){ if (loop_unregister_transfer(fish2_funcs.number)) { printk(KERN_WARNING "loop: unable to unregister twofish transfer\n"); return; } printk(KERN_INFO "loop: unregistered twofish encryption\n");}#if LINUX_VERSION_CODE >= 0x20600module_init(loop_twofish_initfn);module_exit(loop_twofish_exitfn);#endif#if defined(MODULE_LICENSE)MODULE_LICENSE("GPL");#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -