> 8 ); } private function GetB2($A){ return 0x000000ff & ( $A >> 16 ); } private function GetB3($A){ return 0x000000ff & ( $A >> 24 ); } //---------------------------------------- //엔디안 변환 (데이터의 순서 변환) private function EndianChange( $dws ) { return ( $dws >> 24 ) | ( $dws << 24 ) | ( ( $dws << 8 ) & 0x00ff0000 ) | ( ( $dws >> 8 ) & 0x0000ff00 ); } /***************************** SEED round function ****************************/ public function SeedRound( &$L0, &$L1, // [in, out] left-side variable at each round &$R0, &$R1, // [in] right-side variable at each round $K = array() // [in] round keys at each round ) { $T0 = $R0 ^ $K[0]; $T1 = $R1 ^ $K[1]; $T1 ^= $T0; $T1 = $this->SS0[$this->GetB0($T1)] ^ $this->SS1[$this->GetB1($T1)] ^ $this->SS2[$this->GetB2($T1)] ^ $this->SS3[$this->GetB3($T1)]; $T0 += $T1; $T0 = $this->ConvertInt($T0); $T0 = $this->SS0[$this->GetB0($T0)] ^ $this->SS1[$this->GetB1($T0)] ^ $this->SS2[$this->GetB2($T0)] ^ $this->SS3[$this->GetB3($T0)]; $T1 += $T0; $T1 = $this->ConvertInt($T1); $T1 = $this->SS0[$this->GetB0($T1)] ^ $this->SS1[$this->GetB1($T1)] ^ $this->SS2[$this->GetB2($T1)] ^ $this->SS3[$this->GetB3($T1)]; $T0 += $T1; $T0 = $this->ConvertInt($T0); $L0 ^= $T0; $L1 ^= $T1; } //추가된 함수 by mibany (2011-01-21) //PHP 에서는 float를 int로 강제로 형변환이 되지 않는다. //이사실을 전혀 몰랐던 나는 C++ 의 달인 Keige 님의 도움으로 //PHP 로 구현하기 위한 핵심부분인 이 함수를 만들게 되었다. //문제는 고수가 아닌 나에게 이함수 구현이란 내게 어려운 일이었다. //혹시라도 이함수의 오류로 인해 Seed 암호화가 문제가 있을수도 있으니 //고수분들의 도움이 절실하다. private function ConvertInt($float) { $IntMax = PHP_INT_MAX; $IntMin = ( PHP_INT_MAX * -1 ) -1; if(is_float($float) && $float < $IntMin ) { $division = floor($float / $IntMin ); $n = ($division % 2 == 0)?0:$IntMin; if( $float < $IntMin ) $c = $float - ( $IntMin * $division ) - $n; } elseif(is_float($float) && $float > $IntMax) { $division = floor($float / $IntMax ); $n = ($division % 2 == 0)?0:$IntMax; if( $float > $IntMax) $c = $float - ( $IntMax * $division ) - $n - 2; } else $c = $float; return $c; } /************************** SEED encrtyption function *************************/ public function SeedEncrypt( $pbData = array(), // [in] data to be encrypted $pdwRoundKey = array(), // [in] round keys for encryption &$outData = array() // [out] encrypted data ) { $L0 = 0x0; $L1 = 0x0; $R0 = 0x0; $R1 = 0x0; $K = array(); $nCount = 0; // Set up input values for encryption $L0 = ( $pbData[0] & 0x000000ff ); $L0 = ( $L0 << 8 ) ^ ( $pbData[1] & 0x000000ff ); $L0 = ( $L0 << 8 ) ^ ( $pbData[2] & 0x000000ff ); $L0 = ( $L0 << 8 ) ^ ( $pbData[3] & 0x000000ff ); $L1 = ( $pbData[4] & 0x000000ff ); $L1 = ( $L1 << 8 ) ^ ( $pbData[5] & 0x000000ff ); $L1 = ( $L1 << 8 ) ^ ( $pbData[6] & 0x000000ff ); $L1 = ( $L1 << 8 ) ^ ( $pbData[7] & 0x000000ff ); $R0 = ( $pbData[8] & 0x000000ff ); $R0 = ( $R0 <<8 ) ^ ( $pbData[9] & 0x000000ff ); $R0 = ( $R0 <<8 ) ^ ( $pbData[10] & 0x000000ff ); $R0 = ( $R0 <<8 ) ^ ( $pbData[11] & 0x000000ff ); $R1 = ( $pbData[12] & 0x000000ff ); $R1 = ( $R1 <<8 ) ^ ( $pbData[13] & 0x000000ff ); $R1 = ( $R1 <<8 ) ^ ( $pbData[14] & 0x000000ff ); $R1 = ( $R1 <<8 ) ^ ( $pbData[15] & 0x000000ff ); // Reorder for little endian // Because java virtual machine use big endian order in default if (!$this->ENDIAN) { $this->EndianChange($L0); $this->EndianChange($L1); $this->EndianChange($R0); $this->EndianChange($R1); } $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 1 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 2 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 3 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 4 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 5 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 6 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 7 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 8 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 9 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 10 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 11 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 12 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 13 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 14 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 15 */ $K[0] = $pdwRoundKey[$nCount++]; $K[1] = $pdwRoundKey[$nCount++]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 16 */ if (!$this->ENDIAN) { $this->EndianChange($L0); $this->EndianChange($L1); $this->EndianChange($R0); $this->EndianChange($R1); } // Copying output values from last round to outData for ($i=0; $i<16; $i++) $outData[$i] = null; for ($i=0; $i<4; $i++) { $outData[$i] = ( ( ( $R0 ) >>( 8 * ( 3 - $i ) ) ) & 0xff ); $outData[4+$i] = ( ( ( $R1 ) >> ( 8 * ( 3 - $i ) ) ) & 0xff ); $outData[8+$i] = ( ( ( $L0 ) >> ( 8 * ( 3 - $i ) ) ) & 0xff ); $outData[12+$i] = ( ( ( $L1 ) >> ( 8 * ( 3 - $i ) ) ) &0xff ); } } /************************** SEED decrtyption function *************************/ // Same as encrypt, except that round keys are applied in reverse order public function SeedDecrypt( $pbData = array(), // [in] encrypted data $pdwRoundKey = array(), // [in] round keys for decryption &$outData = array() // [out] data to be encrypted ) { $L0 = 0x0; $L1 = 0x0; $R0 = 0x0; $R1 = 0x0; $K = array(); $nCount = 31; // Set up input values for decryption $L0 = ( $pbData[0] & 0x000000ff ); $L0 = ( $L0 << 8 ) ^ ( $pbData[1] & 0x000000ff ); $L0 = ( $L0 << 8 ) ^ ( $pbData[2] & 0x000000ff ); $L0 = ( $L0 << 8 ) ^ ( $pbData[3] & 0x000000ff ); $L1 = ( $pbData[4] & 0x000000ff ); $L1 = ( $L1 << 8 ) ^( $pbData[5] & 0x000000ff ); $L1 = ( $L1 << 8 ) ^ ( $pbData[6] & 0x000000ff ); $L1 = ( $L1 << 8 ) ^ ( $pbData[7] & 0x000000ff ); $R0 = ( $pbData[8] & 0x000000ff ); $R0 = ( $R0 << 8 ) ^ ( $pbData[9] & 0x000000ff ); $R0 = ( $R0 << 8 ) ^ ( $pbData[10] & 0x000000ff ); $R0 = ( $R0 << 8 ) ^ ( $pbData[11] & 0x000000ff ); $R1 = ( $pbData[12] & 0x000000ff ); $R1 = ( $R1 << 8 ) ^ ( $pbData[13] & 0x000000ff ); $R1 = ( $R1 << 8 ) ^ ( $pbData[14] & 0x000000ff ); $R1 = ( $R1 << 8 ) ^ ( $pbData[15] & 0x000000ff ); // Reorder for little endian if (!$this->ENDIAN) { $this->EndianChange($L0); $this->EndianChange($L1); $this->EndianChange($R0); $this->EndianChange($R1); } $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 1 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 2 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 3 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 4 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 5 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 6 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 7 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 8 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 9 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 10 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 11 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 12 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 13 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 14 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount--]; $this->SeedRound($L0, $L1, $R0, $R1, $K); /* 15 */ $K[1] = $pdwRoundKey[$nCount--]; $K[0] = $pdwRoundKey[$nCount]; $this->SeedRound($R0, $R1, $L0, $L1, $K); /* 16 */ if (!$this->ENDIAN) { $this->EndianChange($L0); $this->EndianChange($L1); $this->EndianChange($R0); $this->EndianChange($R1); } // Copy output values from last round to outData for ($i=0; $i<16; $i++) $outData[$i] = null; for ($i=0; $i < 4; $i++) { $outData[$i] = ( ( ( $R0 ) >> ( 8 * ( 3 - $i ) ) ) & 0xff ); $outData[4+$i] = ( ( ( $R1 ) >> ( 8 * ( 3 - $i ) ) ) & 0xff ); $outData[8+$i] = ( ( ( $L0 ) >> ( 8 * ( 3 - $i ) ) ) & 0xff ); $outData[12+$i] = ( ( ( $L1 ) >> ( 8 * ( 3 - $i ) ) ) & 0xff ); } } /************************ Functions for Key schedule **************************/ private function EncRoundKeyUpdate0(&$K = array(), &$A, &$B, &$C, &$D, $Z) { $T0 = $A; $A = ( $A >> 8 & 0x00ffffff ) ^ ( $B << 24 ); $B = ( $B >> 8 & 0x00ffffff ) ^ ( $T0 << 24 ); $T00 = (int) $A + (int) $C - (int) $this->KC[$Z]; $T00 = $this->ConvertInt($T00); $T11 = (int) $B + (int) $this->KC[$Z] - (int) $D; $T11 = $this->ConvertInt($T11); $K[0] = $this->SS0[$this->GetB0($T00)] ^ $this->SS1[$this->GetB1($T00)] ^ $this->SS2[$this->GetB2($T00)] ^ $this->SS3[$this->GetB3($T00)]; $K[1] = $this->SS0[$this->GetB0($T11)] ^ $this->SS1[$this->GetB1($T11)] ^ $this->SS2[$this->GetB2($T11)] ^ $this->SS3[$this->GetB3($T11)]; } private function EncRoundKeyUpdate1(&$K = array(), &$A, &$B, &$C, &$D, $Z) { $T0 = $C; $C = ( $C << 8 ) ^ ( $D >> 24 & 0x000000ff ); $D = ( $D << 8 ) ^ ( $T0 >> 24 & 0x000000ff ); $T00 = (int) $A + (int) $C - (int) $this->KC[$Z]; $T00 = $this->ConvertInt($T00); $T11 = (int) $B + (int) $this->KC[$Z] - (int) $D; $T11 = $this->ConvertInt($T11); $K[0] = $this->SS0[$this->GetB0($T00)] ^ $this->SS1[$this->GetB1($T00)] ^ $this->SS2[$this->GetB2($T00)] ^ $this->SS3[$this->GetB3($T00)]; $K[1] = $this->SS0[$this->GetB0($T11)] ^ $this->SS1[$this->GetB1($T11)] ^ $this->SS2[$this->GetB2($T11)] ^ $this->SS3[$this->GetB3($T11)]; } /******************************** Key Schedule ********************************/ public function SeedRoundKey( &$pdwRoundKey = array(), // [out] round keys for encryption or decryption $pbUserKey = array() // [in] secret user key ) { $K = array(); $nCount = 2; // Set up input values for Key Schedule $A = @( $pbUserKey[0] & 0x000000ff ); $A = ( $A << 8 ) ^ @( $pbUserKey[1] & 0x000000ff ); $A = ( $A << 8 ) ^ @( $pbUserKey[2] & 0x000000ff ); $A = ( $A << 8 ) ^ @( $pbUserKey[3] & 0x000000ff ); $B = @( $pbUserKey[4] & 0x000000ff ); $B = ( $B<<8 ) ^ @( $pbUserKey[5] & 0x000000ff ); $B = ( $B<<8 ) ^ @( $pbUserKey[6] & 0x000000ff ); $B = ( $B<<8 ) ^ @( $pbUserKey[7] & 0x000000ff ); $C = @( $pbUserKey[8] & 0x000000ff ); $C = ( $C << 8 ) ^ @( $pbUserKey[9] & 0x000000ff ); $C = ( $C << 8 ) ^ @( $pbUserKey[10] & 0x000000ff ); $C = ( $C << 8 ) ^ @( $pbUserKey[11] & 0x000000ff ); $D = @( $pbUserKey[12] & 0x000000ff ); $D = ( $D << 8 ) ^ @($pbUserKey[13] & 0x000000ff ); $D = ( $D << 8 ) ^ @( $pbUserKey[14] & 0x000000ff ); $D = ( $D << 8 ) ^ @( $pbUserKey[15] & 0x000000ff ); // reorder for little endian if (!$this->ENDIAN) { $A = $this->EndianChange($A); $B = $this->EndianChange($B); $C = $this->EndianChange($C); $D = $this->EndianChange($D); } $T0 = (int) $A + (int) $C - (int) $this->KC[0]; $T0 = $this->ConvertInt($T0); $T1 = (int) $B - (int) $D + (int) $this->KC[0]; $T1 = $this->ConvertInt($T1); $pdwRoundKey[0] = $this->SS0[$this->GetB0($T0)] ^ $this->SS1[$this->GetB1($T0)] ^ $this->SS2[$this->GetB2($T0)] ^ $this->SS3[$this->GetB3($T0)]; $pdwRoundKey[1] = $this->SS0[$this->GetB0($T1)] ^ $this->SS1[$this->GetB1($T1)] ^ $this->SS2[$this->GetB2($T1)] ^ $this->SS3[$this->GetB3($T1)]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 1 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate1($K, $A, $B, $C, $D, 2 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 3 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate1($K, $A, $B, $C, $D, 4 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 5 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate1($K, $A, $B, $C, $D, 6 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 7 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate1($K, $A, $B, $C, $D, 8 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 9 ); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate1($K, $A, $B, $C, $D, 10); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 11); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate1($K, $A, $B, $C, $D, 12); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 13); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate1($K, $A, $B, $C, $D, 14); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; $this->EncRoundKeyUpdate0($K, $A, $B, $C, $D, 15); $pdwRoundKey[$nCount++] = $K[0]; $pdwRoundKey[$nCount++] = $K[1]; } public function SeedRoundKeyText(&$pdwRoundKey, $pbUserKey) { $Data = []; $len = strlen($pbUserKey); for ($i = 0; $i < $len; $i++) { $Data[$i] = ord($pbUserKey[$i]); // ✅ {} -> [] } $this->SeedRoundKey($pdwRoundKey, $Data); } public function SeedEncryptText($pbData, $pdwRoundKey, &$outData) { $Data = []; $len = strlen($pbData); for ($i = 0; $i < $len; $i++) { $Data[$i] = ord($pbData[$i]); // ✅ {} -> [] } $this->SeedEncrypt($Data, $pdwRoundKey, $outData); } public function SeedDecryptText($pbData, $pdwRoundKey, &$outData) { $Data = []; $len = strlen($pbData); for ($i = 0; $i < $len; $i++) { $Data[$i] = ord($pbData[$i]); // ✅ {} -> [] } $this->SeedDecrypt($Data, $pdwRoundKey, $outData); } }