zipCryptStream.cpp
Engine/source/core/util/zip/zipCryptStream.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "core/util/zip/zipCryptStream.h" 25#include "core/util/zip/crctab.h" 26 27#include "console/console.h" 28 29//----------------------------------------------------------------------------- 30// Constructor/Destructor 31//----------------------------------------------------------------------------- 32 33ZipCryptRStream::ZipCryptRStream() : mStream(NULL), mFileEndPos(0), mPassword(NULL) 34{ 35} 36 37ZipCryptRStream::~ZipCryptRStream() 38{ 39} 40 41//----------------------------------------------------------------------------- 42// Private Methods 43//----------------------------------------------------------------------------- 44 45U32 ZipCryptRStream::fillBuffer(const U32 in_attemptSize, void *pBuffer) 46{ 47 AssertFatal(mStream != NULL, "No stream to fill from?"); 48 AssertFatal(mStream->getStatus() != Stream::Closed, 49 "Fill from a closed stream?"); 50 51 U32 currPos = mStream->getPosition(); 52 53 U32 actualReadSize; 54 if (in_attemptSize + currPos > mFileEndPos) { 55 actualReadSize = mFileEndPos - currPos; 56 } else { 57 actualReadSize = in_attemptSize; 58 } 59 60 if (mStream->read(actualReadSize, pBuffer) == true) { 61 return actualReadSize; 62 } else { 63 AssertWarn(false, "Read failed while trying to fill buffer"); 64 return 0; 65 } 66} 67 68//----------------------------------------------------------------------------- 69// Public Methods 70//----------------------------------------------------------------------------- 71 72void ZipCryptRStream::setPassword(const char *password) 73{ 74 mKeys[0] = 305419896; 75 mKeys[1] = 591751049; 76 mKeys[2] = 878082192; 77 78 mPassword = password; 79 const char *pPtr = password; 80 while(*pPtr) 81 { 82 updateKeys(*pPtr); 83 pPtr++; 84 } 85} 86 87bool ZipCryptRStream::attachStream(Stream* io_pSlaveStream) 88{ 89 mStream = io_pSlaveStream; 90 mStreamStartPos = mStream->getPosition(); 91 92 // [tom, 12/20/2005] Encrypted zip files have an extra 12 bytes 93 // of entropy before the file data. 94 95 U8 buffer[12]; 96 if(mStream->read(sizeof(buffer), &buffer)) 97 { 98 // Initialize keys 99 for(S32 i = 0;i < sizeof(buffer);i++) 100 { 101 updateKeys(buffer[i] ^= decryptByte()); 102 } 103 104 // if(buffer[11] !) 105 mFileStartPos = mStream->getPosition(); 106 107 setStatus(Ok); 108 return true; 109 } 110 return false; 111} 112 113void ZipCryptRStream::detachStream() 114{ 115 mStream = NULL; 116 117 // Clear keys, just in case 118 dMemset(&mKeys, 0, sizeof(mKeys)); 119 120 setStatus(Closed); 121} 122 123U32 ZipCryptRStream::getPosition() const 124{ 125 return mStream->getPosition(); 126} 127 128bool ZipCryptRStream::setPosition(const U32 in_newPosition) 129{ 130 if(in_newPosition > mFileEndPos) 131 return false; 132 133 U32 curPos = getPosition(); 134 U32 readSize = in_newPosition - mFileStartPos; 135 bool ret = true; 136 137 if(in_newPosition < curPos) 138 { 139 // Reposition to start of stream 140 Stream *stream = getStream(); 141 U32 startPos = mStreamStartPos; 142 const char *password = mPassword; 143 detachStream(); 144 setPassword(password); 145 stream->setPosition(startPos); 146 ret = attachStream(stream); 147 148 if(in_newPosition == mFileStartPos) 149 return ret; 150 } 151 152 // Read until we reach the new position 153 U8 *buffer = new U8 [1024]; 154 while(readSize >= 1024) 155 { 156 readSize -= 1024; 157 ret = _read(1024, buffer); 158 if(! ret) 159 break; 160 } 161 162 if(readSize > 0 && ret) 163 { 164 ret = _read(readSize, buffer); 165 } 166 delete [] buffer; 167 168 return ret; 169} 170 171//----------------------------------------------------------------------------- 172// Protected Methods 173//----------------------------------------------------------------------------- 174 175void ZipCryptRStream::updateKeys(const U8 c) 176{ 177 mKeys[0] = ZC_CRC32(mKeys[0], c); 178 mKeys[1] += mKeys[0] & 0x000000ff; 179 mKeys[1] = mKeys[1] * 134775813 + 1; 180 U32 k = mKeys[1] >> 24; 181 mKeys[2] = ZC_CRC32(mKeys[2], k); 182} 183 184U8 ZipCryptRStream::decryptByte() 185{ 186 U16 temp; 187 temp = (mKeys[2] & 0xffff) | 2; 188 return (temp * (temp ^ 1)) >> 8; 189} 190 191bool ZipCryptRStream::_read(const U32 in_numBytes, void* out_pBuffer) 192{ 193 U32 numRead = fillBuffer(in_numBytes, out_pBuffer); 194 if(numRead > 0) 195 { 196 // Decrypt 197 U8 *pBytes = (U8 *)out_pBuffer; 198 for(S32 i = 0;i < numRead;i++) 199 { 200 updateKeys(pBytes[i] ^= decryptByte()); 201 } 202 return true; 203 } 204 return false; 205} 206