Home | History | Annotate | Download | only in arcfour
      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