1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/sysmacros.h>
  28 #include <modes/modes.h>
  29 #include "aes_impl.h"
  30 #ifndef _KERNEL
  31 #include <stdlib.h>
  32 #endif  /* !_KERNEL */
  33 
  34 
  35 /* Copy a 16-byte AES block from "in" to "out" */
  36 void
  37 aes_copy_block(uint8_t *in, uint8_t *out)
  38 {
  39         if (IS_P2ALIGNED2(in, out, sizeof (uint32_t))) {
  40                 /* LINTED: pointer alignment */
  41                 *(uint32_t *)&out[0] = *(uint32_t *)&in[0];
  42                 /* LINTED: pointer alignment */
  43                 *(uint32_t *)&out[4] = *(uint32_t *)&in[4];
  44                 /* LINTED: pointer alignment */
  45                 *(uint32_t *)&out[8] = *(uint32_t *)&in[8];
  46                 /* LINTED: pointer alignment */
  47                 *(uint32_t *)&out[12] = *(uint32_t *)&in[12];
  48         } else {
  49                 AES_COPY_BLOCK(in, out);
  50         }
  51 }
  52 
  53 
  54 /* XOR a 16-byte AES block of data into dst */
  55 void
  56 aes_xor_block(uint8_t *data, uint8_t *dst)
  57 {
  58         if (IS_P2ALIGNED2(dst, data, sizeof (uint32_t))) {
  59                 /* LINTED: pointer alignment */
  60                 *(uint32_t *)&dst[0] ^= *(uint32_t *)&data[0];
  61                 /* LINTED: pointer alignment */
  62                 *(uint32_t *)&dst[4] ^= *(uint32_t *)&data[4];
  63                 /* LINTED: pointer alignment */
  64                 *(uint32_t *)&dst[8] ^= *(uint32_t *)&data[8];
  65                 /* LINTED: pointer alignment */
  66                 *(uint32_t *)&dst[12] ^= *(uint32_t *)&data[12];
  67         } else {
  68                 AES_XOR_BLOCK(data, dst);
  69         }
  70 }
  71 
  72 
  73 /*
  74  * Encrypt multiple blocks of data according to mode.
  75  */
  76 int
  77 aes_encrypt_contiguous_blocks(void *ctx, char *data, size_t length,
  78     crypto_data_t *out)
  79 {
  80         aes_ctx_t *aes_ctx = ctx;
  81         int rv;
  82 
  83         if (aes_ctx->ac_flags & CTR_MODE) {
  84                 rv = ctr_mode_contiguous_blocks(ctx, data, length, out,
  85                     AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
  86 #ifdef _KERNEL
  87         } else if (aes_ctx->ac_flags & CCM_MODE) {
  88                 rv = ccm_mode_encrypt_contiguous_blocks(ctx, data, length,
  89                     out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
  90                     aes_xor_block);
  91         } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
  92                 rv = gcm_mode_encrypt_contiguous_blocks(ctx, data, length,
  93                     out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
  94                     aes_xor_block);
  95 #endif
  96         } else if (aes_ctx->ac_flags & CBC_MODE) {
  97                 rv = cbc_encrypt_contiguous_blocks(ctx,
  98                     data, length, out, AES_BLOCK_LEN, aes_encrypt_block,
  99                     aes_copy_block, aes_xor_block);
 100         } else {
 101                 rv = ecb_cipher_contiguous_blocks(ctx, data, length, out,
 102                     AES_BLOCK_LEN, aes_encrypt_block);
 103         }
 104         return (rv);
 105 }
 106 
 107 
 108 /*
 109  * Decrypt multiple blocks of data according to mode.
 110  */
 111 int
 112 aes_decrypt_contiguous_blocks(void *ctx, char *data, size_t length,
 113     crypto_data_t *out)
 114 {
 115         aes_ctx_t *aes_ctx = ctx;
 116         int rv;
 117 
 118         if (aes_ctx->ac_flags & CTR_MODE) {
 119                 rv = ctr_mode_contiguous_blocks(ctx, data, length, out,
 120                     AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
 121                 if (rv == CRYPTO_DATA_LEN_RANGE)
 122                         rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
 123 #ifdef _KERNEL
 124         } else if (aes_ctx->ac_flags & CCM_MODE) {
 125                 rv = ccm_mode_decrypt_contiguous_blocks(ctx, data, length,
 126                     out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
 127                     aes_xor_block);
 128         } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
 129                 rv = gcm_mode_decrypt_contiguous_blocks(ctx, data, length,
 130                     out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
 131                     aes_xor_block);
 132 #endif
 133         } else if (aes_ctx->ac_flags & CBC_MODE) {
 134                 rv = cbc_decrypt_contiguous_blocks(ctx, data, length, out,
 135                     AES_BLOCK_LEN, aes_decrypt_block, aes_copy_block,
 136                     aes_xor_block);
 137         } else {
 138                 rv = ecb_cipher_contiguous_blocks(ctx, data, length, out,
 139                     AES_BLOCK_LEN, aes_decrypt_block);
 140                 if (rv == CRYPTO_DATA_LEN_RANGE)
 141                         rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
 142         }
 143         return (rv);
 144 }