diff --git a/cocos2dx/support/zip_support/ZipUtils.cpp b/cocos2dx/support/zip_support/ZipUtils.cpp index a639efa7fa..59d7820201 100644 --- a/cocos2dx/support/zip_support/ZipUtils.cpp +++ b/cocos2dx/support/zip_support/ZipUtils.cpp @@ -33,23 +33,13 @@ NS_CC_BEGIN -static unsigned int caw_key[4] = {0,0,0,0}; -static unsigned int caw_longKey[1024]; -static bool caw_longKeyValid = false; +unsigned int ZipUtils::s_uEncryptedPvrKeyParts[4] = {0,0,0,0}; +unsigned int ZipUtils::s_uEncryptionKey[1024]; +bool ZipUtils::s_bEncryptionKeyIsValid = false; -void caw_setkey_part(int index, unsigned int value) -{ - CCAssert(index >= 0, "Cocos2d: key part index cannot be less than 0"); - CCAssert(index <= 3, "Cocos2d: key part index cannot be greater than 3"); - - if(caw_key[index] != value) - { - caw_key[index] = value; - caw_longKeyValid = false; - } -} +// --------------------- ZipUtils --------------------- -static inline void caw_encdec (unsigned int *data, int len) +inline void ZipUtils::ccDecodeEncodedPvr(unsigned int *data, int len) { const int enclen = 1024; const int securelen = 512; @@ -57,39 +47,39 @@ static inline void caw_encdec (unsigned int *data, int len) // check if key was set // make sure to call caw_setkey_part() for all 4 key parts - CCAssert(caw_key[0] != 0, "Cocos2D: CCZ file is encrypted but key part 0 is not set. Did you call caw_setkey_part(...)?"); - CCAssert(caw_key[1] != 0, "Cocos2D: CCZ file is encrypted but key part 1 is not set. Did you call caw_setkey_part(...)?"); - CCAssert(caw_key[2] != 0, "Cocos2D: CCZ file is encrypted but key part 2 is not set. Did you call caw_setkey_part(...)?"); - CCAssert(caw_key[3] != 0, "Cocos2D: CCZ file is encrypted but key part 3 is not set. Did you call caw_setkey_part(...)?"); + CCAssert(s_uEncryptedPvrKeyParts[0] != 0, "Cocos2D: CCZ file is encrypted but key part 0 is not set. Did you call ZipUtils::ccSetPvrEncryptionKeyPart(...)?"); + CCAssert(s_uEncryptedPvrKeyParts[1] != 0, "Cocos2D: CCZ file is encrypted but key part 1 is not set. Did you call ZipUtils::ccSetPvrEncryptionKeyPart(...)?"); + CCAssert(s_uEncryptedPvrKeyParts[2] != 0, "Cocos2D: CCZ file is encrypted but key part 2 is not set. Did you call ZipUtils::ccSetPvrEncryptionKeyPart(...)?"); + CCAssert(s_uEncryptedPvrKeyParts[3] != 0, "Cocos2D: CCZ file is encrypted but key part 3 is not set. Did you call ZipUtils::ccSetPvrEncryptionKeyPart(...)?"); // create long key - if(!caw_longKeyValid) + if(!s_bEncryptionKeyIsValid) { unsigned int y, p, e; unsigned int rounds = 6; unsigned int sum = 0; - unsigned int z = caw_longKey[enclen-1]; + unsigned int z = s_uEncryptionKey[enclen-1]; do { #define DELTA 0x9e3779b9 -#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (caw_key[(p&3)^e] ^ z))) +#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (s_uEncryptedPvrKeyParts[(p&3)^e] ^ z))) sum += DELTA; e = (sum >> 2) & 3; for (p = 0; p < enclen - 1; p++) { - y = caw_longKey[p + 1]; - z = caw_longKey[p] += MX; + y = s_uEncryptionKey[p + 1]; + z = s_uEncryptionKey[p] += MX; } - y = caw_longKey[0]; - z = caw_longKey[enclen - 1] += MX; + y = s_uEncryptionKey[0]; + z = s_uEncryptionKey[enclen - 1] += MX; } while (--rounds); - caw_longKeyValid = true; + s_bEncryptionKeyIsValid = true; } int b = 0; @@ -98,7 +88,7 @@ static inline void caw_encdec (unsigned int *data, int len) // encrypt first part completely for(; i < len && i < securelen; i++) { - data[i] ^= caw_longKey[b++]; + data[i] ^= s_uEncryptionKey[b++]; if(b >= enclen) { @@ -109,7 +99,7 @@ static inline void caw_encdec (unsigned int *data, int len) // encrypt second section partially for(; i < len; i += distance) { - data[i] ^= caw_longKey[b++]; + data[i] ^= s_uEncryptionKey[b++]; if(b >= enclen) { @@ -118,7 +108,7 @@ static inline void caw_encdec (unsigned int *data, int len) } } -static inline unsigned int caw_checksum(const unsigned int *data, int len) +inline unsigned int ZipUtils::ccChecksumPvr(const unsigned int *data, int len) { unsigned int cs = 0; const int cslen = 128; @@ -133,8 +123,6 @@ static inline unsigned int caw_checksum(const unsigned int *data, int len) return cs; } -// --------------------- ZipUtils --------------------- - // memory in iPhone is precious // Should buffer factor be 1.5 instead of 2 ? #define BUFFER_INC_FACTOR (2) @@ -377,16 +365,16 @@ int ZipUtils::ccInflateCCZFile(const char *path, unsigned char **out) unsigned int* ints = (unsigned int*)(compressed+12); int enclen = (fileLen-12)/4; - caw_encdec(ints, enclen); + ccDecodeEncodedPvr(ints, enclen); #if COCOS2D_DEBUG > 0 // verify checksum in debug mode - unsigned int calculated = caw_checksum(ints, enclen); + unsigned int calculated = ccChecksumPvr(ints, enclen); unsigned int required = CC_SWAP_INT32_BIG_TO_HOST( header->reserved ); if(calculated != required) { - CCLOG("cocos2d: Can't decrypt image file: Invalid decryption key"); + CCLOG("cocos2d: Can't decrypt image file. Is the decryption key valid?"); delete [] compressed; return -1; } @@ -426,6 +414,18 @@ int ZipUtils::ccInflateCCZFile(const char *path, unsigned char **out) return len; } +void ZipUtils::ccSetPvrEncryptionKeyPart(int index, unsigned int value) +{ + CCAssert(index >= 0, "Cocos2d: key part index cannot be less than 0"); + CCAssert(index <= 3, "Cocos2d: key part index cannot be greater than 3"); + + if(s_uEncryptedPvrKeyParts[index] != value) + { + s_uEncryptedPvrKeyParts[index] = value; + s_bEncryptionKeyIsValid = false; + } +} + // --------------------- ZipFile --------------------- // from unzip.cpp #define UNZ_MAXFILENAMEINZIP 256 diff --git a/cocos2dx/support/zip_support/ZipUtils.h b/cocos2dx/support/zip_support/ZipUtils.h index f955ea21f3..1e40389840 100644 --- a/cocos2dx/support/zip_support/ZipUtils.h +++ b/cocos2dx/support/zip_support/ZipUtils.h @@ -28,42 +28,22 @@ THE SOFTWARE. namespace cocos2d { - /** - * Set the TexturePacker encryption key - * - * If your key used to encrypt the pvr.ccz file is - * aaaaaaaabbbbbbbbccccccccdddddddd - * you have to call this function 4 times: - * caw_setkey_part(0, 0xaaaaaaaa); - * caw_setkey_part(1, 0xbbbbbbbb); - * caw_setkey_part(2, 0xcccccccc); - * caw_setkey_part(3, 0xdddddddd); - * - * Distribute the call accross some files but make sure - * to call all of the parts *before* loading the first - * spritesheet. - * - * @param index part of the key [0..3] - * @param value value of the key part - */ - void caw_setkey_part(int index, uint32_t value); - /* XXX: pragma pack ??? */ /** @struct CCZHeader */ struct CCZHeader { - unsigned char sig[4]; // signature. Should be 'CCZ!' 4 bytes - unsigned short compression_type; // should 0 - unsigned short version; // should be 2 (although version type==1 is also supported) - unsigned int reserved; // Reserved for users. - unsigned int len; // size of the uncompressed file + unsigned char sig[4]; // signature. Should be 'CCZ!' 4 bytes + unsigned short compression_type; // should 0 + unsigned short version; // should be 2 (although version type==1 is also supported) + unsigned int reserved; // Reserved for users. + unsigned int len; // size of the uncompressed file }; enum { - CCZ_COMPRESSION_ZLIB, // zlib format. - CCZ_COMPRESSION_BZIP2, // bzip2 format (not supported yet) - CCZ_COMPRESSION_GZIP, // gzip format (not supported yet) - CCZ_COMPRESSION_NONE, // plain (not supported yet) + CCZ_COMPRESSION_ZLIB, // zlib format. + CCZ_COMPRESSION_BZIP2, // bzip2 format (not supported yet) + CCZ_COMPRESSION_GZIP, // gzip format (not supported yet) + CCZ_COMPRESSION_NONE, // plain (not supported yet) }; class ZipUtils @@ -108,9 +88,38 @@ namespace cocos2d */ static int ccInflateCCZFile(const char *filename, unsigned char **out); + /** + * Set the pvr.ccz encryption key + * + * If your key used to encrypt the pvr.ccz file is + * aaaaaaaabbbbbbbbccccccccdddddddd + * you have to call this function 4 times: + * ZipUtils::caw_setkey_part(0, 0xaaaaaaaa); + * ZipUtils::caw_setkey_part(1, 0xbbbbbbbb); + * ZipUtils::caw_setkey_part(2, 0xcccccccc); + * ZipUtils::caw_setkey_part(3, 0xdddddddd); + * + * Distribute the call across some files but make sure + * to call all of the parts *before* loading the first + * spritesheet. + * + * Note that encrpytion is *never* 100% secure and the key code + * can be cracked by knowledgable persons. + * + * @param index part of the key [0..3] + * @param value value of the key part + */ + static void ccSetPvrEncryptionKeyPart(int index, unsigned int value); + private: static int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, - unsigned int outLenghtHint); + unsigned int outLenghtHint); + static inline void ccDecodeEncodedPvr (unsigned int *data, int len); + static inline unsigned int ccChecksumPvr(const unsigned int *data, int len); + + static unsigned int s_uEncryptedPvrKeyParts[4]; + static unsigned int s_uEncryptionKey[1024]; + static bool s_bEncryptionKeyIsValid; }; // forward declaration diff --git a/samples/Cpp/TestCpp/Classes/TexturePackerEncryptionTest/TextureAtlasEncryptionTest.cpp b/samples/Cpp/TestCpp/Classes/TexturePackerEncryptionTest/TextureAtlasEncryptionTest.cpp index 97e316158e..b275bca47f 100644 --- a/samples/Cpp/TestCpp/Classes/TexturePackerEncryptionTest/TextureAtlasEncryptionTest.cpp +++ b/samples/Cpp/TestCpp/Classes/TexturePackerEncryptionTest/TextureAtlasEncryptionTest.cpp @@ -44,10 +44,10 @@ void TextureAtlasEncryptionDemo::onEnter() // Load the encrypted atlas // 1) Set the encryption keys or step 2 will fail - caw_setkey_part(0, 0xaaaaaaaa); - caw_setkey_part(1, 0xbbbbbbbb); - caw_setkey_part(2, 0xcccccccc); - caw_setkey_part(3, 0xdddddddd); + ZipUtils::ccSetPvrEncryptionKeyPart(0, 0xaaaaaaaa); + ZipUtils::ccSetPvrEncryptionKeyPart(1, 0xbbbbbbbb); + ZipUtils::ccSetPvrEncryptionKeyPart(2, 0xcccccccc); + ZipUtils::ccSetPvrEncryptionKeyPart(3, 0xdddddddd); // 2) Load the encrypted atlas CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("Images/encryptedAtlas.plist", "Images/encryptedAtlas.pvr.ccz");