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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "@(#)arcfour_crypt.c    1.7     08/03/20 SMI"
  27 
  28 #include "arcfour.h"
  29 
  30 #if defined(__amd64)
  31 #ifdef _KERNEL
  32 #include <sys/x86_archext.h>
  33 #include <sys/cpuvar.h>
  34 
  35 #else
  36 #include <sys/auxv.h>
  37 #endif  /* _KERNEL */
  38 #endif  /* __amd64 */
  39 
  40 #if !defined(__amd64)
  41 /* Initialize the key stream 'key' using the key value */
  42 void
  43 arcfour_key_init(ARCFour_key *key, uchar_t *keyval, int keyvallen)
  44 {
  45 /* EXPORT DELETE START */
  46 
  47         uchar_t ext_keyval[256];
  48         uchar_t tmp;
  49         int i, j;
  50 
  51         /* Normalize key length to 256 */
  52         for (i = j = 0; i < 256; i++, j++) {
  53                 if (j == keyvallen)
  54                         j = 0;
  55                 ext_keyval[i] = keyval[j];
  56         }
  57 
  58         for (i = 0; i < 256; i++)
  59                 key->arr[i] = (uchar_t)i;
  60 
  61         j = 0;
  62         for (i = 0; i < 256; i++) {
  63                 j = (j + key->arr[i] + ext_keyval[i]) % 256;
  64                 tmp = key->arr[i];
  65                 key->arr[i] = key->arr[j];
  66                 key->arr[j] = tmp;
  67         }
  68         key->i = 0;
  69         key->j = 0;
  70 
  71 /* EXPORT DELETE END */
  72 }
  73 
  74 
  75 /*
  76  * Encipher 'in' using 'key'.
  77  * in and out can point to the same location
  78  */
  79 void
  80 arcfour_crypt(ARCFour_key *key, uchar_t *in, uchar_t *out, size_t len)
  81 {
  82         size_t ii;
  83         uchar_t tmp, i, j;
  84 
  85 /* EXPORT DELETE START */
  86 
  87         /*
  88          * The sun4u has a version of arcfour_crypt_aligned() hand-tuned for
  89          * the cases where the input and output  buffers are aligned on
  90          * a multiple of 8-byte boundary.
  91          */
  92 #ifdef  sun4u
  93         int index;
  94 
  95         index = (((uint64_t)(uintptr_t)in) & 0x7);
  96 
  97         /* Get the 'in' on an 8-byte alignment */
  98         if (index > 0) {
  99                 i = key->i;
 100                 j = key->j;
 101                 for (index = 8 - (uint64_t)(uintptr_t)in & 0x7;
 102                     (index-- > 0) && len > 0;
 103                     len--, in++, out++) {
 104                         i = i + 1;
 105                         j = j + key->arr[i];
 106                         tmp = key->arr[i];
 107                         key->arr[i] = key->arr[j];
 108                         key->arr[j] = tmp;
 109                         tmp = key->arr[i] + key->arr[j];
 110                         *out = *in ^ key->arr[tmp];
 111                 }
 112                 key->i = i;
 113                 key->j = j;
 114 
 115         }
 116         if (len == 0)
 117                 return;
 118 
 119         /* See if we're fortunate and 'out' got aligned as well */
 120 
 121         if ((((uint64_t)(uintptr_t)out) & 7) != 0) {
 122 #endif  /* sun4u */
 123                 i = key->i;
 124                 j = key->j;
 125                 for (ii = 0; ii < len; ii++) {
 126                         i = i + 1;
 127                         j = j + key->arr[i];
 128                         tmp = key->arr[i];
 129                         key->arr[i] = key->arr[j];
 130                         key->arr[j] = tmp;
 131                         tmp = key->arr[i] + key->arr[j];
 132                         out[ii] = in[ii] ^ key->arr[tmp];
 133                 }
 134                 key->i = i;
 135                 key->j = j;
 136 #ifdef  sun4u
 137         } else {
 138                 arcfour_crypt_aligned(key, len, in, out);
 139         }
 140 #endif  /* sun4u */
 141 
 142 /* EXPORT DELETE END */
 143 }
 144 
 145 #else
 146 
 147 /*
 148  * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64).
 149  */
 150 int
 151 arcfour_crypt_on_intel(void)
 152 {
 153 #ifdef _KERNEL
 154         return (cpuid_getvendor(CPU) == X86_VENDOR_Intel);
 155 #else
 156         uint_t  ui;
 157         (void) getisax(&ui, 1);
 158         return ((ui & AV_386_AMD_MMX) == 0);
 159 #endif  /* _KERNEL */
 160 }
 161 #endif  /* !__amd64 */