cipher_aes_gcm_hw_s390x.inc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * Copyright 2001-2021 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. * IBM S390X support for AES GCM.
  11. * This file is included by cipher_aes_gcm_hw.c
  12. */
  13. /* iv + padding length for iv lengths != 12 */
  14. #define S390X_gcm_ivpadlen(i) ((((i) + 15) >> 4 << 4) + 16)
  15. /* Additional flag or'ed to fc for decryption */
  16. #define S390X_gcm_decrypt_flag(ctx) (((ctx)->enc) ? 0 : S390X_DECRYPT)
  17. #define S390X_gcm_fc(A,C) ((A)->plat.s390x.fc | (A)->plat.s390x.hsflag |\
  18. S390X_gcm_decrypt_flag((C)))
  19. static int s390x_aes_gcm_initkey(PROV_GCM_CTX *ctx,
  20. const unsigned char *key, size_t keylen)
  21. {
  22. PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
  23. ctx->key_set = 1;
  24. memcpy(&actx->plat.s390x.param.kma.k, key, keylen);
  25. actx->plat.s390x.fc = S390X_AES_FC(keylen);
  26. return 1;
  27. }
  28. static int s390x_aes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv,
  29. size_t ivlen)
  30. {
  31. PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
  32. S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
  33. kma->t.g[0] = 0;
  34. kma->t.g[1] = 0;
  35. kma->tpcl = 0;
  36. kma->taadl = 0;
  37. actx->plat.s390x.mreslen = 0;
  38. actx->plat.s390x.areslen = 0;
  39. actx->plat.s390x.kreslen = 0;
  40. if (ivlen == GCM_IV_DEFAULT_SIZE) {
  41. memcpy(&kma->j0, iv, ivlen);
  42. kma->j0.w[3] = 1;
  43. kma->cv.w = 1;
  44. actx->plat.s390x.hsflag = 0;
  45. } else {
  46. unsigned long long ivbits = ivlen << 3;
  47. size_t len = S390X_gcm_ivpadlen(ivlen);
  48. unsigned char iv_zero_pad[S390X_gcm_ivpadlen(GCM_IV_MAX_SIZE)];
  49. /*
  50. * The IV length needs to be zero padded to be a multiple of 16 bytes
  51. * followed by 8 bytes of zeros and 8 bytes for the IV length.
  52. * The GHASH of this value can then be calculated.
  53. */
  54. memcpy(iv_zero_pad, iv, ivlen);
  55. memset(iv_zero_pad + ivlen, 0, len - ivlen);
  56. memcpy(iv_zero_pad + len - sizeof(ivbits), &ivbits, sizeof(ivbits));
  57. /*
  58. * Calculate the ghash of the iv - the result is stored into the tag
  59. * param.
  60. */
  61. s390x_kma(iv_zero_pad, len, NULL, 0, NULL, actx->plat.s390x.fc, kma);
  62. actx->plat.s390x.hsflag = S390X_KMA_HS; /* The hash subkey is set */
  63. /* Copy the 128 bit GHASH result into J0 and clear the tag */
  64. kma->j0.g[0] = kma->t.g[0];
  65. kma->j0.g[1] = kma->t.g[1];
  66. kma->t.g[0] = 0;
  67. kma->t.g[1] = 0;
  68. /* Set the 32 bit counter */
  69. kma->cv.w = kma->j0.w[3];
  70. }
  71. return 1;
  72. }
  73. static int s390x_aes_gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag)
  74. {
  75. PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
  76. S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
  77. unsigned char out[AES_BLOCK_SIZE];
  78. unsigned int fc;
  79. int rc;
  80. kma->taadl <<= 3;
  81. kma->tpcl <<= 3;
  82. fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC;
  83. s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen,
  84. actx->plat.s390x.mres, actx->plat.s390x.mreslen, out,
  85. fc, kma);
  86. /* gctx->mres already returned to the caller */
  87. OPENSSL_cleanse(out, actx->plat.s390x.mreslen);
  88. if (ctx->enc) {
  89. ctx->taglen = GCM_TAG_MAX_SIZE;
  90. memcpy(tag, kma->t.b, ctx->taglen);
  91. rc = 1;
  92. } else {
  93. rc = (CRYPTO_memcmp(tag, kma->t.b, ctx->taglen) == 0);
  94. }
  95. return rc;
  96. }
  97. static int s390x_aes_gcm_one_shot(PROV_GCM_CTX *ctx,
  98. unsigned char *aad, size_t aad_len,
  99. const unsigned char *in, size_t in_len,
  100. unsigned char *out,
  101. unsigned char *tag, size_t taglen)
  102. {
  103. PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
  104. S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
  105. unsigned int fc;
  106. int rc;
  107. kma->taadl = aad_len << 3;
  108. kma->tpcl = in_len << 3;
  109. fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC;
  110. s390x_kma(aad, aad_len, in, in_len, out, fc, kma);
  111. if (ctx->enc) {
  112. memcpy(tag, kma->t.b, taglen);
  113. rc = 1;
  114. } else {
  115. rc = (CRYPTO_memcmp(tag, kma->t.b, taglen) == 0);
  116. }
  117. return rc;
  118. }
  119. /*
  120. * Process additional authenticated data. Returns 1 on success. Code is
  121. * big-endian.
  122. */
  123. static int s390x_aes_gcm_aad_update(PROV_GCM_CTX *ctx,
  124. const unsigned char *aad, size_t len)
  125. {
  126. PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
  127. S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
  128. unsigned long long alen;
  129. unsigned int fc;
  130. int n, rem;
  131. /* If already processed pt/ct then error */
  132. if (kma->tpcl != 0)
  133. return 0;
  134. /* update the total aad length */
  135. alen = kma->taadl + len;
  136. if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len))
  137. return 0;
  138. kma->taadl = alen;
  139. /* check if there is any existing aad data from a previous add */
  140. n = actx->plat.s390x.areslen;
  141. if (n) {
  142. /* add additional data to a buffer until it has 16 bytes */
  143. while (n && len) {
  144. actx->plat.s390x.ares[n] = *aad;
  145. ++aad;
  146. --len;
  147. n = (n + 1) & 0xf;
  148. }
  149. /* ctx->ares contains a complete block if offset has wrapped around */
  150. if (!n) {
  151. fc = S390X_gcm_fc(actx, ctx);
  152. s390x_kma(actx->plat.s390x.ares, 16, NULL, 0, NULL, fc, kma);
  153. actx->plat.s390x.hsflag = S390X_KMA_HS;
  154. }
  155. actx->plat.s390x.areslen = n;
  156. }
  157. /* If there are leftover bytes (< 128 bits) save them for next time */
  158. rem = len & 0xf;
  159. /* Add any remaining 16 byte blocks (128 bit each) */
  160. len &= ~(size_t)0xf;
  161. if (len) {
  162. fc = S390X_gcm_fc(actx, ctx);
  163. s390x_kma(aad, len, NULL, 0, NULL, fc, kma);
  164. actx->plat.s390x.hsflag = S390X_KMA_HS;
  165. aad += len;
  166. }
  167. if (rem) {
  168. actx->plat.s390x.areslen = rem;
  169. do {
  170. --rem;
  171. actx->plat.s390x.ares[rem] = aad[rem];
  172. } while (rem);
  173. }
  174. return 1;
  175. }
  176. /*-
  177. * En/de-crypt plain/cipher-text and authenticate ciphertext. Returns 1 for
  178. * success. Code is big-endian.
  179. */
  180. static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx,
  181. const unsigned char *in, size_t len,
  182. unsigned char *out)
  183. {
  184. PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
  185. S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
  186. const unsigned char *inptr;
  187. unsigned long long mlen;
  188. unsigned int fc;
  189. union {
  190. unsigned int w[4];
  191. unsigned char b[16];
  192. } buf;
  193. size_t inlen;
  194. int n, rem, i;
  195. mlen = kma->tpcl + len;
  196. if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
  197. return 0;
  198. kma->tpcl = mlen;
  199. fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD;
  200. n = actx->plat.s390x.mreslen;
  201. if (n) {
  202. inptr = in;
  203. inlen = len;
  204. while (n && inlen) {
  205. actx->plat.s390x.mres[n] = *inptr;
  206. n = (n + 1) & 0xf;
  207. ++inptr;
  208. --inlen;
  209. }
  210. /* ctx->mres contains a complete block if offset has wrapped around */
  211. if (!n) {
  212. s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen,
  213. actx->plat.s390x.mres, 16, buf.b, fc, kma);
  214. actx->plat.s390x.hsflag = S390X_KMA_HS;
  215. fc |= S390X_KMA_HS;
  216. actx->plat.s390x.areslen = 0;
  217. /* previous call already encrypted/decrypted its remainder,
  218. * see comment below */
  219. n = actx->plat.s390x.mreslen;
  220. while (n) {
  221. *out = buf.b[n];
  222. n = (n + 1) & 0xf;
  223. ++out;
  224. ++in;
  225. --len;
  226. }
  227. actx->plat.s390x.mreslen = 0;
  228. }
  229. }
  230. rem = len & 0xf;
  231. len &= ~(size_t)0xf;
  232. if (len) {
  233. s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, in, len, out,
  234. fc, kma);
  235. in += len;
  236. out += len;
  237. actx->plat.s390x.hsflag = S390X_KMA_HS;
  238. actx->plat.s390x.areslen = 0;
  239. }
  240. /*-
  241. * If there is a remainder, it has to be saved such that it can be
  242. * processed by kma later. However, we also have to do the for-now
  243. * unauthenticated encryption/decryption part here and now...
  244. */
  245. if (rem) {
  246. if (!actx->plat.s390x.mreslen) {
  247. buf.w[0] = kma->j0.w[0];
  248. buf.w[1] = kma->j0.w[1];
  249. buf.w[2] = kma->j0.w[2];
  250. buf.w[3] = kma->cv.w + 1;
  251. s390x_km(buf.b, 16, actx->plat.s390x.kres,
  252. fc & 0x1f, &kma->k);
  253. }
  254. n = actx->plat.s390x.mreslen;
  255. for (i = 0; i < rem; i++) {
  256. actx->plat.s390x.mres[n + i] = in[i];
  257. out[i] = in[i] ^ actx->plat.s390x.kres[n + i];
  258. }
  259. actx->plat.s390x.mreslen += rem;
  260. }
  261. return 1;
  262. }
  263. static const PROV_GCM_HW s390x_aes_gcm = {
  264. s390x_aes_gcm_initkey,
  265. s390x_aes_gcm_setiv,
  266. s390x_aes_gcm_aad_update,
  267. s390x_aes_gcm_cipher_update,
  268. s390x_aes_gcm_cipher_final,
  269. s390x_aes_gcm_one_shot
  270. };
  271. const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits)
  272. {
  273. if ((keybits == 128 && S390X_aes_128_gcm_CAPABLE)
  274. || (keybits == 192 && S390X_aes_192_gcm_CAPABLE)
  275. || (keybits == 256 && S390X_aes_256_gcm_CAPABLE))
  276. return &s390x_aes_gcm;
  277. return &aes_gcm;
  278. }