cipher_aes_ccm_hw_s390x.inc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * Copyright 2001-2019 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. /*-
  10. * S390X support for AES CCM.
  11. * This file is included by cipher_ccm_hw.c
  12. */
  13. #define S390X_CCM_AAD_FLAG 0x40
  14. static int s390x_aes_ccm_initkey(PROV_CCM_CTX *ctx,
  15. const unsigned char *key, size_t keylen)
  16. {
  17. PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
  18. sctx->ccm.s390x.fc = S390X_AES_FC(keylen);
  19. memcpy(&sctx->ccm.s390x.kmac.k, key, keylen);
  20. /* Store encoded m and l. */
  21. sctx->ccm.s390x.nonce.b[0] = ((ctx->l - 1) & 0x7)
  22. | (((ctx->m - 2) >> 1) & 0x7) << 3;
  23. memset(sctx->ccm.s390x.nonce.b + 1, 0, sizeof(sctx->ccm.s390x.nonce.b));
  24. sctx->ccm.s390x.blocks = 0;
  25. ctx->key_set = 1;
  26. return 1;
  27. }
  28. static int s390x_aes_ccm_setiv(PROV_CCM_CTX *ctx,
  29. const unsigned char *nonce, size_t noncelen,
  30. size_t mlen)
  31. {
  32. PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
  33. sctx->ccm.s390x.nonce.b[0] &= ~S390X_CCM_AAD_FLAG;
  34. sctx->ccm.s390x.nonce.g[1] = mlen;
  35. memcpy(sctx->ccm.s390x.nonce.b + 1, nonce, 15 - ctx->l);
  36. return 1;
  37. }
  38. /*-
  39. * Process additional authenticated data. Code is big-endian.
  40. */
  41. static int s390x_aes_ccm_setaad(PROV_CCM_CTX *ctx,
  42. const unsigned char *aad, size_t alen)
  43. {
  44. PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
  45. unsigned char *ptr;
  46. int i, rem;
  47. if (!alen)
  48. return 1;
  49. sctx->ccm.s390x.nonce.b[0] |= S390X_CCM_AAD_FLAG;
  50. /* Suppress 'type-punned pointer dereference' warning. */
  51. ptr = sctx->ccm.s390x.buf.b;
  52. if (alen < ((1 << 16) - (1 << 8))) {
  53. *(uint16_t *)ptr = alen;
  54. i = 2;
  55. } else if (sizeof(alen) == 8
  56. && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) {
  57. *(uint16_t *)ptr = 0xffff;
  58. *(uint64_t *)(ptr + 2) = alen;
  59. i = 10;
  60. } else {
  61. *(uint16_t *)ptr = 0xfffe;
  62. *(uint32_t *)(ptr + 2) = alen;
  63. i = 6;
  64. }
  65. while (i < 16 && alen) {
  66. sctx->ccm.s390x.buf.b[i] = *aad;
  67. ++aad;
  68. --alen;
  69. ++i;
  70. }
  71. while (i < 16) {
  72. sctx->ccm.s390x.buf.b[i] = 0;
  73. ++i;
  74. }
  75. sctx->ccm.s390x.kmac.icv.g[0] = 0;
  76. sctx->ccm.s390x.kmac.icv.g[1] = 0;
  77. s390x_kmac(sctx->ccm.s390x.nonce.b, 32, sctx->ccm.s390x.fc,
  78. &sctx->ccm.s390x.kmac);
  79. sctx->ccm.s390x.blocks += 2;
  80. rem = alen & 0xf;
  81. alen &= ~(size_t)0xf;
  82. if (alen) {
  83. s390x_kmac(aad, alen, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
  84. sctx->ccm.s390x.blocks += alen >> 4;
  85. aad += alen;
  86. }
  87. if (rem) {
  88. for (i = 0; i < rem; i++)
  89. sctx->ccm.s390x.kmac.icv.b[i] ^= aad[i];
  90. s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
  91. sctx->ccm.s390x.kmac.icv.b, sctx->ccm.s390x.fc,
  92. sctx->ccm.s390x.kmac.k);
  93. sctx->ccm.s390x.blocks++;
  94. }
  95. return 1;
  96. }
  97. /*-
  98. * En/de-crypt plain/cipher-text. Compute tag from plaintext. Returns 1 for
  99. * success.
  100. */
  101. static int s390x_aes_ccm_auth_encdec(PROV_CCM_CTX *ctx,
  102. const unsigned char *in,
  103. unsigned char *out, size_t len, int enc)
  104. {
  105. PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
  106. size_t n, rem;
  107. unsigned int i, l, num;
  108. unsigned char flags;
  109. flags = sctx->ccm.s390x.nonce.b[0];
  110. if (!(flags & S390X_CCM_AAD_FLAG)) {
  111. s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.kmac.icv.b,
  112. sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
  113. sctx->ccm.s390x.blocks++;
  114. }
  115. l = flags & 0x7;
  116. sctx->ccm.s390x.nonce.b[0] = l;
  117. /*-
  118. * Reconstruct length from encoded length field
  119. * and initialize it with counter value.
  120. */
  121. n = 0;
  122. for (i = 15 - l; i < 15; i++) {
  123. n |= sctx->ccm.s390x.nonce.b[i];
  124. sctx->ccm.s390x.nonce.b[i] = 0;
  125. n <<= 8;
  126. }
  127. n |= sctx->ccm.s390x.nonce.b[15];
  128. sctx->ccm.s390x.nonce.b[15] = 1;
  129. if (n != len)
  130. return 0; /* length mismatch */
  131. if (enc) {
  132. /* Two operations per block plus one for tag encryption */
  133. sctx->ccm.s390x.blocks += (((len + 15) >> 4) << 1) + 1;
  134. if (sctx->ccm.s390x.blocks > (1ULL << 61))
  135. return 0; /* too much data */
  136. }
  137. num = 0;
  138. rem = len & 0xf;
  139. len &= ~(size_t)0xf;
  140. if (enc) {
  141. /* mac-then-encrypt */
  142. if (len)
  143. s390x_kmac(in, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
  144. if (rem) {
  145. for (i = 0; i < rem; i++)
  146. sctx->ccm.s390x.kmac.icv.b[i] ^= in[len + i];
  147. s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
  148. sctx->ccm.s390x.kmac.icv.b,
  149. sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
  150. }
  151. CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks,
  152. sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b,
  153. &num, (ctr128_f)AES_ctr32_encrypt);
  154. } else {
  155. /* decrypt-then-mac */
  156. CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks,
  157. sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b,
  158. &num, (ctr128_f)AES_ctr32_encrypt);
  159. if (len)
  160. s390x_kmac(out, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
  161. if (rem) {
  162. for (i = 0; i < rem; i++)
  163. sctx->ccm.s390x.kmac.icv.b[i] ^= out[len + i];
  164. s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
  165. sctx->ccm.s390x.kmac.icv.b,
  166. sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
  167. }
  168. }
  169. /* encrypt tag */
  170. for (i = 15 - l; i < 16; i++)
  171. sctx->ccm.s390x.nonce.b[i] = 0;
  172. s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.buf.b,
  173. sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
  174. sctx->ccm.s390x.kmac.icv.g[0] ^= sctx->ccm.s390x.buf.g[0];
  175. sctx->ccm.s390x.kmac.icv.g[1] ^= sctx->ccm.s390x.buf.g[1];
  176. sctx->ccm.s390x.nonce.b[0] = flags; /* restore flags field */
  177. return 1;
  178. }
  179. static int s390x_aes_ccm_gettag(PROV_CCM_CTX *ctx,
  180. unsigned char *tag, size_t tlen)
  181. {
  182. PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
  183. if (tlen > ctx->m)
  184. return 0;
  185. memcpy(tag, sctx->ccm.s390x.kmac.icv.b, tlen);
  186. return 1;
  187. }
  188. static int s390x_aes_ccm_auth_encrypt(PROV_CCM_CTX *ctx,
  189. const unsigned char *in,
  190. unsigned char *out, size_t len,
  191. unsigned char *tag, size_t taglen)
  192. {
  193. int rv;
  194. rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 1);
  195. if (rv && tag != NULL)
  196. rv = s390x_aes_ccm_gettag(ctx, tag, taglen);
  197. return rv;
  198. }
  199. static int s390x_aes_ccm_auth_decrypt(PROV_CCM_CTX *ctx,
  200. const unsigned char *in,
  201. unsigned char *out, size_t len,
  202. unsigned char *expected_tag,
  203. size_t taglen)
  204. {
  205. int rv = 0;
  206. PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
  207. rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 0);
  208. if (rv) {
  209. if (CRYPTO_memcmp(sctx->ccm.s390x.kmac.icv.b, expected_tag, ctx->m) != 0)
  210. rv = 0;
  211. }
  212. if (rv == 0)
  213. OPENSSL_cleanse(out, len);
  214. return rv;
  215. }
  216. static const PROV_CCM_HW s390x_aes_ccm = {
  217. s390x_aes_ccm_initkey,
  218. s390x_aes_ccm_setiv,
  219. s390x_aes_ccm_setaad,
  220. s390x_aes_ccm_auth_encrypt,
  221. s390x_aes_ccm_auth_decrypt,
  222. s390x_aes_ccm_gettag
  223. };
  224. const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keybits)
  225. {
  226. if ((keybits == 128 && S390X_aes_128_ccm_CAPABLE)
  227. || (keybits == 192 && S390X_aes_192_ccm_CAPABLE)
  228. || (keybits == 256 && S390X_aes_256_ccm_CAPABLE))
  229. return &s390x_aes_ccm;
  230. return &aes_ccm;
  231. }