static int test_cipher_cycles(struct blkcipher_desc *desc, int enc, struct scatterlist *sg, int blen) { unsigned long cycles = 0; int ret = 0; int i; local_bh_disable(); local_irq_disable(); /* Warm-up run. */ for (i = 0; i < 4; i++) { if (enc) ret = crypto_blkcipher_encrypt(desc, sg, sg, blen); else ret = crypto_blkcipher_decrypt(desc, sg, sg, blen); if (ret) goto out; } /* The real thing. */ for (i = 0; i < 8; i++) { cycles_t start, end; start = get_cycles(); if (enc) ret = crypto_blkcipher_encrypt(desc, sg, sg, blen); else ret = crypto_blkcipher_decrypt(desc, sg, sg, blen); end = get_cycles(); if (ret) goto out; cycles += end - start; } out: local_irq_enable(); local_bh_enable(); if (ret == 0) printk("1 operation in %lu cycles (%d bytes)\n", (cycles + 4) / 8, blen); return ret; }
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; 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); err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); if (err) BT_ERR("Encrypt data error %d", err); return err; }
static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { int ret; struct blkcipher_walk walk; struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx( crypto_blkcipher_tfm(desc->tfm)); struct blkcipher_desc fallback_desc = { .tfm = ctx->fallback, .info = desc->info, .flags = desc->flags }; if (in_interrupt()) { ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src, nbytes); } else { blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { pagefault_disable(); enable_kernel_altivec(); aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, walk.dst.virt.addr, (nbytes & AES_BLOCK_MASK)/AES_BLOCK_SIZE, &ctx->enc_key, walk.iv); pagefault_enable(); crypto_inc(walk.iv, AES_BLOCK_SIZE); nbytes &= AES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, &walk, nbytes); } if (walk.nbytes) { p8_aes_ctr_final(ctx, &walk); ret = blkcipher_walk_done(desc, &walk, 0); } } return ret; } struct crypto_alg p8_aes_ctr_alg = { .cra_name = "ctr(aes)", .cra_driver_name = "p8_aes_ctr", .cra_module = THIS_MODULE, .cra_priority = 1000, .cra_type = &crypto_blkcipher_type, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, .cra_alignmask = 0, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct p8_aes_ctr_ctx), .cra_init = p8_aes_ctr_init, .cra_exit = p8_aes_ctr_exit, .cra_blkcipher = { .ivsize = 0, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .setkey = p8_aes_ctr_setkey, .encrypt = p8_aes_ctr_crypt, .decrypt = p8_aes_ctr_crypt, }, };
int aes_encrypt(char *buf, unsigned int keylen, void *read_buf, size_t src_len) { struct scatterlist sg; struct blkcipher_desc desc; int ret; struct crypto_blkcipher *tfm = crypto_alloc_blkcipher("cbc(aes)", 0, 0); if (IS_ERR(tfm)) {return PTR_ERR(tfm);} desc.tfm = tfm; desc.flags=0; ret = crypto_blkcipher_setkey((void *)tfm, buf, keylen); if(ret) { printk(KERN_ALERT "\n setkey failed\n"); goto free_tfm; } printk(KERN_ALERT "\n setkey passed\n"); sg_set_buf(&sg, read_buf, src_len); ret = crypto_blkcipher_encrypt(&desc, &sg, &sg, src_len); if (ret) { goto free_tfm; } free_tfm: crypto_free_blkcipher(tfm); return ret; }
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; }
int my_encrypt(char *input, int inputlen, char *output, int outputlen, char *key, int keylen) { struct crypto_blkcipher *tfm = NULL; struct blkcipher_desc desc; struct scatterlist src[1], dst[1]; unsigned int retval = 0; tfm = crypto_alloc_blkcipher("ctr(aes)", 0, 0); if (IS_ERR(tfm)) { printk(KERN_INFO "crypto_alloc_blkcipher failed\n"); return -EINVAL; } desc.tfm = tfm; desc.flags = 0; retval = crypto_blkcipher_setkey(tfm, key, keylen); if (retval) { printk(KERN_INFO "crypto_blkcipher_setkey failed\n"); crypto_free_blkcipher(tfm); return -EINVAL; } sg_init_table(src, 1); sg_set_buf(&src[0], input, inputlen); sg_init_table(dst, 1); sg_set_buf(dst, output, outputlen); retval = crypto_blkcipher_encrypt(&desc, dst, src, inputlen); crypto_free_blkcipher(tfm); return retval; }
/* Perform WEP encryption on given skb that has at least 4 bytes of headroom * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, * so the payload length increases with 8 bytes. * * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) */ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct prism2_wep_data *wep = priv; u32 klen, len; u8 key[WEP_KEY_LEN + 3]; u8 *pos; struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; u32 crc; u8 *icv; struct scatterlist sg; if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || skb->len < hdr_len) { printk(KERN_ERR "Error!!! headroom=%d tailroom=%d skblen=%d" " hdr_len=%d\n", skb_headroom(skb), skb_tailroom(skb), skb->len, hdr_len); return -1; } len = skb->len - hdr_len; pos = skb_push(skb, 4); memmove(pos, pos + 4, hdr_len); pos += hdr_len; klen = 3 + wep->key_len; wep->iv++; /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) * can be used to speedup attacks, so avoid using them. */ if ((wep->iv & 0xff00) == 0xff00) { u8 B = (wep->iv >> 16) & 0xff; if (B >= 3 && B < klen) wep->iv += 0x0100; } /* Prepend 24-bit IV to RC4 key and TX frame */ *pos++ = key[0] = (wep->iv >> 16) & 0xff; *pos++ = key[1] = (wep->iv >> 8) & 0xff; *pos++ = key[2] = wep->iv & 0xff; *pos++ = wep->key_idx << 6; /* Copy rest of the WEP key (the secret part) */ memcpy(key + 3, wep->key, wep->key_len); if (!tcb_desc->bHwSec) { /* Append little-endian CRC32 and encrypt it to produce ICV */ crc = ~crc32_le(~0, pos, len); icv = skb_put(skb, 4); icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; icv[3] = crc >> 24; sg_init_one(&sg, pos, len+4); crypto_blkcipher_setkey(wep->tx_tfm, key, klen); return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); }
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 encrypt_decrypt_file(char *buf, unsigned char *key, int len, int flag) { struct crypto_blkcipher *blkcipher = NULL; char *cipher = "ctr(aes)"; struct scatterlist sg; struct blkcipher_desc desc; int rc; blkcipher = crypto_alloc_blkcipher(cipher, 0, 0); if (IS_ERR(blkcipher)) { printk("could not allocate blkcipher handle for %s\n", cipher); rc= -PTR_ERR(blkcipher); goto out; } if (crypto_blkcipher_setkey(blkcipher, key, 16)) { printk("key could not be set\n"); rc = -EAGAIN; goto out; } desc.flags = 0; desc.tfm = blkcipher; sg_init_one(&sg, buf, len); /* encrypt data */ if(flag == 1) { rc = crypto_blkcipher_encrypt(&desc, &sg, &sg, len); if(rc){ printk("Encryption failed \n"); rc = -EFAULT; goto out; } } /* decrypt data */ else if(flag == 0) { rc = crypto_blkcipher_decrypt(&desc, &sg, &sg, len); if(rc){ printk("Decryption failed \n"); rc = -EFAULT; goto out; } } return 0; out: if (blkcipher) crypto_free_blkcipher(blkcipher); return rc; }
static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct prism2_wep_data *wep = priv; struct blkcipher_desc desc = { .tfm = wep->tx_tfm }; u32 klen, len; u8 key[WEP_KEY_LEN + 3]; u8 *pos; u32 crc; u8 *icv; struct scatterlist sg; if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || skb->len < hdr_len) return -1; len = skb->len - hdr_len; pos = skb_push(skb, 4); memmove(pos, pos + 4, hdr_len); pos += hdr_len; klen = 3 + wep->key_len; wep->iv++; /* */ if ((wep->iv & 0xff00) == 0xff00) { u8 B = (wep->iv >> 16) & 0xff; if (B >= 3 && B < klen) wep->iv += 0x0100; } /* */ *pos++ = key[0] = (wep->iv >> 16) & 0xff; *pos++ = key[1] = (wep->iv >> 8) & 0xff; *pos++ = key[2] = wep->iv & 0xff; *pos++ = wep->key_idx << 6; /* */ memcpy(key + 3, wep->key, wep->key_len); /* */ crc = ~crc32_le(~0, pos, len); icv = skb_put(skb, 4); icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; icv[3] = crc >> 24; crypto_blkcipher_setkey(wep->tx_tfm, key, klen); sg_init_one(&sg, pos, len + 4); return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); }
static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead); unsigned int authsize = crypto_aead_authsize(aead); unsigned int nbytes = req->cryptlen - (enc ? 0 : authsize); struct blkcipher_desc desc = { .tfm = ctx->null, }; return crypto_blkcipher_encrypt(&desc, req->dst, req->src, nbytes); } static int crypto_rfc4543_encrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req); struct aead_request *subreq; int err; if (req->src != req->dst) { err = crypto_rfc4543_copy_src_to_dst(req, true); if (err) return err; } subreq = crypto_rfc4543_crypt(req, true); err = crypto_aead_encrypt(subreq); if (err) return err; scatterwalk_map_and_copy(rctx->auth_tag, req->dst, req->cryptlen, crypto_aead_authsize(aead), 1); return 0; } static int crypto_rfc4543_decrypt(struct aead_request *req) { int err; if (req->src != req->dst) { err = crypto_rfc4543_copy_src_to_dst(req, false); if (err) return err; } req = crypto_rfc4543_crypt(req, false); return crypto_aead_decrypt(req); }
int calc_seckey(struct cifs_ses *ses) { int rc; struct crypto_blkcipher *tfm_arc4; struct scatterlist sgin, sgout; struct blkcipher_desc desc; unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */ get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE); tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm_arc4)) { rc = PTR_ERR(tfm_arc4); cifs_dbg(VFS, "could not allocate crypto API arc4\n"); return rc; } desc.tfm = tfm_arc4; rc = crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not set response as a key\n", __func__); return rc; } sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE); sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); if (rc) { cifs_dbg(VFS, "could not encrypt session key rc: %d\n", rc); crypto_free_blkcipher(tfm_arc4); return rc; } /* make secondary_key/nonce as session key */ memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); /* and make len as that of session key only */ ses->auth_key.len = CIFS_SESS_KEY_SIZE; crypto_free_blkcipher(tfm_arc4); return rc; }
static inline void test2(void) { struct crypto_blkcipher *tfm; int rc; unsigned char *crap; struct blkcipher_desc desc; struct scatterlist in, out; printk(KERN_INFO "test in\n"); crap = kmalloc(4096, GFP_KERNEL); tfm = crypto_alloc_blkcipher("rsa", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { printk(KERN_INFO "crypto_alloc_blkcipher()\n"); return; } rc = crypto_blkcipher_setkey(tfm, key, sizeof(key) - 1); printk(KERN_INFO "crypto_blkcipher_setkey = %d\n", rc); strcpy(crap, "AABC"); desc.tfm = tfm; desc.flags = 0; sg_init_table(&in, 1); sg_set_buf(&in, crap, 4); sg_init_table(&out, 1); sg_set_buf(&out, crap, 4096); rc = crypto_blkcipher_encrypt(&desc, &out, &in, 4); printk(KERN_INFO "crypto_blkcipher_encrypt RC %d %x %x %x\n", rc, crap[0], crap[1], crap[2]); sg_init_one(&in, crap, rc); sg_init_one(&out, crap, 4096); rc = crypto_blkcipher_decrypt(&desc, &out, &in, rc); printk(KERN_INFO "crypto_blkcipher_decrypt RC %d %x %x %x\n", rc, crap[0], crap[1], crap[2]); crypto_free_blkcipher(tfm); kfree(crap); printk(KERN_INFO "test out\n"); }
/* Before returning data to userspace, encrypt decrypted data. */ static int derived_key_encrypt(struct encrypted_key_payload *epayload, const u8 *derived_key, unsigned int derived_keylen) { struct scatterlist sg_in[2]; struct scatterlist sg_out[1]; struct blkcipher_desc desc; unsigned int encrypted_datalen; unsigned int padlen; char pad[16]; int ret; encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); padlen = encrypted_datalen - epayload->decrypted_datalen; ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, epayload->iv, ivsize); if (ret < 0) goto out; dump_decrypted_data(epayload); memset(pad, 0, sizeof pad); sg_init_table(sg_in, 2); sg_set_buf(&sg_in[0], epayload->decrypted_data, epayload->decrypted_datalen); sg_set_buf(&sg_in[1], pad, padlen); sg_init_table(sg_out, 1); sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen); ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen); crypto_free_blkcipher(desc.tfm); if (ret < 0) pr_err("encrypted_key: failed to encrypt (%d)\n", ret); else dump_encrypted_data(epayload, encrypted_datalen); out: return ret; }
static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc, struct scatterlist *sg, int blen, int sec) { unsigned long start, end; int bcount; int ret; for (start = jiffies, end = start + sec * HZ, bcount = 0; time_before(jiffies, end); bcount++) { if (enc) ret = crypto_blkcipher_encrypt(desc, sg, sg, blen); else ret = crypto_blkcipher_decrypt(desc, sg, sg, blen); if (ret) return ret; } printk("%d operations in %d seconds (%ld bytes)\n", bcount, sec, (long)bcount * blen); return 0; }
static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) { struct blkcipher_desc desc; struct scatterlist sg; uint8_t tmp[16], data[16]; int err; if (tfm == NULL) { BT_ERR("tfm %p", tfm); return -EINVAL; } desc.tfm = tfm; desc.flags = 0; /* The most significant octet of key corresponds to k[0] */ swap128(k, tmp); err = crypto_blkcipher_setkey(tfm, tmp, 16); if (err) { BT_ERR("cipher setkey failed: %d", err); return err; } /* Most significant octet of plaintextData corresponds to data[0] */ swap128(r, data); sg_init_one(&sg, data, 16); err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); if (err) BT_ERR("Encrypt data error %d", err); /* Most significant octet of encryptedData corresponds to data[0] */ swap128(data, r); return err; }
int wrapfs_encrypt_page(struct page *dst_page, struct page *src_page, char *key) { int ret = 0; struct crypto_blkcipher *tfm = NULL; struct blkcipher_desc desc; const char *algo = "ctr(aes)"; struct scatterlist src_sg, dst_sg; sg_init_table(&src_sg, 1); sg_init_table(&dst_sg, 1); sg_set_page(&src_sg, src_page, PAGE_CACHE_SIZE, 0); sg_set_page(&dst_sg, dst_page, PAGE_CACHE_SIZE, 0); tfm = crypto_alloc_blkcipher(algo,0,CRYPTO_ALG_ASYNC); if(IS_ERR(tfm)){ printk(KERN_ERR "AES: cipher: Failed to load transform for %ld\n",PTR_ERR(tfm)); return PTR_ERR(tfm); } desc.tfm = tfm; desc.flags = 0; ret = crypto_blkcipher_setkey(tfm,key,32); ret = crypto_blkcipher_encrypt(&desc, &dst_sg, &src_sg, PAGE_CACHE_SIZE); if (ret) { printk(KERN_ERR "Error encrypting\n"); goto out; } out: crypto_free_blkcipher(tfm); return ret; }
/* * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. * Well, not what's written there, but rather what they meant. */ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) { struct scatterlist sg_in[1], sg_out[1]; struct blkcipher_desc desc = { .tfm = state->arc4 }; get_new_key_from_sha(state); if (!initial_key) { crypto_blkcipher_setkey(state->arc4, state->sha1_digest, state->keylen); sg_init_table(sg_in, 1); sg_init_table(sg_out, 1); setup_sg(sg_in, state->sha1_digest, state->keylen); setup_sg(sg_out, state->session_key, state->keylen); if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, state->keylen) != 0) { printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); } } else { memcpy(state->session_key, state->sha1_digest, state->keylen); } if (state->keylen == 8) { /* See RFC 3078 */ state->session_key[0] = 0xd1; state->session_key[1] = 0x26; state->session_key[2] = 0x9e; } crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen); } /* * Allocate space for a (de)compressor. */ static void *mppe_alloc(unsigned char *options, int optlen) { struct ppp_mppe_state *state; unsigned int digestsize; if (optlen != CILEN_MPPE + sizeof(state->master_key) || options[0] != CI_MPPE || options[1] != CILEN_MPPE) goto out; state = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) goto out; state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(state->arc4)) { state->arc4 = NULL; goto out_free; } state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(state->sha1)) { state->sha1 = NULL; goto out_free; } digestsize = crypto_hash_digestsize(state->sha1); if (digestsize < MPPE_MAX_KEY_LEN) goto out_free; state->sha1_digest = kmalloc(digestsize, GFP_KERNEL); if (!state->sha1_digest) goto out_free; /* Save keys. */ memcpy(state->master_key, &options[CILEN_MPPE], sizeof(state->master_key)); memcpy(state->session_key, state->master_key, sizeof(state->master_key)); /* * We defer initial key generation until mppe_init(), as mppe_alloc() * is called frequently during negotiation. */ return (void *)state; out_free: if (state->sha1_digest) kfree(state->sha1_digest); if (state->sha1) crypto_free_hash(state->sha1); if (state->arc4) crypto_free_blkcipher(state->arc4); kfree(state); out: return NULL; } /* * Deallocate space for a (de)compressor. */ static void mppe_free(void *arg) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; if (state) { if (state->sha1_digest) kfree(state->sha1_digest); if (state->sha1) crypto_free_hash(state->sha1); if (state->arc4) crypto_free_blkcipher(state->arc4); kfree(state); } } /* * Initialize (de)compressor state. */ static int mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, const char *debugstr) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; unsigned char mppe_opts; if (optlen != CILEN_MPPE || options[0] != CI_MPPE || options[1] != CILEN_MPPE) return 0; MPPE_CI_TO_OPTS(&options[2], mppe_opts); if (mppe_opts & MPPE_OPT_128) state->keylen = 16; else if (mppe_opts & MPPE_OPT_40) state->keylen = 8; else { printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr, unit); return 0; } if (mppe_opts & MPPE_OPT_STATEFUL) state->stateful = 1; /* Generate the initial session key. */ mppe_rekey(state, 1); if (debug) { int i; char mkey[sizeof(state->master_key) * 2 + 1]; char skey[sizeof(state->session_key) * 2 + 1]; printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", debugstr, unit, (state->keylen == 16) ? 128 : 40, (state->stateful) ? "stateful" : "stateless"); for (i = 0; i < sizeof(state->master_key); i++) sprintf(mkey + i * 2, "%02x", state->master_key[i]); for (i = 0; i < sizeof(state->session_key); i++) sprintf(skey + i * 2, "%02x", state->session_key[i]); printk(KERN_DEBUG "%s[%d]: keys: master: %s initial session: %s\n", debugstr, unit, mkey, skey); } /* * Initialize the coherency count. The initial value is not specified * in RFC 3078, but we can make a reasonable assumption that it will * start at 0. Setting it to the max here makes the comp/decomp code * do the right thing (determined through experiment). */ state->ccount = MPPE_CCOUNT_SPACE - 1; /* * Note that even though we have initialized the key table, we don't * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. */ state->bits = MPPE_BIT_ENCRYPTED; state->unit = unit; state->debug = debug; return 1; } static int mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit, int hdrlen, int debug) { /* ARGSUSED */ return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init"); } /* * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), * tell the compressor to rekey. Note that we MUST NOT rekey for * every CCP Reset-Request; we only rekey on the next xmit packet. * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. * So, rekeying for every CCP Reset-Request is broken as the peer will not * know how many times we've rekeyed. (If we rekey and THEN get another * CCP Reset-Request, we must rekey again.) */ static void mppe_comp_reset(void *arg) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; state->bits |= MPPE_BIT_FLUSHED; } /* * Compress (encrypt) a packet. * It's strange to call this a compressor, since the output is always * MPPE_OVHD + 2 bytes larger than the input. */ static int mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, int isize, int osize) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; struct blkcipher_desc desc = { .tfm = state->arc4 }; int proto; struct scatterlist sg_in[1], sg_out[1]; /* * Check that the protocol is in the range we handle. */ proto = PPP_PROTOCOL(ibuf); if (proto < 0x0021 || proto > 0x00fa) return 0; /* Make sure we have enough room to generate an encrypted packet. */ if (osize < isize + MPPE_OVHD + 2) { /* Drop the packet if we should encrypt it, but can't. */ printk(KERN_DEBUG "mppe_compress[%d]: osize too small! " "(have: %d need: %d)\n", state->unit, osize, osize + MPPE_OVHD + 2); return -1; } osize = isize + MPPE_OVHD + 2; /* * Copy over the PPP header and set control bits. */ obuf[0] = PPP_ADDRESS(ibuf); obuf[1] = PPP_CONTROL(ibuf); obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */ obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */ obuf += PPP_HDRLEN; state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; if (state->debug >= 7) printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit, state->ccount); obuf[0] = state->ccount >> 8; obuf[1] = state->ccount & 0xff; if (!state->stateful || /* stateless mode */ ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ /* We must rekey */ if (state->debug && state->stateful) printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n", state->unit); mppe_rekey(state, 0); state->bits |= MPPE_BIT_FLUSHED; } obuf[0] |= state->bits; state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ obuf += MPPE_OVHD; ibuf += 2; /* skip to proto field */ isize -= 2; /* Encrypt packet */ sg_init_table(sg_in, 1); sg_init_table(sg_out, 1); setup_sg(sg_in, ibuf, isize); setup_sg(sg_out, obuf, osize); if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) { printk(KERN_DEBUG "crypto_cypher_encrypt failed\n"); return -1; } state->stats.unc_bytes += isize; state->stats.unc_packets++; state->stats.comp_bytes += osize; state->stats.comp_packets++; return osize; } /* * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going * to look bad ... and the longer the link is up the worse it will get. */ static void mppe_comp_stats(void *arg, struct compstat *stats) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; *stats = state->stats; } static int mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit, int hdrlen, int mru, int debug) { /* ARGSUSED */ return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init"); } /* * We received a CCP Reset-Ack. Just ignore it. */ static void mppe_decomp_reset(void *arg) { /* ARGSUSED */ return; } /* * Decompress (decrypt) an MPPE packet. */ static int mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, int osize) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; struct blkcipher_desc desc = { .tfm = state->arc4 }; unsigned ccount; int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; int sanity = 0; struct scatterlist sg_in[1], sg_out[1]; if (isize <= PPP_HDRLEN + MPPE_OVHD) { if (state->debug) printk(KERN_DEBUG "mppe_decompress[%d]: short pkt (%d)\n", state->unit, isize); return DECOMP_ERROR; } /* * Make sure we have enough room to decrypt the packet. * Note that for our test we only subtract 1 byte whereas in * mppe_compress() we added 2 bytes (+MPPE_OVHD); * this is to account for possible PFC. */ if (osize < isize - MPPE_OVHD - 1) { printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! " "(have: %d need: %d)\n", state->unit, osize, isize - MPPE_OVHD - 1); return DECOMP_ERROR; } osize = isize - MPPE_OVHD - 2; /* assume no PFC */ ccount = MPPE_CCOUNT(ibuf); if (state->debug >= 7) printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", state->unit, ccount); /* sanity checks -- terminate with extreme prejudice */ if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) { printk(KERN_DEBUG "mppe_decompress[%d]: ENCRYPTED bit not set!\n", state->unit); state->sanity_errors += 100; sanity = 1; } if (!state->stateful && !flushed) { printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in " "stateless mode!\n", state->unit); state->sanity_errors += 100; sanity = 1; } if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on " "flag packet!\n", state->unit); state->sanity_errors += 100; sanity = 1; } if (sanity) { if (state->sanity_errors < SANITY_MAX) return DECOMP_ERROR; else /* * Take LCP down if the peer is sending too many bogons. * We don't want to do this for a single or just a few * instances since it could just be due to packet corruption. */ return DECOMP_FATALERROR; } /* * Check the coherency count. */ if (!state->stateful) { /* RFC 3078, sec 8.1. Rekey for every packet. */ while (state->ccount != ccount) { mppe_rekey(state, 0); state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; } } else { /* RFC 3078, sec 8.2. */ if (!state->discard) { /* normal state */ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; if (ccount != state->ccount) { /* * (ccount > state->ccount) * Packet loss detected, enter the discard state. * Signal the peer to rekey (by sending a CCP Reset-Request). */ state->discard = 1; return DECOMP_ERROR; } } else { /* discard state */ if (!flushed) { /* ccp.c will be silent (no additional CCP Reset-Requests). */ return DECOMP_ERROR; } else { /* Rekey for every missed "flag" packet. */ while ((ccount & ~0xff) != (state->ccount & ~0xff)) { mppe_rekey(state, 0); state->ccount = (state->ccount + 256) % MPPE_CCOUNT_SPACE; } /* reset */ state->discard = 0; state->ccount = ccount; /* * Another problem with RFC 3078 here. It implies that the * peer need not send a Reset-Ack packet. But RFC 1962 * requires it. Hopefully, M$ does send a Reset-Ack; even * though it isn't required for MPPE synchronization, it is * required to reset CCP state. */ } } if (flushed) mppe_rekey(state, 0); } /* * Fill in the first part of the PPP header. The protocol field * comes from the decrypted data. */ obuf[0] = PPP_ADDRESS(ibuf); /* +1 */ obuf[1] = PPP_CONTROL(ibuf); /* +1 */ obuf += 2; ibuf += PPP_HDRLEN + MPPE_OVHD; isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */ /* net osize: isize-4 */ /* * Decrypt the first byte in order to check if it is * a compressed or uncompressed protocol field. */ sg_init_table(sg_in, 1); sg_init_table(sg_out, 1); setup_sg(sg_in, ibuf, 1); setup_sg(sg_out, obuf, 1); if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) { printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); return DECOMP_ERROR; } /* * Do PFC decompression. * This would be nicer if we were given the actual sk_buff * instead of a char *. */ if ((obuf[0] & 0x01) != 0) { obuf[1] = obuf[0]; obuf[0] = 0; obuf++; osize++; } /* And finally, decrypt the rest of the packet. */ setup_sg(sg_in, ibuf + 1, isize - 1); setup_sg(sg_out, obuf + 1, osize - 1); if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) { printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); return DECOMP_ERROR; } state->stats.unc_bytes += osize; state->stats.unc_packets++; state->stats.comp_bytes += isize; state->stats.comp_packets++; /* good packet credit */ state->sanity_errors >>= 1; return osize; } /* * Incompressible data has arrived (this should never happen!). * We should probably drop the link if the protocol is in the range * of what should be encrypted. At the least, we should drop this * packet. (How to do this?) */ static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; if (state->debug && (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa)) printk(KERN_DEBUG "mppe_incomp[%d]: incompressible (unencrypted) data! " "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf)); state->stats.inc_bytes += icnt; state->stats.inc_packets++; state->stats.unc_bytes += icnt; state->stats.unc_packets++; } /************************************************************* * Module interface table *************************************************************/ /* * Procedures exported to if_ppp.c. */ static struct compressor ppp_mppe = { .compress_proto = CI_MPPE, .comp_alloc = mppe_alloc, .comp_free = mppe_free, .comp_init = mppe_comp_init, .comp_reset = mppe_comp_reset, .compress = mppe_compress, .comp_stat = mppe_comp_stats, .decomp_alloc = mppe_alloc, .decomp_free = mppe_free, .decomp_init = mppe_decomp_init, .decomp_reset = mppe_decomp_reset, .decompress = mppe_decompress, .incomp = mppe_incomp, .decomp_stat = mppe_comp_stats, .owner = THIS_MODULE, .comp_extra = MPPE_PAD, }; /* * ppp_mppe_init() * * Prior to allowing load, try to load the arc4 and sha1 crypto * libraries. The actual use will be allocated later, but * this way the module will fail to insmod if they aren't available. */ static int __init ppp_mppe_init(void) { int answer; if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) && crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC))) return -ENODEV; sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL); if (!sha_pad) return -ENOMEM; sha_pad_init(sha_pad); answer = ppp_register_compressor(&ppp_mppe); if (answer == 0) printk(KERN_INFO "PPP MPPE Compression module registered\n"); else kfree(sha_pad); return answer; } static void __exit ppp_mppe_cleanup(void) { ppp_unregister_compressor(&ppp_mppe); kfree(sha_pad); } module_init(ppp_mppe_init); module_exit(ppp_mppe_cleanup);
/* Main encrypt function * referenced from ceph_aes_encrypt() function * returns length encrypted */ int encrypt_data(const void *key, int length_key, void *to_buffer, const void *from_buffer, size_t *to_length, size_t from_length, char *algo_name){ struct scatterlist scatter_list_src[2]; struct scatterlist scatter_list_dest[1]; struct crypto_blkcipher *tfm = crypto_alloc_blkcipher(algo_name, 0, CRYPTO_ALG_ASYNC); struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; size_t null_padding = (0x10 - (from_length & 0x0f)); int return_value = 0; char padding_array[48]; printk("algo_name: %s\n", algo_name); /* check to see if the cipher struct is set properly */ if(IS_ERR(tfm)) { printk("Error in setting tfm\n"); return PTR_ERR(tfm); } memset(padding_array, null_padding, null_padding); *to_length = from_length + null_padding; /* let's set the key for the cipher */ crypto_blkcipher_setkey((void *)tfm, key, length_key); sg_init_table(scatter_list_src, 2); sg_set_buf(&scatter_list_src[0], from_buffer, from_length); sg_set_buf(&scatter_list_src[1], padding_array, null_padding); sg_init_table(scatter_list_dest, 1); sg_set_buf(scatter_list_dest, to_buffer,*to_length); /* let's start encrypting */ return_value = crypto_blkcipher_encrypt(&desc, scatter_list_dest, scatter_list_src, from_length + null_padding); /* free up the blk cipher */ crypto_free_blkcipher(tfm); if (return_value < 0) { printk(KERN_CRIT "crypto_blcipher encryption failed with errno %d.\n",return_value); } return return_value; } int decrypt_data(const void *key, int length_key, void *to_buffer, const void *from_buffer, size_t *to_length, size_t from_length, char *algo_name) { int return_value =0; int end_element; char padding_array[48]; struct scatterlist scatter_list_src[1]; struct scatterlist scatter_list_dest[2]; struct crypto_blkcipher *tfm = crypto_alloc_blkcipher(algo_name, 0, CRYPTO_ALG_ASYNC); struct blkcipher_desc desc = { .tfm = tfm }; printk("algo_name: %s\n", algo_name); /* check to see if the cipher struct is set properly */ if(IS_ERR(tfm)) { return PTR_ERR(tfm); } /* Setting the key for Block cipher */ crypto_blkcipher_setkey((void *)tfm, key, length_key); sg_init_table(scatter_list_src, 1); sg_init_table(scatter_list_dest, 2); sg_set_buf(scatter_list_src, from_buffer, from_length); sg_set_buf(&scatter_list_dest[0], to_buffer, *to_length); sg_set_buf(&scatter_list_dest[1], padding_array, sizeof(padding_array)); /* let's decrypt using crypto_blkcipher */ return_value = crypto_blkcipher_decrypt(&desc, scatter_list_dest, scatter_list_src, from_length); /* Free up the blk cipher */ crypto_free_blkcipher(tfm); if (return_value < 0) { printk(KERN_CRIT "crypto_blcipher decryption failed 1.\n"); return return_value; } if (from_length <= *to_length) end_element = ((char *)to_buffer)[from_length - 1]; else end_element = padding_array[from_length - *to_length - 1]; if (end_element <= 16 && from_length >= end_element) { *to_length = from_length - end_element; } else { printk(KERN_CRIT "crypto_blcipher decryption failed 2.\n"); return -EPERM; //bad padding } return return_value; }
static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct prism2_wep_data *wep = priv; u32 klen, len; u8 key[WEP_KEY_LEN + 3]; u8 *pos; cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; #endif u32 crc; u8 *icv; struct scatterlist sg; if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || skb->len < hdr_len) return -1; len = skb->len - hdr_len; pos = skb_push(skb, 4); memmove(pos, pos + 4, hdr_len); pos += hdr_len; klen = 3 + wep->key_len; wep->iv++; if ((wep->iv & 0xff00) == 0xff00) { u8 B = (wep->iv >> 16) & 0xff; if (B >= 3 && B < klen) wep->iv += 0x0100; } *pos++ = key[0] = (wep->iv >> 16) & 0xff; *pos++ = key[1] = (wep->iv >> 8) & 0xff; *pos++ = key[2] = wep->iv & 0xff; *pos++ = wep->key_idx << 6; memcpy(key + 3, wep->key, wep->key_len); if (!tcb_desc->bHwSec) { #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) crc = ~crc32_le(~0, pos, len); #else crc = ~ether_crc_le(len, pos); #endif icv = skb_put(skb, 4); icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; icv[3] = crc >> 24; #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) crypto_cipher_setkey(wep->tfm, key, klen); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = len + 4; crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); return 0; #else crypto_blkcipher_setkey(wep->tx_tfm, key, klen); #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = len + 4; #else sg_init_one(&sg, pos, len+4); #endif return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); #endif }
/* Perform WEP encryption on given skb that has at least 4 bytes of headroom * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, * so the payload length increases with 8 bytes. * * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) */ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct prism2_wep_data *wep = priv; u32 klen, len; u8 key[WEP_KEY_LEN + 3]; u8 *pos; cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; #endif u32 crc; u8 *icv; struct scatterlist sg; if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || skb->len < hdr_len) return -1; len = skb->len - hdr_len; pos = skb_push(skb, 4); memmove(pos, pos + 4, hdr_len); pos += hdr_len; klen = 3 + wep->key_len; wep->iv++; /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) * can be used to speedup attacks, so avoid using them. */ if ((wep->iv & 0xff00) == 0xff00) { u8 B = (wep->iv >> 16) & 0xff; if (B >= 3 && B < klen) wep->iv += 0x0100; } /* Prepend 24-bit IV to RC4 key and TX frame */ *pos++ = key[0] = (wep->iv >> 16) & 0xff; *pos++ = key[1] = (wep->iv >> 8) & 0xff; *pos++ = key[2] = wep->iv & 0xff; *pos++ = wep->key_idx << 6; /* Copy rest of the WEP key (the secret part) */ memcpy(key + 3, wep->key, wep->key_len); if (!tcb_desc->bHwSec) { /* Append little-endian CRC32 and encrypt it to produce ICV */ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) crc = ~crc32_le(~0, pos, len); #else crc = ~ether_crc_le(len, pos); #endif icv = skb_put(skb, 4); icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; icv[3] = crc >> 24; #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) crypto_cipher_setkey(wep->tfm, key, klen); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = len + 4; crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); return 0; #else crypto_blkcipher_setkey(wep->tx_tfm, key, klen); #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = len + 4; #else sg_init_one(&sg, pos, len+4); #endif return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); #endif }
void test_aes(void) { struct crypto_blkcipher *tfm; struct blkcipher_desc desc; u32 bs; int i,j; u32 npages; struct scatterlist *src; struct scatterlist *dst; char *buf; char **ins, **outs; unsigned int ret; u8 key[] = {0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x12}; npages = MAX_BLK_SIZE/PAGE_SIZE; src = kmalloc(npages*sizeof(struct scatterlist), __GFP_ZERO|GFP_KERNEL); if (!src) { printk("taes ERROR: failed to alloc src\n"); return; } dst = kmalloc(npages*sizeof(struct scatterlist), __GFP_ZERO|GFP_KERNEL); if (!dst) { printk("taes ERROR: failed to alloc dst\n"); kfree(src); return; } ins = kmalloc(npages*sizeof(char*), __GFP_ZERO|GFP_KERNEL); if (!ins) { printk("taes ERROR: failed to alloc ins\n"); kfree(src); kfree(dst); return; } outs = kmalloc(npages*sizeof(char*), __GFP_ZERO|GFP_KERNEL); if (!outs) { printk("taes ERROR: failed to alloc outs\n"); kfree(src); kfree(dst); kfree(ins); return; } tfm = crypto_alloc_blkcipher(CIPHER, 0, 0); if (IS_ERR(tfm)) { printk("failed to load transform for %s: %ld\n", CIPHER, PTR_ERR(tfm)); goto out; } desc.tfm = tfm; desc.flags = 0; ret = crypto_blkcipher_setkey(tfm, key, sizeof(key)); if (ret) { printk("setkey() failed flags=%x\n", crypto_blkcipher_get_flags(tfm)); goto out; } sg_init_table(src, npages); for (i=0; i<npages; i++) { buf = (void *)__get_free_page(GFP_KERNEL); if (!buf) { printk("taes ERROR: alloc free page error\n"); goto free_err_pages; } ins[i] = buf; strcpy(buf, "this is a plain text!"); sg_set_buf(src+i, buf, PAGE_SIZE); buf = (void *)__get_free_page(GFP_KERNEL); if (!buf) { printk("taes ERROR: alloc free page error\n"); goto free_err_pages; } outs[i] = buf; sg_set_buf(dst+i, buf, PAGE_SIZE); } for (bs = MAX_BLK_SIZE; bs >= MIN_BLK_SIZE; bs>>=1) { struct timeval t0, t1; long int enc, dec; do_gettimeofday(&t0); for (j=0; j<TEST_TIMES; j++) { ret = crypto_blkcipher_encrypt(&desc, dst, src, bs); if (ret) { printk("taes ERROR: enc error\n"); goto free_err_pages; } } do_gettimeofday(&t1); enc = 1000000*(t1.tv_sec-t0.tv_sec) + ((int)(t1.tv_usec) - (int)(t0.tv_usec)); do_gettimeofday(&t0); for (j=0; j<TEST_TIMES; j++) { ret = crypto_blkcipher_decrypt(&desc, src, dst, bs); if (ret) { printk("taes ERROR: dec error\n"); goto free_err_pages; } } do_gettimeofday(&t1); dec = 1000000*(t1.tv_sec-t0.tv_sec) + ((int)(t1.tv_usec) - (int)(t0.tv_usec)); printk("Size %u, enc %ld, dec %ld\n", bs, enc, dec); } free_err_pages: for (i=0; i<npages && ins[i]; i++){ free_page((unsigned long)ins[i]); } for (i=0; i<npages && outs[i]; i++){ free_page((unsigned long)outs[i]); } out: kfree(src); kfree(dst); kfree(ins); kfree(outs); crypto_free_blkcipher(tfm); }
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 aml_keybox_aes_encrypt(const void *key, int key_len, const u8 *aes_iv, void *dst, size_t *dst_len, const void *src, size_t src_len) { struct scatterlist sg_in[1], sg_out[1]; struct crypto_blkcipher *tfm = aml_keybox_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; int ret; void *iv; int ivsize; if(src_len & 0x0f){ printk("%s:%d,src_len %d is not 16byte align",__func__,__LINE__,src_len); return -1; } if (IS_ERR(tfm)){ printk("%s:%d,crypto_alloc fail\n",__func__,__LINE__); return PTR_ERR(tfm); } *dst_len = src_len ; crypto_blkcipher_setkey((void *) tfm, key, key_len); sg_init_table(sg_in, 1); sg_set_buf(&sg_in[0], src, src_len); sg_init_table(sg_out, 1); sg_set_buf(sg_out, dst, *dst_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); //printk("key_len:%d,ivsize:%d\n",key_len,ivsize); memcpy(iv, aes_iv, ivsize); ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,src_len); crypto_free_blkcipher(tfm); if (ret < 0){ printk("%s:%d,ceph_aes_crypt failed %d\n", __func__,__LINE__,ret); return ret; } return 0; } static int aml_keybox_aes_decrypt(const void *key, int key_len, const u8 *aes_iv, void *dst, size_t *dst_len, const void *src, size_t src_len) { struct scatterlist sg_in[1], sg_out[1]; struct crypto_blkcipher *tfm = aml_keybox_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm }; void *iv; int ivsize; int ret; // int last_byte; if(src_len &0x0f){ printk("%s:%d,src_len %d is not 16byte align",__func__,__LINE__,src_len); return -1; } if (IS_ERR(tfm)){ printk("%s:%d,crypto_alloc fail\n",__func__,__LINE__); return PTR_ERR(tfm); } crypto_blkcipher_setkey((void *) tfm, key, key_len); sg_init_table(sg_in, 1); sg_init_table(sg_out, 1); sg_set_buf(sg_in, src, src_len); sg_set_buf(&sg_out[0], dst, *dst_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); //printk("key_len:%d,ivsize:%d\n",key_len,ivsize); memcpy(iv, aes_iv, ivsize); ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len); crypto_free_blkcipher(tfm); if (ret < 0){ printk("%s:%d,ceph_aes_decrypt failed %d\n", __func__,__LINE__,ret); return ret; } *dst_len = src_len; return 0; } int aes_crypto_encrypt(void *dst,size_t *dst_len,const void *src,size_t src_len) { int ret; unsigned char iv_aes[16]; unsigned char key_aes[32]; memcpy(iv_aes,&default_AESkey[0],16); memcpy(key_aes,&default_AESkey[16],32); ret = aml_keybox_aes_encrypt(key_aes,sizeof(key_aes),iv_aes,dst,dst_len,src,src_len); return ret; }
/* * CC-MAC function WUSB1.0[6.5] * * Take a data string and produce the encrypted CBC Counter-mode MIC * * Note the names for most function arguments are made to (more or * less) match those used in the pseudo-function definition given in * WUSB1.0[6.5]. * * @tfm_cbc: CBC(AES) blkcipher handle (initialized) * * @tfm_aes: AES cipher handle (initialized) * * @mic: buffer for placing the computed MIC (Message Integrity * Code). This is exactly 8 bytes, and we expect the buffer to * be at least eight bytes in length. * * @key: 128 bit symmetric key * * @n: CCM nonce * * @a: ASCII string, 14 bytes long (I guess zero padded if needed; * we use exactly 14 bytes). * * @b: data stream to be processed; cannot be a global or const local * (will confuse the scatterlists) * * @blen: size of b... * * Still not very clear how this is done, but looks like this: we * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we * take the payload and divide it in blocks (16 bytes), xor them with * the previous crypto result (16 bytes) and crypt it, repeat the next * block with the output of the previous one, rinse wash (I guess this * is what AES CBC mode means...but I truly have no idea). So we use * the CBC(AES) blkcipher, that does precisely that. The IV (Initial * Vector) is 16 bytes and is set to zero, so * * See rfc3610. Linux crypto has a CBC implementation, but the * documentation is scarce, to say the least, and the example code is * so intricated that is difficult to understand how things work. Most * of this is guess work -- bite me. * * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and * using the 14 bytes of @a to fill up * b1.{mac_header,e0,security_reserved,padding}. * * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of * l(m) is orthogonal, they bear no relationship, so it is not * in conflict with the parameter's relation that * WUSB1.0[6.4.2]) defines. * * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in * first errata released on 2005/07. * * NOTE: we need to clean IV to zero at each invocation to make sure * we start with a fresh empty Initial Vector, so that the CBC * works ok. * * NOTE: blen is not aligned to a block size, we'll pad zeros, that's * what sg[4] is for. Maybe there is a smarter way to do this. */ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, struct crypto_cipher *tfm_aes, void *mic, const struct aes_ccm_nonce *n, const struct aes_ccm_label *a, const void *b, size_t blen) { int result = 0; struct blkcipher_desc desc; struct aes_ccm_b0 b0; struct aes_ccm_b1 b1; struct aes_ccm_a ax; struct scatterlist sg[4], sg_dst; void *iv, *dst_buf; size_t ivsize, dst_size; const u8 bzero[16] = { 0 }; size_t zero_padding; /* * These checks should be compile time optimized out * ensure @a fills b1's mac_header and following fields */ WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la)); WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block)); WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block)); WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block)); result = -ENOMEM; zero_padding = sizeof(struct aes_ccm_block) - blen % sizeof(struct aes_ccm_block); zero_padding = blen % sizeof(struct aes_ccm_block); if (zero_padding) zero_padding = sizeof(struct aes_ccm_block) - zero_padding; dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; dst_buf = kzalloc(dst_size, GFP_KERNEL); if (dst_buf == NULL) { printk(KERN_ERR "E: can't alloc destination buffer\n"); goto error_dst_buf; } iv = crypto_blkcipher_crt(tfm_cbc)->iv; ivsize = crypto_blkcipher_ivsize(tfm_cbc); memset(iv, 0, ivsize); /* Setup B0 */ b0.flags = 0x59; /* Format B0 */ b0.ccm_nonce = *n; b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ /* Setup B1 * * The WUSB spec is anything but clear! WUSB1.0[6.5] * says that to initialize B1 from A with 'l(a) = blen + * 14'--after clarification, it means to use A's contents * for MAC Header, EO, sec reserved and padding. */ b1.la = cpu_to_be16(blen + 14); memcpy(&b1.mac_header, a, sizeof(*a)); sg_init_table(sg, ARRAY_SIZE(sg)); sg_set_buf(&sg[0], &b0, sizeof(b0)); sg_set_buf(&sg[1], &b1, sizeof(b1)); sg_set_buf(&sg[2], b, blen); /* 0 if well behaved :) */ sg_set_buf(&sg[3], bzero, zero_padding); sg_init_one(&sg_dst, dst_buf, dst_size); desc.tfm = tfm_cbc; desc.flags = 0; result = crypto_blkcipher_encrypt(&desc, &sg_dst, sg, dst_size); if (result < 0) { printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n", result); goto error_cbc_crypt; } /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5] * The procedure is to AES crypt the A0 block and XOR the MIC * Tag against it; we only do the first 8 bytes and place it * directly in the destination buffer. * * POS Crypto API: size is assumed to be AES's block size. * Thanks for documenting it -- tip taken from airo.c */ ax.flags = 0x01; /* as per WUSB 1.0 spec */ ax.ccm_nonce = *n; ax.counter = 0; crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); bytewise_xor(mic, &ax, iv, 8); result = 8; error_cbc_crypt: kfree(dst_buf); error_dst_buf: return result; }
static int echainiv_encrypt(struct aead_request *req) { struct crypto_aead *geniv = crypto_aead_reqtfm(req); struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); struct aead_request *subreq = aead_request_ctx(req); crypto_completion_t compl; void *data; u8 *info; unsigned int ivsize = crypto_aead_ivsize(geniv); int err; if (req->cryptlen < ivsize) return -EINVAL; aead_request_set_tfm(subreq, ctx->geniv.child); compl = echainiv_encrypt_complete; data = req; info = req->iv; if (req->src != req->dst) { struct blkcipher_desc desc = { .tfm = ctx->null, }; err = crypto_blkcipher_encrypt( &desc, req->dst, req->src, req->assoclen + req->cryptlen); if (err) return err; } if (unlikely(!IS_ALIGNED((unsigned long)info, crypto_aead_alignmask(geniv) + 1))) { info = kmalloc(ivsize, req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: GFP_ATOMIC); if (!info) return -ENOMEM; memcpy(info, req->iv, ivsize); } aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->dst, req->dst, req->cryptlen - ivsize, info); aead_request_set_ad(subreq, req->assoclen + ivsize); crypto_xor(info, ctx->salt, ivsize); scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); echainiv_read_iv(info, ivsize); err = crypto_aead_encrypt(subreq); echainiv_encrypt_complete2(req, err); return err; } static int echainiv_decrypt(struct aead_request *req) { struct crypto_aead *geniv = crypto_aead_reqtfm(req); struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); struct aead_request *subreq = aead_request_ctx(req); crypto_completion_t compl; void *data; unsigned int ivsize = crypto_aead_ivsize(geniv); if (req->cryptlen < ivsize + crypto_aead_authsize(geniv)) return -EINVAL; aead_request_set_tfm(subreq, ctx->geniv.child); compl = req->base.complete; data = req->base.data; aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen - ivsize, req->iv); aead_request_set_ad(subreq, req->assoclen + ivsize); scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); if (req->src != req->dst) scatterwalk_map_and_copy(req->iv, req->dst, req->assoclen, ivsize, 1); return crypto_aead_decrypt(subreq); } static int echainiv_init(struct crypto_tfm *tfm) { struct crypto_aead *geniv = __crypto_aead_cast(tfm); struct echainiv_ctx *ctx = crypto_aead_ctx(geniv); int err; spin_lock_init(&ctx->geniv.lock); crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); err = crypto_get_default_rng(); if (err) goto out; err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, crypto_aead_ivsize(geniv)); crypto_put_default_rng(); if (err) goto out; ctx->null = crypto_get_default_null_skcipher(); err = PTR_ERR(ctx->null); if (IS_ERR(ctx->null)) goto out; err = aead_geniv_init(tfm); if (err) goto drop_null; ctx->geniv.child = geniv->child; geniv->child = geniv; out: return err; drop_null: crypto_put_default_null_skcipher(); goto out; } static void echainiv_exit(struct crypto_tfm *tfm) { struct echainiv_ctx *ctx = crypto_tfm_ctx(tfm); crypto_free_aead(ctx->geniv.child); crypto_put_default_null_skcipher(); } static int echainiv_aead_create(struct crypto_template *tmpl, struct rtattr **tb) { struct aead_instance *inst; struct crypto_aead_spawn *spawn; struct aead_alg *alg; int err; inst = aead_geniv_alloc(tmpl, tb, 0, 0); if (IS_ERR(inst)) return PTR_ERR(inst); spawn = aead_instance_ctx(inst); alg = crypto_spawn_aead_alg(spawn); if (alg->base.cra_aead.encrypt) goto done; err = -EINVAL; if (inst->alg.ivsize & (sizeof(u32) - 1) || inst->alg.ivsize > MAX_IV_SIZE) goto free_inst; inst->alg.encrypt = echainiv_encrypt; inst->alg.decrypt = echainiv_decrypt; inst->alg.base.cra_init = echainiv_init; inst->alg.base.cra_exit = echainiv_exit; inst->alg.base.cra_alignmask |= __alignof__(u32) - 1; inst->alg.base.cra_ctxsize = sizeof(struct echainiv_ctx); inst->alg.base.cra_ctxsize += inst->alg.ivsize; done: err = aead_register_instance(tmpl, inst); if (err) goto free_inst; out: return err; free_inst: aead_geniv_free(inst); goto out; } static void echainiv_free(struct crypto_instance *inst) { aead_geniv_free(aead_instance(inst)); }
static int ceph_aes_encrypt(const void *key, int key_len, void *dst, size_t *dst_len, const void *src, size_t src_len) { struct scatterlist sg_in[2], sg_out[1]; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; int ret; void *iv; int ivsize; size_t zero_padding = (0x10 - (src_len & 0x0f)); char pad[16]; if (IS_ERR(tfm)) return PTR_ERR(tfm); memset(pad, zero_padding, zero_padding); *dst_len = src_len + zero_padding; crypto_blkcipher_setkey((void *)tfm, key, key_len); sg_init_table(sg_in, 2); sg_set_buf(&sg_in[0], src, src_len); sg_set_buf(&sg_in[1], pad, zero_padding); sg_init_table(sg_out, 1); sg_set_buf(sg_out, dst, *dst_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); memcpy(iv, aes_iv, ivsize); ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, src_len + zero_padding); crypto_free_blkcipher(tfm); if (ret < 0) pr_err("ceph_aes_crypt failed %d\n", ret); return 0; } static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, size_t *dst_len, const void *src1, size_t src1_len, const void *src2, size_t src2_len) { struct scatterlist sg_in[3], sg_out[1]; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; int ret; void *iv; int ivsize; size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f)); char pad[16]; if (IS_ERR(tfm)) return PTR_ERR(tfm); memset(pad, zero_padding, zero_padding); *dst_len = src1_len + src2_len + zero_padding; crypto_blkcipher_setkey((void *)tfm, key, key_len); sg_init_table(sg_in, 3); sg_set_buf(&sg_in[0], src1, src1_len); sg_set_buf(&sg_in[1], src2, src2_len); sg_set_buf(&sg_in[2], pad, zero_padding); sg_init_table(sg_out, 1); sg_set_buf(sg_out, dst, *dst_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); memcpy(iv, aes_iv, ivsize); ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, src1_len + src2_len + zero_padding); crypto_free_blkcipher(tfm); if (ret < 0) pr_err("ceph_aes_crypt2 failed %d\n", ret); return 0; } static int ceph_aes_decrypt(const void *key, int key_len, void *dst, size_t *dst_len, const void *src, size_t src_len) { struct scatterlist sg_in[1], sg_out[2]; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm }; char pad[16]; void *iv; int ivsize; int ret; int last_byte; if (IS_ERR(tfm)) return PTR_ERR(tfm); crypto_blkcipher_setkey((void *)tfm, key, key_len); sg_init_table(sg_in, 1); sg_init_table(sg_out, 2); sg_set_buf(sg_in, src, src_len); sg_set_buf(&sg_out[0], dst, *dst_len); sg_set_buf(&sg_out[1], pad, sizeof(pad)); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); memcpy(iv, aes_iv, ivsize); ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len); crypto_free_blkcipher(tfm); if (ret < 0) { pr_err("ceph_aes_decrypt failed %d\n", ret); return ret; } if (src_len <= *dst_len) last_byte = ((char *)dst)[src_len - 1]; else last_byte = pad[src_len - *dst_len - 1]; if (last_byte <= 16 && src_len >= last_byte) { *dst_len = src_len - last_byte; } else { pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n", last_byte, (int)src_len); return -EPERM; } return 0; } static int ceph_aes_decrypt2(const void *key, int key_len, void *dst1, size_t *dst1_len, void *dst2, size_t *dst2_len, const void *src, size_t src_len) { struct scatterlist sg_in[1], sg_out[3]; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm }; char pad[16]; void *iv; int ivsize; int ret; int last_byte; if (IS_ERR(tfm)) return PTR_ERR(tfm); sg_init_table(sg_in, 1); sg_set_buf(sg_in, src, src_len); sg_init_table(sg_out, 3); sg_set_buf(&sg_out[0], dst1, *dst1_len); sg_set_buf(&sg_out[1], dst2, *dst2_len); sg_set_buf(&sg_out[2], pad, sizeof(pad)); crypto_blkcipher_setkey((void *)tfm, key, key_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); memcpy(iv, aes_iv, ivsize); ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len); crypto_free_blkcipher(tfm); if (ret < 0) { pr_err("ceph_aes_decrypt failed %d\n", ret); return ret; } if (src_len <= *dst1_len) last_byte = ((char *)dst1)[src_len - 1]; else if (src_len <= *dst1_len + *dst2_len) last_byte = ((char *)dst2)[src_len - *dst1_len - 1]; else last_byte = pad[src_len - *dst1_len - *dst2_len - 1]; if (last_byte <= 16 && src_len >= last_byte) { src_len -= last_byte; } else { pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n", last_byte, (int)src_len); return -EPERM; } if (src_len < *dst1_len) { *dst1_len = src_len; *dst2_len = 0; } else { *dst2_len = src_len - *dst1_len; } return 0; } int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, const void *src, size_t src_len) { switch (secret->type) { case CEPH_CRYPTO_NONE: if (*dst_len < src_len) return -ERANGE; memcpy(dst, src, src_len); *dst_len = src_len; return 0; case CEPH_CRYPTO_AES: return ceph_aes_decrypt(secret->key, secret->len, dst, dst_len, src, src_len); default: return -EINVAL; } } int ceph_decrypt2(struct ceph_crypto_key *secret, void *dst1, size_t *dst1_len, void *dst2, size_t *dst2_len, const void *src, size_t src_len) { size_t t; switch (secret->type) { case CEPH_CRYPTO_NONE: if (*dst1_len + *dst2_len < src_len) return -ERANGE; t = min(*dst1_len, src_len); memcpy(dst1, src, t); *dst1_len = t; src += t; src_len -= t; if (src_len) { t = min(*dst2_len, src_len); memcpy(dst2, src, t); *dst2_len = t; } return 0; case CEPH_CRYPTO_AES: return ceph_aes_decrypt2(secret->key, secret->len, dst1, dst1_len, dst2, dst2_len, src, src_len); default: return -EINVAL; } } int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, const void *src, size_t src_len) { switch (secret->type) { case CEPH_CRYPTO_NONE: if (*dst_len < src_len) return -ERANGE; memcpy(dst, src, src_len); *dst_len = src_len; return 0; case CEPH_CRYPTO_AES: return ceph_aes_encrypt(secret->key, secret->len, dst, dst_len, src, src_len); default: return -EINVAL; } } int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, const void *src1, size_t src1_len, const void *src2, size_t src2_len) { switch (secret->type) { case CEPH_CRYPTO_NONE: if (*dst_len < src1_len + src2_len) return -ERANGE; memcpy(dst, src1, src1_len); memcpy(dst + src1_len, src2, src2_len); *dst_len = src1_len + src2_len; return 0; case CEPH_CRYPTO_AES: return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len, src1, src1_len, src2, src2_len); default: return -EINVAL; } } int ceph_key_instantiate(struct key *key, const void *data, size_t datalen) { struct ceph_crypto_key *ckey; int ret; void *p; ret = -EINVAL; if (datalen <= 0 || datalen > 32767 || !data) goto err; ret = key_payload_reserve(key, datalen); if (ret < 0) goto err; ret = -ENOMEM; ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); if (!ckey) goto err; p = (void *)data; ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen); if (ret < 0) goto err_ckey; key->payload.data = ckey; return 0; err_ckey: kfree(ckey); err: return ret; } int ceph_key_match(const struct key *key, const void *description) { return strcmp(key->description, description) == 0; } void ceph_key_destroy(struct key *key) { struct ceph_crypto_key *ckey = key->payload.data; ceph_crypto_key_destroy(ckey); kfree(ckey); } struct key_type key_type_ceph = { .name = "ceph", .instantiate = ceph_key_instantiate, .match = ceph_key_match, .destroy = ceph_key_destroy, }; int ceph_crypto_init(void) { return register_key_type(&key_type_ceph); } void ceph_crypto_shutdown(void) { unregister_key_type(&key_type_ceph); }
static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, struct crypto_cipher *tfm_aes, void *mic, const struct aes_ccm_nonce *n, const struct aes_ccm_label *a, const void *b, size_t blen) { int result = 0; struct blkcipher_desc desc; struct aes_ccm_b0 b0; struct aes_ccm_b1 b1; struct aes_ccm_a ax; struct scatterlist sg[4], sg_dst; void *iv, *dst_buf; size_t ivsize, dst_size; const u8 bzero[16] = { 0 }; size_t zero_padding; WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la)); WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block)); WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block)); WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block)); result = -ENOMEM; zero_padding = sizeof(struct aes_ccm_block) - blen % sizeof(struct aes_ccm_block); zero_padding = blen % sizeof(struct aes_ccm_block); if (zero_padding) zero_padding = sizeof(struct aes_ccm_block) - zero_padding; dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; dst_buf = kzalloc(dst_size, GFP_KERNEL); if (dst_buf == NULL) { printk(KERN_ERR "E: can't alloc destination buffer\n"); goto error_dst_buf; } iv = crypto_blkcipher_crt(tfm_cbc)->iv; ivsize = crypto_blkcipher_ivsize(tfm_cbc); memset(iv, 0, ivsize); b0.flags = 0x59; b0.ccm_nonce = *n; b0.lm = cpu_to_be16(0); b1.la = cpu_to_be16(blen + 14); memcpy(&b1.mac_header, a, sizeof(*a)); sg_init_table(sg, ARRAY_SIZE(sg)); sg_set_buf(&sg[0], &b0, sizeof(b0)); sg_set_buf(&sg[1], &b1, sizeof(b1)); sg_set_buf(&sg[2], b, blen); sg_set_buf(&sg[3], bzero, zero_padding); sg_init_one(&sg_dst, dst_buf, dst_size); desc.tfm = tfm_cbc; desc.flags = 0; result = crypto_blkcipher_encrypt(&desc, &sg_dst, sg, dst_size); if (result < 0) { printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n", result); goto error_cbc_crypt; } ax.flags = 0x01; ax.ccm_nonce = *n; ax.counter = 0; crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); bytewise_xor(mic, &ax, iv, 8); result = 8; error_cbc_crypt: kfree(dst_buf); error_dst_buf: return result; }
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; }