📄 cryptocop.c
字号:
current_out_cdesc->next = ed; current_out_cdesc = ed; } else { /* Set EOP in the current out descriptor since the only active module is * the one needing the EOP. */ current_out_cdesc->dma_descr->out_eop = 1; } } if (cipher_ctx.done && cipher_ctx.active) cipher_ctx.active = 0; if (digest_ctx.done && digest_ctx.active) digest_ctx.active = 0; if (csum_ctx.done && csum_ctx.active) csum_ctx.active = 0; indata_ix += odsc->length; odsc = odsc->next; } /* while (odsc) */ /* Process descriptors. */ DEBUG(printk("cryptocop_setup_dma_list: done parsing operation descriptors\n")); if (cipher_ctx.tcfg && (cipher_ctx.active || !cipher_ctx.done)){ DEBUG_API(printk("cryptocop_setup_dma_list: cipher operation not terminated.\n")); failed = -EINVAL; goto error_cleanup; } if (digest_ctx.tcfg && (digest_ctx.active || !digest_ctx.done)){ DEBUG_API(printk("cryptocop_setup_dma_list: digest operation not terminated.\n")); failed = -EINVAL; goto error_cleanup; } if (csum_ctx.tcfg && (csum_ctx.active || !csum_ctx.done)){ DEBUG_API(printk("cryptocop_setup_dma_list: csum operation not terminated.\n")); failed = -EINVAL; goto error_cleanup; } failed = append_input_descriptors(operation, ¤t_in_cdesc, ¤t_out_cdesc, &cipher_ctx, alloc_flag); if (failed){ DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed)); goto error_cleanup; } failed = append_input_descriptors(operation, ¤t_in_cdesc, ¤t_out_cdesc, &digest_ctx, alloc_flag); if (failed){ DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed)); goto error_cleanup; } failed = append_input_descriptors(operation, ¤t_in_cdesc, ¤t_out_cdesc, &csum_ctx, alloc_flag); if (failed){ DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed)); goto error_cleanup; } DEBUG(printk("cryptocop_setup_dma_list: int_op=0x%p, *int_op=0x%p\n", int_op, *int_op)); (*int_op)->cdesc_out = out_cdesc_head.next; (*int_op)->cdesc_in = in_cdesc_head.next; DEBUG(printk("cryptocop_setup_dma_list: out_cdesc_head=0x%p in_cdesc_head=0x%p\n", (*int_op)->cdesc_out, (*int_op)->cdesc_in)); setup_descr_chain(out_cdesc_head.next); setup_descr_chain(in_cdesc_head.next); /* Last but not least: mark the last DMA in descriptor for a INTR and EOL and the the * last DMA out descriptor for EOL. */ current_in_cdesc->dma_descr->intr = 1; current_in_cdesc->dma_descr->eol = 1; current_out_cdesc->dma_descr->eol = 1; /* Setup DMA contexts. */ (*int_op)->ctx_out.next = NULL; (*int_op)->ctx_out.eol = 1; (*int_op)->ctx_out.intr = 0; (*int_op)->ctx_out.store_mode = 0; (*int_op)->ctx_out.en = 0; (*int_op)->ctx_out.dis = 0; (*int_op)->ctx_out.md0 = 0; (*int_op)->ctx_out.md1 = 0; (*int_op)->ctx_out.md2 = 0; (*int_op)->ctx_out.md3 = 0; (*int_op)->ctx_out.md4 = 0; (*int_op)->ctx_out.saved_data = (dma_descr_data*)virt_to_phys((*int_op)->cdesc_out->dma_descr); (*int_op)->ctx_out.saved_data_buf = (*int_op)->cdesc_out->dma_descr->buf; /* Already physical address. */ (*int_op)->ctx_in.next = NULL; (*int_op)->ctx_in.eol = 1; (*int_op)->ctx_in.intr = 0; (*int_op)->ctx_in.store_mode = 0; (*int_op)->ctx_in.en = 0; (*int_op)->ctx_in.dis = 0; (*int_op)->ctx_in.md0 = 0; (*int_op)->ctx_in.md1 = 0; (*int_op)->ctx_in.md2 = 0; (*int_op)->ctx_in.md3 = 0; (*int_op)->ctx_in.md4 = 0; (*int_op)->ctx_in.saved_data = (dma_descr_data*)virt_to_phys((*int_op)->cdesc_in->dma_descr); (*int_op)->ctx_in.saved_data_buf = (*int_op)->cdesc_in->dma_descr->buf; /* Already physical address. */ DEBUG(printk("cryptocop_setup_dma_list: done\n")); return 0;error_cleanup: { /* Free all allocated resources. */ struct cryptocop_dma_desc *tmp_cdesc; while (digest_ctx.pad_descs){ tmp_cdesc = digest_ctx.pad_descs->next; free_cdesc(digest_ctx.pad_descs); digest_ctx.pad_descs = tmp_cdesc; } while (csum_ctx.pad_descs){ tmp_cdesc = csum_ctx.pad_descs->next; free_cdesc(csum_ctx.pad_descs); csum_ctx.pad_descs = tmp_cdesc; } assert(cipher_ctx.pad_descs == NULL); /* The ciphers are never padded. */ if (*int_op != NULL) delete_internal_operation(*int_op); } DEBUG_API(printk("cryptocop_setup_dma_list: done with error %d\n", failed)); return failed;}static void delete_internal_operation(struct cryptocop_int_operation *iop){ void *ptr = iop->alloc_ptr; struct cryptocop_dma_desc *cd = iop->cdesc_out; struct cryptocop_dma_desc *next; DEBUG(printk("delete_internal_operation: iop=0x%p, alloc_ptr=0x%p\n", iop, ptr)); while (cd) { next = cd->next; free_cdesc(cd); cd = next; } cd = iop->cdesc_in; while (cd) { next = cd->next; free_cdesc(cd); cd = next; } kfree(ptr);}#define MD5_MIN_PAD_LENGTH (9)#define MD5_PAD_LENGTH_FIELD_LENGTH (8)static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length){ size_t padlen = MD5_BLOCK_LENGTH - (hashed_length % MD5_BLOCK_LENGTH); unsigned char *p; int i; unsigned long long int bit_length = hashed_length << 3; if (padlen < MD5_MIN_PAD_LENGTH) padlen += MD5_BLOCK_LENGTH; p = kmalloc(padlen, alloc_flag); if (!pad) return -ENOMEM; *p = 0x80; memset(p+1, 0, padlen - 1); DEBUG(printk("create_md5_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length)); i = padlen - MD5_PAD_LENGTH_FIELD_LENGTH; while (bit_length != 0){ p[i++] = bit_length % 0x100; bit_length >>= 8; } *pad = (char*)p; *pad_length = padlen; return 0;}#define SHA1_MIN_PAD_LENGTH (9)#define SHA1_PAD_LENGTH_FIELD_LENGTH (8)static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length){ size_t padlen = SHA1_BLOCK_LENGTH - (hashed_length % SHA1_BLOCK_LENGTH); unsigned char *p; int i; unsigned long long int bit_length = hashed_length << 3; if (padlen < SHA1_MIN_PAD_LENGTH) padlen += SHA1_BLOCK_LENGTH; p = kmalloc(padlen, alloc_flag); if (!pad) return -ENOMEM; *p = 0x80; memset(p+1, 0, padlen - 1); DEBUG(printk("create_sha1_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length)); i = padlen - 1; while (bit_length != 0){ p[i--] = bit_length % 0x100; bit_length >>= 8; } *pad = (char*)p; *pad_length = padlen; return 0;}static int transform_ok(struct cryptocop_transform_init *tinit){ switch (tinit->alg){ case cryptocop_alg_csum: switch (tinit->csum_mode){ case cryptocop_csum_le: case cryptocop_csum_be: break; default: DEBUG_API(printk("transform_ok: Bad mode set for csum transform\n")); return -EINVAL; } case cryptocop_alg_mem2mem: case cryptocop_alg_md5: case cryptocop_alg_sha1: if (tinit->keylen != 0) { DEBUG_API(printk("transform_ok: non-zero keylength, %d, for a digest/csum algorithm\n", tinit->keylen)); return -EINVAL; /* This check is a bit strict. */ } break; case cryptocop_alg_des: if (tinit->keylen != 64) { DEBUG_API(printk("transform_ok: keylen %d invalid for DES\n", tinit->keylen)); return -EINVAL; } break; case cryptocop_alg_3des: if (tinit->keylen != 192) { DEBUG_API(printk("transform_ok: keylen %d invalid for 3DES\n", tinit->keylen)); return -EINVAL; } break; case cryptocop_alg_aes: if (tinit->keylen != 128 && tinit->keylen != 192 && tinit->keylen != 256) { DEBUG_API(printk("transform_ok: keylen %d invalid for AES\n", tinit->keylen)); return -EINVAL; } break; case cryptocop_no_alg: default: DEBUG_API(printk("transform_ok: no such algorithm %d\n", tinit->alg)); return -EINVAL; } switch (tinit->alg){ case cryptocop_alg_des: case cryptocop_alg_3des: case cryptocop_alg_aes: if (tinit->cipher_mode != cryptocop_cipher_mode_ecb && tinit->cipher_mode != cryptocop_cipher_mode_cbc) return -EINVAL; default: break; } return 0;}int cryptocop_new_session(cryptocop_session_id *sid, struct cryptocop_transform_init *tinit, int alloc_flag){ struct cryptocop_session *sess; struct cryptocop_transform_init *tfrm_in = tinit; struct cryptocop_transform_init *tmp_in; int no_tfrms = 0; int i; unsigned long int flags; init_stream_coprocessor(); /* For safety if we are called early */ while (tfrm_in){ int err; ++no_tfrms; if ((err = transform_ok(tfrm_in))) { DEBUG_API(printk("cryptocop_new_session, bad transform\n")); return err; } tfrm_in = tfrm_in->next; } if (0 == no_tfrms) { DEBUG_API(printk("cryptocop_new_session, no transforms specified\n")); return -EINVAL; } sess = kmalloc(sizeof(struct cryptocop_session), alloc_flag); if (!sess){ DEBUG_API(printk("cryptocop_new_session, kmalloc cryptocop_session\n")); return -ENOMEM; } sess->tfrm_ctx = kmalloc(no_tfrms * sizeof(struct cryptocop_transform_ctx), alloc_flag); if (!sess->tfrm_ctx) { DEBUG_API(printk("cryptocop_new_session, kmalloc cryptocop_transform_ctx\n")); kfree(sess); return -ENOMEM; } tfrm_in = tinit; for (i = 0; i < no_tfrms; i++){ tmp_in = tfrm_in->next; while (tmp_in){ if (tmp_in->tid == tfrm_in->tid) { DEBUG_API(printk("cryptocop_new_session, duplicate transform ids\n")); kfree(sess->tfrm_ctx); kfree(sess); return -EINVAL; } tmp_in = tmp_in->next; } memcpy(&sess->tfrm_ctx[i].init, tfrm_in, sizeof(struct cryptocop_transform_init)); sess->tfrm_ctx[i].dec_key_set = 0; sess->tfrm_ctx[i].next = &sess->tfrm_ctx[i] + 1; tfrm_in = tfrm_in->next; } sess->tfrm_ctx[i-1].next = NULL; spin_lock_irqsave(&cryptocop_sessions_lock, flags); sess->sid = next_sid; next_sid++; /* TODO If we are really paranoid we should do duplicate check to handle sid wraparound. * OTOH 2^64 is a really large number of session. */ if (next_sid == 0) next_sid = 1; /* Prepend to session list. */ sess->next = cryptocop_sessions; cryptocop_sessions = sess; spin_unlock_irqrestore(&cryptocop_sessions_lock, flags); *sid = sess->sid; return 0;}int cryptocop_free_session(cryptocop_session_id sid){ struct cryptocop_transform_ctx *tc; struct cryptocop_session *sess = NULL; struct cryptocop_session *psess = NULL; unsigned long int flags; int i; LIST_HEAD(remove_list); struct list_head *node, *tmp; struct cryptocop_prio_job *pj; DEBUG(printk("cryptocop_free_session: sid=%lld\n", sid)); spin_lock_irqsave(&cryptocop_sessions_lock, flags); sess = cryptocop_sessions; while (sess && sess->sid != sid){ psess = sess; sess = sess->next; } if (sess){ if (psess){ psess->next = sess->next; } else { cryptocop_sessions = sess->next; } } spin_unlock_irqrestore(&cryptocop_sessions_lock, flags); if (!sess) return -EINVAL; /* Remove queued jobs. */ spin_lock_irqsave(&cryptocop_job_queue_lock, flags); for (i = 0; i < cryptocop_prio_no_prios; i++){ if (!list_empty(&(cryptocop_job_queues[i].jobs))){ list_for_each_safe(node, tmp, &(cryptocop_job_queues[i].jobs)) { pj = list_entry(node, struct cryptocop_prio_job, node); if (pj->oper->sid == sid) { list_move_tail(node, &remove_list); } } } } spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags); list_for_each_safe(node, tmp, &remove_list) { list_del(node); pj = list_entry(node, struct cryptocop_prio_job, node); pj->oper->operation_status = -EAGAIN; /* EAGAIN is not ideal for job/session terminated but it's the best choice I know of. */ DEBUG(printk("cryptocop_free_session: pj=0x%p, pj->oper=0x%p, pj->iop=0x%p\n", pj, pj->oper, pj->iop)); pj->oper->cb(pj->oper, pj->oper->cb_data); delete_internal_operation(pj->iop); kfree(pj); } tc = sess->tfrm_ctx; /* Erase keying data. */ while (tc){ DEBUG(printk("cryptocop_free_session: memset keys, tfrm id=%d\n", tc->init.tid)); memset(tc->init.key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH); memset(tc->dec_key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH); tc = tc->next; } kfree(sess->tfrm_ctx); kfree(sess); return 0;}static struct cryptocop_session *get_session(cryptocop_session_id sid){ struct cryptocop_session *sess; unsigned long int flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -