1227Skais /* 2227Skais * CDDL HEADER START 3227Skais * 4227Skais * The contents of this file are subject to the terms of the 5*6125Sbubbva * Common Development and Distribution License (the "License"). 6*6125Sbubbva * You may not use this file except in compliance with the License. 7227Skais * 8227Skais * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9227Skais * or http://www.opensolaris.org/os/licensing. 10227Skais * See the License for the specific language governing permissions 11227Skais * and limitations under the License. 12227Skais * 13227Skais * When distributing Covered Code, include this CDDL HEADER in each 14227Skais * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15227Skais * If applicable, add the following below this CDDL HEADER, with the 16227Skais * fields enclosed by brackets "[]" replaced with your own identifying 17227Skais * information: Portions Copyright [yyyy] [name of copyright owner] 18227Skais * 19227Skais * CDDL HEADER END 20227Skais */ 21227Skais /* 22*6125Sbubbva * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23227Skais * Use is subject to license terms. 24227Skais */ 25227Skais 26227Skais #pragma ident "%Z%%M% %I% %E% SMI" 27227Skais 28227Skais #include "../arcfour.h" 29227Skais 30227Skais /* Initialize the key stream 'key' using the key value */ 31227Skais void 32227Skais arcfour_key_init(ARCFour_key *key, uchar_t *keyval, int keyvallen) 33227Skais { 34227Skais /* EXPORT DELETE START */ 35227Skais 36227Skais uchar_t ext_keyval[256]; 37227Skais uchar_t tmp; 38227Skais int i, j; 39227Skais 40227Skais for (i = j = 0; i < 256; i++, j++) { 41227Skais if (j == keyvallen) 42227Skais j = 0; 43227Skais 44227Skais ext_keyval[i] = keyval[j]; 45227Skais } 46227Skais for (i = 0; i < 256; i++) 47227Skais key->arr[i] = (uchar_t)i; 48227Skais 49227Skais j = 0; 50227Skais for (i = 0; i < 256; i++) { 51227Skais j = (j + key->arr[i] + ext_keyval[i]) % 256; 52227Skais tmp = key->arr[i]; 53227Skais key->arr[i] = key->arr[j]; 54227Skais key->arr[j] = tmp; 55227Skais } 56227Skais key->i = 0; 57227Skais key->j = 0; 58227Skais 59227Skais /* EXPORT DELETE END */ 60227Skais } 61227Skais 62227Skais 63227Skais /* 64227Skais * Encipher 'in' using 'key. 65227Skais * in and out can point to the same location 66227Skais */ 67227Skais void 68227Skais arcfour_crypt(ARCFour_key *key, uchar_t *in, uchar_t *out, size_t len) 69227Skais { 70227Skais size_t ii, it; 71227Skais unsigned long long in0, out0, merge = 0, merge0 = 0, merge1, mask = 0; 72227Skais uchar_t i, j, *base, jj, *base1, tmp; 73227Skais unsigned int tmp0, tmp1, i_accum, count = 0, shift = 0, i1; 74227Skais 75227Skais 76227Skais /* EXPORT DELETE START */ 77227Skais int index; 78227Skais 79227Skais base = key->arr; 80227Skais 81*6125Sbubbva index = (((uintptr_t)in) & 0x7); 82227Skais 83227Skais /* Get the 'in' on an 8-byte alignment */ 84227Skais if (index > 0) { 85227Skais i = key->i; 86227Skais j = key->j; 87*6125Sbubbva 88*6125Sbubbva for (index = 8 - index; (index-- > 0) && len > 0; 89227Skais len--, in++, out++) { 90*6125Sbubbva 91227Skais i = i + 1; 92227Skais j = j + key->arr[i]; 93227Skais tmp = key->arr[i]; 94227Skais key->arr[i] = key->arr[j]; 95227Skais key->arr[j] = tmp; 96227Skais tmp = key->arr[i] + key->arr[j]; 97227Skais *out = *in ^ key->arr[tmp]; 98227Skais } 99227Skais key->i = i; 100227Skais key->j = j; 101227Skais 102227Skais } 103227Skais if (len == 0) 104227Skais return; 105227Skais 106227Skais /* See if we're fortunate and 'out' got aligned as well */ 107227Skais 108227Skais 109227Skais /* 110227Skais * Niagara optimized version for 111227Skais * the cases where the input and output buffers are aligned on 112227Skais * a multiple of 8-byte boundary. 113227Skais */ 114227Skais #ifdef sun4v 115*6125Sbubbva if ((((uintptr_t)out) & 7) != 0) { 116227Skais #endif /* sun4v */ 117227Skais i = key->i; 118227Skais j = key->j; 119227Skais for (ii = 0; ii < len; ii++) { 120227Skais i = i + 1; 121227Skais tmp0 = base[i]; 122227Skais j = j + tmp0; 123227Skais tmp1 = base[j]; 124227Skais base[i] = tmp1; 125227Skais base[j] = tmp0; 126227Skais tmp0 += tmp1; 127227Skais tmp0 = tmp0 & 0xff; 128227Skais out[ii] = in[ii] ^ base[tmp0]; 129227Skais } 130227Skais key->i = i; 131227Skais key->j = j; 132227Skais #ifdef sun4v 133227Skais } else { 134227Skais i = key->i; 135227Skais j = key->j; 136227Skais 137227Skais /* 138227Skais * Want to align base[i] on a 2B boundary -- allows updates 139227Skais * via [i] to be performed in 2B chunks (reducing # of stores). 140227Skais * Requires appropriate alias detection. 141227Skais */ 142227Skais 143227Skais if (((i+1) % 2) != 0) { 144227Skais i = i + 1; 145227Skais tmp0 = base[i]; 146227Skais j = j + tmp0; 147227Skais tmp1 = base[j]; 148227Skais 149227Skais base[i] = tmp1; 150227Skais base[j] = tmp0; 151227Skais 152227Skais tmp0 += tmp1; 153227Skais tmp0 = tmp0 & 0xff; 154227Skais 155227Skais merge0 = (unsigned long long)(base[tmp0]) << 56; 156227Skais shift = 8; mask = 0xff; 157227Skais } 158227Skais 159227Skais /* 160227Skais * Note - in and out may now be misaligned - 161227Skais * as updating [out] in 8B chunks need to handle this 162227Skais * possibility. Also could have a 1B overrun. 163227Skais * Need to drop out of loop early as a result. 164227Skais */ 165227Skais 166227Skais for (ii = 0, i1 = i; ii < ((len-1) & (~7)); 167227Skais ii += 8, i1 = i1&0xff) { 168227Skais 169227Skais /* 170227Skais * If i < less than 248, know wont wrap around 171227Skais * (i % 256), so don't need to bother with masking i 172227Skais * after each increment 173227Skais */ 174227Skais if (i1 < 248) { 175227Skais 176227Skais /* BYTE 0 */ 177227Skais i1 = (i1 + 1); 178227Skais 179227Skais /* 180227Skais * Creating this base pointer reduces subsequent 181227Skais * arihmetic ops required to load [i] 182227Skais * 183227Skais * N.B. don't need to check if [j] aliases. 184227Skais * [i] and [j] end up with the same values 185227Skais * anyway. 186227Skais */ 187227Skais base1 = &base[i1]; 188227Skais 189227Skais tmp0 = base1[0]; 190227Skais j = j + tmp0; 191227Skais 192227Skais tmp1 = base[j]; 193227Skais /* 194227Skais * Don't store [i] yet 195227Skais */ 196227Skais i_accum = tmp1; 197227Skais base[j] = tmp0; 198227Skais 199227Skais tmp0 += tmp1; 200227Skais tmp0 = tmp0 & 0xff; 201227Skais 202227Skais /* 203227Skais * Check [tmp0] doesn't alias with [i] 204227Skais */ 205227Skais 206227Skais /* 207227Skais * Updating [out] in 8B chunks 208227Skais */ 209227Skais if (i1 == tmp0) { 210227Skais merge = 211227Skais (unsigned long long)(i_accum) << 56; 212227Skais } else { 213227Skais merge = 214227Skais (unsigned long long)(base[tmp0]) << 215227Skais 56; 216227Skais } 217227Skais 218227Skais /* BYTE 1 */ 219227Skais tmp0 = base1[1]; 220227Skais 221227Skais j = j + tmp0; 222227Skais 223227Skais /* 224227Skais * [j] can now alias with [i] and [i-1] 225227Skais * If alias abort speculation 226227Skais */ 227227Skais if ((i1 ^ j) < 2) { 228227Skais base1[0] = i_accum; 229227Skais 230227Skais tmp1 = base[j]; 231227Skais 232227Skais base1[1] = tmp1; 233227Skais base[j] = tmp0; 234227Skais 235227Skais tmp0 += tmp1; 236227Skais tmp0 = tmp0 & 0xff; 237227Skais 238227Skais merge |= (unsigned long long) 239227Skais (base[tmp0]) << 48; 240227Skais } else { 241227Skais 242227Skais tmp1 = base[j]; 243227Skais 244227Skais i_accum = i_accum << 8; 245227Skais i_accum |= tmp1; 246227Skais 247227Skais base[j] = tmp0; 248227Skais 249227Skais tmp0 += tmp1; 250227Skais tmp0 = tmp0 & 0xff; 251227Skais 252227Skais /* 253227Skais * Speculation suceeded! Update [i] 254227Skais * in 2B chunk 255227Skais */ 256227Skais *((unsigned short *) &base[i1]) = 257227Skais i_accum; 258227Skais 259227Skais merge |= 260227Skais (unsigned long long)(base[tmp0]) << 261227Skais 48; 262227Skais } 263227Skais 264227Skais 265227Skais /* 266227Skais * Too expensive to perform [i] speculation for 267227Skais * every byte. Just need to reduce frequency 268227Skais * of stores until store buffer full stalls 269227Skais * are not the bottleneck. 270227Skais */ 271227Skais 272227Skais /* BYTE 2 */ 273227Skais tmp0 = base1[2]; 274227Skais j = j + tmp0; 275227Skais tmp1 = base[j]; 276227Skais base1[2] = tmp1; 277227Skais base[j] = tmp0; 278227Skais tmp1 += tmp0; 279227Skais tmp1 = tmp1 & 0xff; 280227Skais merge |= (unsigned long long)(base[tmp1]) << 40; 281227Skais 282227Skais /* BYTE 3 */ 283227Skais tmp0 = base1[3]; 284227Skais j = j + tmp0; 285227Skais tmp1 = base[j]; 286227Skais base1[3] = tmp1; 287227Skais base[j] = tmp0; 288227Skais tmp0 += tmp1; 289227Skais tmp0 = tmp0 & 0xff; 290227Skais merge |= (unsigned long long)(base[tmp0]) << 32; 291227Skais 292227Skais /* BYTE 4 */ 293227Skais tmp0 = base1[4]; 294227Skais j = j + tmp0; 295227Skais tmp1 = base[j]; 296227Skais base1[4] = tmp1; 297227Skais base[j] = tmp0; 298227Skais tmp0 += tmp1; 299227Skais tmp0 = tmp0 & 0xff; 300227Skais merge |= (unsigned long long)(base[tmp0]) << 24; 301227Skais 302227Skais /* BYTE 5 */ 303227Skais tmp0 = base1[5]; 304227Skais j = j + tmp0; 305227Skais tmp1 = base[j]; 306227Skais base1[5] = tmp1; 307227Skais base[j] = tmp0; 308227Skais tmp0 += tmp1; 309227Skais tmp0 = tmp0 & 0xff; 310227Skais merge |= (unsigned long long)(base[tmp0]) << 16; 311227Skais 312227Skais /* BYTE 6 */ 313227Skais i1 = (i1+6); 314227Skais tmp0 = base1[6]; 315227Skais j = j + tmp0; 316227Skais tmp1 = base[j]; 317227Skais i_accum = tmp1; 318227Skais base[j] = tmp0; 319227Skais 320227Skais tmp0 += tmp1; 321227Skais tmp0 = tmp0 & 0xff; 322227Skais 323227Skais if (i1 == tmp0) { 324227Skais merge |= 325227Skais (unsigned long long)(i_accum) << 8; 326227Skais } else { 327227Skais merge |= 328227Skais (unsigned long long)(base[tmp0]) << 329227Skais 8; 330227Skais } 331227Skais 332227Skais /* BYTE 7 */ 333227Skais tmp0 = base1[7]; 334227Skais 335227Skais /* 336227Skais * Perform [i] speculation again. Indentical 337227Skais * to that performed for BYTE0 and BYTE1. 338227Skais */ 339227Skais j = j + tmp0; 340227Skais if ((i1 ^ j) < 2) { 341227Skais base1[6] = i_accum; 342227Skais tmp1 = base[j]; 343227Skais 344227Skais base1[7] = tmp1; 345227Skais base[j] = tmp0; 346227Skais 347227Skais tmp0 += tmp1; 348227Skais tmp0 = tmp0 & 0xff; 349227Skais 350227Skais merge |= 351227Skais (unsigned long long)(base[tmp0]); 352227Skais 353227Skais } else { 354227Skais tmp1 = base[j]; 355227Skais 356227Skais i_accum = i_accum << 8; 357227Skais i_accum |= tmp1; 358227Skais 359227Skais base[j] = tmp0; 360227Skais 361227Skais tmp0 += tmp1; 362227Skais tmp0 = tmp0 & 0xff; 363227Skais 364227Skais *((unsigned short *) &base[i1]) = 365227Skais i_accum; 366227Skais 367227Skais merge |= 368227Skais (unsigned long long)(base[tmp0]); 369227Skais } 370227Skais i1++; 371227Skais } else { 372227Skais /* 373227Skais * i is too close to wrap-around to allow 374227Skais * masking to be disregarded 375227Skais */ 376227Skais 377227Skais /* 378227Skais * Same old speculation for BYTE 0 and BYTE 1 379227Skais */ 380227Skais 381227Skais /* BYTE 0 */ 382227Skais i1 = (i1 + 1) & 0xff; 383227Skais jj = i1; 384227Skais 385227Skais tmp0 = base[i1]; 386227Skais j = j + tmp0; 387227Skais 388227Skais tmp1 = base[j]; 389227Skais i_accum = tmp1; 390227Skais base[j] = tmp0; 391227Skais 392227Skais tmp0 += tmp1; 393227Skais tmp0 = tmp0 & 0xff; 394227Skais 395227Skais if (i1 == tmp0) { 396227Skais merge = 397227Skais (unsigned long long)(i_accum) << 56; 398227Skais } else { 399227Skais merge = 400227Skais (unsigned long long)(base[tmp0]) << 401227Skais 56; 402227Skais } 403227Skais 404227Skais /* BYTE 1 */ 405227Skais tmp0 = base[i1+1]; 406227Skais 407227Skais j = j + tmp0; 408227Skais 409227Skais if ((jj ^ j) < 2) { 410227Skais base[jj] = i_accum; 411227Skais 412227Skais tmp1 = base[j]; 413227Skais 414227Skais base[i1+1] = tmp1; 415227Skais base[j] = tmp0; 416227Skais 417227Skais tmp0 += tmp1; 418227Skais tmp0 = tmp0 & 0xff; 419227Skais 420227Skais merge |= 421227Skais (unsigned long long)(base[tmp0]) << 422227Skais 48; 423227Skais } else { 424227Skais 425227Skais tmp1 = base[j]; 426227Skais 427227Skais i_accum = i_accum << 8; 428227Skais i_accum |= tmp1; 429227Skais 430227Skais base[j] = tmp0; 431227Skais 432227Skais tmp0 += tmp1; 433227Skais tmp0 = tmp0 & 0xff; 434227Skais 435227Skais *((unsigned short *) &base[jj]) = 436227Skais i_accum; 437227Skais 438227Skais merge |= 439227Skais (unsigned long long)(base[tmp0]) << 440227Skais 48; 441227Skais } 442227Skais 443227Skais /* BYTE 2 */ 444227Skais /* 445227Skais * As know i must be even when enter loop (to 446227Skais * satisfy alignment), can only wrap around 447227Skais * on the even bytes. So just need to perform 448227Skais * mask every 2nd byte 449227Skais */ 450227Skais i1 = (i1 + 2) & 0xff; 451227Skais tmp0 = base[i1]; 452227Skais j = j + tmp0; 453227Skais tmp1 = base[j]; 454227Skais base[i1] = tmp1; 455227Skais base[j] = tmp0; 456227Skais tmp0 += tmp1; 457227Skais tmp0 = tmp0 & 0xff; 458227Skais merge |= (unsigned long long)(base[tmp0]) << 40; 459227Skais 460227Skais /* BYTE 3 */ 461227Skais tmp0 = base[i1+1]; 462227Skais j = j + tmp0; 463227Skais tmp1 = base[j]; 464227Skais base[i1+1] = tmp1; 465227Skais base[j] = tmp0; 466227Skais tmp0 += tmp1; 467227Skais tmp0 = tmp0 & 0xff; 468227Skais merge |= (unsigned long long)(base[tmp0]) << 32; 469227Skais 470227Skais /* BYTE 4 */ 471227Skais i1 = (i1 + 2) & 0xff; 472227Skais tmp0 = base[i1]; 473227Skais j = j + tmp0; 474227Skais tmp1 = base[j]; 475227Skais base[i1] = tmp1; 476227Skais base[j] = tmp0; 477227Skais tmp0 += tmp1; 478227Skais tmp0 = tmp0 & 0xff; 479227Skais merge |= (unsigned long long)(base[tmp0]) << 24; 480227Skais 481227Skais /* BYTE 5 */ 482227Skais tmp0 = base[i1+1]; 483227Skais j = j + tmp0; 484227Skais tmp1 = base[j]; 485227Skais base[i1+1] = tmp1; 486227Skais base[j] = tmp0; 487227Skais tmp0 += tmp1; 488227Skais tmp0 = tmp0 & 0xff; 489227Skais merge |= (unsigned long long)(base[tmp0]) << 16; 490227Skais 491227Skais /* BYTE 6 */ 492227Skais i1 = (i1+2) &0xff; 493227Skais jj = i1; 494227Skais tmp0 = base[i1]; 495227Skais 496227Skais j = j + tmp0; 497227Skais 498227Skais tmp1 = base[j]; 499227Skais i_accum = tmp1; 500227Skais base[j] = tmp0; 501227Skais 502227Skais 503227Skais tmp0 += tmp1; 504227Skais tmp0 = tmp0 & 0xff; 505227Skais 506227Skais if (i1 == tmp0) { 507227Skais merge |= 508227Skais (unsigned long long)(i_accum) << 8; 509227Skais } else { 510227Skais merge |= 511227Skais (unsigned long long)(base[tmp0]) << 512227Skais 8; 513227Skais } 514227Skais 515227Skais /* BYTE 7 */ 516227Skais i1++; 517227Skais tmp0 = base[i1]; 518227Skais 519227Skais j = j + tmp0; 520227Skais if ((jj ^ j) < 2) { 521227Skais base[jj] = i_accum; 522227Skais tmp1 = base[j]; 523227Skais 524227Skais base[i1] = tmp1; 525227Skais base[j] = tmp0; 526227Skais 527227Skais tmp0 += tmp1; 528227Skais tmp0 = tmp0 & 0xff; 529227Skais 530227Skais merge |= 531227Skais (unsigned long long)(base[tmp0]); 532227Skais 533227Skais } else { 534227Skais tmp1 = base[j]; 535227Skais 536227Skais i_accum = i_accum << 8; 537227Skais i_accum |= tmp1; 538227Skais 539227Skais base[j] = tmp0; 540227Skais 541227Skais tmp0 += tmp1; 542227Skais tmp0 = tmp0 & 0xff; 543227Skais 544227Skais *((unsigned short *) &base[jj]) = 545227Skais i_accum; 546227Skais 547227Skais merge |= 548227Skais (unsigned long long)(base[tmp0]); 549227Skais } 550227Skais } 551227Skais 552227Skais /* 553227Skais * Perform update to [out] 554227Skais * Remember could be alignment issues 555227Skais */ 556227Skais in0 = *((unsigned long long *) (&in[ii])); 557227Skais 558227Skais merge1 = merge0 | (merge >> shift); 559227Skais 560227Skais merge0 = (merge & mask) << 56; 561227Skais 562227Skais in0 = in0 ^ merge1; 563227Skais 564227Skais *((unsigned long long *) (&out[ii])) = in0; 565227Skais } 566227Skais 567227Skais i = i1; 568227Skais 569227Skais /* 570227Skais * Handle any overrun 571227Skais */ 572227Skais if (shift) { 573227Skais out[ii] = in[ii] ^ (merge0 >> 56); 574227Skais ii++; 575227Skais } 576227Skais 577227Skais /* 578227Skais * Handle final few bytes 579227Skais */ 580227Skais for (; ii < len; ii++) { 581227Skais i = i + 1; 582227Skais tmp0 = base[i]; 583227Skais j = j + tmp0; 584227Skais tmp1 = base[j]; 585227Skais 586227Skais base[i] = tmp1; 587227Skais base[j] = tmp0; 588227Skais 589227Skais tmp0 += tmp1; 590227Skais tmp0 = tmp0 & 0xff; 591227Skais out[ii] = in[ii] ^ base[tmp0]; 592227Skais } 593227Skais key->i = i; 594227Skais key->j = j; 595227Skais } 596227Skais #endif /* sun4v */ 597227Skais 598227Skais /* EXPORT DELETE END */ 599227Skais } 600