/** * Finish hash calculation, copy hash digest to buffer, clean up hash descriptor * * \param[in] req ahash request * \param[out] hash pointer to hash buffer to store hash digest * \param[in,out] hash_len pointer to hash buffer size, if \a hash == NULL * or hash_len == NULL only free \a hdesc instead * of computing the hash * * \retval 0 for success * \retval -EOVERFLOW if hash_len is too small for the hash digest * \retval negative errno for other errors from lower layers */ int cfs_crypto_hash_final(struct ahash_request *req, unsigned char *hash, unsigned int *hash_len) { int size = crypto_ahash_digestsize(crypto_ahash_reqtfm(req)); int err; if (!hash || !hash_len) { err = 0; goto free; } if (*hash_len < size) { err = -EOVERFLOW; goto free; } ahash_request_set_crypt(req, NULL, hash, 0); err = crypto_ahash_final(req); if (err == 0) *hash_len = size; free: crypto_free_ahash(crypto_ahash_reqtfm(req)); ahash_request_free(req); return err; }
static int gcm_hash_final(struct aead_request *req, struct crypto_gcm_req_priv_ctx *pctx) { struct ahash_request *ahreq = &pctx->u.ahreq; ahash_request_set_callback(ahreq, aead_request_flags(req), gcm_hash_final_done, req); ahash_request_set_crypt(ahreq, NULL, pctx->iauth_tag, 0); return crypto_ahash_final(ahreq); }
int fmpdev_hash_final(struct fmp_info *info, struct hash_data *hdata, void *output) { int ret; reinit_completion(&hdata->async.result->completion); ahash_request_set_crypt(hdata->async.request, NULL, output, 0); ret = crypto_ahash_final(hdata->async.request); return waitfor(info, hdata->async.result, ret); }
static int n2_hash_async_final(struct ahash_request *req) { struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; rctx->fallback_req.result = req->result; return crypto_ahash_final(&rctx->fallback_req); }
static int ghash_async_final(struct ahash_request *req) { struct ahash_request *cryptd_req = ahash_request_ctx(req); if (!irq_fpu_usable()) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; memcpy(cryptd_req, req, sizeof(*req)); ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); return crypto_ahash_final(cryptd_req); } else { struct shash_desc *desc = cryptd_shash_desc(cryptd_req); return crypto_shash_final(desc, req->result); } }
static int calc_buffer_ahash_atfm(const void *buf, loff_t len, struct ima_digest_data *hash, struct crypto_ahash *tfm) { struct ahash_request *req; struct scatterlist sg; struct ahash_completion res; int rc, ahash_rc = 0; hash->length = crypto_ahash_digestsize(tfm); req = ahash_request_alloc(tfm, GFP_KERNEL); if (!req) return -ENOMEM; init_completion(&res.completion); ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, ahash_complete, &res); rc = ahash_wait(crypto_ahash_init(req), &res); if (rc) goto out; sg_init_one(&sg, buf, len); ahash_request_set_crypt(req, &sg, NULL, len); ahash_rc = crypto_ahash_update(req); /* wait for the update request to complete */ rc = ahash_wait(ahash_rc, &res); if (!rc) { ahash_request_set_crypt(req, NULL, hash->digest, 0); rc = ahash_wait(crypto_ahash_final(req), &res); } out: ahash_request_free(req); return rc; }
static int ima_calc_file_hash_atfm(struct file *file, struct ima_digest_data *hash, struct crypto_ahash *tfm) { loff_t i_size, offset; char *rbuf[2] = { NULL, }; int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0; struct ahash_request *req; struct scatterlist sg[1]; struct ahash_completion res; size_t rbuf_size[2]; hash->length = crypto_ahash_digestsize(tfm); req = ahash_request_alloc(tfm, GFP_KERNEL); if (!req) return -ENOMEM; init_completion(&res.completion); ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, ahash_complete, &res); rc = ahash_wait(crypto_ahash_init(req), &res); if (rc) goto out1; i_size = i_size_read(file_inode(file)); if (i_size == 0) goto out2; /* * Try to allocate maximum size of memory. * Fail if even a single page cannot be allocated. */ rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1); if (!rbuf[0]) { rc = -ENOMEM; goto out1; } /* Only allocate one buffer if that is enough. */ if (i_size > rbuf_size[0]) { /* * Try to allocate secondary buffer. If that fails fallback to * using single buffering. Use previous memory allocation size * as baseline for possible allocation size. */ rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0], &rbuf_size[1], 0); } if (!(file->f_mode & FMODE_READ)) { file->f_mode |= FMODE_READ; read = 1; } for (offset = 0; offset < i_size; offset += rbuf_len) { if (!rbuf[1] && offset) { /* Not using two buffers, and it is not the first * read/request, wait for the completion of the * previous ahash_update() request. */ rc = ahash_wait(ahash_rc, &res); if (rc) goto out3; } /* read buffer */ rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); rc = integrity_kernel_read(file, offset, rbuf[active], rbuf_len); if (rc != rbuf_len) goto out3; if (rbuf[1] && offset) { /* Using two buffers, and it is not the first * read/request, wait for the completion of the * previous ahash_update() request. */ rc = ahash_wait(ahash_rc, &res); if (rc) goto out3; } sg_init_one(&sg[0], rbuf[active], rbuf_len); ahash_request_set_crypt(req, sg, NULL, rbuf_len); ahash_rc = crypto_ahash_update(req); if (rbuf[1]) active = !active; /* swap buffers, if we use two */ } /* wait for the last update request to complete */ rc = ahash_wait(ahash_rc, &res); out3: if (read) file->f_mode &= ~FMODE_READ; ima_free_pages(rbuf[0], rbuf_size[0]); ima_free_pages(rbuf[1], rbuf_size[1]); out2: if (!rc) { ahash_request_set_crypt(req, NULL, hash->digest, 0); rc = ahash_wait(crypto_ahash_final(req), &res); } out1: ahash_request_free(req); return rc; }
/** * iscsi_tcp_segment_done - check whether the segment is complete * @tcp_conn: iscsi tcp connection * @segment: iscsi segment to check * @recv: set to one of this is called from the recv path * @copied: number of bytes copied * * Check if we're done receiving this segment. If the receive * buffer is full but we expect more data, move on to the * next entry in the scatterlist. * * If the amount of data we received isn't a multiple of 4, * we will transparently receive the pad bytes, too. * * This function must be re-entrant. */ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment, int recv, unsigned copied) { struct scatterlist sg; unsigned int pad; ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n", segment->copied, copied, segment->size, recv ? "recv" : "xmit"); if (segment->hash && copied) { /* * If a segment is kmapd we must unmap it before sending * to the crypto layer since that will try to kmap it again. */ iscsi_tcp_segment_unmap(segment); if (!segment->data) { sg_init_table(&sg, 1); sg_set_page(&sg, sg_page(segment->sg), copied, segment->copied + segment->sg_offset + segment->sg->offset); } else sg_init_one(&sg, segment->data + segment->copied, copied); ahash_request_set_crypt(segment->hash, &sg, NULL, copied); crypto_ahash_update(segment->hash); } segment->copied += copied; if (segment->copied < segment->size) { iscsi_tcp_segment_map(segment, recv); return 0; } segment->total_copied += segment->copied; segment->copied = 0; segment->size = 0; /* Unmap the current scatterlist page, if there is one. */ iscsi_tcp_segment_unmap(segment); /* Do we have more scatterlist entries? */ ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "total copied %u total size %u\n", segment->total_copied, segment->total_size); if (segment->total_copied < segment->total_size) { /* Proceed to the next entry in the scatterlist. */ iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg), 0); iscsi_tcp_segment_map(segment, recv); BUG_ON(segment->size == 0); return 0; } /* Do we need to handle padding? */ if (!(tcp_conn->iscsi_conn->session->tt->caps & CAP_PADDING_OFFLOAD)) { pad = iscsi_padding(segment->total_copied); if (pad != 0) { ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "consume %d pad bytes\n", pad); segment->total_size += pad; segment->size = pad; segment->data = segment->padbuf; return 0; } } /* * Set us up for transferring the data digest. hdr digest * is completely handled in hdr done function. */ if (segment->hash) { ahash_request_set_crypt(segment->hash, NULL, segment->digest, 0); crypto_ahash_final(segment->hash); iscsi_tcp_segment_splice_digest(segment, recv ? segment->recv_digest : segment->digest); return 0; } return 1; }
static int tegra_crypto_sha(struct tegra_sha_req *sha_req) { struct crypto_ahash *tfm; struct scatterlist sg[1]; char result[64]; struct ahash_request *req; struct tegra_crypto_completion sha_complete; void *hash_buff; unsigned long *xbuf[XBUFSIZE]; int ret = -ENOMEM; tfm = crypto_alloc_ahash(sha_req->algo, 0, 0); if (IS_ERR(tfm)) { printk(KERN_ERR "alg: hash: Failed to load transform for %s: " "%ld\n", sha_req->algo, PTR_ERR(tfm)); goto out_alloc; } req = ahash_request_alloc(tfm, GFP_KERNEL); if (!req) { printk(KERN_ERR "alg: hash: Failed to allocate request for " "%s\n", sha_req->algo); goto out_noreq; } ret = alloc_bufs(xbuf); if (ret < 0) { pr_err("alloc_bufs failed"); goto out_buf; } init_completion(&sha_complete.restart); memset(result, 0, 64); hash_buff = xbuf[0]; memcpy(hash_buff, sha_req->plaintext, sha_req->plaintext_sz); sg_init_one(&sg[0], hash_buff, sha_req->plaintext_sz); if (sha_req->keylen) { crypto_ahash_clear_flags(tfm, ~0); ret = crypto_ahash_setkey(tfm, sha_req->key, sha_req->keylen); if (ret) { printk(KERN_ERR "alg: hash: setkey failed on " " %s: ret=%d\n", sha_req->algo, -ret); goto out; } } ahash_request_set_crypt(req, sg, result, sha_req->plaintext_sz); ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_init(req)); if (ret) { pr_err("alg: hash: init failed on " "for %s: ret=%d\n", sha_req->algo, -ret); goto out; } ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_update(req)); if (ret) { pr_err("alg: hash: update failed on " "for %s: ret=%d\n", sha_req->algo, -ret); goto out; } ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_final(req)); if (ret) { pr_err("alg: hash: final failed on " "for %s: ret=%d\n", sha_req->algo, -ret); goto out; } ret = copy_to_user((void __user *)sha_req->result, (const void *)result, crypto_ahash_digestsize(tfm)); if (ret) { ret = -EFAULT; pr_err("alg: hash: copy_to_user failed (%d) for %s\n", ret, sha_req->algo); } out: free_bufs(xbuf); out_buf: ahash_request_free(req); out_noreq: crypto_free_ahash(tfm); out_alloc: return ret; }
static int hmac_sha_update(const char *algo, char *data_in, size_t dlen, char *hash_out, size_t outlen) { int rc = 0; struct crypto_ahash *tfm; struct scatterlist sg[TVMEMSIZE]; struct ahash_request *req; struct hmac_sha_result tresult; int i, j; /* Set hash output to 0 initially */ memset(hash_out, 0, outlen); init_completion(&tresult.completion); tfm = crypto_alloc_ahash(algo, 0, 0); if (IS_ERR(tfm)) { printk(KERN_ERR "crypto_alloc_ahash failed\n"); rc = PTR_ERR(tfm); goto err_tfm; } req = ahash_request_alloc(tfm, GFP_KERNEL); if (!req) { printk(KERN_ERR "failed to allocate request\n"); rc = -ENOMEM; goto err_req; } if (crypto_ahash_digestsize(tfm) > outlen) { printk(KERN_ERR "tfm size > result buffer\n"); rc = -EINVAL; goto err_req; } ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, hmac_sha_complete, &tresult); sg_init_table(sg, TVMEMSIZE); i = 0; j = dlen; while (j > PAGE_SIZE) { sg_set_buf(sg + i, tvmem[i], PAGE_SIZE); memcpy(tvmem[i], data_in + i * PAGE_SIZE, PAGE_SIZE); i++; j -= PAGE_SIZE; } sg_set_buf(sg + i, tvmem[i], j); memcpy(tvmem[i], data_in + i * PAGE_SIZE, j); crypto_ahash_clear_flags(tfm, -0); ahash_request_set_crypt(req, sg, hash_out, dlen); rc = crypto_ahash_init(req); rc = do_one_ahash_op(req, crypto_ahash_update(req)); if (rc) goto out; rc = do_one_ahash_op(req, crypto_ahash_final(req)); out: ahash_request_free(req); err_req: crypto_free_ahash(tfm); err_tfm: return rc; }