Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adress sanitycheck for aes encrypted zip #143

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion ZipZap.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
5BC58CA618745940002FAE04 /* large-test-encrypted-standard.zip in Resources */ = {isa = PBXBuildFile; fileRef = 5BC58CA418745940002FAE04 /* large-test-encrypted-standard.zip */; };
5BC58CA718745940002FAE04 /* small-test-encrypted-standard.zip in Resources */ = {isa = PBXBuildFile; fileRef = 5BC58CA518745940002FAE04 /* small-test-encrypted-standard.zip */; };
5BC58CAC18745D22002FAE04 /* ZZStandardCryptoEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B50392E187069E4002B2B12 /* ZZStandardCryptoEngine.cpp */; };
5C61FD201CDBBC1A00208C18 /* small-test-encrypted-aes256-corrupted.zip in Resources */ = {isa = PBXBuildFile; fileRef = 5C61FD1F1CDBBC1A00208C18 /* small-test-encrypted-aes256-corrupted.zip */; };
5CD91DA71CF9973A000F6B09 /* small-test-encrypted-aes256-corrupted.zip in Resources */ = {isa = PBXBuildFile; fileRef = 5CD91DA61CF9973A000F6B09 /* small-test-encrypted-aes256-corrupted.zip */; };
BF8624AD1BB7495200C12EEE /* ZZAESDecryptInputStream.mm in Sources */ = {isa = PBXBuildFile; fileRef = D8ABBF3D18883528002858BE /* ZZAESDecryptInputStream.mm */; };
BF8624AE1BB7495200C12EEE /* ZZArchive.mm in Sources */ = {isa = PBXBuildFile; fileRef = D899CFDB162C608300112F49 /* ZZArchive.mm */; };
BF8624AF1BB7495200C12EEE /* ZZArchiveEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = D899CFD9162C608300112F49 /* ZZArchiveEntry.m */; };
Expand Down Expand Up @@ -242,6 +244,8 @@
5B50393218707C36002B2B12 /* ZZStandardDecryptInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZZStandardDecryptInputStream.h; sourceTree = "<group>"; };
5BC58CA418745940002FAE04 /* large-test-encrypted-standard.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "large-test-encrypted-standard.zip"; sourceTree = "<group>"; };
5BC58CA518745940002FAE04 /* small-test-encrypted-standard.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "small-test-encrypted-standard.zip"; sourceTree = "<group>"; };
5C61FD1F1CDBBC1A00208C18 /* small-test-encrypted-aes256-corrupted.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "small-test-encrypted-aes256-corrupted.zip"; sourceTree = "<group>"; };
5CD91DA61CF9973A000F6B09 /* small-test-encrypted-aes256-corrupted.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "small-test-encrypted-aes256-corrupted.zip"; sourceTree = "<group>"; };
BF8624CB1BB7495200C12EEE /* ZipZap.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ZipZap.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BF8624EF1BB74B1F00C12EEE /* libZipZap.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libZipZap.a; sourceTree = BUILT_PRODUCTS_DIR; };
D804E4C8187645FE00289404 /* ZZDataProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZZDataProvider.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -450,6 +454,7 @@
D87BA1AA1B3D5B2900ED7EB3 /* dog.jpg */,
D87BA1AB1B3D5B2900ED7EB3 /* dog.png */,
D8E366EA188832C0009F3008 /* large-test-encrypted-aes128.zip */,
5CD91DA61CF9973A000F6B09 /* small-test-encrypted-aes256-corrupted.zip */,
D8E366EB188832C0009F3008 /* large-test-encrypted-aes192.zip */,
D8E366EC188832C0009F3008 /* large-test-encrypted-aes256.zip */,
5BC58CA418745940002FAE04 /* large-test-encrypted-standard.zip */,
Expand All @@ -459,6 +464,7 @@
D8E366ED188832C0009F3008 /* small-test-encrypted-aes128.zip */,
D8E366EE188832C0009F3008 /* small-test-encrypted-aes192.zip */,
D8E366EF188832C0009F3008 /* small-test-encrypted-aes256.zip */,
5C61FD1F1CDBBC1A00208C18 /* small-test-encrypted-aes256-corrupted.zip */,
5BC58CA518745940002FAE04 /* small-test-encrypted-standard.zip */,
D87BA1AF1B3D5B2900ED7EB3 /* 拉链.txt */,
);
Expand Down Expand Up @@ -760,7 +766,7 @@
D899CF77162C5E8400112F49 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0730;
TargetAttributes = {
D87BA1F71B3D6DEA00ED7EB3 = {
CreatedOnToolsVersion = 6.3.2;
Expand Down Expand Up @@ -815,10 +821,12 @@
D8E366F5188832C0009F3008 /* small-test-encrypted-aes256.zip in Resources */,
D899CFA2162C5EC100112F49 /* InfoPlist.strings in Resources */,
D8E366F0188832C0009F3008 /* large-test-encrypted-aes128.zip in Resources */,
5C61FD201CDBBC1A00208C18 /* small-test-encrypted-aes256-corrupted.zip in Resources */,
D8E366F2188832C0009F3008 /* large-test-encrypted-aes256.zip in Resources */,
5BC58CA718745940002FAE04 /* small-test-encrypted-standard.zip in Resources */,
D87BA1B51B3D5B2900ED7EB3 /* 拉链.txt in Resources */,
D8E366F1188832C0009F3008 /* large-test-encrypted-aes192.zip in Resources */,
5CD91DA71CF9973A000F6B09 /* small-test-encrypted-aes256-corrupted.zip in Resources */,
D87BA1B01B3D5B2900ED7EB3 /* dog.jpg in Resources */,
D8E366F3188832C0009F3008 /* small-test-encrypted-aes128.zip in Resources */,
D87BA1B31B3D5B2900ED7EB3 /* lorem-ipsum.txt in Resources */,
Expand Down Expand Up @@ -1181,6 +1189,7 @@
CURRENT_PROJECT_VERSION = 8;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
Expand All @@ -1196,6 +1205,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down Expand Up @@ -28,7 +28,26 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D899CF95162C5EC100112F49"
BuildableName = "ZipZapTests.xctest"
BlueprintName = "ZipZapTests"
ReferencedContainer = "container:ZipZap.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D8D140D21B423B1100C411B0"
BuildableName = "ZipZap.framework"
BlueprintName = "ZipZap (OS X Framework)"
ReferencedContainer = "container:ZipZap.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
169 changes: 108 additions & 61 deletions ZipZap/ZZOldArchiveEntry.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@
@interface ZZOldArchiveEntry ()

- (NSData*)fileData;

- (BOOL)checkEncryptionAndCompression:(out NSError**)error;
- (NSInputStream*)streamForData:(NSData*)data withPassword:(NSString*)password error:(out NSError**)error;
- (BOOL)check:(out NSError**)error;
- (BOOL)checkEncryptionMode:(out NSError**)error;
- (BOOL)checkCompressionMode:(out NSError**)error;
- (BOOL)checkLocalHeader:(out NSError**)error;
- (BOOL)checkLocalEncryptionMode:(out NSError**)error;
- (BOOL)checkCRC:(out NSError**)error;

@end

Expand All @@ -47,7 +51,7 @@ - (instancetype)initWithCentralFileHeader:(struct ZZCentralFileHeader*)centralFi

if ((_centralFileHeader->generalPurposeBitFlag & ZZGeneralPurposeBitFlag::encrypted) != ZZGeneralPurposeBitFlag::none)
{
ZZWinZipAESExtraField *winZipAESRecord = _centralFileHeader->extraField<ZZWinZipAESExtraField>();
ZZWinZipAESExtraField* winZipAESRecord = _centralFileHeader->extraField<ZZWinZipAESExtraField>();
if (winZipAESRecord)
_encryptionMode = ZZEncryptionModeWinZipAES;
else if ((_centralFileHeader->generalPurposeBitFlag & ZZGeneralPurposeBitFlag::encryptionStrong) != ZZGeneralPurposeBitFlag::none)
Expand Down Expand Up @@ -75,7 +79,7 @@ - (NSData*)fileData
}
else if (_encryptionMode == ZZEncryptionModeWinZipAES)
{
ZZWinZipAESExtraField *winZipAESRecord = _localFileHeader->extraField<ZZWinZipAESExtraField>();
ZZWinZipAESExtraField* winZipAESRecord = _localFileHeader->extraField<ZZWinZipAESExtraField>();
if (winZipAESRecord)
{
size_t saltLength = getSaltLength(winZipAESRecord->encryptionStrength);
Expand All @@ -91,7 +95,7 @@ - (ZZCompressionMethod)compressionMethod
{
if (_encryptionMode == ZZEncryptionModeWinZipAES)
{
ZZWinZipAESExtraField *winZipAESRecord = _centralFileHeader->extraField<ZZWinZipAESExtraField>();
ZZWinZipAESExtraField* winZipAESRecord = _centralFileHeader->extraField<ZZWinZipAESExtraField>();
if (winZipAESRecord)
return winZipAESRecord->compressionMethod;
}
Expand Down Expand Up @@ -171,6 +175,56 @@ - (NSStringEncoding)encoding
}

- (BOOL)check:(out NSError**)error
{
if (![self checkEncryptionMode:error])
return NO;

if (![self checkCompressionMode:error])
return NO;


if (![self checkLocalHeader:error])
return NO;

if (![self checkLocalEncryptionMode:error])
return NO;

if (![self checkCRC:error])
return NO;

return YES;
}

- (BOOL)checkEncryptionMode:(out NSError**)error
{
switch (_encryptionMode)
{
case ZZEncryptionModeNone:
case ZZEncryptionModeStandard:
case ZZEncryptionModeWinZipAES:
break;
default:
return ZZRaiseErrorNo(error, ZZUnsupportedEncryptionMethod, @{});
}
return YES;
}

- (BOOL)checkCompressionMode:(out NSError**)error
{
switch (self.compressionMethod)
{
case ZZCompressionMethod::stored:
case ZZCompressionMethod::deflated:
break;
default:
return ZZRaiseErrorNo(error, ZZUnsupportedCompressionMethod, @{});
}

return YES;
}


- (BOOL)checkLocalHeader:(out NSError**)error
{
// descriptor fields either from local file header or data descriptor
uint32_t dataDescriptorSignature;
Expand All @@ -193,21 +247,6 @@ - (BOOL)check:(out NSError**)error
localUncompressedSize = dataDescriptor->uncompressedSize;
}

// figure out local encryption mode
ZZEncryptionMode localEncryptionMode;
if ((_localFileHeader->generalPurposeBitFlag & ZZGeneralPurposeBitFlag::encrypted) != ZZGeneralPurposeBitFlag::none)
{
ZZWinZipAESExtraField *winZipAESRecord = _localFileHeader->extraField<ZZWinZipAESExtraField>();

if (winZipAESRecord)
localEncryptionMode = ZZEncryptionModeWinZipAES;
else if ((_localFileHeader->generalPurposeBitFlag & ZZGeneralPurposeBitFlag::encryptionStrong) != ZZGeneralPurposeBitFlag::none)
localEncryptionMode = ZZEncryptionModeStrong;
else
localEncryptionMode = ZZEncryptionModeStandard;
}
else
localEncryptionMode = ZZEncryptionModeNone;

// sanity check:
if (
Expand All @@ -216,7 +255,7 @@ - (BOOL)check:(out NSError**)error
// general fields in local and central headers match
|| _localFileHeader->versionNeededToExtract != _centralFileHeader->versionNeededToExtract
|| _localFileHeader->generalPurposeBitFlag != _centralFileHeader->generalPurposeBitFlag
|| _localFileHeader->compressionMethod != self.compressionMethod
|| _localFileHeader->compressionMethod != _centralFileHeader->compressionMethod
|| _localFileHeader->lastModFileDate != _centralFileHeader->lastModFileDate
|| _localFileHeader->lastModFileTime != _centralFileHeader->lastModFileTime
|| _localFileHeader->fileNameLength != _centralFileHeader->fileNameLength
Expand All @@ -226,59 +265,67 @@ - (BOOL)check:(out NSError**)error
|| dataDescriptorSignature != ZZDataDescriptor::sign
|| localCrc32 != _centralFileHeader->crc32
|| localCompressedSize != _centralFileHeader->compressedSize
|| localUncompressedSize != _centralFileHeader->uncompressedSize
|| localEncryptionMode != _encryptionMode)
|| localUncompressedSize != _centralFileHeader->uncompressedSize)
return ZZRaiseErrorNo(error, ZZLocalFileReadErrorCode, nil);

if (_encryptionMode == ZZEncryptionModeStandard)
{
// validate encrypted CRC (?)
unsigned char crcBytes[4];
memcpy(&crcBytes[0], &_centralFileHeader->crc32, 4);

crcBytes[3] = (crcBytes[3] & 0xFF);
crcBytes[2] = ((crcBytes[3] >> 8) & 0xFF);
crcBytes[1] = ((crcBytes[3] >> 16) & 0xFF);
crcBytes[0] = ((crcBytes[3] >> 24) & 0xFF);

if (crcBytes[2] > 0 || crcBytes[1] > 0 || crcBytes[0] > 0)
return ZZRaiseErrorNo(error, ZZInvalidCRChecksum, @{});
}

return YES;
}

- (NSString*)fileNameWithEncoding:(NSStringEncoding)encoding
- (BOOL)checkLocalEncryptionMode:(out NSError**)error
{
return [[NSString alloc] initWithBytes:_centralFileHeader->fileName()
length:_centralFileHeader->fileNameLength
encoding:encoding];
ZZEncryptionMode localEncryptionMode;
if ((_localFileHeader->generalPurposeBitFlag & ZZGeneralPurposeBitFlag::encrypted) != ZZGeneralPurposeBitFlag::none)
{
ZZWinZipAESExtraField* winZipAESRecord = _localFileHeader->extraField<ZZWinZipAESExtraField>();
if (winZipAESRecord)
localEncryptionMode = ZZEncryptionModeWinZipAES;
else if ((_localFileHeader->generalPurposeBitFlag & ZZGeneralPurposeBitFlag::encryptionStrong) != ZZGeneralPurposeBitFlag::none)
localEncryptionMode = ZZEncryptionModeStrong;
else
localEncryptionMode = ZZEncryptionModeStandard;
}
else
localEncryptionMode = ZZEncryptionModeNone;

if (localEncryptionMode != _encryptionMode) {
return ZZRaiseErrorNo(error, ZZLocalFileReadErrorCode, nil);
}
return YES;
}

- (BOOL)checkEncryptionAndCompression:(out NSError**)error
- (BOOL)checkCRC:(out NSError**)error
{
switch (_encryptionMode)
if (_encryptionMode == ZZEncryptionModeStandard)
{
case ZZEncryptionModeNone:
case ZZEncryptionModeStandard:
case ZZEncryptionModeWinZipAES:
break;
default:
return ZZRaiseErrorNo(error, ZZUnsupportedEncryptionMethod, @{});
return YES;
}

switch (self.compressionMethod)
if (_encryptionMode == ZZEncryptionModeWinZipAES)
{
case ZZCompressionMethod::stored:
case ZZCompressionMethod::deflated:
break;
default:
return ZZRaiseErrorNo(error, ZZUnsupportedCompressionMethod, @{});
ZZWinZipAESExtraField* winZipAESRecord = _centralFileHeader->extraField<ZZWinZipAESExtraField>();
switch(winZipAESRecord->versionNumber)
{
case ZZWinZipAESExtraField::version_AE2:
if (_centralFileHeader->crc32 != 0)
return ZZRaiseErrorNo(error, ZZInvalidCRChecksum, @{});
else
return YES;
break;
case ZZWinZipAESExtraField::version_AE1:
return YES;
break;
}
}

return YES;
}

- (NSString*)fileNameWithEncoding:(NSStringEncoding)encoding
{
return [[NSString alloc] initWithBytes:_centralFileHeader->fileName()
length:_centralFileHeader->fileNameLength
encoding:encoding];
}

- (NSInputStream*)streamForData:(NSData*)data withPassword:(NSString*)password error:(out NSError**)error
{
// We need to output an error, becase in AES we have (most of the time) knowledge about the password verification even before starting to decrypt. So we should not supply a stream when we KNOW that the password is wrong.
Expand Down Expand Up @@ -335,16 +382,16 @@ - (NSInputStream*)streamForData:(NSData*)data withPassword:(NSString*)password e

- (NSInputStream*)newStreamWithPassword:(NSString*)password error:(out NSError**)error
{
if (![self checkEncryptionAndCompression:error])
if (![self check:error])
return nil;

NSData* fileData = [self fileData];
return [self streamForData:fileData withPassword:password error:error];
}

- (NSData*)newDataWithPassword:(NSString*)password error:(out NSError**)error
{
if (![self checkEncryptionAndCompression:error])
if (![self check:error])
return nil;

NSData* fileData = [self fileData];
Expand Down Expand Up @@ -395,7 +442,7 @@ - (NSData*)newDataWithPassword:(NSString*)password error:(out NSError**)error

- (CGDataProviderRef)newDataProviderWithPassword:(NSString*)password error:(out NSError**)error
{
if (![self checkEncryptionAndCompression:error])
if (![self check:error])
return nil;

NSData* fileData = [self fileData];
Expand Down
Loading