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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #define ARCFOUR_LOOP_OPTIMIZED
35 /* ARCFour_key.flag values */
36 #define ARCFOUR_ON_INTEL 1
37 #define ARCFOUR_ON_AMD64 0
40 #include <sys/x86_archext.h>
41 #include <sys/cpuvar.h>
50 * Initialize the key stream 'key' using the key value.
53 * keyval User-provided key
54 * keyvallen Length, in bytes, of keyval
56 * key Initialized ARCFOUR key schedule, based on keyval
59 arcfour_key_init(ARCFour_key
*key
, uchar_t
*keyval
, int keyvallen
)
61 uchar_t ext_keyval
[256];
65 /* Normalize key length to 256 */
66 for (i
= j
= 0; i
< 256; i
++, j
++) {
69 ext_keyval
[i
] = keyval
[j
];
72 for (i
= 0; i
< 256; i
++)
73 key
->arr
[i
] = (uchar_t
)i
;
76 for (i
= 0; i
< 256; i
++) {
77 j
= (j
+ key
->arr
[i
] + ext_keyval
[i
]) & 0xff;
79 key
->arr
[i
] = key
->arr
[j
];
89 * Encipher 'in' using 'key'.
92 * key ARCFOUR key, initialized by arcfour_key_init()
94 * out Buffer to contain output text
95 * len Length, in bytes, of the in and out buffers
98 * out Buffer containing output text
100 * Note: in and out can point to the same location
103 arcfour_crypt(ARCFour_key
*key
, uchar_t
*in
, uchar_t
*out
, size_t len
)
106 if (key
->flag
== ARCFOUR_ON_AMD64
) {
107 arcfour_crypt_asm(key
, in
, out
, len
);
108 } else { /* Intel EM64T */
112 uchar_t i
, j
, ti
, tj
;
113 #ifdef ARCFOUR_LOOP_OPTIMIZED
124 * The sun4u has a version of arcfour_crypt_aligned() hand-tuned for
125 * the cases where the input and output buffers are aligned on
126 * a multiple of 8-byte boundary.
131 index
= (((uint64_t)(uintptr_t)in
) & 0x7);
133 /* Get the 'in' on an 8-byte alignment */
137 for (index
= 8 - (uint64_t)(uintptr_t)in
& 0x7;
138 (index
-- > 0) && len
> 0;
139 len
--, in
++, out
++) {
143 key
->arr
[i
] = key
->arr
[j
];
145 tmp
= key
->arr
[i
] + key
->arr
[j
];
146 *out
= *in
^ key
->arr
[tmp
];
155 /* See if we're fortunate and 'out' got aligned as well */
157 if ((((uint64_t)(uintptr_t)out
) & 7) != 0) {
164 #ifndef ARCFOUR_LOOP_OPTIMIZED
166 * This loop is hasn't been reordered, but is kept for reference
167 * purposes as it's more readable
169 for (ii
= 0; ii
< len
; ++ii
) {
176 out
[ii
] = in
[ii
] ^ arr
[(ti
+ tj
) & 0xff];
181 * This for loop is optimized by carefully spreading out
182 * memory access and storage to avoid conflicts,
183 * allowing the processor to process operations in parallel
193 arr_ij
= arr
[(ti
+ tj
) & 0xff];
196 for (ii
= 0; ii
< len
; ) {
204 /* save result from previous loop: */
205 out
[ii
] = in
[ii
] ^ arr_ij
;
208 arr_ij
= arr
[(ti
+ tj
) & 0xff];
210 /* save result from last loop: */
211 out
[ii
] = in
[ii
] ^ arr_ij
;
219 arcfour_crypt_aligned(key
, len
, in
, out
);
230 * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64).
231 * Cache the result, as the CPU can't change.
233 * Note: the userland version uses getisax() and checks for an AMD-64-only
234 * feature. The kernel version uses cpuid_getvendor().
237 arcfour_crypt_on_intel(void)
239 static int cached_result
= -1;
241 if (cached_result
== -1) { /* first time */
243 cached_result
= (cpuid_getvendor(CPU
) == X86_VENDOR_Intel
);
247 (void) getisax(&ui
, 1);
248 cached_result
= ((ui
& AV_386_AMD_MMX
) == 0);
252 return (cached_result
);