17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5160abee0Sda73024 * Common Development and Distribution License (the "License"). 6160abee0Sda73024 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2292a8e44dSDan OpenSolaris Anderson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 2692a8e44dSDan OpenSolaris Anderson #define ARCFOUR_LOOP_OPTIMIZED 277c478bd9Sstevel@tonic-gate 28*8de5c4f4SDan OpenSolaris Anderson #ifndef _KERNEL 29*8de5c4f4SDan OpenSolaris Anderson #include <stdint.h> 30*8de5c4f4SDan OpenSolaris Anderson #endif /* _KERNEL */ 31*8de5c4f4SDan OpenSolaris Anderson 327c478bd9Sstevel@tonic-gate #include "arcfour.h" 337c478bd9Sstevel@tonic-gate 34160abee0Sda73024 #if defined(__amd64) 3592a8e44dSDan OpenSolaris Anderson /* ARCFour_key.flag values */ 3692a8e44dSDan OpenSolaris Anderson #define ARCFOUR_ON_INTEL 1 3792a8e44dSDan OpenSolaris Anderson #define ARCFOUR_ON_AMD64 0 3892a8e44dSDan OpenSolaris Anderson 3955553f71Sda73024 #ifdef _KERNEL 4055553f71Sda73024 #include <sys/x86_archext.h> 4155553f71Sda73024 #include <sys/cpuvar.h> 4255553f71Sda73024 4355553f71Sda73024 #else 4455553f71Sda73024 #include <sys/auxv.h> 4555553f71Sda73024 #endif /* _KERNEL */ 46160abee0Sda73024 #endif /* __amd64 */ 47160abee0Sda73024 4892a8e44dSDan OpenSolaris Anderson #ifndef __amd64 4992a8e44dSDan OpenSolaris Anderson /* 5092a8e44dSDan OpenSolaris Anderson * Initialize the key stream 'key' using the key value. 5192a8e44dSDan OpenSolaris Anderson * 5292a8e44dSDan OpenSolaris Anderson * Input: 5392a8e44dSDan OpenSolaris Anderson * keyval User-provided key 5492a8e44dSDan OpenSolaris Anderson * keyvallen Length, in bytes, of keyval 5592a8e44dSDan OpenSolaris Anderson * Output: 5692a8e44dSDan OpenSolaris Anderson * key Initialized ARCFOUR key schedule, based on keyval 5792a8e44dSDan OpenSolaris Anderson */ 587c478bd9Sstevel@tonic-gate void 597c478bd9Sstevel@tonic-gate arcfour_key_init(ARCFour_key *key, uchar_t *keyval, int keyvallen) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate uchar_t ext_keyval[256]; 627c478bd9Sstevel@tonic-gate uchar_t tmp; 637c478bd9Sstevel@tonic-gate int i, j; 647c478bd9Sstevel@tonic-gate 6555553f71Sda73024 /* Normalize key length to 256 */ 667c478bd9Sstevel@tonic-gate for (i = j = 0; i < 256; i++, j++) { 677c478bd9Sstevel@tonic-gate if (j == keyvallen) 687c478bd9Sstevel@tonic-gate j = 0; 697c478bd9Sstevel@tonic-gate ext_keyval[i] = keyval[j]; 707c478bd9Sstevel@tonic-gate } 7155553f71Sda73024 727c478bd9Sstevel@tonic-gate for (i = 0; i < 256; i++) 737c478bd9Sstevel@tonic-gate key->arr[i] = (uchar_t)i; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate j = 0; 767c478bd9Sstevel@tonic-gate for (i = 0; i < 256; i++) { 7792a8e44dSDan OpenSolaris Anderson j = (j + key->arr[i] + ext_keyval[i]) & 0xff; 787c478bd9Sstevel@tonic-gate tmp = key->arr[i]; 797c478bd9Sstevel@tonic-gate key->arr[i] = key->arr[j]; 807c478bd9Sstevel@tonic-gate key->arr[j] = tmp; 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate key->i = 0; 837c478bd9Sstevel@tonic-gate key->j = 0; 847c478bd9Sstevel@tonic-gate } 8592a8e44dSDan OpenSolaris Anderson #endif /* !__amd64 */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 89160abee0Sda73024 * Encipher 'in' using 'key'. 9092a8e44dSDan OpenSolaris Anderson * 9192a8e44dSDan OpenSolaris Anderson * Input: 9292a8e44dSDan OpenSolaris Anderson * key ARCFOUR key, initialized by arcfour_key_init() 9392a8e44dSDan OpenSolaris Anderson * in Input text 9492a8e44dSDan OpenSolaris Anderson * out Buffer to contain output text 9592a8e44dSDan OpenSolaris Anderson * len Length, in bytes, of the in and out buffers 9692a8e44dSDan OpenSolaris Anderson * 9792a8e44dSDan OpenSolaris Anderson * Output: 9892a8e44dSDan OpenSolaris Anderson * out Buffer containing output text 9992a8e44dSDan OpenSolaris Anderson * 10092a8e44dSDan OpenSolaris Anderson * Note: in and out can point to the same location 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate void 1037c478bd9Sstevel@tonic-gate arcfour_crypt(ARCFour_key *key, uchar_t *in, uchar_t *out, size_t len) 1047c478bd9Sstevel@tonic-gate { 10592a8e44dSDan OpenSolaris Anderson #ifdef __amd64 10692a8e44dSDan OpenSolaris Anderson if (key->flag == ARCFOUR_ON_AMD64) { 10792a8e44dSDan OpenSolaris Anderson arcfour_crypt_asm(key, in, out, len); 10892a8e44dSDan OpenSolaris Anderson } else { /* Intel EM64T */ 10992a8e44dSDan OpenSolaris Anderson #endif /* amd64 */ 1107c478bd9Sstevel@tonic-gate 11192a8e44dSDan OpenSolaris Anderson size_t ii; 11292a8e44dSDan OpenSolaris Anderson uchar_t i, j, ti, tj; 11392a8e44dSDan OpenSolaris Anderson #ifdef ARCFOUR_LOOP_OPTIMIZED 11492a8e44dSDan OpenSolaris Anderson uchar_t arr_ij; 11592a8e44dSDan OpenSolaris Anderson #endif 11692a8e44dSDan OpenSolaris Anderson #ifdef __amd64 11792a8e44dSDan OpenSolaris Anderson uint32_t *arr; 11892a8e44dSDan OpenSolaris Anderson #else 11992a8e44dSDan OpenSolaris Anderson uchar_t *arr; 12092a8e44dSDan OpenSolaris Anderson #endif 12192a8e44dSDan OpenSolaris Anderson 12292a8e44dSDan OpenSolaris Anderson #ifdef sun4u 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * The sun4u has a version of arcfour_crypt_aligned() hand-tuned for 1257c478bd9Sstevel@tonic-gate * the cases where the input and output buffers are aligned on 1267c478bd9Sstevel@tonic-gate * a multiple of 8-byte boundary. 1277c478bd9Sstevel@tonic-gate */ 1287c478bd9Sstevel@tonic-gate int index; 12992a8e44dSDan OpenSolaris Anderson uchar_t tmp; 1307c478bd9Sstevel@tonic-gate 1314cc1ac68Skrishna index = (((uint64_t)(uintptr_t)in) & 0x7); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* Get the 'in' on an 8-byte alignment */ 1347c478bd9Sstevel@tonic-gate if (index > 0) { 1357c478bd9Sstevel@tonic-gate i = key->i; 1367c478bd9Sstevel@tonic-gate j = key->j; 1374cc1ac68Skrishna for (index = 8 - (uint64_t)(uintptr_t)in & 0x7; 1384cc1ac68Skrishna (index-- > 0) && len > 0; 1397c478bd9Sstevel@tonic-gate len--, in++, out++) { 14092a8e44dSDan OpenSolaris Anderson ++i; 1417c478bd9Sstevel@tonic-gate j = j + key->arr[i]; 1427c478bd9Sstevel@tonic-gate tmp = key->arr[i]; 1437c478bd9Sstevel@tonic-gate key->arr[i] = key->arr[j]; 1447c478bd9Sstevel@tonic-gate key->arr[j] = tmp; 1457c478bd9Sstevel@tonic-gate tmp = key->arr[i] + key->arr[j]; 1467c478bd9Sstevel@tonic-gate *out = *in ^ key->arr[tmp]; 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate key->i = i; 1497c478bd9Sstevel@tonic-gate key->j = j; 1507c478bd9Sstevel@tonic-gate } 15192a8e44dSDan OpenSolaris Anderson 1527c478bd9Sstevel@tonic-gate if (len == 0) 1537c478bd9Sstevel@tonic-gate return; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* See if we're fortunate and 'out' got aligned as well */ 1567c478bd9Sstevel@tonic-gate 1574cc1ac68Skrishna if ((((uint64_t)(uintptr_t)out) & 7) != 0) { 1587c478bd9Sstevel@tonic-gate #endif /* sun4u */ 15992a8e44dSDan OpenSolaris Anderson 1607c478bd9Sstevel@tonic-gate i = key->i; 1617c478bd9Sstevel@tonic-gate j = key->j; 16292a8e44dSDan OpenSolaris Anderson arr = key->arr; 16392a8e44dSDan OpenSolaris Anderson 16492a8e44dSDan OpenSolaris Anderson #ifndef ARCFOUR_LOOP_OPTIMIZED 16592a8e44dSDan OpenSolaris Anderson /* 16692a8e44dSDan OpenSolaris Anderson * This loop is hasn't been reordered, but is kept for reference 16792a8e44dSDan OpenSolaris Anderson * purposes as it's more readable 16892a8e44dSDan OpenSolaris Anderson */ 16992a8e44dSDan OpenSolaris Anderson for (ii = 0; ii < len; ++ii) { 17092a8e44dSDan OpenSolaris Anderson ++i; 17192a8e44dSDan OpenSolaris Anderson ti = arr[i]; 17292a8e44dSDan OpenSolaris Anderson j = j + ti; 17392a8e44dSDan OpenSolaris Anderson tj = arr[j]; 17492a8e44dSDan OpenSolaris Anderson arr[j] = ti; 17592a8e44dSDan OpenSolaris Anderson arr[i] = tj; 17692a8e44dSDan OpenSolaris Anderson out[ii] = in[ii] ^ arr[(ti + tj) & 0xff]; 1777c478bd9Sstevel@tonic-gate } 17892a8e44dSDan OpenSolaris Anderson 17992a8e44dSDan OpenSolaris Anderson #else 18092a8e44dSDan OpenSolaris Anderson /* 18192a8e44dSDan OpenSolaris Anderson * This for loop is optimized by carefully spreading out 18292a8e44dSDan OpenSolaris Anderson * memory access and storage to avoid conflicts, 18392a8e44dSDan OpenSolaris Anderson * allowing the processor to process operations in parallel 18492a8e44dSDan OpenSolaris Anderson */ 18592a8e44dSDan OpenSolaris Anderson 18692a8e44dSDan OpenSolaris Anderson /* for loop setup */ 18792a8e44dSDan OpenSolaris Anderson ++i; 18892a8e44dSDan OpenSolaris Anderson ti = arr[i]; 18992a8e44dSDan OpenSolaris Anderson j = j + ti; 19092a8e44dSDan OpenSolaris Anderson tj = arr[j]; 19192a8e44dSDan OpenSolaris Anderson arr[j] = ti; 19292a8e44dSDan OpenSolaris Anderson arr[i] = tj; 19392a8e44dSDan OpenSolaris Anderson arr_ij = arr[(ti + tj) & 0xff]; 19492a8e44dSDan OpenSolaris Anderson --len; 19592a8e44dSDan OpenSolaris Anderson 19692a8e44dSDan OpenSolaris Anderson for (ii = 0; ii < len; ) { 19792a8e44dSDan OpenSolaris Anderson ++i; 19892a8e44dSDan OpenSolaris Anderson ti = arr[i]; 19992a8e44dSDan OpenSolaris Anderson j = j + ti; 20092a8e44dSDan OpenSolaris Anderson tj = arr[j]; 20192a8e44dSDan OpenSolaris Anderson arr[j] = ti; 20292a8e44dSDan OpenSolaris Anderson arr[i] = tj; 20392a8e44dSDan OpenSolaris Anderson 20492a8e44dSDan OpenSolaris Anderson /* save result from previous loop: */ 20592a8e44dSDan OpenSolaris Anderson out[ii] = in[ii] ^ arr_ij; 20692a8e44dSDan OpenSolaris Anderson 20792a8e44dSDan OpenSolaris Anderson ++ii; 20892a8e44dSDan OpenSolaris Anderson arr_ij = arr[(ti + tj) & 0xff]; 20992a8e44dSDan OpenSolaris Anderson } 21092a8e44dSDan OpenSolaris Anderson /* save result from last loop: */ 21192a8e44dSDan OpenSolaris Anderson out[ii] = in[ii] ^ arr_ij; 21292a8e44dSDan OpenSolaris Anderson #endif 21392a8e44dSDan OpenSolaris Anderson 2147c478bd9Sstevel@tonic-gate key->i = i; 2157c478bd9Sstevel@tonic-gate key->j = j; 21692a8e44dSDan OpenSolaris Anderson 2177c478bd9Sstevel@tonic-gate #ifdef sun4u 2187c478bd9Sstevel@tonic-gate } else { 2197c478bd9Sstevel@tonic-gate arcfour_crypt_aligned(key, len, in, out); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate #endif /* sun4u */ 22292a8e44dSDan OpenSolaris Anderson #ifdef __amd64 22392a8e44dSDan OpenSolaris Anderson } 22492a8e44dSDan OpenSolaris Anderson #endif /* amd64 */ 2257c478bd9Sstevel@tonic-gate } 22655553f71Sda73024 22755553f71Sda73024 22892a8e44dSDan OpenSolaris Anderson #ifdef __amd64 22955553f71Sda73024 /* 23055553f71Sda73024 * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64). 231*8de5c4f4SDan OpenSolaris Anderson * Cache the result, as the CPU can't change. 232*8de5c4f4SDan OpenSolaris Anderson * 233*8de5c4f4SDan OpenSolaris Anderson * Note: the userland version uses getisax() and checks for an AMD-64-only 234*8de5c4f4SDan OpenSolaris Anderson * feature. The kernel version uses cpuid_getvendor(). 23555553f71Sda73024 */ 23655553f71Sda73024 int 23755553f71Sda73024 arcfour_crypt_on_intel(void) 23855553f71Sda73024 { 239*8de5c4f4SDan OpenSolaris Anderson static int cached_result = -1; 240*8de5c4f4SDan OpenSolaris Anderson 241*8de5c4f4SDan OpenSolaris Anderson if (cached_result == -1) { /* first time */ 24255553f71Sda73024 #ifdef _KERNEL 243*8de5c4f4SDan OpenSolaris Anderson cached_result = (cpuid_getvendor(CPU) == X86_VENDOR_Intel); 24455553f71Sda73024 #else 24555553f71Sda73024 uint_t ui; 246*8de5c4f4SDan OpenSolaris Anderson 24755553f71Sda73024 (void) getisax(&ui, 1); 248*8de5c4f4SDan OpenSolaris Anderson cached_result = ((ui & AV_386_AMD_MMX) == 0); 24955553f71Sda73024 #endif /* _KERNEL */ 25055553f71Sda73024 } 251*8de5c4f4SDan OpenSolaris Anderson 252*8de5c4f4SDan OpenSolaris Anderson return (cached_result); 253*8de5c4f4SDan OpenSolaris Anderson } 25492a8e44dSDan OpenSolaris Anderson #endif /* __amd64 */ 255