static void AES_cbc(const __u8 *iv, int ivLength, const __u8 *key, int keyLength, const __u8 *input, int inputLength, __u8 *output, int encrypt) { struct scatterlist src[1]; struct scatterlist dst[1]; struct blkcipher_desc desc; struct crypto_blkcipher *cipher = crypto_alloc_blkcipher("cbc(aes)", 0, 0); crypto_blkcipher_setkey(cipher, key, keyLength); sg_init_table(dst, 1); sg_init_table(src, 1); sg_set_buf(&dst[0], output, inputLength); sg_set_buf(&src[0], input, inputLength); desc.tfm = cipher; desc.flags = 0; crypto_blkcipher_set_iv(cipher, iv, ivLength); if (encrypt) crypto_blkcipher_encrypt(&desc, dst, src, inputLength); else crypto_blkcipher_decrypt(&desc, dst, src, inputLength); crypto_free_blkcipher(cipher); }
static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) { struct blkcipher_desc desc; struct scatterlist sg; int err, iv_len; unsigned char iv[128]; if (tfm == NULL) { BT_ERR("tfm %p", tfm); return -EINVAL; } desc.tfm = tfm; desc.flags = 0; err = crypto_blkcipher_setkey(tfm, k, 16); if (err) { BT_ERR("cipher setkey failed: %d", err); return err; } sg_init_one(&sg, r, 16); iv_len = crypto_blkcipher_ivsize(tfm); if (iv_len) { memset(&iv, 0xff, iv_len); crypto_blkcipher_set_iv(tfm, iv, iv_len); } err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); if (err) BT_ERR("Encrypt data error %d", err); return err; }
static int encrypt_Cipher(char *key, char *src, char *dest, unsigned int len, int *written) { struct crypto_blkcipher *blkcipher = NULL; char *cipher = "cbc(aes)"; struct scatterlist sg_in[2]; struct scatterlist sg_out[1]; struct blkcipher_desc desc; unsigned int encrypted_datalen; unsigned int padlen; char pad[16]; char *iv=NULL; int ret = -EFAULT; encrypted_datalen = nearestRoundup(len); padlen = encrypted_datalen - len; blkcipher = crypto_alloc_blkcipher(cipher, 0, 0); if (IS_ERR(blkcipher)) { printk("could not allocate blkcipher handle for %s\n", cipher); return -PTR_ERR(blkcipher); } if (crypto_blkcipher_setkey(blkcipher, key, strlen(key))) { printk("key could not be set\n"); ret = -EAGAIN; goto out; } desc.flags = 0; desc.tfm = blkcipher; iv = (char *)kmalloc(crypto_blkcipher_ivsize(blkcipher) , GFP_KERNEL); if(iv==NULL) { printk("Initialisation vector not initialised\n"); ret = -ENOMEM; goto out; } memset(iv, 0, crypto_blkcipher_ivsize(blkcipher)); memset(pad, 0, sizeof pad); sg_init_table(sg_in, 2); sg_set_buf(&sg_in[0], src, len); sg_set_buf(&sg_in[1], pad, padlen); sg_init_table(sg_out, 1); sg_set_buf(sg_out, dest, encrypted_datalen); crypto_blkcipher_set_iv(blkcipher, iv, crypto_blkcipher_ivsize(blkcipher)); ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen); (*written) = encrypted_datalen; printk("Cipher Encryption operation completed\n"); kfree(iv); crypto_free_blkcipher(blkcipher); return ret; out: if (blkcipher) crypto_free_blkcipher(blkcipher); if (iv) kfree(iv); return ret; }
static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key, unsigned int key_len, const u8 *iv, unsigned int ivsize) { int ret; desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(desc->tfm)) { pr_err("encrypted_key: failed to load %s transform (%ld)\n", blkcipher_alg, PTR_ERR(desc->tfm)); return PTR_ERR(desc->tfm); } desc->flags = 0; ret = crypto_blkcipher_setkey(desc->tfm, key, key_len); if (ret < 0) { pr_err("encrypted_key: failed to setkey (%d)\n", ret); crypto_free_blkcipher(desc->tfm); return ret; } crypto_blkcipher_set_iv(desc->tfm, iv, ivsize); return 0; }
static int tf_self_test_perform_blkcipher( const char *alg_name, const struct blkcipher_test_vector *tv, bool decrypt) { struct blkcipher_desc desc = {0}; struct scatterlist sg_in, sg_out; unsigned char *in = NULL; unsigned char *out = NULL; unsigned in_size, out_size; int error; desc.tfm = crypto_alloc_blkcipher(alg_name, 0, 0); if (IS_ERR_OR_NULL(desc.tfm)) { ERROR("crypto_alloc_blkcipher(%s) failed", alg_name); error = (desc.tfm == NULL ? -ENOMEM : (int)desc.tfm); goto abort; } INFO("%s alg_name=%s driver_name=%s key_size=%u block_size=%u", decrypt ? "decrypt" : "encrypt", alg_name, crypto_tfm_alg_driver_name(crypto_blkcipher_tfm(desc.tfm)), tv->key_length * 8, crypto_blkcipher_blocksize(desc.tfm)); in_size = tv->length; in = kmalloc(in_size, GFP_KERNEL); if (IS_ERR_OR_NULL(in)) { ERROR("kmalloc(%u) failed: %d", in_size, (int)in); error = (in == NULL ? -ENOMEM : (int)in); goto abort; } memcpy(in, decrypt ? tv->ciphertext : tv->plaintext, tv->length); out_size = tv->length + crypto_blkcipher_blocksize(desc.tfm); out = kmalloc(out_size, GFP_KERNEL); if (IS_ERR_OR_NULL(out)) { ERROR("kmalloc(%u) failed: %d", out_size, (int)out); error = (out == NULL ? -ENOMEM : (int)out); goto abort; } error = crypto_blkcipher_setkey(desc.tfm, tv->key, tv->key_length); if (error) { ERROR("crypto_alloc_setkey(%s) failed", alg_name); goto abort; } TF_TRACE_ARRAY(tv->key, tv->key_length); if (tv->iv != NULL) { unsigned iv_length = crypto_blkcipher_ivsize(desc.tfm); crypto_blkcipher_set_iv(desc.tfm, tv->iv, iv_length); TF_TRACE_ARRAY(tv->iv, iv_length); } sg_init_one(&sg_in, in, tv->length); sg_init_one(&sg_out, out, tv->length); TF_TRACE_ARRAY(in, tv->length); (decrypt ? crypto_blkcipher_decrypt : crypto_blkcipher_encrypt) (&desc, &sg_out, &sg_in, tv->length); if (error) { ERROR("crypto_blkcipher_%s(%s) failed", decrypt ? "decrypt" : "encrypt", alg_name); goto abort; } TF_TRACE_ARRAY(out, tv->length); crypto_free_blkcipher(desc.tfm); if (memcmp((decrypt ? tv->plaintext : tv->ciphertext), out, tv->length)) { ERROR("Wrong %s/%u %s result", alg_name, tv->key_length * 8, decrypt ? "decryption" : "encryption"); error = -EINVAL; } else { INFO("%s/%u: %s successful", alg_name, tv->key_length * 8, decrypt ? "decryption" : "encryption"); error = 0; } kfree(in); kfree(out); return error; abort: if (!IS_ERR_OR_NULL(desc.tfm)) crypto_free_blkcipher(desc.tfm); if (!IS_ERR_OR_NULL(out)) kfree(out); if (!IS_ERR_OR_NULL(in)) kfree(in); return error; }
static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) { int err; int hdr_len; struct ipv6hdr *top_iph; struct ipv6_esp_hdr *esph; struct crypto_blkcipher *tfm; struct blkcipher_desc desc; struct esp_data *esp; struct sk_buff *trailer; int blksize; int clen; int alen; int nfrags; esp = x->data; hdr_len = skb->h.raw - skb->data + sizeof(*esph) + esp->conf.ivlen; /* Strip IP+ESP header. */ __skb_pull(skb, hdr_len); /* Now skb is pure payload to encrypt */ err = -ENOMEM; /* Round to block size */ clen = skb->len; alen = esp->auth.icv_trunc_len; tfm = esp->conf.tfm; desc.tfm = tfm; desc.flags = 0; blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); clen = ALIGN(clen + 2, blksize); if (esp->conf.padlen) clen = ALIGN(clen, esp->conf.padlen); if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) { goto error; } /* Fill padding... */ do { int i; for (i=0; i<clen-skb->len - 2; i++) *(u8*)(trailer->tail + i) = i+1; } while (0); *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2; pskb_put(skb, trailer, clen - skb->len); top_iph = (struct ipv6hdr *)__skb_push(skb, hdr_len); esph = (struct ipv6_esp_hdr *)skb->h.raw; top_iph->payload_len = htons(skb->len + alen - sizeof(*top_iph)); *(u8*)(trailer->tail - 1) = *skb->nh.raw; *skb->nh.raw = IPPROTO_ESP; esph->spi = x->id.spi; esph->seq_no = htonl(++x->replay.oseq); xfrm_aevent_doreplay(x); if (esp->conf.ivlen) { if (unlikely(!esp->conf.ivinitted)) { get_random_bytes(esp->conf.ivec, esp->conf.ivlen); esp->conf.ivinitted = 1; } crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); } do { struct scatterlist *sg = &esp->sgbuf[0]; if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto error; } skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); err = crypto_blkcipher_encrypt(&desc, sg, sg, clen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); } while (0); if (unlikely(err)) goto error; if (esp->conf.ivlen) { memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen); crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen); } if (esp->auth.icv_full_len) { err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data, sizeof(*esph) + esp->conf.ivlen + clen); memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen); } error: return err; }
static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *iph; struct ipv6_esp_hdr *esph; struct esp_data *esp = x->data; struct crypto_blkcipher *tfm = esp->conf.tfm; struct blkcipher_desc desc = { .tfm = tfm }; struct sk_buff *trailer; int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); int alen = esp->auth.icv_trunc_len; int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen; int hdr_len = skb->h.raw - skb->nh.raw; int nfrags; int ret = 0; if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) { ret = -EINVAL; goto out; } if (elen <= 0 || (elen & (blksize-1))) { ret = -EINVAL; goto out; } /* If integrity check is required, do this. */ if (esp->auth.icv_full_len) { u8 sum[alen]; ret = esp_mac_digest(esp, skb, 0, skb->len - alen); if (ret) goto out; if (skb_copy_bits(skb, skb->len - alen, sum, alen)) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { x->stats.integrity_failed++; ret = -EINVAL; goto out; } } if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) { ret = -EINVAL; goto out; } skb->ip_summed = CHECKSUM_NONE; esph = (struct ipv6_esp_hdr*)skb->data; iph = skb->nh.ipv6h; /* Get ivec. This can be wrong, check against another impls. */ if (esp->conf.ivlen) crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen); { u8 nexthdr[2]; struct scatterlist *sg = &esp->sgbuf[0]; u8 padlen; if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) { ret = -ENOMEM; goto out; } } skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); if (unlikely(ret)) goto out; if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) BUG(); padlen = nexthdr[0]; if (padlen+2 >= elen) { LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen); ret = -EINVAL; goto out; } /* ... check padding bits here. Silly. :-) */ pskb_trim(skb, skb->len - alen - padlen - 2); ret = nexthdr[1]; } skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - hdr_len; out: return ret; }
/* * Note: detecting truncated vs. non-truncated authentication data is very * expensive, so we only support truncated data, which is the recommended * and common case. */ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) { struct iphdr *iph; struct ip_esp_hdr *esph; struct esp_data *esp = x->data; struct crypto_blkcipher *tfm = esp->conf.tfm; struct blkcipher_desc desc = { .tfm = tfm }; struct sk_buff *trailer; int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); int alen = esp->auth.icv_trunc_len; int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; int nfrags; int ihl; u8 nexthdr[2]; struct scatterlist *sg; int padlen; int err; if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) goto out; if (elen <= 0 || (elen & (blksize-1))) goto out; /* If integrity check is required, do this. */ if (esp->auth.icv_full_len) { u8 sum[alen]; err = esp_mac_digest(esp, skb, 0, skb->len - alen); if (err) goto out; if (skb_copy_bits(skb, skb->len - alen, sum, alen)) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { x->stats.integrity_failed++; goto out; } } if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) goto out; skb->ip_summed = CHECKSUM_NONE; esph = (struct ip_esp_hdr*)skb->data; /* Get ivec. This can be wrong, check against another impls. */ if (esp->conf.ivlen) crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen); sg = &esp->sgbuf[0]; if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto out; } skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); err = crypto_blkcipher_decrypt(&desc, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); if (unlikely(err)) return err; if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) BUG(); padlen = nexthdr[0]; if (padlen+2 >= elen) goto out; /* ... check padding bits here. Silly. :-) */ iph = skb->nh.iph; ihl = iph->ihl * 4; if (x->encap) { struct xfrm_encap_tmpl *encap = x->encap; struct udphdr *uh = (void *)(skb->nh.raw + ihl); /* * 1) if the NAT-T peer's IP or port changed then * advertize the change to the keying daemon. * This is an inbound SA, so just compare * SRC ports. */ if (iph->saddr != x->props.saddr.a4 || uh->source != encap->encap_sport) { xfrm_address_t ipaddr; ipaddr.a4 = iph->saddr; km_new_mapping(x, &ipaddr, uh->source); /* XXX: perhaps add an extra * policy check here, to see * if we should allow or * reject a packet from a * different source * address/port. */ } /* * 2) ignore UDP/TCP checksums in case * of NAT-T in Transport Mode, or * perform other post-processing fixes * as per draft-ietf-ipsec-udp-encaps-06, * section 3.1.2 */ if (x->props.mode == XFRM_MODE_TRANSPORT || x->props.mode == XFRM_MODE_BEET) skb->ip_summed = CHECKSUM_UNNECESSARY; } iph->protocol = nexthdr[1]; pskb_trim(skb, skb->len - alen - padlen - 2); skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - ihl; return 0; out: return -EINVAL; }
static int esp_output(struct xfrm_state *x, struct sk_buff *skb) { int err; struct iphdr *top_iph; struct ip_esp_hdr *esph; struct crypto_blkcipher *tfm; struct blkcipher_desc desc; struct esp_data *esp; struct sk_buff *trailer; int blksize; int clen; int alen; int nfrags; /* Strip IP+ESP header. */ __skb_pull(skb, skb->h.raw - skb->data); /* Now skb is pure payload to encrypt */ err = -ENOMEM; /* Round to block size */ clen = skb->len; esp = x->data; alen = esp->auth.icv_trunc_len; tfm = esp->conf.tfm; desc.tfm = tfm; desc.flags = 0; blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); clen = ALIGN(clen + 2, blksize); if (esp->conf.padlen) clen = ALIGN(clen, esp->conf.padlen); if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) goto error; /* Fill padding... */ do { int i; for (i=0; i<clen-skb->len - 2; i++) *(u8*)(trailer->tail + i) = i+1; } while (0); *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2; pskb_put(skb, trailer, clen - skb->len); __skb_push(skb, skb->data - skb->nh.raw); top_iph = skb->nh.iph; esph = (struct ip_esp_hdr *)(skb->nh.raw + top_iph->ihl*4); top_iph->tot_len = htons(skb->len + alen); *(u8*)(trailer->tail - 1) = top_iph->protocol; /* this is non-NULL only with UDP Encapsulation */ if (x->encap) { struct xfrm_encap_tmpl *encap = x->encap; struct udphdr *uh; u32 *udpdata32; uh = (struct udphdr *)esph; uh->source = encap->encap_sport; uh->dest = encap->encap_dport; uh->len = htons(skb->len + alen - top_iph->ihl*4); uh->check = 0; switch (encap->encap_type) { default: case UDP_ENCAP_ESPINUDP: esph = (struct ip_esp_hdr *)(uh + 1); break; case UDP_ENCAP_ESPINUDP_NON_IKE: udpdata32 = (u32 *)(uh + 1); udpdata32[0] = udpdata32[1] = 0; esph = (struct ip_esp_hdr *)(udpdata32 + 2); break; } top_iph->protocol = IPPROTO_UDP; } else top_iph->protocol = IPPROTO_ESP; esph->spi = x->id.spi; esph->seq_no = htonl(++x->replay.oseq); xfrm_aevent_doreplay(x); if (esp->conf.ivlen) { if (unlikely(!esp->conf.ivinitted)) { get_random_bytes(esp->conf.ivec, esp->conf.ivlen); esp->conf.ivinitted = 1; } crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); } do { struct scatterlist *sg = &esp->sgbuf[0]; if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto error; } skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); err = crypto_blkcipher_encrypt(&desc, sg, sg, clen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); } while (0); if (unlikely(err)) goto error; if (esp->conf.ivlen) { memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen); crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen); } if (esp->auth.icv_full_len) { err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data, sizeof(*esph) + esp->conf.ivlen + clen); memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen); } ip_send_check(top_iph); error: return err; }
/** * handle_enc_dec * @f: pointer to file_struct struct which has all the information about input, temporary and output files * @buf: data which has to be encrypted or decrypted * @n_bytes: number of bytes to be encrypted or decrypted * @key: key used for encryption or decryption * @flags: encrypt or decrypt to indicate the desired operation * * Encrypts or decrypts the data as per the flags parameter. Resultant encrypted or decrypted data is stored in buf.This data is written * to temporary file. For encryption, the encrypted data is written to temporary file. For decryption, the decrypted data is written to * temporary file. * * Returns zero on success; non-zero otherwise; */ int handle_enc_dec(struct file_struct *f, unsigned char *buf, int n_bytes, char *key, int flags) { int err = 0, i, temp; struct crypto_blkcipher *blkcipher = NULL; unsigned char aes_key[AES_KEY_SIZE]; unsigned char iv[AES_KEY_SIZE] = "\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11"; struct scatterlist sg; struct blkcipher_desc desc; if (n_bytes%AES_KEY_SIZE != 0) { printk(KERN_ALERT"size not multiple of 16 for encryption\n"); err = -EINVAL; goto ERR; } for (i = 0 ; i < AES_KEY_SIZE ; i++) aes_key[i] = key[i]; blkcipher = crypto_alloc_blkcipher("cbc(aes)", 0, 0); if (IS_ERR(blkcipher)) { printk(KERN_ALERT"could not allocate blkcipher handle for %s\n", "cbsaes"); err = PTR_ERR(blkcipher); goto ERR; } if (crypto_blkcipher_setkey(blkcipher, aes_key, AES_KEY_SIZE)) { printk(KERN_ALERT"key could not be set\n"); err = -EAGAIN; goto ERR; } crypto_blkcipher_set_iv(blkcipher, iv, AES_KEY_SIZE); desc.flags = 0; desc.tfm = blkcipher; sg_init_one(&sg, buf, n_bytes); printk(KERN_ALERT"sg iinited\n"); /* encrypt data in place */ if (flags == 1) { crypto_blkcipher_encrypt(&desc, &sg, &sg, n_bytes); printk(KERN_ALERT"encryption done\n"); } else { crypto_blkcipher_decrypt(&desc, &sg, &sg, n_bytes); printk(KERN_ALERT"Decryption done\n"); } printk(KERN_ALERT"printing enc/dec data\n"); printk(KERN_ALERT"Cipher operation completed\n"); temp = write_to_file(f->filp_temp, buf, n_bytes); if (blkcipher) crypto_free_blkcipher(blkcipher); err = 0; ERR: return err; }
/* * Function definition for sys_xcrypt. * This function encrypts/decrypts files using AES Block Cipher algorithm using CBC mode. */ asmlinkage int sys_xcrypt( const char * const infile, const char * const opfile, const char * const keybuf, const int keylen, const short int flags ) { const char algo[] = "cbc(aes)"; char *ipBuf = NULL, *opBuf = NULL, *iv = NULL, *inFile = NULL, *opFile = NULL, *keyBuf = NULL; int errno = 0, ret = 0; int actReadLen = 0, actWriteLen = 0, padLen = 0, blkSiz = 0, ipFileLen = 0, opFileLen = 0, keyLen = 0; int delOpFile = 0, prmbLen = 0, idx = 0; unsigned int fileSize = 0, factor = 1; struct file *inFilePtr = NULL, *opFilePtr = NULL; struct crypto_blkcipher *tfm = NULL; struct blkcipher_desc desc; struct scatterlist sg[2]; struct dentry *tmpDentry; struct inode *tmpInode = NULL; mm_segment_t oldfs; /* Check for NULL pointers or invalid values */ if( ( NULL == infile ) || ( NULL == opfile ) || ( NULL == keybuf ) || ( ( _FLAG_ENCRYPT_ != flags ) && ( _FLAG_DECRYPT_ != flags ) ) ) { printk( KERN_ALERT "Invalid I/P" ); errno = -EINVAL; goto OUT_OK; } /* Verify if all the pointers belong to the user's own address space */ ret = access_ok( VERIFY_READ, infile, 0 ); if( !ret ) { printk( KERN_ALERT "Invalid pointer to I/P file passed as argument" ); errno = -EFAULT; goto OUT_OK; } ret = access_ok( VERIFY_READ, opfile, 0 ); if( !ret ) { printk( KERN_ALERT "Invalid pointer to O/P file passed as argument" ); errno = -EFAULT; goto OUT_OK; } ret = access_ok( VERIFY_READ, keybuf, 0 ); if( !ret ) { printk( KERN_ALERT "Invalid pointer to Password passed as argument" ); errno = -EFAULT; goto OUT_OK; } /* Find out the length of the i/p buffers */ ipFileLen = strlen_user( infile ); opFileLen = strlen_user( opfile ); keyLen = strlen_user( keybuf ); /* Allocate buffers to copy i/p arguments from user space to kernel space */ inFile = kmalloc( ipFileLen, GFP_KERNEL ); if( NULL == inFile ) { errno = -ENOMEM; goto OUT_OK; } else { ret = strncpy_from_user( inFile, infile, ipFileLen ); if( ret < 0 ) { errno = ret; goto OUT_IP; } } opFile = kmalloc( opFileLen, GFP_KERNEL ); if( NULL == opFile ) { errno = -ENOMEM; goto OUT_IP; } else { ret = strncpy_from_user( opFile, opfile, opFileLen ); if( ret < 0 ) { errno = ret; goto OUT_IP; } } keyBuf = kmalloc( keyLen, GFP_KERNEL ); if( NULL == keyBuf ) { errno = -ENOMEM; goto OUT_IP; } else { ret = strncpy_from_user( keyBuf, keybuf, keyLen ); if( ret < 0 ) { errno = ret; goto OUT_IP; } } /* Open I/P file. It will report error in case of non-existing file and bad permissions but not bad owner */ inFilePtr = filp_open( inFile, O_RDONLY, 0 ); if ( !inFilePtr || IS_ERR( inFilePtr ) ) { errno = (int)PTR_ERR( inFilePtr ); printk( KERN_ALERT "Error opening i/p file: %d\n", errno ); inFilePtr = NULL; goto OUT_IP; } /* Check if the file is a regular file or not */ if( !S_ISREG( inFilePtr->f_path.dentry->d_inode->i_mode ) ) { printk( KERN_ALERT "Error as file is not a regular one" ); errno = -EBADF; goto OUT_FILE; } /* Check if the I/p file and the process owner match */ if( ( current->real_cred->uid != inFilePtr->f_path.dentry->d_inode->i_uid ) && ( current->real_cred->uid != 0 ) ) { printk( KERN_ALERT "Error as owner of file and process does not match" ); errno = -EACCES; goto OUT_FILE; } /* Open O/P file with error handling */ opFilePtr = filp_open( opFile, O_WRONLY | O_CREAT | O_EXCL, 0 ); if ( !opFilePtr || IS_ERR( opFilePtr ) ) { errno = (int)PTR_ERR( opFilePtr ); printk( KERN_ALERT "Error opening o/p file: %d\n", errno ); opFilePtr = NULL; goto OUT_FILE; } /* * Check if the infile and opfile point to the same file * If they reside on the different file partition and have same name then it should be allowed else not */ if( ( inFilePtr->f_path.dentry->d_inode->i_sb == opFilePtr->f_path.dentry->d_inode->i_sb ) && ( inFilePtr->f_path.dentry->d_inode->i_ino == opFilePtr->f_path.dentry->d_inode->i_ino ) ) { printk( KERN_ALERT "I/p and O/p file cannot be same" ); errno = -EINVAL; goto OUT_FILE; } /* Set the o/p file permission to i/p file */ opFilePtr->f_path.dentry->d_inode->i_mode = inFilePtr->f_path.dentry->d_inode->i_mode; /* Set the file position to the beginning of the file */ inFilePtr->f_pos = 0; opFilePtr->f_pos = 0; /* Allocate buffer to read data into and to write data to. For performance reasons, set its size equal to PAGE_SIZE */ ipBuf = kmalloc( PAGE_SIZE, GFP_KERNEL ); if( NULL == ipBuf ) { errno = -ENOMEM; goto OUT_FILE; } memset( ipBuf, _NULL_CHAR_, PAGE_SIZE ); opBuf = kmalloc( PAGE_SIZE, GFP_KERNEL ); if( NULL == opBuf ) { errno = -ENOMEM; goto OUT_DATA_PAGE; } memset( opBuf, _NULL_CHAR_, PAGE_SIZE ); /* Allocate tfm */ tfm = crypto_alloc_blkcipher( algo, 0, CRYPTO_ALG_ASYNC ); if ( NULL == tfm ) { printk( KERN_ALERT "Failed to load transform for %s: %ld\n", algo, PTR_ERR( tfm ) ); errno = -EINVAL; goto OUT_DATA_PAGE; } /* Initialize desc */ desc.tfm = tfm; desc.flags = 0; ret = crypto_blkcipher_setkey( tfm, keybuf, keylen ); if( ret ) { printk( "Setkey() failed. Flags=%x\n", crypto_blkcipher_get_flags( tfm ) ); errno = -EINVAL; goto OUT_CIPHER; } /* Initialize sg structure */ FILL_SG( &sg[0], ipBuf, PAGE_SIZE ); FILL_SG( &sg[1], opBuf, PAGE_SIZE ); /* Get the block size */ blkSiz = ((tfm->base).__crt_alg)->cra_blocksize; /* Initialize IV */ iv = kmalloc( blkSiz, GFP_KERNEL ); if( NULL == iv ) { errno = -ENOMEM; goto OUT_CIPHER; } memset( iv, _NULL_CHAR_, blkSiz ); crypto_blkcipher_set_iv( tfm, iv, crypto_blkcipher_ivsize( tfm ) ); /* Store the key and file size in encrypted form in the preamble */ switch( flags ) { case _FLAG_ENCRYPT_: memcpy( ipBuf, keybuf, keylen ); prmbLen = keylen; fileSize = (unsigned int)inFilePtr->f_path.dentry->d_inode->i_size; while( fileSize ) { ipBuf[ prmbLen + idx ] = fileSize % 10; fileSize /= 10; ++idx; } prmbLen += idx; #ifdef _DEBUG_ printk( KERN_ALERT "idx=%d prmbLen=%d\n", idx, prmbLen ); #endif memset( ipBuf + prmbLen, _ETX_, _UL_MAX_SIZE_ - idx ); prmbLen += ( _UL_MAX_SIZE_ - idx ); #ifdef _DEBUG_ printk( KERN_ALERT "prmbLen=%d\n", prmbLen ); #endif padLen = blkSiz - ( prmbLen % blkSiz ); memset( ipBuf + prmbLen, _ETX_, padLen ); prmbLen += padLen; #ifdef _DEBUG_ printk( KERN_ALERT "padLen=%d prmbLen=%d\n", padLen, prmbLen ); #endif ret = crypto_blkcipher_encrypt( &desc, &sg[1], &sg[0], prmbLen ); if (ret) { printk( KERN_ALERT "Encryption failed. Flags=0x%x\n", tfm->base.crt_flags ); delOpFile = 1; goto OUT_IV; } oldfs = get_fs(); set_fs( KERNEL_DS ); opFilePtr->f_op->write( opFilePtr, opBuf, prmbLen, &opFilePtr->f_pos ); /* Reset the address space to user one */ set_fs( oldfs ); break; case _FLAG_DECRYPT_: /* Set the address space to kernel one */ oldfs = get_fs(); set_fs( KERNEL_DS ); prmbLen = keylen + _UL_MAX_SIZE_; padLen = blkSiz - ( prmbLen % blkSiz ); prmbLen += padLen; #ifdef _DEBUG_ printk( KERN_ALERT "padLen=%d prmbLen=%d\n", padLen, prmbLen ); #endif actReadLen = inFilePtr->f_op->read( inFilePtr, ipBuf, prmbLen, &inFilePtr->f_pos ); if( actReadLen != prmbLen ) { printk( KERN_ALERT "Requested number of bytes for preamble are lesser" ); delOpFile = 1; goto OUT_IV; } #ifdef _DEBUG_ printk( KERN_ALERT "actReadLen=%d\n", actReadLen ); #endif /* Reset the address space to user one */ set_fs( oldfs ); ret = crypto_blkcipher_decrypt( &desc, &sg[1], &sg[0], prmbLen ); if (ret) { printk( KERN_ALERT "Decryption failed. Flags=0x%x\n", tfm->base.crt_flags ); delOpFile = 1; goto OUT_IV; } ret = memcmp( keybuf, opBuf, keylen ); if( ret ) { printk( "Wrong password entered." ); errno = -EKEYREJECTED; goto OUT_IV; } idx = 0; fileSize = 0; while( opBuf[ keylen + idx ] != _ETX_ ) { fileSize += opBuf[ keylen + idx ] * factor; factor *= 10; ++idx; } #ifdef _DEBUG_ printk( KERN_ALERT "idx=%d fileSize=%u\n", idx, fileSize ); #endif break; } /* Read file till the file pointer reaches to the EOF */ while( inFilePtr->f_pos < inFilePtr->f_path.dentry->d_inode->i_size ) { /* Initialize it to NULL char */ memset( ipBuf, _NULL_CHAR_, PAGE_SIZE ); memset( opBuf, _NULL_CHAR_, PAGE_SIZE ); /* Set the address space to kernel one */ oldfs = get_fs(); set_fs( KERNEL_DS ); actReadLen = inFilePtr->f_op->read( inFilePtr, ipBuf, PAGE_SIZE, &inFilePtr->f_pos ); /* Reset the address space to user one */ set_fs( oldfs ); /* As per the i/p flag, do encryption/decryption */ switch( flags ) { case _FLAG_ENCRYPT_: /* For encryption ensure padding as per the block size */ #ifdef _DEBUG_ printk( KERN_ALERT "Bytes read from I/P file ::%d::\n", actReadLen ); #endif if( actReadLen % blkSiz ) { padLen = blkSiz - ( actReadLen % blkSiz ); memset( ipBuf + actReadLen, _ETX_, padLen ); actReadLen += padLen; } #ifdef _DEBUG_ printk( KERN_ALERT "Pad Length ::%d::\n", padLen ); printk( KERN_ALERT "Data read from I/P file ::%s::\n", ipBuf ); #endif /* Encrypt the data */ ret = crypto_blkcipher_encrypt( &desc, &sg[1], &sg[0], PAGE_SIZE ); if (ret) { printk( KERN_ALERT "Encryption failed. Flags=0x%x\n", tfm->base.crt_flags ); delOpFile = 1; goto OUT_IV; } break; case _FLAG_DECRYPT_: /* Decrypt the data */ ret = crypto_blkcipher_decrypt( &desc, &sg[1], &sg[0], PAGE_SIZE ); if (ret) { printk( KERN_ALERT "Decryption failed. Flags=0x%x\n", tfm->base.crt_flags ); delOpFile = 1; goto OUT_IV; } #ifdef _DEBUG_ printk( KERN_ALERT "Bytes read from I/P file ::%d::\n", actReadLen ); #endif while( _ETX_ == opBuf[ actReadLen - 1 ] ) { opBuf[ actReadLen - 1 ] = _NULL_CHAR_; --actReadLen; } #ifdef _DEBUG_ printk( KERN_ALERT "Bytes read from I/P file ::%d::\n", actReadLen ); printk( KERN_ALERT "Data read from I/P file ::%s::\n", opBuf ); #endif break; } /* * Start writing to the o/p file * Set the address space to kernel one */ oldfs = get_fs(); set_fs( KERNEL_DS ); actWriteLen = opFilePtr->f_op->write( opFilePtr, opBuf, actReadLen, &opFilePtr->f_pos ); /* Reset the address space to user one */ set_fs( oldfs ); #ifdef _DEBUG_ printk( KERN_ALERT "Bytes written to O/P file ::%d::\n", actWriteLen ); #endif } /* Free iv */ OUT_IV: kfree( iv ); iv = NULL; printk( KERN_ALERT "Memory for IV freed ..." ); /* Free tfm */ OUT_CIPHER: crypto_free_blkcipher( tfm ); printk( KERN_ALERT "Encryption Transform freed ..." ); /* Free i/p and o/p buffers */ OUT_DATA_PAGE: if( ipBuf ) { kfree( ipBuf ); ipBuf = NULL; } if( opBuf ) { kfree( opBuf ); opBuf = NULL; } printk( KERN_ALERT "Memory for encrption/decryption freed ..." ); /* Close any open files */ OUT_FILE: if( inFilePtr ) { filp_close( inFilePtr, NULL ); inFilePtr = NULL; printk( KERN_ALERT "I/p file closed ..." ); } if( opFilePtr ) { filp_close( opFilePtr, NULL ); opFilePtr = NULL; printk( KERN_ALERT "O/p file closed ..." ); } if( delOpFile ) { opFilePtr = filp_open( opFile, O_WRONLY , 0 ); if ( !opFilePtr || IS_ERR( opFilePtr ) ) { opFilePtr = NULL; goto OUT_IP; } tmpDentry = opFilePtr->f_path.dentry; tmpInode = tmpDentry->d_parent->d_inode; filp_close( opFilePtr, NULL ); vfs_unlink( tmpInode, tmpDentry ); printk( KERN_ALERT "O/p file deleted ..." ); } OUT_IP: if( inFile ) { kfree( inFile ); inFile = NULL; } if( opFile ) { kfree( opFile ); opFile = NULL; } if( keyBuf ) { kfree( keyBuf ); keyBuf = NULL; } printk( KERN_ALERT "Memory for I/P parameters freed ..." ); /* Return final status */ OUT_OK: printk( KERN_ALERT "Exiting function sys_xcrypt ..." ); return errno; }