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 #define ARCFOUR_LOOP_OPTIMIZED 27 28 #include "arcfour.h" 29 30 #if defined(__amd64) 31 /* ARCFour_key.flag values */ 32 #define ARCFOUR_ON_INTEL 1 33 #define ARCFOUR_ON_AMD64 0 34 35 #ifdef _KERNEL 36 #include <sys/x86_archext.h> 37 #include <sys/cpuvar.h> 38 39 #else 40 #include <sys/auxv.h> 41 #endif /* _KERNEL */ 42 #endif /* __amd64 */ 43 44 #ifndef __amd64 45 /* 46 * Initialize the key stream 'key' using the key value. 47 * 48 * Input: 49 * keyval User-provided key 50 * keyvallen Length, in bytes, of keyval 51 * Output: 52 * key Initialized ARCFOUR key schedule, based on keyval 53 */ 54 void 55 arcfour_key_init(ARCFour_key *key, uchar_t *keyval, int keyvallen) 56 { 57 /* EXPORT DELETE START */ 58 59 uchar_t ext_keyval[256]; 60 uchar_t tmp; 61 int i, j; 62 63 /* Normalize key length to 256 */ 64 for (i = j = 0; i < 256; i++, j++) { 65 if (j == keyvallen) 66 j = 0; 67 ext_keyval[i] = keyval[j]; 68 } 69 70 for (i = 0; i < 256; i++) 71 key->arr[i] = (uchar_t)i; 72 73 j = 0; 74 for (i = 0; i < 256; i++) { 75 j = (j + key->arr[i] + ext_keyval[i]) & 0xff; 76 tmp = key->arr[i]; 77 key->arr[i] = key->arr[j]; 78 key->arr[j] = tmp; 79 } 80 key->i = 0; 81 key->j = 0; 82 83 /* EXPORT DELETE END */ 84 } 85 #endif /* !__amd64 */ 86 87 88 /* 89 * Encipher 'in' using 'key'. 90 * 91 * Input: 92 * key ARCFOUR key, initialized by arcfour_key_init() 93 * in Input text 94 * out Buffer to contain output text 95 * len Length, in bytes, of the in and out buffers 96 * 97 * Output: 98 * out Buffer containing output text 99 * 100 * Note: in and out can point to the same location 101 */ 102 void 103 arcfour_crypt(ARCFour_key *key, uchar_t *in, uchar_t *out, size_t len) 104 { 105 /* EXPORT DELETE START */ 106 #ifdef __amd64 107 if (key->flag == ARCFOUR_ON_AMD64) { 108 arcfour_crypt_asm(key, in, out, len); 109 } else { /* Intel EM64T */ 110 #endif /* amd64 */ 111 112 size_t ii; 113 uchar_t i, j, ti, tj; 114 #ifdef ARCFOUR_LOOP_OPTIMIZED 115 uchar_t arr_ij; 116 #endif 117 #ifdef __amd64 118 uint32_t *arr; 119 #else 120 uchar_t *arr; 121 #endif 122 123 #ifdef sun4u 124 /* 125 * The sun4u has a version of arcfour_crypt_aligned() hand-tuned for 126 * the cases where the input and output buffers are aligned on 127 * a multiple of 8-byte boundary. 128 */ 129 int index; 130 uchar_t tmp; 131 132 index = (((uint64_t)(uintptr_t)in) & 0x7); 133 134 /* Get the 'in' on an 8-byte alignment */ 135 if (index > 0) { 136 i = key->i; 137 j = key->j; 138 for (index = 8 - (uint64_t)(uintptr_t)in & 0x7; 139 (index-- > 0) && len > 0; 140 len--, in++, out++) { 141 ++i; 142 j = j + key->arr[i]; 143 tmp = key->arr[i]; 144 key->arr[i] = key->arr[j]; 145 key->arr[j] = tmp; 146 tmp = key->arr[i] + key->arr[j]; 147 *out = *in ^ key->arr[tmp]; 148 } 149 key->i = i; 150 key->j = j; 151 } 152 153 if (len == 0) 154 return; 155 156 /* See if we're fortunate and 'out' got aligned as well */ 157 158 if ((((uint64_t)(uintptr_t)out) & 7) != 0) { 159 #endif /* sun4u */ 160 161 i = key->i; 162 j = key->j; 163 arr = key->arr; 164 165 #ifndef ARCFOUR_LOOP_OPTIMIZED 166 /* 167 * This loop is hasn't been reordered, but is kept for reference 168 * purposes as it's more readable 169 */ 170 for (ii = 0; ii < len; ++ii) { 171 ++i; 172 ti = arr[i]; 173 j = j + ti; 174 tj = arr[j]; 175 arr[j] = ti; 176 arr[i] = tj; 177 out[ii] = in[ii] ^ arr[(ti + tj) & 0xff]; 178 } 179 180 #else 181 /* 182 * This for loop is optimized by carefully spreading out 183 * memory access and storage to avoid conflicts, 184 * allowing the processor to process operations in parallel 185 */ 186 187 /* for loop setup */ 188 ++i; 189 ti = arr[i]; 190 j = j + ti; 191 tj = arr[j]; 192 arr[j] = ti; 193 arr[i] = tj; 194 arr_ij = arr[(ti + tj) & 0xff]; 195 --len; 196 197 for (ii = 0; ii < len; ) { 198 ++i; 199 ti = arr[i]; 200 j = j + ti; 201 tj = arr[j]; 202 arr[j] = ti; 203 arr[i] = tj; 204 205 /* save result from previous loop: */ 206 out[ii] = in[ii] ^ arr_ij; 207 208 ++ii; 209 arr_ij = arr[(ti + tj) & 0xff]; 210 } 211 /* save result from last loop: */ 212 out[ii] = in[ii] ^ arr_ij; 213 #endif 214 215 key->i = i; 216 key->j = j; 217 218 #ifdef sun4u 219 } else { 220 arcfour_crypt_aligned(key, len, in, out); 221 } 222 #endif /* sun4u */ 223 #ifdef __amd64 224 } 225 #endif /* amd64 */ 226 227 /* EXPORT DELETE END */ 228 } 229 230 231 #ifdef __amd64 232 /* 233 * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64). 234 */ 235 int 236 arcfour_crypt_on_intel(void) 237 { 238 #ifdef _KERNEL 239 return (cpuid_getvendor(CPU) == X86_VENDOR_Intel); 240 #else 241 uint_t ui; 242 (void) getisax(&ui, 1); 243 return ((ui & AV_386_AMD_MMX) == 0); 244 #endif /* _KERNEL */ 245 } 246 #endif /* __amd64 */ 247