cipher.c revision e406322b4b963e622f41d76193d8ca9e5435adb8
1/* 2 * Cryptographic API. 3 * 4 * Cipher operations. 5 * 6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the Free 10 * Software Foundation; either version 2 of the License, or (at your option) 11 * any later version. 12 * 13 */ 14#include <linux/kernel.h> 15//#include <linux/crypto.h> 16#include "rtl_crypto.h" 17#include <linux/errno.h> 18#include <linux/mm.h> 19#include <linux/slab.h> 20#include <asm/scatterlist.h> 21#include "internal.h" 22#include "scatterwalk.h" 23 24typedef void (cryptfn_t)(void *, u8 *, const u8 *); 25typedef void (procfn_t)(struct crypto_tfm *, u8 *, 26 u8*, cryptfn_t, int enc, void *, int); 27 28static inline void xor_64(u8 *a, const u8 *b) 29{ 30 ((u32 *)a)[0] ^= ((u32 *)b)[0]; 31 ((u32 *)a)[1] ^= ((u32 *)b)[1]; 32} 33 34static inline void xor_128(u8 *a, const u8 *b) 35{ 36 ((u32 *)a)[0] ^= ((u32 *)b)[0]; 37 ((u32 *)a)[1] ^= ((u32 *)b)[1]; 38 ((u32 *)a)[2] ^= ((u32 *)b)[2]; 39 ((u32 *)a)[3] ^= ((u32 *)b)[3]; 40} 41 42 43/* 44 * Generic encrypt/decrypt wrapper for ciphers, handles operations across 45 * multiple page boundaries by using temporary blocks. In user context, 46 * the kernel is given a chance to schedule us once per block. 47 */ 48static int crypt(struct crypto_tfm *tfm, 49 struct scatterlist *dst, 50 struct scatterlist *src, 51 unsigned int nbytes, cryptfn_t crfn, 52 procfn_t prfn, int enc, void *info) 53{ 54 struct scatter_walk walk_in, walk_out; 55 const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); 56 u8 tmp_src[bsize]; 57 u8 tmp_dst[bsize]; 58 59 if (!nbytes) 60 return 0; 61 62 if (nbytes % bsize) { 63 tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; 64 return -EINVAL; 65 } 66 67 scatterwalk_start(&walk_in, src); 68 scatterwalk_start(&walk_out, dst); 69 70 for(;;) { 71 u8 *src_p, *dst_p; 72 int in_place; 73 74 scatterwalk_map(&walk_in, 0); 75 scatterwalk_map(&walk_out, 1); 76 src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src); 77 dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst); 78 in_place = scatterwalk_samebuf(&walk_in, &walk_out, 79 src_p, dst_p); 80 81 nbytes -= bsize; 82 83 scatterwalk_copychunks(src_p, &walk_in, bsize, 0); 84 85 prfn(tfm, dst_p, src_p, crfn, enc, info, in_place); 86 87 scatterwalk_done(&walk_in, 0, nbytes); 88 89 scatterwalk_copychunks(dst_p, &walk_out, bsize, 1); 90 scatterwalk_done(&walk_out, 1, nbytes); 91 92 if (!nbytes) 93 return 0; 94 95 crypto_yield(tfm); 96 } 97} 98 99static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, 100 cryptfn_t fn, int enc, void *info, int in_place) 101{ 102 u8 *iv = info; 103 104 /* Null encryption */ 105 if (!iv) 106 return; 107 108 if (enc) { 109 tfm->crt_u.cipher.cit_xor_block(iv, src); 110 fn(crypto_tfm_ctx(tfm), dst, iv); 111 memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm)); 112 } else { 113 u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0]; 114 u8 *buf = in_place ? stack : dst; 115 116 fn(crypto_tfm_ctx(tfm), buf, src); 117 tfm->crt_u.cipher.cit_xor_block(buf, iv); 118 memcpy(iv, src, crypto_tfm_alg_blocksize(tfm)); 119 if (buf != dst) 120 memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm)); 121 } 122} 123 124static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, 125 cryptfn_t fn, int enc, void *info, int in_place) 126{ 127 fn(crypto_tfm_ctx(tfm), dst, src); 128} 129 130static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) 131{ 132 struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; 133 134 if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { 135 tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 136 return -EINVAL; 137 } else 138 return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen, 139 &tfm->crt_flags); 140} 141 142static int ecb_encrypt(struct crypto_tfm *tfm, 143 struct scatterlist *dst, 144 struct scatterlist *src, unsigned int nbytes) 145{ 146 return crypt(tfm, dst, src, nbytes, 147 tfm->__crt_alg->cra_cipher.cia_encrypt, 148 ecb_process, 1, NULL); 149} 150 151static int ecb_decrypt(struct crypto_tfm *tfm, 152 struct scatterlist *dst, 153 struct scatterlist *src, 154 unsigned int nbytes) 155{ 156 return crypt(tfm, dst, src, nbytes, 157 tfm->__crt_alg->cra_cipher.cia_decrypt, 158 ecb_process, 1, NULL); 159} 160 161static int cbc_encrypt(struct crypto_tfm *tfm, 162 struct scatterlist *dst, 163 struct scatterlist *src, 164 unsigned int nbytes) 165{ 166 return crypt(tfm, dst, src, nbytes, 167 tfm->__crt_alg->cra_cipher.cia_encrypt, 168 cbc_process, 1, tfm->crt_cipher.cit_iv); 169} 170 171static int cbc_encrypt_iv(struct crypto_tfm *tfm, 172 struct scatterlist *dst, 173 struct scatterlist *src, 174 unsigned int nbytes, u8 *iv) 175{ 176 return crypt(tfm, dst, src, nbytes, 177 tfm->__crt_alg->cra_cipher.cia_encrypt, 178 cbc_process, 1, iv); 179} 180 181static int cbc_decrypt(struct crypto_tfm *tfm, 182 struct scatterlist *dst, 183 struct scatterlist *src, 184 unsigned int nbytes) 185{ 186 return crypt(tfm, dst, src, nbytes, 187 tfm->__crt_alg->cra_cipher.cia_decrypt, 188 cbc_process, 0, tfm->crt_cipher.cit_iv); 189} 190 191static int cbc_decrypt_iv(struct crypto_tfm *tfm, 192 struct scatterlist *dst, 193 struct scatterlist *src, 194 unsigned int nbytes, u8 *iv) 195{ 196 return crypt(tfm, dst, src, nbytes, 197 tfm->__crt_alg->cra_cipher.cia_decrypt, 198 cbc_process, 0, iv); 199} 200 201static int nocrypt(struct crypto_tfm *tfm, 202 struct scatterlist *dst, 203 struct scatterlist *src, 204 unsigned int nbytes) 205{ 206 return -ENOSYS; 207} 208 209static int nocrypt_iv(struct crypto_tfm *tfm, 210 struct scatterlist *dst, 211 struct scatterlist *src, 212 unsigned int nbytes, u8 *iv) 213{ 214 return -ENOSYS; 215} 216 217int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) 218{ 219 u32 mode = flags & CRYPTO_TFM_MODE_MASK; 220 221 tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; 222 if (flags & CRYPTO_TFM_REQ_WEAK_KEY) 223 tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY; 224 225 return 0; 226} 227 228int crypto_init_cipher_ops(struct crypto_tfm *tfm) 229{ 230 int ret = 0; 231 struct cipher_tfm *ops = &tfm->crt_cipher; 232 233 ops->cit_setkey = setkey; 234 235 switch (tfm->crt_cipher.cit_mode) { 236 case CRYPTO_TFM_MODE_ECB: 237 ops->cit_encrypt = ecb_encrypt; 238 ops->cit_decrypt = ecb_decrypt; 239 break; 240 241 case CRYPTO_TFM_MODE_CBC: 242 ops->cit_encrypt = cbc_encrypt; 243 ops->cit_decrypt = cbc_decrypt; 244 ops->cit_encrypt_iv = cbc_encrypt_iv; 245 ops->cit_decrypt_iv = cbc_decrypt_iv; 246 break; 247 248 case CRYPTO_TFM_MODE_CFB: 249 ops->cit_encrypt = nocrypt; 250 ops->cit_decrypt = nocrypt; 251 ops->cit_encrypt_iv = nocrypt_iv; 252 ops->cit_decrypt_iv = nocrypt_iv; 253 break; 254 255 case CRYPTO_TFM_MODE_CTR: 256 ops->cit_encrypt = nocrypt; 257 ops->cit_decrypt = nocrypt; 258 ops->cit_encrypt_iv = nocrypt_iv; 259 ops->cit_decrypt_iv = nocrypt_iv; 260 break; 261 262 default: 263 BUG(); 264 } 265 266 if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) { 267 268 switch (crypto_tfm_alg_blocksize(tfm)) { 269 case 8: 270 ops->cit_xor_block = xor_64; 271 break; 272 273 case 16: 274 ops->cit_xor_block = xor_128; 275 break; 276 277 default: 278 printk(KERN_WARNING "%s: block size %u not supported\n", 279 crypto_tfm_alg_name(tfm), 280 crypto_tfm_alg_blocksize(tfm)); 281 ret = -EINVAL; 282 goto out; 283 } 284 285 ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm); 286 ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL); 287 if (ops->cit_iv == NULL) 288 ret = -ENOMEM; 289 } 290 291out: 292 return ret; 293} 294 295void crypto_exit_cipher_ops(struct crypto_tfm *tfm) 296{ 297 if (tfm->crt_cipher.cit_iv) 298 kfree(tfm->crt_cipher.cit_iv); 299} 300