1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 5764 da73024 * Common Development and Distribution License (the "License"). 6 5764 da73024 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9110 opensolaris * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 9110 opensolaris #define ARCFOUR_LOOP_OPTIMIZED 27 11141 opensolaris 28 11141 opensolaris #ifndef _KERNEL 29 11141 opensolaris #include <stdint.h> 30 11141 opensolaris #endif /* _KERNEL */ 31 0 stevel 32 0 stevel #include "arcfour.h" 33 5764 da73024 34 5764 da73024 #if defined(__amd64) 35 9110 opensolaris /* ARCFour_key.flag values */ 36 9110 opensolaris #define ARCFOUR_ON_INTEL 1 37 9110 opensolaris #define ARCFOUR_ON_AMD64 0 38 9110 opensolaris 39 6281 da73024 #ifdef _KERNEL 40 6281 da73024 #include <sys/x86_archext.h> 41 6281 da73024 #include <sys/cpuvar.h> 42 0 stevel 43 6281 da73024 #else 44 6281 da73024 #include <sys/auxv.h> 45 6281 da73024 #endif /* _KERNEL */ 46 6281 da73024 #endif /* __amd64 */ 47 6281 da73024 48 9110 opensolaris #ifndef __amd64 49 9110 opensolaris /* 50 9110 opensolaris * Initialize the key stream 'key' using the key value. 51 9110 opensolaris * 52 9110 opensolaris * Input: 53 9110 opensolaris * keyval User-provided key 54 9110 opensolaris * keyvallen Length, in bytes, of keyval 55 9110 opensolaris * Output: 56 9110 opensolaris * key Initialized ARCFOUR key schedule, based on keyval 57 9110 opensolaris */ 58 0 stevel void 59 0 stevel arcfour_key_init(ARCFour_key *key, uchar_t *keyval, int keyvallen) 60 0 stevel { 61 0 stevel /* EXPORT DELETE START */ 62 0 stevel 63 0 stevel uchar_t ext_keyval[256]; 64 0 stevel uchar_t tmp; 65 0 stevel int i, j; 66 0 stevel 67 6281 da73024 /* Normalize key length to 256 */ 68 0 stevel for (i = j = 0; i < 256; i++, j++) { 69 0 stevel if (j == keyvallen) 70 0 stevel j = 0; 71 0 stevel ext_keyval[i] = keyval[j]; 72 0 stevel } 73 6281 da73024 74 0 stevel for (i = 0; i < 256; i++) 75 0 stevel key->arr[i] = (uchar_t)i; 76 0 stevel 77 0 stevel j = 0; 78 0 stevel for (i = 0; i < 256; i++) { 79 9110 opensolaris j = (j + key->arr[i] + ext_keyval[i]) & 0xff; 80 0 stevel tmp = key->arr[i]; 81 0 stevel key->arr[i] = key->arr[j]; 82 0 stevel key->arr[j] = tmp; 83 0 stevel } 84 0 stevel key->i = 0; 85 0 stevel key->j = 0; 86 0 stevel 87 0 stevel /* EXPORT DELETE END */ 88 0 stevel } 89 9110 opensolaris #endif /* !__amd64 */ 90 0 stevel 91 0 stevel 92 0 stevel /* 93 5764 da73024 * Encipher 'in' using 'key'. 94 9110 opensolaris * 95 9110 opensolaris * Input: 96 9110 opensolaris * key ARCFOUR key, initialized by arcfour_key_init() 97 9110 opensolaris * in Input text 98 9110 opensolaris * out Buffer to contain output text 99 9110 opensolaris * len Length, in bytes, of the in and out buffers 100 9110 opensolaris * 101 9110 opensolaris * Output: 102 9110 opensolaris * out Buffer containing output text 103 9110 opensolaris * 104 9110 opensolaris * Note: in and out can point to the same location 105 0 stevel */ 106 0 stevel void 107 0 stevel arcfour_crypt(ARCFour_key *key, uchar_t *in, uchar_t *out, size_t len) 108 0 stevel { 109 9110 opensolaris /* EXPORT DELETE START */ 110 9110 opensolaris #ifdef __amd64 111 9110 opensolaris if (key->flag == ARCFOUR_ON_AMD64) { 112 9110 opensolaris arcfour_crypt_asm(key, in, out, len); 113 9110 opensolaris } else { /* Intel EM64T */ 114 9110 opensolaris #endif /* amd64 */ 115 0 stevel 116 9110 opensolaris size_t ii; 117 9110 opensolaris uchar_t i, j, ti, tj; 118 9110 opensolaris #ifdef ARCFOUR_LOOP_OPTIMIZED 119 9110 opensolaris uchar_t arr_ij; 120 9110 opensolaris #endif 121 9110 opensolaris #ifdef __amd64 122 9110 opensolaris uint32_t *arr; 123 9110 opensolaris #else 124 9110 opensolaris uchar_t *arr; 125 9110 opensolaris #endif 126 0 stevel 127 9110 opensolaris #ifdef sun4u 128 0 stevel /* 129 0 stevel * The sun4u has a version of arcfour_crypt_aligned() hand-tuned for 130 9110 opensolaris * the cases where the input and output buffers are aligned on 131 0 stevel * a multiple of 8-byte boundary. 132 0 stevel */ 133 9110 opensolaris int index; 134 9110 opensolaris uchar_t tmp; 135 0 stevel 136 416 krishna index = (((uint64_t)(uintptr_t)in) & 0x7); 137 0 stevel 138 0 stevel /* Get the 'in' on an 8-byte alignment */ 139 0 stevel if (index > 0) { 140 0 stevel i = key->i; 141 0 stevel j = key->j; 142 416 krishna for (index = 8 - (uint64_t)(uintptr_t)in & 0x7; 143 416 krishna (index-- > 0) && len > 0; 144 0 stevel len--, in++, out++) { 145 9110 opensolaris ++i; 146 0 stevel j = j + key->arr[i]; 147 0 stevel tmp = key->arr[i]; 148 0 stevel key->arr[i] = key->arr[j]; 149 0 stevel key->arr[j] = tmp; 150 0 stevel tmp = key->arr[i] + key->arr[j]; 151 0 stevel *out = *in ^ key->arr[tmp]; 152 0 stevel } 153 0 stevel key->i = i; 154 0 stevel key->j = j; 155 9110 opensolaris } 156 0 stevel 157 0 stevel if (len == 0) 158 0 stevel return; 159 0 stevel 160 0 stevel /* See if we're fortunate and 'out' got aligned as well */ 161 0 stevel 162 416 krishna if ((((uint64_t)(uintptr_t)out) & 7) != 0) { 163 0 stevel #endif /* sun4u */ 164 9110 opensolaris 165 9110 opensolaris i = key->i; 166 9110 opensolaris j = key->j; 167 9110 opensolaris arr = key->arr; 168 9110 opensolaris 169 9110 opensolaris #ifndef ARCFOUR_LOOP_OPTIMIZED 170 9110 opensolaris /* 171 9110 opensolaris * This loop is hasn't been reordered, but is kept for reference 172 9110 opensolaris * purposes as it's more readable 173 9110 opensolaris */ 174 9110 opensolaris for (ii = 0; ii < len; ++ii) { 175 9110 opensolaris ++i; 176 9110 opensolaris ti = arr[i]; 177 9110 opensolaris j = j + ti; 178 9110 opensolaris tj = arr[j]; 179 9110 opensolaris arr[j] = ti; 180 9110 opensolaris arr[i] = tj; 181 9110 opensolaris out[ii] = in[ii] ^ arr[(ti + tj) & 0xff]; 182 9110 opensolaris } 183 9110 opensolaris 184 9110 opensolaris #else 185 9110 opensolaris /* 186 9110 opensolaris * This for loop is optimized by carefully spreading out 187 9110 opensolaris * memory access and storage to avoid conflicts, 188 9110 opensolaris * allowing the processor to process operations in parallel 189 9110 opensolaris */ 190 9110 opensolaris 191 9110 opensolaris /* for loop setup */ 192 9110 opensolaris ++i; 193 9110 opensolaris ti = arr[i]; 194 9110 opensolaris j = j + ti; 195 9110 opensolaris tj = arr[j]; 196 9110 opensolaris arr[j] = ti; 197 9110 opensolaris arr[i] = tj; 198 9110 opensolaris arr_ij = arr[(ti + tj) & 0xff]; 199 9110 opensolaris --len; 200 9110 opensolaris 201 9110 opensolaris for (ii = 0; ii < len; ) { 202 9110 opensolaris ++i; 203 9110 opensolaris ti = arr[i]; 204 9110 opensolaris j = j + ti; 205 9110 opensolaris tj = arr[j]; 206 9110 opensolaris arr[j] = ti; 207 9110 opensolaris arr[i] = tj; 208 9110 opensolaris 209 9110 opensolaris /* save result from previous loop: */ 210 9110 opensolaris out[ii] = in[ii] ^ arr_ij; 211 9110 opensolaris 212 9110 opensolaris ++ii; 213 9110 opensolaris arr_ij = arr[(ti + tj) & 0xff]; 214 9110 opensolaris } 215 9110 opensolaris /* save result from last loop: */ 216 9110 opensolaris out[ii] = in[ii] ^ arr_ij; 217 9110 opensolaris #endif 218 9110 opensolaris 219 9110 opensolaris key->i = i; 220 9110 opensolaris key->j = j; 221 9110 opensolaris 222 0 stevel #ifdef sun4u 223 0 stevel } else { 224 0 stevel arcfour_crypt_aligned(key, len, in, out); 225 0 stevel } 226 0 stevel #endif /* sun4u */ 227 9110 opensolaris #ifdef __amd64 228 9110 opensolaris } 229 9110 opensolaris #endif /* amd64 */ 230 0 stevel 231 0 stevel /* EXPORT DELETE END */ 232 0 stevel } 233 6281 da73024 234 6281 da73024 235 9110 opensolaris #ifdef __amd64 236 6281 da73024 /* 237 6281 da73024 * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64). 238 11141 opensolaris * Cache the result, as the CPU can't change. 239 11141 opensolaris * 240 11141 opensolaris * Note: the userland version uses getisax() and checks for an AMD-64-only 241 11141 opensolaris * feature. The kernel version uses cpuid_getvendor(). 242 6281 da73024 */ 243 6281 da73024 int 244 6281 da73024 arcfour_crypt_on_intel(void) 245 6281 da73024 { 246 11141 opensolaris static int cached_result = -1; 247 11141 opensolaris 248 11141 opensolaris if (cached_result == -1) { /* first time */ 249 6281 da73024 #ifdef _KERNEL 250 11141 opensolaris cached_result = (cpuid_getvendor(CPU) == X86_VENDOR_Intel); 251 6281 da73024 #else 252 11141 opensolaris uint_t ui; 253 11141 opensolaris 254 11141 opensolaris (void) getisax(&ui, 1); 255 11141 opensolaris cached_result = ((ui & AV_386_AMD_MMX) == 0); 256 6281 da73024 #endif /* _KERNEL */ 257 11141 opensolaris } 258 11141 opensolaris 259 11141 opensolaris return (cached_result); 260 6281 da73024 } 261 9110 opensolaris #endif /* __amd64 */ 262