digest.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Cryptographic API.
  3. *
  4. * Digest operations.
  5. *
  6. * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the Free
  10. * Software Foundation; either version 2 of the License, or (at your option)
  11. * any later version.
  12. *
  13. */
  14. #include <crypto/internal/hash.h>
  15. #include <crypto/scatterwalk.h>
  16. #include <linux/mm.h>
  17. #include <linux/errno.h>
  18. #include <linux/hardirq.h>
  19. #include <linux/highmem.h>
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/scatterlist.h>
  23. #include "internal.h"
  24. static int init(struct hash_desc *desc)
  25. {
  26. struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
  27. tfm->__crt_alg->cra_digest.dia_init(tfm);
  28. return 0;
  29. }
  30. static int update2(struct hash_desc *desc,
  31. struct scatterlist *sg, unsigned int nbytes)
  32. {
  33. struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
  34. unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
  35. if (!nbytes)
  36. return 0;
  37. for (;;) {
  38. struct page *pg = sg_page(sg);
  39. unsigned int offset = sg->offset;
  40. unsigned int l = sg->length;
  41. if (unlikely(l > nbytes))
  42. l = nbytes;
  43. nbytes -= l;
  44. do {
  45. unsigned int bytes_from_page = min(l, ((unsigned int)
  46. (PAGE_SIZE)) -
  47. offset);
  48. char *src = crypto_kmap(pg, 0);
  49. char *p = src + offset;
  50. if (unlikely(offset & alignmask)) {
  51. unsigned int bytes =
  52. alignmask + 1 - (offset & alignmask);
  53. bytes = min(bytes, bytes_from_page);
  54. tfm->__crt_alg->cra_digest.dia_update(tfm, p,
  55. bytes);
  56. p += bytes;
  57. bytes_from_page -= bytes;
  58. l -= bytes;
  59. }
  60. tfm->__crt_alg->cra_digest.dia_update(tfm, p,
  61. bytes_from_page);
  62. crypto_kunmap(src, 0);
  63. crypto_yield(desc->flags);
  64. offset = 0;
  65. pg++;
  66. l -= bytes_from_page;
  67. } while (l > 0);
  68. if (!nbytes)
  69. break;
  70. sg = scatterwalk_sg_next(sg);
  71. }
  72. return 0;
  73. }
  74. static int update(struct hash_desc *desc,
  75. struct scatterlist *sg, unsigned int nbytes)
  76. {
  77. if (WARN_ON_ONCE(in_irq()))
  78. return -EDEADLK;
  79. return update2(desc, sg, nbytes);
  80. }
  81. static int final(struct hash_desc *desc, u8 *out)
  82. {
  83. struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
  84. unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
  85. struct digest_alg *digest = &tfm->__crt_alg->cra_digest;
  86. if (unlikely((unsigned long)out & alignmask)) {
  87. unsigned long align = alignmask + 1;
  88. unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
  89. u8 *dst = (u8 *)ALIGN(addr, align) +
  90. ALIGN(tfm->__crt_alg->cra_ctxsize, align);
  91. digest->dia_final(tfm, dst);
  92. memcpy(out, dst, digest->dia_digestsize);
  93. } else
  94. digest->dia_final(tfm, out);
  95. return 0;
  96. }
  97. static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen)
  98. {
  99. crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK);
  100. return -ENOSYS;
  101. }
  102. static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
  103. {
  104. struct crypto_tfm *tfm = crypto_hash_tfm(hash);
  105. crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK);
  106. return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen);
  107. }
  108. static int digest(struct hash_desc *desc,
  109. struct scatterlist *sg, unsigned int nbytes, u8 *out)
  110. {
  111. if (WARN_ON_ONCE(in_irq()))
  112. return -EDEADLK;
  113. init(desc);
  114. update2(desc, sg, nbytes);
  115. return final(desc, out);
  116. }
  117. int crypto_init_digest_ops(struct crypto_tfm *tfm)
  118. {
  119. struct hash_tfm *ops = &tfm->crt_hash;
  120. struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
  121. if (dalg->dia_digestsize > PAGE_SIZE / 8)
  122. return -EINVAL;
  123. ops->init = init;
  124. ops->update = update;
  125. ops->final = final;
  126. ops->digest = digest;
  127. ops->setkey = dalg->dia_setkey ? setkey : nosetkey;
  128. ops->digestsize = dalg->dia_digestsize;
  129. return 0;
  130. }
  131. void crypto_exit_digest_ops(struct crypto_tfm *tfm)
  132. {
  133. }
  134. static int digest_async_nosetkey(struct crypto_ahash *tfm_async, const u8 *key,
  135. unsigned int keylen)
  136. {
  137. crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
  138. return -ENOSYS;
  139. }
  140. static int digest_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
  141. unsigned int keylen)
  142. {
  143. struct crypto_tfm *tfm = crypto_ahash_tfm(tfm_async);
  144. struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
  145. crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
  146. return dalg->dia_setkey(tfm, key, keylen);
  147. }
  148. static int digest_async_init(struct ahash_request *req)
  149. {
  150. struct crypto_tfm *tfm = req->base.tfm;
  151. struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
  152. dalg->dia_init(tfm);
  153. return 0;
  154. }
  155. static int digest_async_update(struct ahash_request *req)
  156. {
  157. struct crypto_tfm *tfm = req->base.tfm;
  158. struct hash_desc desc = {
  159. .tfm = __crypto_hash_cast(tfm),
  160. .flags = req->base.flags,
  161. };
  162. update(&desc, req->src, req->nbytes);
  163. return 0;
  164. }
  165. static int digest_async_final(struct ahash_request *req)
  166. {
  167. struct crypto_tfm *tfm = req->base.tfm;
  168. struct hash_desc desc = {
  169. .tfm = __crypto_hash_cast(tfm),
  170. .flags = req->base.flags,
  171. };
  172. final(&desc, req->result);
  173. return 0;
  174. }
  175. static int digest_async_digest(struct ahash_request *req)
  176. {
  177. struct crypto_tfm *tfm = req->base.tfm;
  178. struct hash_desc desc = {
  179. .tfm = __crypto_hash_cast(tfm),
  180. .flags = req->base.flags,
  181. };
  182. return digest(&desc, req->src, req->nbytes, req->result);
  183. }
  184. int crypto_init_digest_ops_async(struct crypto_tfm *tfm)
  185. {
  186. struct ahash_tfm *crt = &tfm->crt_ahash;
  187. struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
  188. if (dalg->dia_digestsize > PAGE_SIZE / 8)
  189. return -EINVAL;
  190. crt->init = digest_async_init;
  191. crt->update = digest_async_update;
  192. crt->final = digest_async_final;
  193. crt->digest = digest_async_digest;
  194. crt->setkey = dalg->dia_setkey ? digest_async_setkey :
  195. digest_async_nosetkey;
  196. crt->digestsize = dalg->dia_digestsize;
  197. return 0;
  198. }