function xxtea_decrypt($str, $key) { if ($str == "") { return ""; } $v = str2long($str, false); $k = str2long($key, false); if (count($k) < 4) { for ($i = count($k); $i < 4; $i++) { $k[$i] = 0; } } $n = count($v) - 1; $z = $v[$n]; $y = $v[0]; $delta = 0x9E3779B9; $q = floor(6 + 52 / ($n + 1)); $sum = int32($q * $delta); while ($sum != 0) { $e = $sum >> 2 & 3; for ($p = $n; $p > 0; $p--) { $z = $v[$p - 1]; $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); $y = $v[$p] = int32($v[$p] - $mx); } $z = $v[$n]; $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); $y = $v[0] = int32($v[0] - $mx); $sum = int32($sum - $delta); } return long2str($v, true); }
/** Decipher * @param string binary cipher * @param string * @return string plain-text password */ function decrypt_string($str, $key) { if ($str == "") { return ""; } $key = array_values(unpack("V*", pack("H*", md5($key)))); $v = str2long($str, false); $n = count($v) - 1; $z = $v[$n]; $y = $v[0]; $q = floor(6 + 52 / ($n + 1)); $sum = int32($q * 0x9e3779b9); while ($sum) { $e = $sum >> 2 & 3; for ($p = $n; $p > 0; $p--) { $z = $v[$p - 1]; $mx = xxtea_mx($z, $y, $sum, $key[$p & 3 ^ $e]); $y = int32($v[$p] - $mx); $v[$p] = $y; } $z = $v[$n]; $mx = xxtea_mx($z, $y, $sum, $key[$p & 3 ^ $e]); $y = int32($v[0] - $mx); $v[0] = $y; $sum = int32($sum - 0x9e3779b9); } return long2str($v, true); }
/** * Parse workbook */ function parse_workbook($f_header, $dp) { /*DBG*/ $this->dbglog->debug("parse_workbook() function"); $root_entry_block = $f_header->getLong(0x30); $num_fat_blocks = $f_header->getLong(0x2c); /*TRC*/ $this->dbglog->trace("Header parsed"); $this->fat = array(); $num_fat_blocks1 = $num_fat_blocks > 108 ? 109 : $num_fat_blocks; $pos = 0x4c; for ($i = 0; $i < $num_fat_blocks1; $i++) { /*TRC*/ $this->dbglog->trace("FOR LOOP iteration i =" . $i . " of " . $num_fat_blocks); $fat_block = $f_header->getLong($pos); $fatbuf = $dp->get($fat_block * 0x200, 0x200); $fat = new DataProvider($fatbuf, DP_STRING_SOURCE); if ($fat->getSize() < 0x200) { /*DBG*/ $this->dbglog->debug("parse_workbook() function found (strlen({$fat}) < 0x200) returns 6"); return 6; } for ($j = 0; $j < 0x80; $j++) { $this->fat[] = $fat->getLong($j * 4); } $fat->close(); unset($fat_block, $fatbuf, $fat); $pos += 4; } // read XBAT $pos = $f_header->getLong(XBAT_START) * 512; $blockstart = 109; for ($j = 0; $j < $f_header->getLong(XBAT_COUNT); $j++) { $nblocks = min($f_header->getLong(BAT_COUNT) - $blockstart, 127); for ($i = $blockstart; $i < $nblocks + $blockstart; $i++) { /*TRC*/ $this->dbglog->trace("FOR LOOP iteration (XBAT) i =" . $i . " of " . $num_fat_blocks); $fat_block = $dp->getLong($pos); $fatbuf = $dp->get($fat_block * 0x200, 0x200); $fat = new DataProvider($fatbuf, DP_STRING_SOURCE); if ($fat->getSize() < 0x200) { /*DBG*/ $this->dbglog->debug("parse_workbook() function found (strlen({$fat}) < 0x200) returns 6"); return 6; } for ($j = 0; $j < 0x80; $j++) { $this->fat[] = $fat->getLong($j * 4); } $fat->close(); unset($fat_block, $fatbuf, $fat); $pos += 4; } $blockstart += $nblocks; if ($blockstart < $f_header->getLong(BAT_COUNT)) { // $pos = getlong($pos); } } /*DBG*/ $this->dbglog->dump($this->fat, "\$fat"); if (count($this->fat) < $num_fat_blocks) { /*DBG*/ $this->dbglog->debug("parse_workbook() function found (count({$this->fat}) < {$num_fat_blocks}) returns 6"); return 6; } $chain = $this->get_blocks_chain($root_entry_block); $dir = new DataProvider($dp->ReadFromFat($chain), DP_STRING_SOURCE); unset($chain); $this->sfat = array(); $small_block = $f_header->getLong(0x3c); if ($small_block != 0xfeffffff) { $root_entry_index = $this->find_stream($dir, 'Root Entry'); // Deleted for support MAC files //if( $root_entry_index < 0 ) { /*DBG*/ //$this->dbglog->debug("parse_workbook() function dont found Root Entry returns 6"); //return 6; //} $sdc_start_block = $dir->getLong($root_entry_index * 0x80 + 0x74); $small_data_chain = $this->get_blocks_chain($sdc_start_block); $this->max_sblocks = count($small_data_chain) * 8; $schain = $this->get_blocks_chain($small_block); for ($i = 0; $i < count($schain); $i++) { $sfatbuf = $dp->get($schain[$i] * 0x200, 0x200); $sfat = new DataProvider($sfatbuf, DP_STRING_SOURCE); //$this->dbglog->dump( strlen($sfatbuf), "strlen(\$sftabuf)"); //$this->dbglog->dump( $sfat, "\$sfat"); if ($sfat->getSize() < 0x200) { /*DBG*/ $this->dbglog->debug("parse_workbook() function found (strlen({$sfat}) < 0x200) returns 6"); return 6; } for ($j = 0; $j < 0x80; $j++) { $this->sfat[] = $sfat->getLong($j * 4); } $sfat->close(); unset($sfatbuf, $sfat); } unset($schain); $sfcbuf = $dp->ReadFromFat($small_data_chain); $sdp = new DataProvider($sfcbuf, DP_STRING_SOURCE); unset($sfcbuf, $small_data_chain); } $workbook_index = $this->find_stream($dir, 'Workbook'); if ($workbook_index < 0) { $workbook_index = $this->find_stream($dir, 'Book'); if ($workbook_index < 0) { /*DBG*/ $this->dbglog->debug("parse_workbook() function workbook index not found returns 7"); return 7; } } $workbook_start_block = $dir->getLong($workbook_index * 0x80 + 0x74); $workbook_length = $dir->getLong($workbook_index * 0x80 + 0x78); $wb = ''; if ($workbook_length > 0) { if ($workbook_length >= 0x1000) { $chain = $this->get_blocks_chain($workbook_start_block); $wb = $dp->ReadFromFat($chain); } else { $chain = $this->get_blocks_chain($workbook_start_block, true); $wb = $sdp->ReadFromFat($chain, 0x40); unset($sdp); } $wb = substr($wb, 0, $workbook_length); if (strlen($wb) != $workbook_length) { return 6; } unset($chain); } // Unset fat arrays unset($this->fat, $this->sfat); if (strlen($wb) <= 0) { /*DBG*/ $this->dbglog->debug("parse_workbook() function workbook found (strlen({$wb}) <= 0) returns 7"); return 7; } if (strlen($wb) < 4) { /*DBG*/ $this->dbglog->debug("parse_workbook() function workbook found (strlen({$wb}) < 4) returns 6"); return 6; } // parse workbook header if (strlen($wb) < 256 * ord($wb[3]) + ord($wb[2])) { /*DBG*/ $this->dbglog->debug("parse_workbook() function workbook found (strlen({$wb}) < 256*ord({$wb['3']})+ord({$wb['2']})) < 4) returns 6"); return 6; } if (ord($wb[0]) != 0x9) { /*DBG*/ $this->dbglog->debug("parse_workbook() function workbook found (ord({$wb['0']}) != 0x09) returns 6"); return 6; } $vers = ord($wb[1]); if ($vers != 0 && $vers != 2 && $vers != 4 && $vers != 8) { return 8; } if ($vers != 8) { $biff_ver = ($ver + 4) / 2; } else { if (strlen($wb) < 12) { return 6; } switch (ord($wb[4]) + 256 * ord($wb[5])) { case 0x500: if (ord($wb[0xa]) + 256 * ord($wb[0xb]) < 1994) { $biff_ver = 5; } else { switch (ord($wb[8]) + 256 * ord($wb[9])) { case 2412: case 3218: case 3321: $biff_ver = 5; break; default: $biff_ver = 7; break; } } break; case 0x600: $biff_ver = 8; break; default: return 8; } } if ($biff_ver < 5) { return 8; } $ptr = 0; $this->worksheet['offset'] = array(); $this->worksheet['options'] = array(); $this->worksheet['unicode'] = array(); $this->worksheet['name'] = array(); $this->worksheet['data'] = array(); $this->format = $this->populateFormat(); $this->fonts = array(); $this->fonts[0] = ExcelFont::basicFontRecord(); $this->xf = array(); $this->xf['format'] = array(); $this->xf['font'] = array(); $this->xf['type_prot'] = array(); $this->xf['alignment'] = array(); $this->xf['decoration'] = array(); $xf_cnt = 0; $this->sst['unicode'] = array(); $this->sst['data'] = array(); $opcode = 0; $sst_defined = false; $wblen = strlen($wb); while (ord($wb[$ptr]) != 0xa && $ptr < $wblen) { $oc = ord($wb[$ptr]) + 256 * ord($wb[$ptr + 1]); if ($oc != 0x3c) { $opcode = $oc; } switch ($opcode) { case 0x85: $ofs = str2long(substr($wb, $ptr + 4, 4)); $this->worksheet['offset'][] = $ofs; $this->worksheet['options'][] = ord($wb[$ptr + 8]) + 256 * ord($wb[$ptr + 9]); if ($biff_ver == 8) { $len = ord($wb[$ptr + 10]); if ((ord($wb[$ptr + 11]) & 1) > 0) { $this->worksheet['unicode'][] = true; $len = $len * 2; } else { $this->worksheet['unicode'][] = false; } $this->worksheet['name'][] = substr($wb, $ptr + 12, $len); } else { $this->worksheet['unicode'][] = false; $len = ord($wb[$ptr + 10]); $this->worksheet['name'][] = substr($wb, $ptr + 11, $len); } $pws = $this->parse_worksheet(substr($wb, $ofs)); if (is_array($pws)) { $this->worksheet['data'][] = $pws; } else { return $pws; } break; // Format // Format case 0x41e: $fidx = ord($wb[$ptr + 4]) + 256 * ord($wb[$ptr + 5]); if ($fidx < 0x31 || $fidx == 0x31) { break; } elseif ($biff_ver > 7) { $this->format[$fidx] = $this->getUnicodeString($wb, $ptr + 6); } // echo $wb."---".$this->format[$fidx]."*****<br>"; // FONT 0x31 // echo $wb."---".$this->format[$fidx]."*****<br>"; // FONT 0x31 case EXCEL_FONT_RID: $rec = ExcelFont::getFontRecord($wb, $ptr + 4); $this->fonts[count($this->fonts)] = $rec; /*echo str_replace("\n","<br>\n",ExcelFont::toString($rec,count($this->fonts)-1)); echo "FontRecord<br>" */ break; // XF // XF case 0xe0: $this->xf['font'][$xf_cnt] = ord($wb[$ptr + 4]) + 256 * ord($wb[$ptr + 5]); $this->xf['format'][$xf_cnt] = ord($wb[$ptr + 6]) + 256 * ord($wb[$ptr + 7]); $this->xf['type'][$xf_cnt] = "1"; $this->xf['bitmask'][$xf_cnt] = "1"; $xf_cnt++; break; // SST // SST case 0xfc: if ($biff_ver < 8) { break; } $sbuflen = ord($wb[$ptr + 2]) + 256 * ord($wb[$ptr + 3]); if ($oc != 0x3c) { if ($sst_defined) { return 6; } $snum = str2long(substr($wb, $ptr + 8, 4)); $sptr = $ptr + 12; $sst_defined = true; } else { if ($rslen > $slen) { $sptr = $ptr + 4; $rslen -= $slen; $slen = $rslen; if ((ord($wb[$sptr]) & 1) > 0) { if ($char_bytes == 1) { $sstr = ''; for ($i = 0; $i < strlen($str); $i++) { $sstr .= $str[$i] . chr(0); } $str = $sstr; $char_bytes = 2; } $schar_bytes = 2; } else { $schar_bytes = 1; } if ($sptr + $slen * $schar_bytes > $ptr + 4 + $sbuflen) { $slen = ($ptr + $sbuflen - $sptr + 3) / $schar_bytes; } $sstr = substr($wb, $sptr + 1, $slen * $schar_bytes); if ($char_bytes == 2 && $schar_bytes == 1) { $sstr2 = ''; for ($i = 0; $i < strlen($sstr); $i++) { $sstr2 .= $sstr[$i] . chr(0); } $sstr = $sstr2; } $str .= $sstr; $sptr += $slen * $schar_bytes + 1 + 4 * $rt + $fesz; if ($slen < $rslen) { if ($sptr >= strlen($wb) || $sptr < $ptr + 4 + $sbuflen || ord($wb[$sptr]) != 0x3c) { return 6; } break; } else { if ($char_bytes == 2) { $this->sst['unicode'][] = true; } else { $this->sst['unicode'][] = false; } $this->sst['data'][] = $str; $snum--; } } else { $sptr = $ptr + 4; if ($sptr > $ptr) { $sptr += 4 * $rt + $fesz; } } } while ($sptr < $ptr + 4 + $sbuflen && $sptr < strlen($wb) && $snum > 0) { $rslen = ord($wb[$sptr]) + 256 * ord($wb[$sptr + 1]); $slen = $rslen; if ((ord($wb[$sptr + 2]) & 1) > 0) { $char_bytes = 2; } else { $char_bytes = 1; } $rt = 0; $fesz = 0; switch (ord($wb[$sptr + 2]) & 0xc) { // Rich-Text with Far-East case 0xc: $rt = ord($wb[$sptr + 3]) + 256 * ord($wb[$sptr + 4]); $fesz = str2long(substr($wb, $sptr + 5, 4)); if ($sptr + 9 + $slen * $char_bytes > $ptr + 4 + $sbuflen) { $slen = ($ptr + $sbuflen - $sptr - 5) / $char_bytes; } $str = substr($wb, $sptr + 9, $slen * $char_bytes); $sptr += $slen * $char_bytes + 9; break; // Rich-Text // Rich-Text case 8: $rt = ord($wb[$sptr + 3]) + 256 * ord($wb[$sptr + 4]); if ($sptr + 5 + $slen * $char_bytes > $ptr + 4 + $sbuflen) { $slen = ($ptr + $sbuflen - $sptr - 1) / $char_bytes; } $str = substr($wb, $sptr + 5, $slen * $char_bytes); $sptr += $slen * $char_bytes + 5; break; // Far-East // Far-East case 4: $fesz = str2long(substr($wb, $sptr + 3, 4)); if ($sptr + 7 + $slen * $char_bytes > $ptr + 4 + $sbuflen) { $slen = ($ptr + $sbuflen - $sptr - 3) / $char_bytes; } $str = substr($wb, $sptr + 7, $slen * $char_bytes); $sptr += $slen * $char_bytes + 7; break; // Compressed or uncompressed unicode // Compressed or uncompressed unicode case 0: if ($sptr + 3 + $slen * $char_bytes > $ptr + 4 + $sbuflen) { $slen = ($ptr + $sbuflen - $sptr + 1) / $char_bytes; } $str = substr($wb, $sptr + 3, $slen * $char_bytes); $sptr += $slen * $char_bytes + 3; break; } if ($slen < $rslen) { if ($sptr >= strlen($wb) || $sptr < $ptr + 4 + $sbuflen || ord($wb[$sptr]) != 0x3c) { return 6; } } else { if ($char_bytes == 2) { $this->sst['unicode'][] = true; } else { $this->sst['unicode'][] = false; } $sptr += 4 * $rt + $fesz; $this->sst['data'][] = $str; $snum--; } } // switch break; } // switch // !!! Optimization: // $this->wsb[] = substr($wb,$ptr,4+256*ord($wb[$ptr+3])+ord($wb[$ptr+2])); $ptr += 4 + 256 * ord($wb[$ptr + 3]) + ord($wb[$ptr + 2]); } // while // !!! Optimization: // $this->workbook = $wb; $this->biff_version = $biff_ver; /*DBG*/ $this->dbglog->debug("parse_workbook() function returns 0"); return 0; }
function TEAdecrypt($str, $key = EW_RANDOM_KEY) { $str = ew_UrlDecode($str); if ($str == "") { return ""; } $v = str2long($str, false); $k = str2long($key, false); $cntk = count($k); if ($cntk < 4) { for ($i = $cntk; $i < 4; $i++) { $k[$i] = 0; } } $n = count($v) - 1; $z = $v[$n]; $y = $v[0]; $delta = 0.0; $q = floor(6 + 52 / ($n + 1)); $sum = int32($q * $delta); while ($sum != 0) { $e = $sum >> 2 & 3; for ($p = $n; $p > 0; $p--) { $z = $v[$p - 1]; $mx = int32(($z >> 5 & 0x7ffffff ^ $y << 2) + ($y >> 3 & 0x1fffffff ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); $y = $v[$p] = int32($v[$p] - $mx); } $z = $v[$n]; $mx = int32(($z >> 5 & 0x7ffffff ^ $y << 2) + ($y >> 3 & 0x1fffffff ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); $y = $v[0] = int32($v[0] - $mx); $sum = int32($sum - $delta); } return long2str($v, true); }