diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4898ad8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +AltDeploy.xcodeproj/project.xcworkspace/xcuserdata +AltDeploy.xcodeproj/xcuserdata diff --git a/AltDeploy-Bridge.h b/AltDeploy-Bridge.h new file mode 100644 index 0000000..0c91629 --- /dev/null +++ b/AltDeploy-Bridge.h @@ -0,0 +1,14 @@ +// +// AltDeploy-Bridge.h +// AltDeploy +// +// Created by PixelOmer on 4.01.2020. +// Copyright © 2020 PixelOmer. All rights reserved. +// + +#ifndef AltDeploy_Bridge_h +#define AltDeploy_Bridge_h +#import +#import +#import +#endif /* AltDeploy_Bridge_h */ diff --git a/AltDeploy.xcodeproj/project.pbxproj b/AltDeploy.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b5a2584 --- /dev/null +++ b/AltDeploy.xcodeproj/project.pbxproj @@ -0,0 +1,820 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + CE5F0E3B23C3894300445F16 /* AltPlugin.mailbundle in Resources */ = {isa = PBXBuildFile; fileRef = CE5F0E3A23C3894300445F16 /* AltPlugin.mailbundle */; }; + CE7AA86423C3B66B009EFA51 /* dependencies.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE7AA85823C3B630009EFA51 /* dependencies.a */; }; + CEA24B5E23C1234100A6DB11 /* ALTAppleAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B3023C1234100A6DB11 /* ALTAppleAPI.m */; }; + CEA24B5F23C1234100A6DB11 /* ALTAppleAPI+Authentication.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B3123C1234100A6DB11 /* ALTAppleAPI+Authentication.m */; }; + CEA24B6023C1234100A6DB11 /* ALTAppleAPISession.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B3223C1234100A6DB11 /* ALTAppleAPISession.m */; }; + CEA24B6123C1234100A6DB11 /* ALTSigner.mm in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B3923C1234100A6DB11 /* ALTSigner.mm */; }; + CEA24B6223C1234100A6DB11 /* ALTCapabilities.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B3B23C1234100A6DB11 /* ALTCapabilities.m */; }; + CEA24B6423C1234100A6DB11 /* ALTDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B4723C1234100A6DB11 /* ALTDevice.m */; }; + CEA24B6523C1234100A6DB11 /* ALTAppGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B4823C1234100A6DB11 /* ALTAppGroup.m */; }; + CEA24B6623C1234100A6DB11 /* ALTAppID.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B4A23C1234100A6DB11 /* ALTAppID.m */; }; + CEA24B6723C1234100A6DB11 /* ALTTeam.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B4B23C1234100A6DB11 /* ALTTeam.m */; }; + CEA24B6823C1234100A6DB11 /* ALTCertificateRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B4C23C1234100A6DB11 /* ALTCertificateRequest.m */; }; + CEA24B6923C1234100A6DB11 /* ALTAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B4D23C1234100A6DB11 /* ALTAccount.m */; }; + CEA24B6A23C1234100A6DB11 /* ALTCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B5023C1234100A6DB11 /* ALTCertificate.m */; }; + CEA24B6B23C1234100A6DB11 /* ALTProvisioningProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B5123C1234100A6DB11 /* ALTProvisioningProfile.m */; }; + CEA24B6C23C1234100A6DB11 /* ALTAnisetteData.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B5323C1234100A6DB11 /* ALTAnisetteData.m */; }; + CEA24B6D23C1234100A6DB11 /* ALTApplication.mm in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B5423C1234100A6DB11 /* ALTApplication.mm */; }; + CEA24B6E23C1234100A6DB11 /* ldid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B5823C1234100A6DB11 /* ldid.cpp */; }; + CEA24B6F23C1234100A6DB11 /* NSFileManager+Apps.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B5A23C1234100A6DB11 /* NSFileManager+Apps.m */; }; + CEA24B7023C1234100A6DB11 /* NSError+ALTErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B5C23C1234100A6DB11 /* NSError+ALTErrors.m */; }; + CEA24B7723C1278B00A6DB11 /* NSError+ALTServerError.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B7623C1278B00A6DB11 /* NSError+ALTServerError.m */; }; + CEA24BE023C12A3100A6DB11 /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B8823C12A3100A6DB11 /* unzip.c */; }; + CEA24BE123C12A3100A6DB11 /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B8923C12A3100A6DB11 /* zip.c */; }; + CEA24BE223C12A3100A6DB11 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B8A23C12A3100A6DB11 /* ioapi.c */; }; + CEA24BE323C12A3100A6DB11 /* mztools.c in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B8B23C12A3100A6DB11 /* mztools.c */; }; + CEA24BE423C12A3100A6DB11 /* minizip.c in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B9123C12A3100A6DB11 /* minizip.c */; }; + CEA24BE523C12A3100A6DB11 /* miniunz.c in Sources */ = {isa = PBXBuildFile; fileRef = CEA24B9223C12A3100A6DB11 /* miniunz.c */; }; + CEA24BEB23C130CD00A6DB11 /* ALTDeviceManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = CEA24BE823C130CD00A6DB11 /* ALTDeviceManager.mm */; }; + CEA24BEC23C130CD00A6DB11 /* ALTDeviceManager+Installation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA24BE923C130CD00A6DB11 /* ALTDeviceManager+Installation.swift */; }; + CEA24BF723C132E000A6DB11 /* Result+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA24BF423C132E000A6DB11 /* Result+Conveniences.swift */; }; + CEA24BFB23C133C500A6DB11 /* AnisetteDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA24BFA23C133C500A6DB11 /* AnisetteDataManager.swift */; }; + CEA6378023C3941200CEC7A9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEA6377623C3941200CEC7A9 /* Assets.xcassets */; }; + CEA6378123C3941200CEC7A9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA6377723C3941200CEC7A9 /* ViewController.m */; }; + CEA6378223C3941200CEC7A9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CEA6377823C3941200CEC7A9 /* Main.storyboard */; }; + CEA6378323C3941200CEC7A9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA6377A23C3941200CEC7A9 /* main.m */; }; + CEA6378423C3941200CEC7A9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA6377C23C3941200CEC7A9 /* AppDelegate.m */; }; + CEA6378523C3941200CEC7A9 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = CEA6377D23C3941200CEC7A9 /* Info.plist */; }; + CEA6378623C3941200CEC7A9 /* apple.pem in Resources */ = {isa = PBXBuildFile; fileRef = CEA6377F23C3941200CEC7A9 /* apple.pem */; }; + CEBF417D23C2599C004338D2 /* SAMKeychainQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBF417C23C2599C004338D2 /* SAMKeychainQuery.m */; }; + CEBF418023C259CA004338D2 /* SAMKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBF417F23C259CA004338D2 /* SAMKeychain.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + CEA24AB723C1123F00A6DB11 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 12; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + CE5F0E3A23C3894300445F16 /* AltPlugin.mailbundle */ = {isa = PBXFileReference; lastKnownFileType = folder; path = AltPlugin.mailbundle; sourceTree = ""; }; + CE7AA85723C3B62A009EFA51 /* Dependencies */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Dependencies; sourceTree = ""; }; + CE7AA85823C3B630009EFA51 /* dependencies.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = dependencies.a; path = Dependencies/dependencies.a; sourceTree = ""; }; + CE7AA85A23C3B652009EFA51 /* libimobiledevice.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libimobiledevice.a; path = Dependencies/Individual/libimobiledevice.a; sourceTree = ""; }; + CE7AA85C23C3B655009EFA51 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = Dependencies/Individual/libssl.a; sourceTree = ""; }; + CE7AA85E23C3B657009EFA51 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = Dependencies/Individual/libcrypto.a; sourceTree = ""; }; + CE7AA86023C3B658009EFA51 /* libplist.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplist.a; path = Dependencies/Individual/libplist.a; sourceTree = ""; }; + CE7AA86223C3B65A009EFA51 /* libusbmuxd.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libusbmuxd.a; path = Dependencies/Individual/libusbmuxd.a; sourceTree = ""; }; + CEA24A9923C10F8900A6DB11 /* AltDeploy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AltDeploy.app; sourceTree = BUILT_PRODUCTS_DIR; }; + CEA24B2E23C1234100A6DB11 /* AltSign.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AltSign.h; sourceTree = ""; }; + CEA24B3023C1234100A6DB11 /* ALTAppleAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTAppleAPI.m; sourceTree = ""; }; + CEA24B3123C1234100A6DB11 /* ALTAppleAPI+Authentication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ALTAppleAPI+Authentication.m"; sourceTree = ""; }; + CEA24B3223C1234100A6DB11 /* ALTAppleAPISession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTAppleAPISession.m; sourceTree = ""; }; + CEA24B3323C1234100A6DB11 /* ALTAppleAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAppleAPI.h; sourceTree = ""; }; + CEA24B3423C1234100A6DB11 /* ALTAppleAPI+Authentication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ALTAppleAPI+Authentication.h"; sourceTree = ""; }; + CEA24B3523C1234100A6DB11 /* ALTAppleAPI_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAppleAPI_Private.h; sourceTree = ""; }; + CEA24B3623C1234100A6DB11 /* ALTAppleAPISession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAppleAPISession.h; sourceTree = ""; }; + CEA24B3823C1234100A6DB11 /* ALTSigner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTSigner.h; sourceTree = ""; }; + CEA24B3923C1234100A6DB11 /* ALTSigner.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ALTSigner.mm; sourceTree = ""; }; + CEA24B3B23C1234100A6DB11 /* ALTCapabilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTCapabilities.m; sourceTree = ""; }; + CEA24B3C23C1234100A6DB11 /* ALTCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTCapabilities.h; sourceTree = ""; }; + CEA24B4123C1234100A6DB11 /* ALTAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAccount.h; sourceTree = ""; }; + CEA24B4223C1234100A6DB11 /* ALTCertificateRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTCertificateRequest.h; sourceTree = ""; }; + CEA24B4323C1234100A6DB11 /* ALTTeam.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTTeam.h; sourceTree = ""; }; + CEA24B4423C1234100A6DB11 /* ALTProvisioningProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTProvisioningProfile.h; sourceTree = ""; }; + CEA24B4523C1234100A6DB11 /* ALTCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTCertificate.h; sourceTree = ""; }; + CEA24B4623C1234100A6DB11 /* ALTModel+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ALTModel+Internal.h"; sourceTree = ""; }; + CEA24B4723C1234100A6DB11 /* ALTDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTDevice.m; sourceTree = ""; }; + CEA24B4823C1234100A6DB11 /* ALTAppGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTAppGroup.m; sourceTree = ""; }; + CEA24B4923C1234100A6DB11 /* ALTAnisetteData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAnisetteData.h; sourceTree = ""; }; + CEA24B4A23C1234100A6DB11 /* ALTAppID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTAppID.m; sourceTree = ""; }; + CEA24B4B23C1234100A6DB11 /* ALTTeam.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTTeam.m; sourceTree = ""; }; + CEA24B4C23C1234100A6DB11 /* ALTCertificateRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTCertificateRequest.m; sourceTree = ""; }; + CEA24B4D23C1234100A6DB11 /* ALTAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTAccount.m; sourceTree = ""; }; + CEA24B4E23C1234100A6DB11 /* ALTDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTDevice.h; sourceTree = ""; }; + CEA24B4F23C1234100A6DB11 /* ALTAppGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAppGroup.h; sourceTree = ""; }; + CEA24B5023C1234100A6DB11 /* ALTCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTCertificate.m; sourceTree = ""; }; + CEA24B5123C1234100A6DB11 /* ALTProvisioningProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTProvisioningProfile.m; sourceTree = ""; }; + CEA24B5223C1234100A6DB11 /* ALTAppID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAppID.h; sourceTree = ""; }; + CEA24B5323C1234100A6DB11 /* ALTAnisetteData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTAnisetteData.m; sourceTree = ""; }; + CEA24B5423C1234100A6DB11 /* ALTApplication.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ALTApplication.mm; sourceTree = ""; }; + CEA24B5523C1234100A6DB11 /* ALTApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTApplication.h; sourceTree = ""; }; + CEA24B5723C1234100A6DB11 /* ldid.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ldid.hpp; sourceTree = ""; }; + CEA24B5823C1234100A6DB11 /* ldid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ldid.cpp; sourceTree = ""; }; + CEA24B5A23C1234100A6DB11 /* NSFileManager+Apps.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSFileManager+Apps.m"; sourceTree = ""; }; + CEA24B5B23C1234100A6DB11 /* NSError+ALTErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+ALTErrors.h"; sourceTree = ""; }; + CEA24B5C23C1234100A6DB11 /* NSError+ALTErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+ALTErrors.m"; sourceTree = ""; }; + CEA24B5D23C1234100A6DB11 /* NSFileManager+Apps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSFileManager+Apps.h"; sourceTree = ""; }; + CEA24B7423C1278B00A6DB11 /* NSError+ALTServerError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+ALTServerError.h"; sourceTree = ""; }; + CEA24B7523C1278B00A6DB11 /* AltKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AltKit.h; sourceTree = ""; }; + CEA24B7623C1278B00A6DB11 /* NSError+ALTServerError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+ALTServerError.m"; sourceTree = ""; }; + CEA24B8823C12A3100A6DB11 /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = ""; }; + CEA24B8923C12A3100A6DB11 /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip.c; sourceTree = ""; }; + CEA24B8A23C12A3100A6DB11 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = ""; }; + CEA24B8B23C12A3100A6DB11 /* mztools.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mztools.c; sourceTree = ""; }; + CEA24B8C23C12A3100A6DB11 /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = ""; }; + CEA24B8D23C12A3100A6DB11 /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; + CEA24B8E23C12A3100A6DB11 /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = ""; }; + CEA24B8F23C12A3100A6DB11 /* mztools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mztools.h; sourceTree = ""; }; + CEA24B9023C12A3100A6DB11 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; + CEA24B9123C12A3100A6DB11 /* minizip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = minizip.c; sourceTree = ""; }; + CEA24B9223C12A3100A6DB11 /* miniunz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = miniunz.c; sourceTree = ""; }; + CEA24B9423C12A3100A6DB11 /* cctest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cctest.h; sourceTree = ""; }; + CEA24B9523C12A3100A6DB11 /* cczp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cczp.h; sourceTree = ""; }; + CEA24B9623C12A3100A6DB11 /* ccmd4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmd4.h; sourceTree = ""; }; + CEA24B9723C12A3100A6DB11 /* ccrng_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_priv.h; sourceTree = ""; }; + CEA24B9823C12A3100A6DB11 /* ccrng_sequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_sequence.h; sourceTree = ""; }; + CEA24B9923C12A3100A6DB11 /* ccz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccz.h; sourceTree = ""; }; + CEA24B9A23C12A3100A6DB11 /* ccaes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccaes.h; sourceTree = ""; }; + CEA24B9B23C12A3100A6DB11 /* cchkdf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cchkdf.h; sourceTree = ""; }; + CEA24B9C23C12A3100A6DB11 /* ccec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccec.h; sourceTree = ""; }; + CEA24B9D23C12A3100A6DB11 /* cc_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cc_config.h; sourceTree = ""; }; + CEA24B9E23C12A3100A6DB11 /* ccsrp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccsrp.h; sourceTree = ""; }; + CEA24B9F23C12A3100A6DB11 /* ccrng_ecfips_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_ecfips_test.h; sourceTree = ""; }; + CEA24BA023C12A3100A6DB11 /* ccrng_drbg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_drbg.h; sourceTree = ""; }; + CEA24BA123C12A3100A6DB11 /* cc_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cc_priv.h; sourceTree = ""; }; + CEA24BA223C12A3100A6DB11 /* fipspost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fipspost.h; sourceTree = ""; }; + CEA24BA323C12A3100A6DB11 /* ccec25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccec25519.h; sourceTree = ""; }; + CEA24BA423C12A3100A6DB11 /* ccdh_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdh_priv.h; sourceTree = ""; }; + CEA24BA523C12A3100A6DB11 /* ccder_rsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccder_rsa.h; sourceTree = ""; }; + CEA24BA623C12A3100A6DB11 /* ccrc4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrc4.h; sourceTree = ""; }; + CEA24BA723C12A3100A6DB11 /* ccdes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdes.h; sourceTree = ""; }; + CEA24BA823C12A3100A6DB11 /* ccrsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrsa.h; sourceTree = ""; }; + CEA24BA923C12A3100A6DB11 /* cc_debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cc_debug.h; sourceTree = ""; }; + CEA24BAA23C12A3100A6DB11 /* ccblowfish.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccblowfish.h; sourceTree = ""; }; + CEA24BAB23C12A3100A6DB11 /* ccchacha20poly1305_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccchacha20poly1305_priv.h; sourceTree = ""; }; + CEA24BAC23C12A3100A6DB11 /* cczp_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cczp_priv.h; sourceTree = ""; }; + CEA24BAD23C12A3100A6DB11 /* ccdrbg_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdrbg_impl.h; sourceTree = ""; }; + CEA24BAE23C12A3100A6DB11 /* ccprime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccprime.h; sourceTree = ""; }; + CEA24BAF23C12A3100A6DB11 /* ccrng_pbkdf2_prng.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_pbkdf2_prng.h; sourceTree = ""; }; + CEA24BB023C12A3100A6DB11 /* ccdigest_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdigest_priv.h; sourceTree = ""; }; + CEA24BB123C12A3100A6DB11 /* ccnistkdf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccnistkdf.h; sourceTree = ""; }; + CEA24BB223C12A3100A6DB11 /* ccasn1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccasn1.h; sourceTree = ""; }; + CEA24BB323C12A3100A6DB11 /* ccripemd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccripemd.h; sourceTree = ""; }; + CEA24BB423C12A3100A6DB11 /* ccchacha20poly1305.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccchacha20poly1305.h; sourceTree = ""; }; + CEA24BB523C12A3100A6DB11 /* cc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cc.h; sourceTree = ""; }; + CEA24BB623C12A3100A6DB11 /* ccder_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccder_priv.h; sourceTree = ""; }; + CEA24BB723C12A3100A6DB11 /* ccder_decode_eckey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccder_decode_eckey.h; sourceTree = ""; }; + CEA24BB823C12A3100A6DB11 /* ccrsa_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrsa_priv.h; sourceTree = ""; }; + CEA24BB923C12A3100A6DB11 /* ccdh_gp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdh_gp.h; sourceTree = ""; }; + CEA24BBA23C12A3100A6DB11 /* ccrng_rsafips_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_rsafips_test.h; sourceTree = ""; }; + CEA24BBB23C12A3100A6DB11 /* ccperf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccperf.h; sourceTree = ""; }; + CEA24BBC23C12A3100A6DB11 /* ccder_encode_eckey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccder_encode_eckey.h; sourceTree = ""; }; + CEA24BBD23C12A3100A6DB11 /* ccn_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccn_priv.h; sourceTree = ""; }; + CEA24BBE23C12A3100A6DB11 /* ccz_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccz_priv.h; sourceTree = ""; }; + CEA24BBF23C12A3100A6DB11 /* ccdrbg_factory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdrbg_factory.h; sourceTree = ""; }; + CEA24BC023C12A3100A6DB11 /* ccansikdf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccansikdf.h; sourceTree = ""; }; + CEA24BC123C12A3100A6DB11 /* ccmd2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmd2.h; sourceTree = ""; }; + CEA24BC223C12A3100A6DB11 /* ccsha1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccsha1.h; sourceTree = ""; }; + CEA24BC323C12A3100A6DB11 /* ccecies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccecies.h; sourceTree = ""; }; + CEA24BC423C12A3100A6DB11 /* cc_memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cc_memory.h; sourceTree = ""; }; + CEA24BC523C12A3100A6DB11 /* ccwrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccwrap.h; sourceTree = ""; }; + CEA24BC623C12A3100A6DB11 /* ccmode_factory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmode_factory.h; sourceTree = ""; }; + CEA24BC723C12A3100A6DB11 /* ccrc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrc2.h; sourceTree = ""; }; + CEA24BC823C12A3100A6DB11 /* ccsrp_gp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccsrp_gp.h; sourceTree = ""; }; + CEA24BC923C12A3100A6DB11 /* cccmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cccmac.h; sourceTree = ""; }; + CEA24BCA23C12A3100A6DB11 /* ccn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccn.h; sourceTree = ""; }; + CEA24BCB23C12A3100A6DB11 /* ccmd5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmd5.h; sourceTree = ""; }; + CEA24BCC23C12A3100A6DB11 /* ccrng_system.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_system.h; sourceTree = ""; }; + CEA24BCD23C12A3100A6DB11 /* ccmode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmode.h; sourceTree = ""; }; + CEA24BCE23C12A3100A6DB11 /* ccec_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccec_priv.h; sourceTree = ""; }; + CEA24BCF23C12A3100A6DB11 /* ccrng_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng_test.h; sourceTree = ""; }; + CEA24BD023C12A3100A6DB11 /* cchmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cchmac.h; sourceTree = ""; }; + CEA24BD123C12A3100A6DB11 /* ccpad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccpad.h; sourceTree = ""; }; + CEA24BD223C12A3100A6DB11 /* ccecies_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccecies_priv.h; sourceTree = ""; }; + CEA24BD323C12A3100A6DB11 /* ccsha2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccsha2.h; sourceTree = ""; }; + CEA24BD423C12A3100A6DB11 /* ccpbkdf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccpbkdf2.h; sourceTree = ""; }; + CEA24BD523C12A3100A6DB11 /* ccec25519_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccec25519_priv.h; sourceTree = ""; }; + CEA24BD623C12A3100A6DB11 /* cc_runtime_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cc_runtime_config.h; sourceTree = ""; }; + CEA24BD723C12A3100A6DB11 /* ccdh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdh.h; sourceTree = ""; }; + CEA24BD823C12A3100A6DB11 /* ccmode_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmode_impl.h; sourceTree = ""; }; + CEA24BD923C12A3100A6DB11 /* ccmode_siv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmode_siv.h; sourceTree = ""; }; + CEA24BDA23C12A3100A6DB11 /* ccdrbg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdrbg.h; sourceTree = ""; }; + CEA24BDB23C12A3100A6DB11 /* ccmode_siv_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccmode_siv_priv.h; sourceTree = ""; }; + CEA24BDC23C12A3100A6DB11 /* cccast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cccast.h; sourceTree = ""; }; + CEA24BDD23C12A3100A6DB11 /* ccdigest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccdigest.h; sourceTree = ""; }; + CEA24BDE23C12A3100A6DB11 /* ccder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccder.h; sourceTree = ""; }; + CEA24BDF23C12A3100A6DB11 /* ccrng.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccrng.h; sourceTree = ""; }; + CEA24BE823C130CD00A6DB11 /* ALTDeviceManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ALTDeviceManager.mm; sourceTree = ""; }; + CEA24BE923C130CD00A6DB11 /* ALTDeviceManager+Installation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ALTDeviceManager+Installation.swift"; sourceTree = ""; }; + CEA24BEA23C130CD00A6DB11 /* ALTDeviceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTDeviceManager.h; sourceTree = ""; }; + CEA24BF423C132E000A6DB11 /* Result+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Result+Conveniences.swift"; sourceTree = ""; }; + CEA24BFA23C133C500A6DB11 /* AnisetteDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnisetteDataManager.swift; sourceTree = ""; }; + CEA6377523C3941200CEC7A9 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + CEA6377623C3941200CEC7A9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + CEA6377723C3941200CEC7A9 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + CEA6377923C3941200CEC7A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + CEA6377A23C3941200CEC7A9 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + CEA6377B23C3941200CEC7A9 /* AltDeploy.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = AltDeploy.entitlements; sourceTree = ""; }; + CEA6377C23C3941200CEC7A9 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + CEA6377D23C3941200CEC7A9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CEA6377E23C3941200CEC7A9 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + CEA6377F23C3941200CEC7A9 /* apple.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = apple.pem; sourceTree = ""; }; + CEA6378723C3944400CEC7A9 /* AltDeploy-Bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AltDeploy-Bridge.h"; sourceTree = ""; }; + CEBF417A23C2597E004338D2 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + CEBF417B23C2599C004338D2 /* SAMKeychainQuery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAMKeychainQuery.h; sourceTree = ""; }; + CEBF417C23C2599C004338D2 /* SAMKeychainQuery.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAMKeychainQuery.m; sourceTree = ""; }; + CEBF417E23C259CA004338D2 /* SAMKeychain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAMKeychain.h; sourceTree = ""; }; + CEBF417F23C259CA004338D2 /* SAMKeychain.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAMKeychain.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + CEA24A9623C10F8900A6DB11 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CE7AA86423C3B66B009EFA51 /* dependencies.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + CEA24A9023C10F8900A6DB11 = { + isa = PBXGroup; + children = ( + CEBF417923C25963004338D2 /* SAMKeychain */, + CEA6378723C3944400CEC7A9 /* AltDeploy-Bridge.h */, + CEA24B7323C1278B00A6DB11 /* AltKit */, + CEA24BE723C130CD00A6DB11 /* AltServer */, + CEA6377423C3941200CEC7A9 /* AltDeploy */, + CE5F0E3A23C3894300445F16 /* AltPlugin.mailbundle */, + CEA24B2D23C1234100A6DB11 /* AltSign */, + CEA24B9323C12A3100A6DB11 /* corecrypto */, + CE7AA85723C3B62A009EFA51 /* Dependencies */, + CEA24B8723C12A3100A6DB11 /* minizip */, + CEA24A9A23C10F8900A6DB11 /* Products */, + CEA24AB023C10FCD00A6DB11 /* Frameworks */, + ); + sourceTree = ""; + }; + CEA24A9A23C10F8900A6DB11 /* Products */ = { + isa = PBXGroup; + children = ( + CEA24A9923C10F8900A6DB11 /* AltDeploy.app */, + ); + name = Products; + sourceTree = ""; + }; + CEA24AB023C10FCD00A6DB11 /* Frameworks */ = { + isa = PBXGroup; + children = ( + CE7AA85A23C3B652009EFA51 /* libimobiledevice.a */, + CE7AA86023C3B658009EFA51 /* libplist.a */, + CE7AA85C23C3B655009EFA51 /* libssl.a */, + CE7AA86223C3B65A009EFA51 /* libusbmuxd.a */, + CE7AA85E23C3B657009EFA51 /* libcrypto.a */, + CE7AA85823C3B630009EFA51 /* dependencies.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + CEA24B2D23C1234100A6DB11 /* AltSign */ = { + isa = PBXGroup; + children = ( + CEA24B2E23C1234100A6DB11 /* AltSign.h */, + CEA24B3823C1234100A6DB11 /* ALTSigner.h */, + CEA24B3923C1234100A6DB11 /* ALTSigner.mm */, + CEA24B3B23C1234100A6DB11 /* ALTCapabilities.m */, + CEA24B3C23C1234100A6DB11 /* ALTCapabilities.h */, + CEA24B3023C1234100A6DB11 /* ALTAppleAPI.m */, + CEA24B3123C1234100A6DB11 /* ALTAppleAPI+Authentication.m */, + CEA24B3223C1234100A6DB11 /* ALTAppleAPISession.m */, + CEA24B3323C1234100A6DB11 /* ALTAppleAPI.h */, + CEA24B3423C1234100A6DB11 /* ALTAppleAPI+Authentication.h */, + CEA24B3523C1234100A6DB11 /* ALTAppleAPI_Private.h */, + CEA24B3623C1234100A6DB11 /* ALTAppleAPISession.h */, + CEA24B4123C1234100A6DB11 /* ALTAccount.h */, + CEA24B4223C1234100A6DB11 /* ALTCertificateRequest.h */, + CEA24B4323C1234100A6DB11 /* ALTTeam.h */, + CEA24B4423C1234100A6DB11 /* ALTProvisioningProfile.h */, + CEA24B4523C1234100A6DB11 /* ALTCertificate.h */, + CEA24B4623C1234100A6DB11 /* ALTModel+Internal.h */, + CEA24B4723C1234100A6DB11 /* ALTDevice.m */, + CEA24B4823C1234100A6DB11 /* ALTAppGroup.m */, + CEA24B4923C1234100A6DB11 /* ALTAnisetteData.h */, + CEA24B4A23C1234100A6DB11 /* ALTAppID.m */, + CEA24B4B23C1234100A6DB11 /* ALTTeam.m */, + CEA24B4C23C1234100A6DB11 /* ALTCertificateRequest.m */, + CEA24B4D23C1234100A6DB11 /* ALTAccount.m */, + CEA24B4E23C1234100A6DB11 /* ALTDevice.h */, + CEA24B4F23C1234100A6DB11 /* ALTAppGroup.h */, + CEA24B5023C1234100A6DB11 /* ALTCertificate.m */, + CEA24B5123C1234100A6DB11 /* ALTProvisioningProfile.m */, + CEA24B5223C1234100A6DB11 /* ALTAppID.h */, + CEA24B5323C1234100A6DB11 /* ALTAnisetteData.m */, + CEA24B5423C1234100A6DB11 /* ALTApplication.mm */, + CEA24B5A23C1234100A6DB11 /* NSFileManager+Apps.m */, + CEA24B5B23C1234100A6DB11 /* NSError+ALTErrors.h */, + CEA24B5C23C1234100A6DB11 /* NSError+ALTErrors.m */, + CEA24B5D23C1234100A6DB11 /* NSFileManager+Apps.h */, + CEA24B5523C1234100A6DB11 /* ALTApplication.h */, + CEA24B5623C1234100A6DB11 /* ldid */, + ); + path = AltSign; + sourceTree = ""; + }; + CEA24B5623C1234100A6DB11 /* ldid */ = { + isa = PBXGroup; + children = ( + CEA24B5723C1234100A6DB11 /* ldid.hpp */, + CEA24B5823C1234100A6DB11 /* ldid.cpp */, + ); + path = ldid; + sourceTree = ""; + }; + CEA24B7323C1278B00A6DB11 /* AltKit */ = { + isa = PBXGroup; + children = ( + CEA24B7423C1278B00A6DB11 /* NSError+ALTServerError.h */, + CEA24B7523C1278B00A6DB11 /* AltKit.h */, + CEA24B7623C1278B00A6DB11 /* NSError+ALTServerError.m */, + CEA24BF423C132E000A6DB11 /* Result+Conveniences.swift */, + ); + path = AltKit; + sourceTree = ""; + }; + CEA24B8723C12A3100A6DB11 /* minizip */ = { + isa = PBXGroup; + children = ( + CEA24B8823C12A3100A6DB11 /* unzip.c */, + CEA24B8923C12A3100A6DB11 /* zip.c */, + CEA24B8A23C12A3100A6DB11 /* ioapi.c */, + CEA24B8B23C12A3100A6DB11 /* mztools.c */, + CEA24B8C23C12A3100A6DB11 /* crypt.h */, + CEA24B8D23C12A3100A6DB11 /* zip.h */, + CEA24B8E23C12A3100A6DB11 /* unzip.h */, + CEA24B8F23C12A3100A6DB11 /* mztools.h */, + CEA24B9023C12A3100A6DB11 /* ioapi.h */, + CEA24B9123C12A3100A6DB11 /* minizip.c */, + CEA24B9223C12A3100A6DB11 /* miniunz.c */, + ); + path = minizip; + sourceTree = ""; + }; + CEA24B9323C12A3100A6DB11 /* corecrypto */ = { + isa = PBXGroup; + children = ( + CEA24B9423C12A3100A6DB11 /* cctest.h */, + CEA24B9523C12A3100A6DB11 /* cczp.h */, + CEA24B9623C12A3100A6DB11 /* ccmd4.h */, + CEA24B9723C12A3100A6DB11 /* ccrng_priv.h */, + CEA24B9823C12A3100A6DB11 /* ccrng_sequence.h */, + CEA24B9923C12A3100A6DB11 /* ccz.h */, + CEA24B9A23C12A3100A6DB11 /* ccaes.h */, + CEA24B9B23C12A3100A6DB11 /* cchkdf.h */, + CEA24B9C23C12A3100A6DB11 /* ccec.h */, + CEA24B9D23C12A3100A6DB11 /* cc_config.h */, + CEA24B9E23C12A3100A6DB11 /* ccsrp.h */, + CEA24B9F23C12A3100A6DB11 /* ccrng_ecfips_test.h */, + CEA24BA023C12A3100A6DB11 /* ccrng_drbg.h */, + CEA24BA123C12A3100A6DB11 /* cc_priv.h */, + CEA24BA223C12A3100A6DB11 /* fipspost.h */, + CEA24BA323C12A3100A6DB11 /* ccec25519.h */, + CEA24BA423C12A3100A6DB11 /* ccdh_priv.h */, + CEA24BA523C12A3100A6DB11 /* ccder_rsa.h */, + CEA24BA623C12A3100A6DB11 /* ccrc4.h */, + CEA24BA723C12A3100A6DB11 /* ccdes.h */, + CEA24BA823C12A3100A6DB11 /* ccrsa.h */, + CEA24BA923C12A3100A6DB11 /* cc_debug.h */, + CEA24BAA23C12A3100A6DB11 /* ccblowfish.h */, + CEA24BAB23C12A3100A6DB11 /* ccchacha20poly1305_priv.h */, + CEA24BAC23C12A3100A6DB11 /* cczp_priv.h */, + CEA24BAD23C12A3100A6DB11 /* ccdrbg_impl.h */, + CEA24BAE23C12A3100A6DB11 /* ccprime.h */, + CEA24BAF23C12A3100A6DB11 /* ccrng_pbkdf2_prng.h */, + CEA24BB023C12A3100A6DB11 /* ccdigest_priv.h */, + CEA24BB123C12A3100A6DB11 /* ccnistkdf.h */, + CEA24BB223C12A3100A6DB11 /* ccasn1.h */, + CEA24BB323C12A3100A6DB11 /* ccripemd.h */, + CEA24BB423C12A3100A6DB11 /* ccchacha20poly1305.h */, + CEA24BB523C12A3100A6DB11 /* cc.h */, + CEA24BB623C12A3100A6DB11 /* ccder_priv.h */, + CEA24BB723C12A3100A6DB11 /* ccder_decode_eckey.h */, + CEA24BB823C12A3100A6DB11 /* ccrsa_priv.h */, + CEA24BB923C12A3100A6DB11 /* ccdh_gp.h */, + CEA24BBA23C12A3100A6DB11 /* ccrng_rsafips_test.h */, + CEA24BBB23C12A3100A6DB11 /* ccperf.h */, + CEA24BBC23C12A3100A6DB11 /* ccder_encode_eckey.h */, + CEA24BBD23C12A3100A6DB11 /* ccn_priv.h */, + CEA24BBE23C12A3100A6DB11 /* ccz_priv.h */, + CEA24BBF23C12A3100A6DB11 /* ccdrbg_factory.h */, + CEA24BC023C12A3100A6DB11 /* ccansikdf.h */, + CEA24BC123C12A3100A6DB11 /* ccmd2.h */, + CEA24BC223C12A3100A6DB11 /* ccsha1.h */, + CEA24BC323C12A3100A6DB11 /* ccecies.h */, + CEA24BC423C12A3100A6DB11 /* cc_memory.h */, + CEA24BC523C12A3100A6DB11 /* ccwrap.h */, + CEA24BC623C12A3100A6DB11 /* ccmode_factory.h */, + CEA24BC723C12A3100A6DB11 /* ccrc2.h */, + CEA24BC823C12A3100A6DB11 /* ccsrp_gp.h */, + CEA24BC923C12A3100A6DB11 /* cccmac.h */, + CEA24BCA23C12A3100A6DB11 /* ccn.h */, + CEA24BCB23C12A3100A6DB11 /* ccmd5.h */, + CEA24BCC23C12A3100A6DB11 /* ccrng_system.h */, + CEA24BCD23C12A3100A6DB11 /* ccmode.h */, + CEA24BCE23C12A3100A6DB11 /* ccec_priv.h */, + CEA24BCF23C12A3100A6DB11 /* ccrng_test.h */, + CEA24BD023C12A3100A6DB11 /* cchmac.h */, + CEA24BD123C12A3100A6DB11 /* ccpad.h */, + CEA24BD223C12A3100A6DB11 /* ccecies_priv.h */, + CEA24BD323C12A3100A6DB11 /* ccsha2.h */, + CEA24BD423C12A3100A6DB11 /* ccpbkdf2.h */, + CEA24BD523C12A3100A6DB11 /* ccec25519_priv.h */, + CEA24BD623C12A3100A6DB11 /* cc_runtime_config.h */, + CEA24BD723C12A3100A6DB11 /* ccdh.h */, + CEA24BD823C12A3100A6DB11 /* ccmode_impl.h */, + CEA24BD923C12A3100A6DB11 /* ccmode_siv.h */, + CEA24BDA23C12A3100A6DB11 /* ccdrbg.h */, + CEA24BDB23C12A3100A6DB11 /* ccmode_siv_priv.h */, + CEA24BDC23C12A3100A6DB11 /* cccast.h */, + CEA24BDD23C12A3100A6DB11 /* ccdigest.h */, + CEA24BDE23C12A3100A6DB11 /* ccder.h */, + CEA24BDF23C12A3100A6DB11 /* ccrng.h */, + ); + path = corecrypto; + sourceTree = ""; + }; + CEA24BE723C130CD00A6DB11 /* AltServer */ = { + isa = PBXGroup; + children = ( + CEA24BE823C130CD00A6DB11 /* ALTDeviceManager.mm */, + CEA24BFA23C133C500A6DB11 /* AnisetteDataManager.swift */, + CEA24BE923C130CD00A6DB11 /* ALTDeviceManager+Installation.swift */, + CEA24BEA23C130CD00A6DB11 /* ALTDeviceManager.h */, + ); + path = AltServer; + sourceTree = ""; + }; + CEA6377423C3941200CEC7A9 /* AltDeploy */ = { + isa = PBXGroup; + children = ( + CEA6377523C3941200CEC7A9 /* AppDelegate.h */, + CEA6377623C3941200CEC7A9 /* Assets.xcassets */, + CEA6377723C3941200CEC7A9 /* ViewController.m */, + CEA6377823C3941200CEC7A9 /* Main.storyboard */, + CEA6377A23C3941200CEC7A9 /* main.m */, + CEA6377B23C3941200CEC7A9 /* AltDeploy.entitlements */, + CEA6377C23C3941200CEC7A9 /* AppDelegate.m */, + CEA6377D23C3941200CEC7A9 /* Info.plist */, + CEA6377E23C3941200CEC7A9 /* ViewController.h */, + CEA6377F23C3941200CEC7A9 /* apple.pem */, + ); + path = AltDeploy; + sourceTree = ""; + }; + CEBF417923C25963004338D2 /* SAMKeychain */ = { + isa = PBXGroup; + children = ( + CEBF417A23C2597E004338D2 /* LICENSE */, + CEBF417B23C2599C004338D2 /* SAMKeychainQuery.h */, + CEBF417C23C2599C004338D2 /* SAMKeychainQuery.m */, + CEBF417E23C259CA004338D2 /* SAMKeychain.h */, + CEBF417F23C259CA004338D2 /* SAMKeychain.m */, + ); + path = SAMKeychain; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + CEA24A9823C10F8900A6DB11 /* AltDeploy */ = { + isa = PBXNativeTarget; + buildConfigurationList = CEA24AAD23C10F8A00A6DB11 /* Build configuration list for PBXNativeTarget "AltDeploy" */; + buildPhases = ( + CEA24A9523C10F8900A6DB11 /* Sources */, + CEA24A9623C10F8900A6DB11 /* Frameworks */, + CEA24A9723C10F8900A6DB11 /* Resources */, + CEA24AB723C1123F00A6DB11 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AltDeploy; + productName = "alt-impactor"; + productReference = CEA24A9923C10F8900A6DB11 /* AltDeploy.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + CEA24A9123C10F8900A6DB11 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1130; + ORGANIZATIONNAME = PixelOmer; + TargetAttributes = { + CEA24A9823C10F8900A6DB11 = { + CreatedOnToolsVersion = 11.3; + }; + }; + }; + buildConfigurationList = CEA24A9423C10F8900A6DB11 /* Build configuration list for PBXProject "AltDeploy" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CEA24A9023C10F8900A6DB11; + productRefGroup = CEA24A9A23C10F8900A6DB11 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + CEA24A9823C10F8900A6DB11 /* AltDeploy */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + CEA24A9723C10F8900A6DB11 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CEA6378523C3941200CEC7A9 /* Info.plist in Resources */, + CEA6378223C3941200CEC7A9 /* Main.storyboard in Resources */, + CEA6378023C3941200CEC7A9 /* Assets.xcassets in Resources */, + CEA6378623C3941200CEC7A9 /* apple.pem in Resources */, + CE5F0E3B23C3894300445F16 /* AltPlugin.mailbundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + CEA24A9523C10F8900A6DB11 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CEA24B5E23C1234100A6DB11 /* ALTAppleAPI.m in Sources */, + CEA24B6B23C1234100A6DB11 /* ALTProvisioningProfile.m in Sources */, + CEA24BE323C12A3100A6DB11 /* mztools.c in Sources */, + CEA24B7023C1234100A6DB11 /* NSError+ALTErrors.m in Sources */, + CEA24B6A23C1234100A6DB11 /* ALTCertificate.m in Sources */, + CEA24B6523C1234100A6DB11 /* ALTAppGroup.m in Sources */, + CEA24BE023C12A3100A6DB11 /* unzip.c in Sources */, + CEA24B6F23C1234100A6DB11 /* NSFileManager+Apps.m in Sources */, + CEA24B6E23C1234100A6DB11 /* ldid.cpp in Sources */, + CEA24BFB23C133C500A6DB11 /* AnisetteDataManager.swift in Sources */, + CEA6378123C3941200CEC7A9 /* ViewController.m in Sources */, + CEA24BE523C12A3100A6DB11 /* miniunz.c in Sources */, + CEA24BE423C12A3100A6DB11 /* minizip.c in Sources */, + CEA24B6723C1234100A6DB11 /* ALTTeam.m in Sources */, + CEA6378423C3941200CEC7A9 /* AppDelegate.m in Sources */, + CEA24B6423C1234100A6DB11 /* ALTDevice.m in Sources */, + CEA24B6623C1234100A6DB11 /* ALTAppID.m in Sources */, + CEA24B6D23C1234100A6DB11 /* ALTApplication.mm in Sources */, + CEA24BEB23C130CD00A6DB11 /* ALTDeviceManager.mm in Sources */, + CEA24BE223C12A3100A6DB11 /* ioapi.c in Sources */, + CEA24B6023C1234100A6DB11 /* ALTAppleAPISession.m in Sources */, + CEA24B6823C1234100A6DB11 /* ALTCertificateRequest.m in Sources */, + CEA24B6223C1234100A6DB11 /* ALTCapabilities.m in Sources */, + CEA24B6C23C1234100A6DB11 /* ALTAnisetteData.m in Sources */, + CEA24BE123C12A3100A6DB11 /* zip.c in Sources */, + CEA24B7723C1278B00A6DB11 /* NSError+ALTServerError.m in Sources */, + CEA24BF723C132E000A6DB11 /* Result+Conveniences.swift in Sources */, + CEA24BEC23C130CD00A6DB11 /* ALTDeviceManager+Installation.swift in Sources */, + CEA24B6123C1234100A6DB11 /* ALTSigner.mm in Sources */, + CEBF418023C259CA004338D2 /* SAMKeychain.m in Sources */, + CEBF417D23C2599C004338D2 /* SAMKeychainQuery.m in Sources */, + CEA24B5F23C1234100A6DB11 /* ALTAppleAPI+Authentication.m in Sources */, + CEA6378323C3941200CEC7A9 /* main.m in Sources */, + CEA24B6923C1234100A6DB11 /* ALTAccount.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + CEA6377823C3941200CEC7A9 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + CEA6377923C3941200CEC7A9 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + CEA24AAB23C10F8A00A6DB11 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + CEA24AAC23C10F8A00A6DB11 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + CEA24AAE23C10F8A00A6DB11 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = AltDeploy/AltDeploy.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; + GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; + HEADER_SEARCH_PATHS = ( + /usr/local/include, + "/usr/local/opt/openssl@1.1/include", + ., + ); + INFOPLIST_FILE = "$(SRCROOT)/AltDeploy/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/usr/local/Cellar/libusbmuxd/HEAD-563cd25/lib", + "/usr/local/Cellar/openssl@1.1/1.1.1d/lib", + /usr/local/Cellar/libplist/2.1.0/lib, + "/usr/local/Cellar/libimobiledevice/HEAD-d04f8ff_6/lib", + "$(PROJECT_DIR)/Objects", + "$(PROJECT_DIR)/Dependencies", + "$(PROJECT_DIR)/Dependencies/Individual", + ); + MACOSX_DEPLOYMENT_TARGET = 10.13; + OTHER_CFLAGS = "-Dunix=1"; + PRODUCT_BUNDLE_IDENTIFIER = com.pixelomer.altdeploy; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "AltDeploy-Bridge.h"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + CEA24AAF23C10F8A00A6DB11 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = AltDeploy/AltDeploy.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + /usr/local/include, + "/usr/local/opt/openssl@1.1/include", + ., + ); + INFOPLIST_FILE = "$(SRCROOT)/AltDeploy/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/usr/local/Cellar/libusbmuxd/HEAD-563cd25/lib", + "/usr/local/Cellar/openssl@1.1/1.1.1d/lib", + /usr/local/Cellar/libplist/2.1.0/lib, + "/usr/local/Cellar/libimobiledevice/HEAD-d04f8ff_6/lib", + "$(PROJECT_DIR)/Objects", + "$(PROJECT_DIR)/Dependencies", + "$(PROJECT_DIR)/Dependencies/Individual", + ); + MACOSX_DEPLOYMENT_TARGET = 10.13; + OTHER_CFLAGS = "-Dunix=1"; + PRODUCT_BUNDLE_IDENTIFIER = com.pixelomer.altdeploy; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "AltDeploy-Bridge.h"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + CEA24A9423C10F8900A6DB11 /* Build configuration list for PBXProject "AltDeploy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CEA24AAB23C10F8A00A6DB11 /* Debug */, + CEA24AAC23C10F8A00A6DB11 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CEA24AAD23C10F8A00A6DB11 /* Build configuration list for PBXNativeTarget "AltDeploy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CEA24AAE23C10F8A00A6DB11 /* Debug */, + CEA24AAF23C10F8A00A6DB11 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = CEA24A9123C10F8900A6DB11 /* Project object */; +} diff --git a/AltDeploy.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/AltDeploy.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..eb18fca --- /dev/null +++ b/AltDeploy.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/AltDeploy.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AltDeploy.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/AltDeploy.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/AltDeploy.xcodeproj/xcshareddata/xcschemes/AltDeploy.xcscheme b/AltDeploy.xcodeproj/xcshareddata/xcschemes/AltDeploy.xcscheme new file mode 100644 index 0000000..b234e43 --- /dev/null +++ b/AltDeploy.xcodeproj/xcshareddata/xcschemes/AltDeploy.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AltDeploy/AltDeploy.entitlements b/AltDeploy/AltDeploy.entitlements new file mode 100644 index 0000000..311b32b --- /dev/null +++ b/AltDeploy/AltDeploy.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/AltDeploy/AppDelegate.h b/AltDeploy/AppDelegate.h new file mode 100644 index 0000000..98c22ab --- /dev/null +++ b/AltDeploy/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// AltDeploy +// +// Created by PixelOmer on 4.01.2020. +// Copyright © 2020 PixelOmer. All rights reserved. +// + +#import + +@interface AppDelegate : NSObject + + +@end + diff --git a/AltDeploy/AppDelegate.m b/AltDeploy/AppDelegate.m new file mode 100644 index 0000000..7e38a97 --- /dev/null +++ b/AltDeploy/AppDelegate.m @@ -0,0 +1,25 @@ +// +// AppDelegate.m +// AltDeploy +// +// Created by PixelOmer on 4.01.2020. +// Copyright © 2020 PixelOmer. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Insert code here to initialize your application +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + // Insert code here to tear down your application +} + +@end diff --git a/AltDeploy/Assets.xcassets/AppIcon.appiconset/Contents.json b/AltDeploy/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2db2b1c --- /dev/null +++ b/AltDeploy/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AltDeploy/Assets.xcassets/Contents.json b/AltDeploy/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/AltDeploy/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AltDeploy/Base.lproj/Main.storyboard b/AltDeploy/Base.lproj/Main.storyboard new file mode 100644 index 0000000..bb857b6 --- /dev/null +++ b/AltDeploy/Base.lproj/Main.storyboard @@ -0,0 +1,542 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NSAllRomanInputSourcesLocaleIdentifier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AltDeploy/Info.plist b/AltDeploy/Info.plist new file mode 100644 index 0000000..3a893f2 --- /dev/null +++ b/AltDeploy/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2020 PixelOmer. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + NSSupportsAutomaticTermination + + NSSupportsSuddenTermination + + + diff --git a/AltDeploy/ViewController.h b/AltDeploy/ViewController.h new file mode 100644 index 0000000..4595c0f --- /dev/null +++ b/AltDeploy/ViewController.h @@ -0,0 +1,29 @@ +// +// ViewController.h +// AltDeploy +// +// Created by PixelOmer on 4.01.2020. +// Copyright © 2020 PixelOmer. All rights reserved. +// + +#import + +@interface ViewController : NSViewController { + NSArray *devices; + NSProgress *currentProgress; + NSArray *utilityURLs; + NSURL *selectedFileURL; + NSURL *selectedUtilityURL; + NSMenuItem *pluginMenuItem; +} +@property (weak) IBOutlet NSTextField *descriptionLabel; +@property (weak) IBOutlet NSProgressIndicator *progressIndicator; +@property (weak) IBOutlet NSView *progressContainerView; +@property (weak) IBOutlet NSPopUpButton *deviceButton; +@property (weak) IBOutlet NSPopUpButton *actionButton; +@property (weak) IBOutlet NSButton *startButton; ++ (BOOL)isPluginInstalled; ++ (NSString *)mailBundlesPath; ++ (NSString *)altPluginPath; +@end + diff --git a/AltDeploy/ViewController.m b/AltDeploy/ViewController.m new file mode 100644 index 0000000..62ca2f2 --- /dev/null +++ b/AltDeploy/ViewController.m @@ -0,0 +1,411 @@ +// +// ViewController.m +// AltDeploy +// +// Created by PixelOmer on 4.01.2020. +// Copyright © 2020 PixelOmer. All rights reserved. +// + +#import "ViewController.h" +#import +#import +#import +#import +#import +@class ALTDeviceManager; +@protocol Installation; + +@implementation ViewController + +static NSString *defaultKeyEquivalent; + +static void handle_idevice_event(const idevice_event_t *event, void *user_data) { + ViewController *vc = (__bridge id)user_data; + [vc refreshDevices]; +} + ++ (void)dispatchIfNecessary:(void(^)(void))block { + if ([NSThread isMainThread]) block(); + else dispatch_async(dispatch_get_main_queue(), block); +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(NSProgress *)object change:(NSDictionary *)change context:(void *)context { + [self.class dispatchIfNecessary:^{ + self->_descriptionLabel.stringValue = object.localizedDescription; + self->_progressIndicator.doubleValue = object.fractionCompleted; + }]; +} + +- (void)didClickSaveButton:(NSButton *)sender { + NSSecureTextField *passwordField = objc_getAssociatedObject(sender, @selector(passwordField)); + NSTextField *usernameField = objc_getAssociatedObject(sender, @selector(usernameField)); + [self.class setAppleIDUsername:usernameField.stringValue password:passwordField.stringValue]; + objc_setAssociatedObject(sender, @selector(passwordField), nil, OBJC_ASSOCIATION_RETAIN); + objc_setAssociatedObject(sender, @selector(usernameField), nil, OBJC_ASSOCIATION_RETAIN); + [sender.window close]; +} + +- (void)askForAppleID { + NSViewController *vc = [[NSStoryboard storyboardWithName:@"Main" bundle:NSBundle.mainBundle] instantiateControllerWithIdentifier:@"appleid"]; + NSSecureTextField *passwordField = nil; + NSTextField *usernameField = nil; + NSButton *button = nil; + for (__kindof NSView *view in vc.view.subviews) { + NSLog(@"view: %@", view); + if (view.tag == 300) button = view; + else if (view.tag == 200) passwordField = view; + else if (view.tag == 100) usernameField = view; + } + objc_setAssociatedObject(button, @selector(passwordField), passwordField, OBJC_ASSOCIATION_RETAIN); + objc_setAssociatedObject(button, @selector(usernameField), usernameField, OBJC_ASSOCIATION_RETAIN); + NSString *username; + if ([self.class getAppleIDUsername:&username password:nil]) { + usernameField.stringValue = username; + } + button.action = @selector(didClickSaveButton:); + button.target = self; + [self presentViewControllerAsModalWindow:vc]; +} + +- (void)beginMailPluginInstallation { + BOOL isInstalling = ![self.class isPluginInstalled]; + NSString *script = [NSString stringWithFormat: + @"do shell script \"%@ -i\" with administrator privileges", + NSBundle.mainBundle.executablePath + ]; + NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script]; + NSAlert *alert = [NSAlert new]; + [alert addButtonWithTitle:@"OK"]; + NSDictionary *error; + if ([appleScript executeAndReturnError:&error]) { + alert.messageText = @"Success"; + if (isInstalling) { + alert.informativeText = @"The mail plugin is now installed. To enable this plugin:\n1) Restart the mail app\n2) In mail preferences, press \"Manage Plug-ins...\"\n3) Enable \"AltPlugin.mailbundle\"\n4) Press \"Apply and Restart Mail\"\nThis application relies on this plugin so this plugin must be enabled. It is also necessary to keep the Mail application open while AltDeploy is running."; + } + else { + alert.informativeText = @"The mail plugin was uninstalled successfully."; + } + } + else { + alert.messageText = @"Failure"; + alert.informativeText = error.description; + } + [alert runModal]; + [self reloadMainMenu]; +} + +- (void)didClickInstallPlugin:(id)sender { + [self beginMailPluginInstallation]; +} + +- (void)refreshDevices { + char **udids; + int udid_count = 0; + idevice_error_t error = idevice_get_device_list(&udids, &udid_count); + switch (error) { + case IDEVICE_E_NO_DEVICE: + devices = @[]; + break; + case IDEVICE_E_SUCCESS: { + NSMutableArray *newArray = [NSMutableArray new]; + for (int i=0; i_progressContainerView.hidden = !visible; + self->_deviceButton.hidden = visible; + self->_actionButton.hidden = visible; + self->_startButton.hidden = visible; + }]; +} + +- (void)didClickStart:(id)sender { + if (sender != _startButton) return; + if (![self.class isPluginInstalled]) { + NSAlert *alert = [NSAlert new]; + alert.messageText = @"Missing Mail Plugin"; + alert.informativeText = @"The mail plugin is necessary for this app to function. Install it now?"; + [alert addButtonWithTitle:@"Install"]; + [alert addButtonWithTitle:@"Cancel"]; + NSModalResponse response = [alert runModal]; + if (response == NSAlertFirstButtonReturn) { + [self beginMailPluginInstallation]; + } + return; + } + NSString *username, *password; + if (![self.class getAppleIDUsername:&username password:&password]) { + [self askForAppleID]; + return; + } + NSURL *fileURL = nil; + if (_actionButton.indexOfSelectedItem == 0) { + // Selecteed IPA + fileURL = selectedFileURL; + } + else if (_actionButton.indexOfSelectedItem > 2) { + // Utilitites + fileURL = selectedUtilityURL; + } + if (!fileURL) { + _startButton.enabled = NO; + return; + } + self.progressVisible = YES; + ALTDevice *device = [[ALTDevice alloc] initWithName:@"targetDevice" identifier:devices[_deviceButton.indexOfSelectedItem]]; + NSProgress * __block progress = nil; + progress = [ALTDeviceManager.sharedManager + installApplicationTo:device + appleID:username + password:password + applicationURL:fileURL + completion:^(NSError * _Nullable error) { + [progress removeObserver:self forKeyPath:@"localizedDescription"]; + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSAlert *alert = [NSAlert alertWithError:error]; + [alert addButtonWithTitle:@"Dismiss"]; + [alert runModal]; + self.progressVisible = NO; + }); + } + else { + dispatch_async(dispatch_get_main_queue(), ^{ + self.progressVisible = NO; + }); + } + } + ]; + // FIXME: Race condition + // If the completionHandler is called before the addObserver call, + // the app will crash. + [self observeValueForKeyPath:nil ofObject:progress change:nil context:nil]; + [progress + addObserver:self + forKeyPath:@"localizedDescription" + options:0 + context:nil + ]; +} + ++ (BOOL)getAppleIDUsername:(NSString **)usernamePt password:(NSString **)passwordPt { + NSDictionary *account = [SAMKeychain accountsForService:NSBundle.mainBundle.bundleIdentifier].firstObject; + if (!account) return NO; + NSString *password = [SAMKeychain passwordForService:NSBundle.mainBundle.bundleIdentifier account:account[kSAMKeychainAccountKey]]; + if (!password) return NO; + if (passwordPt) *passwordPt = [password copy]; + if (usernamePt) *usernamePt = [account[kSAMKeychainAccountKey] copy]; + return YES; +} + ++ (NSString *)altPluginPath { + return [NSBundle.mainBundle pathForResource:@"AltPlugin" ofType:@"mailbundle"]; +} + ++ (NSString *)mailBundlesPath { + return @"/Library/Mail/Bundles"; +} + ++ (BOOL)isPluginInstalled { + BOOL isDir; + return ([NSFileManager.defaultManager fileExistsAtPath:[[self mailBundlesPath] stringByAppendingPathComponent:[self altPluginPath].lastPathComponent] isDirectory:&isDir] && isDir); +} + ++ (BOOL)setAppleIDUsername:(NSString *)username password:(NSString *)password { + for (NSDictionary *account in [SAMKeychain accountsForService:NSBundle.mainBundle.bundleIdentifier]) { + [SAMKeychain deletePasswordForService:NSBundle.mainBundle.bundleIdentifier account:account[kSAMKeychainAccountKey]]; + } + return [SAMKeychain setPassword:password forService:NSBundle.mainBundle.bundleIdentifier account:username error:nil]; +} + +- (void)fetchUtilities { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSArray * __block menuItems = nil; + NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://api.pixelomer.com/ALTImpactor/v0/utilities"]]; + if (data) { + NSError *error; + NSArray *array = [NSJSONSerialization + JSONObjectWithData:data + options:0 + error:&error + ]; + if ([array isKindOfClass:[NSArray class]] && !error) { + NSMutableArray *mutableMenuItems = nil; + NSMutableArray *URLs = nil; + for (NSDictionary *dict in array) { + if (![dict isKindOfClass:[NSDictionary class]]) continue; + if (![dict[@"name"] isKindOfClass:[NSString class]]) continue; + if (![dict[@"url"] isKindOfClass:[NSString class]]) continue; + if (!mutableMenuItems) mutableMenuItems = [NSMutableArray new]; + if (!URLs) URLs = [NSMutableArray new]; + NSMenuItem *item = [[NSMenuItem alloc] + initWithTitle:dict[@"name"] + action:nil + keyEquivalent:defaultKeyEquivalent + ]; + item.enabled = YES; + [mutableMenuItems addObject:item]; + [URLs addObject:[NSURL URLWithString:dict[@"url"]]]; + } + self->utilityURLs = [URLs copy]; + menuItems = [mutableMenuItems copy]; + } + } + if (!menuItems) { + menuItems = @[ + [[NSMenuItem alloc] + initWithTitle:@"Failed to load utlities." + action:nil + keyEquivalent:defaultKeyEquivalent + ] + ]; + menuItems.firstObject.enabled = NO; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [self->_actionButton.menu removeItemAtIndex:3]; + for (NSMenuItem *item in menuItems) { + [self->_actionButton.menu addItem:item]; + } + }); + }); +} + +- (void)chooseIPA { + [_actionButton.menu performActionForItemAtIndex:0]; + NSOpenPanel *panel = [NSOpenPanel openPanel]; + panel.allowedFileTypes = @[@"ipa"]; + panel.allowsMultipleSelection = NO; + panel.canChooseDirectories = NO; + panel.canChooseFiles = YES; + panel.resolvesAliases = YES; + _actionButton.enabled = NO; + _startButton.enabled = NO; + [panel beginWithCompletionHandler:^(NSModalResponse result) { + [self.class dispatchIfNecessary:^{ + self->_actionButton.enabled = YES; + if (result == NSModalResponseOK) { + self->selectedFileURL = panel.URLs.firstObject; + } + [self didChooseAction:self->_actionButton]; + }]; + }]; +} + +- (void)didClickAppleID:(id)sender { + [self askForAppleID]; +} + +- (void)didChooseAction:(NSPopUpButton *)sender { + if (sender != _actionButton) return; + NSInteger index = _actionButton.indexOfSelectedItem; + switch (index) { + case 0: + if (selectedFileURL) { + [_actionButton itemAtIndex:0].title = selectedFileURL.lastPathComponent; + } + else { + [_actionButton itemAtIndex:0].title = @"No file selected."; + } + _startButton.enabled = !!selectedFileURL; + break; + case 1: { + // Browse + [self chooseIPA]; + break; + } + case 2: + // Separator + _startButton.enabled = NO; + break; + default: + // Utilities + if (!(_startButton.enabled = !!utilityURLs)) { + selectedUtilityURL = nil; + } + else { + selectedUtilityURL = utilityURLs[index-3]; + } + break; + } + _startButton.enabled = (_deviceButton.menu.itemArray.count && _startButton.enabled); +} + +- (void)reloadMainMenu { + pluginMenuItem.title = [ + ([self.class isPluginInstalled] ? @"Remove" : @"Install") + stringByAppendingString:@" Mail Plugin" + ]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + NSMenuItem *item = NSApp.mainMenu.itemArray[0].submenu.itemArray[2]; + item.action = @selector(didClickAppleID:); + item.target = self; + pluginMenuItem = NSApp.mainMenu.itemArray[0].submenu.itemArray[3]; + pluginMenuItem.action = @selector(didClickInstallPlugin:); + pluginMenuItem.target = self; + [self reloadMainMenu]; + _startButton.target = self; + _startButton.action = @selector(didClickStart:); + _actionButton.action = @selector(didChooseAction:); + _actionButton.target = self; + defaultKeyEquivalent = [_actionButton itemAtIndex:0].keyEquivalent.copy; + devices = @[]; + [self didChooseAction:self->_actionButton]; + [self fetchUtilities]; + idevice_error_t error; + if ((error = idevice_event_subscribe(&handle_idevice_event, (__bridge void *)self)) != IDEVICE_E_SUCCESS) { + [NSException raise:NSInternalInconsistencyException format:@"Failed to subscribe to the iDevice events (%d)", error]; + } +} + +- (void)setRepresentedObject:(id)representedObject { + [super setRepresentedObject:representedObject]; + // Update the view, if already loaded. +} + + +@end diff --git a/AltDeploy/apple.pem b/AltDeploy/apple.pem new file mode 100644 index 0000000..681ea31 --- /dev/null +++ b/AltDeploy/apple.pem @@ -0,0 +1,53 @@ +-----BEGIN CERTIFICATE----- +MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET +MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 +MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw +bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ ++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 +XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w +tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW +q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM +aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 +R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE +ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 +d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl +IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 +YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj +b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp +Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc +NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP +y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 +R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg +xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP +IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX +UKqK1drk/NAJBzewdXUh +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEIjCCAwqgAwIBAgIIAd68xDltoBAwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UE +BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEz +MDIwNzIxNDg0N1oXDTIzMDIwNzIxNDg0N1owgZYxCzAJBgNVBAYTAlVTMRMwEQYD +VQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxv +cGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3Bl +ciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDKOFSmy1aqyCQ5SOmM7uxfuH8mkbw0U3rOfGOA +YXdkXqUHI7Y5/lAtFVZYcC1+xG7BSoU+L/DehBqhV8mvexj/avoVEkkVCBmsqtsq +Mu2WY2hSFT2Miuy/axiV4AOsAX2XBWfODoWVN2rtCbauZ81RZJ/GXNG8V25nNYB2 +NqSHgW44j9grFU57Jdhav06DwY3Sk9UacbVgnJ0zTlX5ElgMhrgWDcHld0WNUEi6 +Ky3klIXh6MSdxmilsKP8Z35wugJZS3dCkTm59c3hTO/AO0iMpuUhXf1qarunFjVg +0uat80YpyejDi+l5wGphZxWy8P3laLxiX27Pmd3vG2P+kmWrAgMBAAGjgaYwgaMw +HQYDVR0OBBYEFIgnFwmpthhgi+zruvZHWcVSVKO3MA8GA1UdEwEB/wQFMAMBAf8w +HwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wLgYDVR0fBCcwJTAjoCGg +H4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5jcmwwDgYDVR0PAQH/BAQDAgGG +MBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQBPz+9Zviz1smwv +j+4ThzLoBTWobot9yWkMudkXvHcs1Gfi/ZptOllc34MBvbKuKmFysa/Nw0Uwj6OD +Dc4dR7Txk4qjdJukw5hyhzs+r0ULklS5MruQGFNrCk4QttkdUGwhgAqJTleMa1s8 +Pab93vcNIx0LSiaHP7qRkkykGRIZbVf1eliHe2iK5IaMSuviSRSqpd1VAKmuu0sw +ruGgsbwpgOYJd+W+NKIByn/c4grmO7i77LpilfMFY0GCzQ87HUyVpNur+cmV6U/k +TecmmYHpvPm0KdIBembhLoz2IYrF+Hjhga6/05Cdqa3zr/04GpZnMBxRpVzscYqC +tGwPDBUf +-----END CERTIFICATE----- diff --git a/AltDeploy/main.m b/AltDeploy/main.m new file mode 100644 index 0000000..121ed9e --- /dev/null +++ b/AltDeploy/main.m @@ -0,0 +1,63 @@ +// +// main.m +// AltDeploy +// +// Created by PixelOmer on 4.01.2020. +// Copyright © 2020 PixelOmer. All rights reserved. +// + +#import +#import "ViewController.h" +#import +#import + +int main(int argc, const char * argv[]) { + if ((argc >= 2) && !strcmp(argv[1], "-i")) { + setuid(0); + seteuid(0); + NSURL *pluginPath = [NSURL fileURLWithPath:[ViewController altPluginPath]]; + NSLog(@"%@", pluginPath); + NSURL *mailBundlesURL = [NSURL fileURLWithPath:ViewController.mailBundlesPath]; + NSURL *destinationURL = [mailBundlesURL URLByAppendingPathComponent:pluginPath.lastPathComponent]; + BOOL wasInstalled = [ViewController isPluginInstalled]; + NSLog(@"%d", wasInstalled); + [NSFileManager.defaultManager removeItemAtURL:destinationURL error:nil]; // Uninstall + if (!wasInstalled) { + // Install + [NSFileManager.defaultManager + createDirectoryAtURL:mailBundlesURL + withIntermediateDirectories:YES + attributes:nil + error:nil + ]; + [NSFileManager.defaultManager + copyItemAtURL:pluginPath + toURL:destinationURL + error:nil + ]; + for (NSString *file in [NSFileManager.defaultManager subpathsOfDirectoryAtPath:mailBundlesURL.path error:nil]) { + chown([mailBundlesURL URLByAppendingPathComponent:file].path.UTF8String, 0, 0); + } + pid_t pid; + const char *proc_argv[] = { + "defaults", + "write", + "/Library/Preferences/com.apple.mail", + "EnableBundles", + "1", + NULL + }; + int success = !posix_spawnp( + &pid, + "defaults", + NULL, + NULL, + (char**)&proc_argv[0], + (char**)&proc_argv[(sizeof(proc_argv)/sizeof(*proc_argv))-1] // Last element of proc_argv, which is always NULL + ); + if (success) waitpid(pid, NULL, 0); + } + return 0; + } + return NSApplicationMain(argc, argv); +} diff --git a/AltKit/AltKit.h b/AltKit/AltKit.h new file mode 100644 index 0000000..759128e --- /dev/null +++ b/AltKit/AltKit.h @@ -0,0 +1,9 @@ +// +// AltKit.h +// AltKit +// +// Created by Riley Testut on 5/30/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "NSError+ALTServerError.h" diff --git a/AltKit/NSError+ALTServerError.h b/AltKit/NSError+ALTServerError.h new file mode 100644 index 0000000..f832947 --- /dev/null +++ b/AltKit/NSError+ALTServerError.h @@ -0,0 +1,40 @@ +// +// NSError+ALTServerError.h +// AltStore +// +// Created by Riley Testut on 5/30/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +extern NSErrorDomain const AltServerErrorDomain; +extern NSErrorDomain const AltServerInstallationErrorDomain; + +typedef NS_ERROR_ENUM(AltServerErrorDomain, ALTServerError) +{ + ALTServerErrorUnknown = 0, + ALTServerErrorConnectionFailed = 1, + ALTServerErrorLostConnection = 2, + + ALTServerErrorDeviceNotFound = 3, + ALTServerErrorDeviceWriteFailed = 4, + + ALTServerErrorInvalidApp = 7, + ALTServerErrorInstallationFailed = 8, + ALTServerErrorMaximumFreeAppLimitReached = 9, + ALTServerErrorUnsupportediOSVersion = 10, + + ALTServerErrorUnknownRequest = 11, + ALTServerErrorUnknownResponse = 12, + + ALTServerErrorInvalidAnisetteData = 13, + ALTServerErrorPluginNotFound = 14 +}; + +NS_ASSUME_NONNULL_BEGIN + +@interface NSError (ALTServerError) +@end + +NS_ASSUME_NONNULL_END diff --git a/AltKit/NSError+ALTServerError.m b/AltKit/NSError+ALTServerError.m new file mode 100644 index 0000000..c726927 --- /dev/null +++ b/AltKit/NSError+ALTServerError.m @@ -0,0 +1,73 @@ +// +// NSError+ALTServerError.m +// AltStore +// +// Created by Riley Testut on 5/30/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "NSError+ALTServerError.h" + +NSErrorDomain const AltServerErrorDomain = @"com.rileytestut.AltServer"; +NSErrorDomain const AltServerInstallationErrorDomain = @"com.rileytestut.AltServer.Installation"; + +@implementation NSError (ALTServerError) + ++ (void)load +{ + [NSError setUserInfoValueProviderForDomain:AltServerErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) { + if ([userInfoKey isEqualToString:NSLocalizedDescriptionKey]) + { + return [error alt_localizedDescription]; + } + + return nil; + }]; +} + +- (nullable NSString *)alt_localizedDescription +{ + switch ((ALTServerError)self.code) + { + case ALTServerErrorUnknown: + return NSLocalizedString(@"An unknown error occured.", @""); + + case ALTServerErrorConnectionFailed: + return NSLocalizedString(@"Could not connect to device.", @""); + + case ALTServerErrorLostConnection: + return NSLocalizedString(@"Lost connection to device.", @""); + + case ALTServerErrorDeviceNotFound: + return NSLocalizedString(@"Could not find the specified device.", @""); + + case ALTServerErrorDeviceWriteFailed: + return NSLocalizedString(@"Failed to write app data to device.", @""); + + case ALTServerErrorInvalidApp: + return NSLocalizedString(@"The app is invalid.", @""); + + case ALTServerErrorInstallationFailed: + return NSLocalizedString(@"An error occured while installing the app.", @""); + + case ALTServerErrorMaximumFreeAppLimitReached: + return NSLocalizedString(@"You have reached the limit of 3 apps per device.", @""); + + case ALTServerErrorUnsupportediOSVersion: + return NSLocalizedString(@"Unsupported iOS version", @""); + + case ALTServerErrorUnknownRequest: + return NSLocalizedString(@"This app does not support this request.", @""); + + case ALTServerErrorUnknownResponse: + return NSLocalizedString(@"Received an unknown response from AltServer.", @""); + + case ALTServerErrorInvalidAnisetteData: + return NSLocalizedString(@"Invalid anisette data.", @""); + + case ALTServerErrorPluginNotFound: + return NSLocalizedString(@"Could not connect to Mail plug-in. Please make sure the plug-in is installed and Mail is running, then try again.", @""); + } +} + +@end diff --git a/AltKit/Result+Conveniences.swift b/AltKit/Result+Conveniences.swift new file mode 100644 index 0000000..2ffec68 --- /dev/null +++ b/AltKit/Result+Conveniences.swift @@ -0,0 +1,76 @@ +// +// Result+Conveniences.swift +// AltStore +// +// Created by Riley Testut on 5/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import Foundation + +public extension Result +{ + var value: Success? { + switch self + { + case .success(let value): return value + case .failure: return nil + } + } + + var error: Failure? { + switch self + { + case .success: return nil + case .failure(let error): return error + } + } + + init(_ value: Success?, _ error: Failure?) + { + switch (value, error) + { + case (let value?, _): self = .success(value) + case (_, let error?): self = .failure(error) + case (nil, nil): preconditionFailure("Either value or error must be non-nil") + } + } +} + +public extension Result where Success == Void +{ + init(_ success: Bool, _ error: Failure?) + { + if success + { + self = .success(()) + } + else if let error = error + { + self = .failure(error) + } + else + { + preconditionFailure("Error must be non-nil if success is false") + } + } +} + +public extension Result +{ + init(_ values: (T?, U?), _ error: Failure?) where Success == (T, U) + { + if let value1 = values.0, let value2 = values.1 + { + self = .success((value1, value2)) + } + else if let error = error + { + self = .failure(error) + } + else + { + preconditionFailure("Error must be non-nil if either provided values are nil") + } + } +} diff --git a/AltPlugin.mailbundle/Contents/Info.plist b/AltPlugin.mailbundle/Contents/Info.plist new file mode 100644 index 0000000..ad39158 --- /dev/null +++ b/AltPlugin.mailbundle/Contents/Info.plist @@ -0,0 +1,84 @@ + + + + + BuildMachineOSBuild + 19A583 + CFBundleDevelopmentRegion + en + CFBundleExecutable + AltPlugin + CFBundleIdentifier + com.rileytestut.AltPlugin + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + AltPlugin + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 11B41 + DTPlatformVersion + GM + DTSDKBuild + 19A547 + DTSDKName + macosx10.15 + DTXcode + 1120 + DTXcodeBuild + 11B41 + LSMinimumSystemVersion + 10.14 + NSHumanReadableCopyright + Copyright © 2019 Riley Testut. All rights reserved. + NSPrincipalClass + ALTPluginService + Supported10.14PluginCompatibilityUUIDs + + # UUIDs for versions from 10.12 to 99.99.99 + # For mail version 10.0 (3226) on OS X Version 10.12 (build 16A319) + 36CCB8BB-2207-455E-89BC-B9D6E47ABB5B + # For mail version 10.1 (3251) on OS X Version 10.12.1 (build 16B2553a) + 9054AFD9-2607-489E-8E63-8B09A749BC61 + # For mail version 10.2 (3259) on OS X Version 10.12.2 (build 16D12b) + 1CD3B36A-0E3B-4A26-8F7E-5BDF96AAC97E + # For mail version 10.3 (3273) on OS X Version 10.12.4 (build 16G1036) + 21560BD9-A3CC-482E-9B99-95B7BF61EDC1 + # For mail version 11.0 (3441.0.1) on OS X Version 10.13 (build 17A315i) + C86CD990-4660-4E36-8CDA-7454DEB2E199 + # For mail version 12.0 (3445.100.39) on OS X Version 10.14.1 (build 18B45d) + A4343FAF-AE18-40D0-8A16-DFAE481AF9C1 + # For mail version 13.0 (3594.4.2) on OS X Version 10.15 (build 19A558d) + 6EEA38FB-1A0B-469B-BB35-4C2E0EEA9053 + + Supported10.15PluginCompatibilityUUIDs + + # UUIDs for versions from 10.12 to 99.99.99 + # For mail version 10.0 (3226) on OS X Version 10.12 (build 16A319) + 36CCB8BB-2207-455E-89BC-B9D6E47ABB5B + # For mail version 10.1 (3251) on OS X Version 10.12.1 (build 16B2553a) + 9054AFD9-2607-489E-8E63-8B09A749BC61 + # For mail version 10.2 (3259) on OS X Version 10.12.2 (build 16D12b) + 1CD3B36A-0E3B-4A26-8F7E-5BDF96AAC97E + # For mail version 10.3 (3273) on OS X Version 10.12.4 (build 16G1036) + 21560BD9-A3CC-482E-9B99-95B7BF61EDC1 + # For mail version 11.0 (3441.0.1) on OS X Version 10.13 (build 17A315i) + C86CD990-4660-4E36-8CDA-7454DEB2E199 + # For mail version 12.0 (3445.100.39) on OS X Version 10.14.1 (build 18B45d) + A4343FAF-AE18-40D0-8A16-DFAE481AF9C1 + # For mail version 13.0 (3594.4.2) on OS X Version 10.15 (build 19A558d) + 6EEA38FB-1A0B-469B-BB35-4C2E0EEA9053 + + + diff --git a/AltPlugin.mailbundle/Contents/MacOS/AltPlugin b/AltPlugin.mailbundle/Contents/MacOS/AltPlugin new file mode 100755 index 0000000..b78c8d1 Binary files /dev/null and b/AltPlugin.mailbundle/Contents/MacOS/AltPlugin differ diff --git a/AltServer/ALTDeviceManager+Installation.swift b/AltServer/ALTDeviceManager+Installation.swift new file mode 100644 index 0000000..1af7bac --- /dev/null +++ b/AltServer/ALTDeviceManager+Installation.swift @@ -0,0 +1,553 @@ +// +// ALTDeviceManager+Installation.swift +// AltServer +// +// Created by Riley Testut on 7/1/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import Cocoa +import UserNotifications +import ObjectiveC + +enum InstallError: LocalizedError +{ + case cancelled + case noTeam + case missingPrivateKey + case missingCertificate + + var errorDescription: String? { + switch self + { + case .cancelled: return NSLocalizedString("The operation was cancelled.", comment: "") + case .noTeam: return "You are not a member of any developer teams." + case .missingPrivateKey: return "The developer certificate's private key could not be found." + case .missingCertificate: return "The developer certificate could not be found." + } + } +} + +extension ALTDeviceManager +{ + @objc func installApplication(to device: ALTDevice, appleID: String, password: String, applicationURL: URL, completion: @escaping (Error?) -> Void) -> Progress + { + let destinationDirectoryURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + + func finish(_ error: Error?, title: String = "") + { + if let error = error { + completion(error) + } + else { + completion(nil) + } + try? FileManager.default.removeItem(at: destinationDirectoryURL) + } + + let progress = Progress.init(totalUnitCount: 19) + progress.localizedDescription = "Requesting anisette data..."; + + AnisetteDataManager.shared.requestAnisetteData { (result) in + do + { + let anisetteData = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Authenticating with your Apple ID..."; + + self.authenticate(appleID: appleID, password: password, anisetteData: anisetteData) { (result) in + do + { + let (account, session) = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Fetching team information..."; + + self.fetchTeam(for: account, session: session) { (result) in + do + { + let team = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Registering device..."; + + self.register(device, team: team, session: session) { (result) in + do + { + let device = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Fetching certificates..."; + + self.fetchCertificate(for: team, session: session) { (result) in + do + { + let certificate = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Downloading your app..."; + + self.downloadApp(applicationURL: applicationURL) { (result) in + do + { + let fileURL = try result.get() + + try FileManager.default.createDirectory(at: destinationDirectoryURL, withIntermediateDirectories: true, attributes: nil) + + let appBundleURL = try FileManager.default.unzipAppBundle(at: fileURL, toDirectory: destinationDirectoryURL) + + do + { + try FileManager.default.removeItem(at: fileURL) + } + catch + { + print("Failed to remove downloaded .ipa.", error) + } + + guard let application = ALTApplication(fileURL: appBundleURL) else { throw ALTError(.invalidApp) } + progress.completedUnitCount += 1 + progress.localizedDescription = "Registering the App ID..."; + + self.registerAppID(name: "AltStore", identifier: "com.rileytestut.AltStore", team: team, session: session) { (result) in + do + { + let appID = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Updating app ID..."; + + self.updateFeatures(for: appID, app: application, team: team, session: session) { (result) in + do + { + let appID = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Fetching the provisioning profile..."; + + self.fetchProvisioningProfile(for: appID, team: team, session: session) { (result) in + do + { + let provisioningProfile = try result.get() + progress.completedUnitCount += 1 + progress.localizedDescription = "Beginning installation..."; + + self.install(application, to: device, team: team, appID: appID, certificate: certificate, profile: provisioningProfile, progress: progress) { (result) in + finish(result.error, title: "Failed to Install AltStore") + } + } + catch + { + finish(error, title: "Failed to Fetch Provisioning Profile") + } + } + } + catch + { + finish(error, title: "Failed to Update App ID") + } + } + } + catch + { + finish(error, title: "Failed to Register App") + } + } + } + catch + { + finish(error, title: "Failed to Download App") + return + } + } + } + catch + { + finish(error, title: "Failed to Fetch Certificate") + } + } + } + catch + { + finish(error, title: "Failed to Register Device") + } + } + } + catch + { + finish(error, title: "Failed to Fetch Team") + } + } + } + catch + { + finish(error, title: "Failed to Authenticate") + } + } + } + catch + { + finish(error, title: "Failed to Fetch Anisette Data") + } + } + + return progress + } + + func downloadApp(applicationURL: URL, completionHandler: @escaping (Result) -> Void) + { + if applicationURL.isFileURL { + DispatchQueue.global().async { + let fileURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID.init().uuidString).appendingPathExtension("ipa") + do { + try FileManager.default.copyItem(at: applicationURL, to: fileURL) + completionHandler(.success(fileURL)) + } + catch let error { + completionHandler(.failure(error)) + } + } + } + else { + let downloadTask = URLSession.shared.downloadTask(with: applicationURL) { (fileURL, response, error) in + do + { + let (fileURL, _) = try Result((fileURL, response), error).get() + completionHandler(.success(fileURL)) + } + catch + { + completionHandler(.failure(error)) + } + } + + downloadTask.resume() + } + } + + func authenticate(appleID: String, password: String, anisetteData: ALTAnisetteData, completionHandler: @escaping (Result<(ALTAccount, ALTAppleAPISession), Error>) -> Void) + { + func handleVerificationCode(_ completionHandler: @escaping (String?) -> Void) + { + DispatchQueue.main.async { + let alert = NSAlert() + alert.messageText = NSLocalizedString("Two-Factor Authentication Enabled", comment: "") + alert.informativeText = NSLocalizedString("Please enter the 6-digit verification code that was sent to your Apple devices.", comment: "") + + let textField = NSTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 22)) + textField.delegate = self + textField.translatesAutoresizingMaskIntoConstraints = false + textField.placeholderString = NSLocalizedString("123456", comment: "") + alert.accessoryView = textField + alert.window.initialFirstResponder = textField + + alert.addButton(withTitle: NSLocalizedString("Continue", comment: "")) + alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) + + self.securityCodeAlert = alert + self.securityCodeTextField = textField + self.validate() + + NSRunningApplication.current.activate(options: .activateIgnoringOtherApps) + + let response = alert.runModal() + if response == .alertFirstButtonReturn + { + let code = textField.stringValue + completionHandler(code) + } + else + { + completionHandler(nil) + } + } + } + + ALTAppleAPI.shared.authenticate(appleID: appleID, password: password, anisetteData: anisetteData, verificationHandler: handleVerificationCode) { (account, session, error) in + if let account = account, let session = session + { + completionHandler(.success((account, session))) + } + else + { + completionHandler(.failure(error ?? ALTAppleAPIError(.unknown))) + } + } + } + + func fetchTeam(for account: ALTAccount, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) + { + func finish(_ result: Result) + { + switch result + { + case .failure(let error): + completionHandler(.failure(error)) + + case .success(let team): + + var isCancelled = false + + if team.type != .free + { + DispatchQueue.main.sync { + let alert = NSAlert() + alert.messageText = NSLocalizedString("Installing AltStore will revoke your iOS development certificate.", comment: "") + alert.informativeText = NSLocalizedString(""" +This will not affect apps you've submitted to the App Store, but may cause apps you've installed to your devices with Xcode to stop working until you reinstall them. + +To prevent this from happening, feel free to try again with another Apple ID to install AltStore. +""", comment: "") + + alert.addButton(withTitle: NSLocalizedString("Continue", comment: "")) + alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) + + NSRunningApplication.current.activate(options: .activateIgnoringOtherApps) + + let buttonIndex = alert.runModal() + if buttonIndex == NSApplication.ModalResponse.alertSecondButtonReturn + { + isCancelled = true + } + } + + if isCancelled + { + return completionHandler(.failure(InstallError.cancelled)) + } + } + + completionHandler(.success(team)) + } + } + + ALTAppleAPI.shared.fetchTeams(for: account, session: session) { (teams, error) in + do + { + let teams = try Result(teams, error).get() + + if let team = teams.first(where: { $0.type == .free }) + { + return finish(.success(team)) + } + else if let team = teams.first(where: { $0.type == .individual }) + { + return finish(.success(team)) + } + else if let team = teams.first + { + return finish(.success(team)) + } + else + { + throw InstallError.noTeam + } + } + catch + { + finish(.failure(error)) + } + } + } + + func fetchCertificate(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) + { + ALTAppleAPI.shared.fetchCertificates(for: team, session: session) { (certificates, error) in + do + { + let certificates = try Result(certificates, error).get() + + if let certificate = certificates.first + { + ALTAppleAPI.shared.revoke(certificate, for: team, session: session) { (success, error) in + do + { + try Result(success, error).get() + self.fetchCertificate(for: team, session: session, completionHandler: completionHandler) + } + catch + { + completionHandler(.failure(error)) + } + } + } + else + { + ALTAppleAPI.shared.addCertificate(machineName: "AltStore", to: team, session: session) { (certificate, error) in + do + { + let certificate = try Result(certificate, error).get() + guard let privateKey = certificate.privateKey else { throw InstallError.missingPrivateKey } + + ALTAppleAPI.shared.fetchCertificates(for: team, session: session) { (certificates, error) in + do + { + let certificates = try Result(certificates, error).get() + + guard let certificate = certificates.first(where: { $0.serialNumber == certificate.serialNumber }) else { + throw InstallError.missingCertificate + } + + certificate.privateKey = privateKey + + completionHandler(.success(certificate)) + } + catch + { + completionHandler(.failure(error)) + } + } + } + catch + { + completionHandler(.failure(error)) + } + } + } + } + catch + { + completionHandler(.failure(error)) + } + } + } + + func registerAppID(name appName: String, identifier: String, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) + { + let bundleID = "com.\(team.identifier).\(identifier)" + + ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { (appIDs, error) in + do + { + let appIDs = try Result(appIDs, error).get() + + if let appID = appIDs.first(where: { $0.bundleIdentifier == bundleID }) + { + completionHandler(.success(appID)) + } + else + { + ALTAppleAPI.shared.addAppID(withName: appName, bundleIdentifier: bundleID, team: team, session: session) { (appID, error) in + completionHandler(Result(appID, error)) + } + } + } + catch + { + completionHandler(.failure(error)) + } + } + } + + func updateFeatures(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) + { + let requiredFeatures = app.entitlements.compactMap { (entitlement, value) -> (ALTFeature, Any)? in + guard let feature = ALTFeature(entitlement: entitlement) else { return nil } + return (feature, value) + } + + var features = requiredFeatures.reduce(into: [ALTFeature: Any]()) { $0[$1.0] = $1.1 } + + if let applicationGroups = app.entitlements[.appGroups] as? [String], !applicationGroups.isEmpty + { + features[.appGroups] = true + } + + let appID = appID.copy() as! ALTAppID + appID.features = features + + ALTAppleAPI.shared.update(appID, team: team, session: session) { (appID, error) in + completionHandler(Result(appID, error)) + } + } + + func register(_ device: ALTDevice, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) + { + ALTAppleAPI.shared.fetchDevices(for: team, session: session) { (devices, error) in + do + { + let devices = try Result(devices, error).get() + + if let device = devices.first(where: { $0.identifier == device.identifier }) + { + completionHandler(.success(device)) + } + else + { + ALTAppleAPI.shared.registerDevice(name: device.name, identifier: device.identifier, team: team, session: session) { (device, error) in + completionHandler(Result(device, error)) + } + } + } + catch + { + completionHandler(.failure(error)) + } + } + } + + func fetchProvisioningProfile(for appID: ALTAppID, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) + { + ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, team: team, session: session) { (profile, error) in + completionHandler(Result(profile, error)) + } + } + + func install(_ application: ALTApplication, to device: ALTDevice, team: ALTTeam, appID: ALTAppID, certificate: ALTCertificate, profile: ALTProvisioningProfile, progress: Progress, completionHandler: @escaping (Result) -> Void) + { + DispatchQueue.global().async { + let resigner = ALTSigner(team: team, certificate: certificate) + resigner.signApp(at: application.fileURL, provisioningProfiles: [profile]) { (success, error) in + do + { + try Result(success, error).get() + + ALTDeviceManager.shared.installApp(at: application.fileURL, toDeviceWithUDID: device.identifier, progress: progress) { (success, error) in + completionHandler(Result(success, error)) + } + } + catch + { + print("Failed to install app", error) + completionHandler(.failure(error)) + } + } + } + } +} + +private var securityCodeAlertKey = 0 +private var securityCodeTextFieldKey = 0 + +extension ALTDeviceManager: NSTextFieldDelegate +{ + var securityCodeAlert: NSAlert? { + get { return objc_getAssociatedObject(self, &securityCodeAlertKey) as? NSAlert } + set { objc_setAssociatedObject(self, &securityCodeAlertKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } + } + + var securityCodeTextField: NSTextField? { + get { return objc_getAssociatedObject(self, &securityCodeTextFieldKey) as? NSTextField } + set { objc_setAssociatedObject(self, &securityCodeTextFieldKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } + } + + public override func controlTextDidChange(_ obj: Notification) + { + self.validate() + } + + public override func controlTextDidEndEditing(_ obj: Notification) + { + self.validate() + } + + private func validate() + { + guard let code = self.securityCodeTextField?.stringValue.trimmingCharacters(in: .whitespacesAndNewlines) else { return } + + if code.count == 6 + { + self.securityCodeAlert?.buttons.first?.isEnabled = true + } + else + { + self.securityCodeAlert?.buttons.first?.isEnabled = false + } + + self.securityCodeAlert?.layout() + } +} diff --git a/AltServer/ALTDeviceManager.h b/AltServer/ALTDeviceManager.h new file mode 100644 index 0000000..ceb6ee2 --- /dev/null +++ b/AltServer/ALTDeviceManager.h @@ -0,0 +1,25 @@ +// +// ALTDeviceManager.h +// AltServer +// +// Created by Riley Testut on 5/24/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTDeviceManager : NSObject + +@property (class, nonatomic, readonly) ALTDeviceManager *sharedManager; + +@property (nonatomic, readonly) NSArray *connectedDevices; +@property (nonatomic, readonly) NSArray *availableDevices; + +- (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid progress:(NSProgress *)progress completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltServer/ALTDeviceManager.mm b/AltServer/ALTDeviceManager.mm new file mode 100644 index 0000000..41fbf9f --- /dev/null +++ b/AltServer/ALTDeviceManager.mm @@ -0,0 +1,706 @@ +// +// ALTDeviceManager.m +// AltServer +// +// Created by Riley Testut on 5/24/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTDeviceManager.h" +#import + +#include +#include +#include +#include +#include +#include + + +void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *udid); + +NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; + +@interface ALTDeviceManager () + +@property (nonatomic, readonly) NSMutableDictionary *installationCompletionHandlers; +@property (nonatomic, readonly) NSMutableDictionary *installationProgress; +@property (nonatomic, readonly) dispatch_queue_t installationQueue; + +@end + +@implementation ALTDeviceManager + ++ (ALTDeviceManager *)sharedManager +{ + static ALTDeviceManager *_manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _manager = [[self alloc] init]; + }); + + return _manager; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _installationCompletionHandlers = [NSMutableDictionary dictionary]; + _installationProgress = [NSMutableDictionary dictionary]; + + _installationQueue = dispatch_queue_create("com.rileytestut.AltServer.InstallationQueue", DISPATCH_QUEUE_SERIAL); + } + + return self; +} + +- (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid progress:(NSProgress *)UIProgress completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler +{ + NSProgress *progress = [NSProgress discreteProgressWithTotalUnitCount:4]; + + dispatch_async(self.installationQueue, ^{ + NSUUID *UUID = [NSUUID UUID]; + __block char *uuidString = (char *)malloc(UUID.UUIDString.length + 1); + strncpy(uuidString, (const char *)UUID.UUIDString.UTF8String, UUID.UUIDString.length); + uuidString[UUID.UUIDString.length] = '\0'; + + __block idevice_t device = NULL; + __block lockdownd_client_t client = NULL; + __block instproxy_client_t ipc = NULL; + __block afc_client_t afc = NULL; + __block misagent_client_t mis = NULL; + __block lockdownd_service_descriptor_t service = NULL; + + NSURL *removedProfilesDirectoryURL = [[[NSFileManager defaultManager] temporaryDirectory] URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSMutableDictionary *preferredProfiles = [NSMutableDictionary dictionary]; + + void (^finish)(NSError *error) = ^(NSError *error) { + + if ([[NSFileManager defaultManager] fileExistsAtPath:removedProfilesDirectoryURL.path isDirectory:nil]) + { + // Reinstall all provisioning profiles we removed before installation. + + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:removedProfilesDirectoryURL.path error:nil]; + for (NSString *filename in contents) + { + NSURL *fileURL = [removedProfilesDirectoryURL URLByAppendingPathComponent:filename]; + + ALTProvisioningProfile *provisioningProfile = [[ALTProvisioningProfile alloc] initWithURL:fileURL]; + if (provisioningProfile == nil) + { + continue; + } + + ALTProvisioningProfile *preferredProfile = preferredProfiles[provisioningProfile.bundleIdentifier]; + if (![preferredProfile isEqual:provisioningProfile]) + { + continue; + } + + plist_t pdata = plist_new_data((const char *)provisioningProfile.data.bytes, provisioningProfile.data.length); + + if (misagent_install(mis, pdata) == MISAGENT_E_SUCCESS) + { + NSLog(@"Reinstalled profile: %@", provisioningProfile.UUID); + } + else + { + int code = misagent_get_status_code(mis); + NSLog(@"Failed to reinstall provisioning profile %@. (%@)", provisioningProfile.UUID, @(code)); + } + } + + [[NSFileManager defaultManager] removeItemAtURL:removedProfilesDirectoryURL error:nil]; + } + + instproxy_client_free(ipc); + afc_client_free(afc); + lockdownd_client_free(client); + misagent_client_free(mis); + idevice_free(device); + lockdownd_service_descriptor_free(service); + + free(uuidString); + uuidString = NULL; + + if (error != nil) + { + completionHandler(NO, error); + } + else + { + completionHandler(YES, nil); + } + }; + + NSURL *appBundleURL = nil; + NSURL *temporaryDirectoryURL = nil; + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Extracting the application..."; + + if ([fileURL.pathExtension.lowercaseString isEqualToString:@"app"]) + { + appBundleURL = fileURL; + temporaryDirectoryURL = nil; + } + else if ([fileURL.pathExtension.lowercaseString isEqualToString:@"ipa"]) + { + NSLog(@"Unzipping .ipa..."); + + temporaryDirectoryURL = [NSFileManager.defaultManager.temporaryDirectory URLByAppendingPathComponent:[[NSUUID UUID] UUIDString] isDirectory:YES]; + + NSError *error = nil; + if (![[NSFileManager defaultManager] createDirectoryAtURL:temporaryDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error]) + { + return finish(error); + } + + appBundleURL = [[NSFileManager defaultManager] unzipAppBundleAtURL:fileURL toDirectory:temporaryDirectoryURL error:&error]; + if (appBundleURL == nil) + { + return finish(error); + } + } + else + { + return finish([NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadCorruptFileError userInfo:@{NSURLErrorKey: fileURL}]); + } + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Connecting to iDevice..."; + + /* Find Device */ + if (idevice_new(&device, udid.UTF8String) != IDEVICE_E_SUCCESS) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorDeviceNotFound userInfo:nil]); + } + + /* Connect to Device */ + lockdownd_error_t error; + if ((error = lockdownd_client_new_with_handshake(device, &client, "altserver")) != LOCKDOWN_E_SUCCESS) + { + NSLog(@"%d", error); + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Connecting to the installation proxy..."; + + /* Connect to Installation Proxy */ + if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || service == NULL) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + if (instproxy_client_new(device, service, &ipc) != INSTPROXY_E_SUCCESS) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + if (service) + { + lockdownd_service_descriptor_free(service); + service = NULL; + } + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Connecting to the misagent..."; + + /* Connect to Misagent */ + // Must connect now, since if we take too long writing files to device, connecting may fail later when managing profiles. + if (lockdownd_start_service(client, "com.apple.misagent", &service) != LOCKDOWN_E_SUCCESS || service == NULL) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + if (misagent_client_new(device, service, &mis) != MISAGENT_E_SUCCESS) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Connecting to the AFC service..."; + + /* Connect to AFC service */ + if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || service == NULL) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + if (afc_client_new(device, service, &afc) != AFC_E_SUCCESS) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + NSURL *stagingURL = [NSURL fileURLWithPath:@"PublicStaging" isDirectory:YES]; + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Preparing for the installation..."; + + /* Prepare for installation */ + char **files = NULL; + if (afc_get_file_info(afc, stagingURL.relativePath.fileSystemRepresentation, &files) != AFC_E_SUCCESS) + { + if (afc_make_directory(afc, stagingURL.relativePath.fileSystemRepresentation) != AFC_E_SUCCESS) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorDeviceWriteFailed userInfo:nil]); + } + } + + if (files) + { + int i = 0; + + while (files[i]) + { + free(files[i]); + i++; + } + + free(files); + } + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Sending files to device..."; + + NSLog(@"Writing to device..."); + + plist_t options = instproxy_client_options_new(); + instproxy_client_options_add(options, "PackageType", "Developer", NULL); + + NSURL *destinationURL = [stagingURL URLByAppendingPathComponent:appBundleURL.lastPathComponent]; + + // Writing files to device should be worth 3/4 of total work. + [progress becomeCurrentWithPendingUnitCount:3]; + + NSError *writeError = nil; + if (![self writeDirectory:appBundleURL toDestinationURL:destinationURL client:afc progress:nil error:&writeError]) + { + return finish(writeError); + } + + NSLog(@"Finished writing to device."); + + if (service) + { + lockdownd_service_descriptor_free(service); + service = NULL; + } + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Sending the provisioning profiles..."; + + /* Provisioning Profiles */ + NSURL *provisioningProfileURL = [appBundleURL URLByAppendingPathComponent:@"embedded.mobileprovision"]; + ALTProvisioningProfile *installationProvisioningProfile = [[ALTProvisioningProfile alloc] initWithURL:provisioningProfileURL]; + if (installationProvisioningProfile != nil) + { + NSError *error = nil; + if (![[NSFileManager defaultManager] createDirectoryAtURL:removedProfilesDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error]) + { + return finish(error); + } + + plist_t rawProfiles = NULL; + + if (misagent_copy_all(mis, &rawProfiles) != MISAGENT_E_SUCCESS) + { + return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + // For some reason, libplist now fails to parse `rawProfiles` correctly. + // Specifically, it no longer recognizes the nodes in the plist array as "data" nodes. + // However, if we encode it as XML then decode it again, it'll work ¯\_(ツ)_/¯ + char *plistXML = nullptr; + uint32_t plistLength = 0; + plist_to_xml(rawProfiles, &plistXML, &plistLength); + + plist_t profiles = NULL; + plist_from_xml(plistXML, plistLength, &profiles); + + uint32_t profileCount = plist_array_get_size(profiles); + for (int i = 0; i < profileCount; i++) + { + plist_t profile = plist_array_get_item(profiles, i); + if (plist_get_node_type(profile) != PLIST_DATA) + { + continue; + } + + char *bytes = NULL; + uint64_t length = 0; + + plist_get_data_val(profile, &bytes, &length); + if (bytes == NULL) + { + continue; + } + + NSData *data = [NSData dataWithBytes:(const void *)bytes length:length]; + ALTProvisioningProfile *provisioningProfile = [[ALTProvisioningProfile alloc] initWithData:data]; + + if (![provisioningProfile isFreeProvisioningProfile]) + { + NSLog(@"Ignoring: %@ (Team: %@)", provisioningProfile.bundleIdentifier, provisioningProfile.teamIdentifier); + continue; + } + + ALTProvisioningProfile *preferredProfile = preferredProfiles[provisioningProfile.bundleIdentifier]; + if (preferredProfile != nil) + { + if ([provisioningProfile.expirationDate compare:preferredProfile.expirationDate] == NSOrderedDescending) + { + preferredProfiles[provisioningProfile.bundleIdentifier] = provisioningProfile; + } + } + else + { + preferredProfiles[provisioningProfile.bundleIdentifier] = provisioningProfile; + } + + NSString *filename = [NSString stringWithFormat:@"%@.mobileprovision", [[NSUUID UUID] UUIDString]]; + NSURL *fileURL = [removedProfilesDirectoryURL URLByAppendingPathComponent:filename]; + + NSError *copyError = nil; + if (![provisioningProfile.data writeToURL:fileURL options:NSDataWritingAtomic error:©Error]) + { + NSLog(@"Failed to copy profile to temporary URL. %@", copyError); + continue; + } + + if (misagent_remove(mis, provisioningProfile.UUID.UUIDString.lowercaseString.UTF8String) == MISAGENT_E_SUCCESS) + { + NSLog(@"Removed provisioning profile: %@ (Team: %@)", provisioningProfile.bundleIdentifier, provisioningProfile.teamIdentifier); + } + else + { + int code = misagent_get_status_code(mis); + NSLog(@"Failed to remove provisioning profile %@ (Team: %@). Error Code: %@", provisioningProfile.bundleIdentifier, provisioningProfile.teamIdentifier, @(code)); + } + } + + plist_free(rawProfiles); + plist_free(profiles); + + lockdownd_client_free(client); + client = NULL; + } + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1]; + + self.installationProgress[UUID] = installationProgress; + self.installationCompletionHandlers[UUID] = ^(NSError *error) { + finish(error); + + if (temporaryDirectoryURL != nil) + { + NSError *error = nil; + if (![[NSFileManager defaultManager] removeItemAtURL:temporaryDirectoryURL error:&error]) + { + NSLog(@"Error removing temporary directory. %@", error); + } + } + + dispatch_semaphore_signal(semaphore); + }; + + UIProgress.completedUnitCount += 1; + UIProgress.localizedDescription = @"Finalizing..."; + + NSLog(@"Installing to device %@...", udid); + + instproxy_install(ipc, destinationURL.relativePath.fileSystemRepresentation, options, ALTDeviceManagerUpdateStatus, uuidString); + instproxy_client_options_free(options); + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + }); + + return progress; +} + +- (BOOL)writeDirectory:(NSURL *)directoryURL toDestinationURL:(NSURL *)destinationURL client:(afc_client_t)afc progress:(NSProgress *)progress error:(NSError **)error +{ + afc_make_directory(afc, destinationURL.relativePath.fileSystemRepresentation); + + if (progress == nil) + { + NSDirectoryEnumerator *countEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryURL + includingPropertiesForKeys:@[] + options:0 + errorHandler:^BOOL(NSURL * _Nonnull url, NSError * _Nonnull error) { + if (error) { + NSLog(@"[Error] %@ (%@)", error, url); + return NO; + } + + return YES; + }]; + + NSInteger totalCount = 0; + for (NSURL *__unused fileURL in countEnumerator) + { + totalCount++; + } + + progress = [NSProgress progressWithTotalUnitCount:totalCount]; + } + + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryURL + includingPropertiesForKeys:@[NSURLIsDirectoryKey] + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants + errorHandler:^BOOL(NSURL * _Nonnull url, NSError * _Nonnull error) { + if (error) { + NSLog(@"[Error] %@ (%@)", error, url); + return NO; + } + + return YES; + }]; + + for (NSURL *fileURL in enumerator) + { + NSNumber *isDirectory = nil; + if (![fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:error]) + { + return NO; + } + + if ([isDirectory boolValue]) + { + NSURL *destinationDirectoryURL = [destinationURL URLByAppendingPathComponent:fileURL.lastPathComponent isDirectory:YES]; + if (![self writeDirectory:fileURL toDestinationURL:destinationDirectoryURL client:afc progress:progress error:error]) + { + return NO; + } + } + else + { + NSURL *destinationFileURL = [destinationURL URLByAppendingPathComponent:fileURL.lastPathComponent isDirectory:NO]; + if (![self writeFile:fileURL toDestinationURL:destinationFileURL client:afc error:error]) + { + return NO; + } + } + + progress.completedUnitCount += 1; + } + + return YES; +} + +- (BOOL)writeFile:(NSURL *)fileURL toDestinationURL:(NSURL *)destinationURL client:(afc_client_t)afc error:(NSError **)error +{ + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:fileURL.path]; + if (fileHandle == nil) + { + if (error) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileNoSuchFileError userInfo:@{NSURLErrorKey: fileURL}]; + } + + return NO; + } + + NSData *data = [fileHandle readDataToEndOfFile]; + + uint64_t af = 0; + if ((afc_file_open(afc, destinationURL.relativePath.fileSystemRepresentation, AFC_FOPEN_WRONLY, &af) != AFC_E_SUCCESS) || af == 0) + { + if (error) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSURLErrorKey: destinationURL}]; + } + + return NO; + } + + BOOL success = YES; + uint32_t bytesWritten = 0; + + while (bytesWritten < data.length) + { + uint32_t count = 0; + + if (afc_file_write(afc, af, (const char *)data.bytes + bytesWritten, (uint32_t)data.length - bytesWritten, &count) != AFC_E_SUCCESS) + { + if (error) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSURLErrorKey: destinationURL}]; + } + + success = NO; + break; + } + + bytesWritten += count; + } + + if (bytesWritten != data.length) + { + if (error) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSURLErrorKey: destinationURL}]; + } + + success = NO; + } + + afc_file_close(afc, af); + + return success; +} + +#pragma mark - Getters - + +- (NSArray *)connectedDevices +{ + return [self availableDevicesIncludingNetworkDevices:NO]; +} + +- (NSArray *)availableDevices +{ + return [self availableDevicesIncludingNetworkDevices:YES]; +} + +- (NSArray *)availableDevicesIncludingNetworkDevices:(BOOL)includingNetworkDevices +{ + includingNetworkDevices = NO; + NSMutableSet *connectedDevices = [NSMutableSet set]; + + int count = 0; + char **udids = NULL; + if (idevice_get_device_list(&udids, &count) < 0) + { + fprintf(stderr, "ERROR: Unable to retrieve device list!\n"); + return @[]; + } + + for (int i = 0; i < count; i++) + { + char *udid = udids[i]; + + idevice_t device = NULL; + idevice_new(&device, udid); + + if (!device) + { + continue; + } + + lockdownd_client_t client = NULL; + int result = lockdownd_client_new(device, &client, "altserver"); + if (result != LOCKDOWN_E_SUCCESS) + { + fprintf(stderr, "ERROR: Connecting to device %s failed! (%d)\n", udid, result); + + idevice_free(device); + + continue; + } + + char *device_name = NULL; + if (lockdownd_get_device_name(client, &device_name) != LOCKDOWN_E_SUCCESS || device_name == NULL) + { + fprintf(stderr, "ERROR: Could not get device name!\n"); + + lockdownd_client_free(client); + idevice_free(device); + + continue; + } + + lockdownd_client_free(client); + idevice_free(device); + + NSString *name = [NSString stringWithCString:device_name encoding:NSUTF8StringEncoding]; + NSString *identifier = [NSString stringWithCString:udid encoding:NSUTF8StringEncoding]; + + ALTDevice *altDevice = [[ALTDevice alloc] initWithName:name identifier:identifier]; + [connectedDevices addObject:altDevice]; + + if (device_name != NULL) + { + free(device_name); + } + } + + idevice_device_list_free(udids); + + return connectedDevices.allObjects; +} + +@end + +#pragma mark - Callbacks - + +void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *uuid) +{ + NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:[NSString stringWithUTF8String:(const char *)uuid]]; + + NSProgress *progress = ALTDeviceManager.sharedManager.installationProgress[UUID]; + if (progress == nil) + { + return; + } + + int percent = -1; + instproxy_status_get_percent_complete(status, &percent); + + char *name = NULL; + char *description = NULL; + uint64_t code = 0; + instproxy_status_get_error(status, &name, &description, &code); + + if ((percent == -1 && progress.completedUnitCount > 0) || code != 0 || name != NULL) + { + void (^completionHandler)(NSError *) = ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID]; + if (completionHandler != nil) + { + if (code != 0 || name != NULL) + { + NSLog(@"Error installing app. %@ (%@). %@", @(code), @(name), @(description)); + + NSError *error = nil; + + if (code == 3892346913) + { + error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorMaximumFreeAppLimitReached userInfo:nil]; + } + else + { + NSString *errorName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; + if ([errorName isEqualToString:@"DeviceOSVersionTooLow"]) + { + error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorUnsupportediOSVersion userInfo:nil]; + } + else + { + NSError *underlyingError = [NSError errorWithDomain:AltServerInstallationErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: @(description)}]; + error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorInstallationFailed userInfo:@{NSUnderlyingErrorKey: underlyingError}]; + } + } + + completionHandler(error); + } + else + { + NSLog(@"Finished installing app!"); + completionHandler(nil); + } + + ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID] = nil; + ALTDeviceManager.sharedManager.installationProgress[UUID] = nil; + } + } + else if (progress.completedUnitCount < percent) + { + progress.completedUnitCount = percent; + + NSLog(@"Installation Progress: %@", @(percent)); + } +} diff --git a/AltServer/AnisetteDataManager.swift b/AltServer/AnisetteDataManager.swift new file mode 100644 index 0000000..6c96236 --- /dev/null +++ b/AltServer/AnisetteDataManager.swift @@ -0,0 +1,78 @@ +// +// AnisetteDataManager.swift +// AltServer +// +// Created by Riley Testut on 11/16/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import Foundation + +class AnisetteDataManager: NSObject +{ + static let shared = AnisetteDataManager() + + private var anisetteDataCompletionHandlers: [String: (Result) -> Void] = [:] + private var anisetteDataTimers: [String: Timer] = [:] + + private override init() + { + super.init() + + DistributedNotificationCenter.default().addObserver(self, selector: #selector(AnisetteDataManager.handleAnisetteDataResponse(_:)), name: Notification.Name("com.rileytestut.AltServer.AnisetteDataResponse"), object: nil) + } + + func requestAnisetteData(_ completion: @escaping (Result) -> Void) + { + let requestUUID = UUID().uuidString + self.anisetteDataCompletionHandlers[requestUUID] = completion + + let timer = Timer(timeInterval: 1.0, repeats: false) { (timer) in + self.finishRequest(forUUID: requestUUID, result: .failure(ALTServerError(.pluginNotFound))) + } + self.anisetteDataTimers[requestUUID] = timer + + RunLoop.main.add(timer, forMode: .defaultRunLoopMode) + + DistributedNotificationCenter.default().postNotificationName(Notification.Name("com.rileytestut.AltServer.FetchAnisetteData"), object: nil, userInfo: ["requestUUID": requestUUID], options: .deliverImmediately) + } +} + +private extension AnisetteDataManager +{ + @objc func handleAnisetteDataResponse(_ notification: Notification) + { + guard let userInfo = notification.userInfo, let requestUUID = userInfo["requestUUID"] as? String else { return } + + if + let archivedAnisetteData = userInfo["anisetteData"] as? Data, + let anisetteData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ALTAnisetteData.self, from: archivedAnisetteData) + { + if let range = anisetteData!.deviceDescription.lowercased().range(of: "(com.apple.mail") + { + var adjustedDescription = anisetteData!.deviceDescription[..) + { + let completionHandler = self.anisetteDataCompletionHandlers[requestUUID] + self.anisetteDataCompletionHandlers[requestUUID] = nil + + let timer = self.anisetteDataTimers[requestUUID] + self.anisetteDataTimers[requestUUID] = nil + + timer?.invalidate() + completionHandler?(result) + } +} diff --git a/AltSign/ALTAccount.h b/AltSign/ALTAccount.h new file mode 100644 index 0000000..1678cf6 --- /dev/null +++ b/AltSign/ALTAccount.h @@ -0,0 +1,24 @@ +// +// ALTAccount.h +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAccount : NSObject + +@property (nonatomic, copy) NSString *appleID; +@property (nonatomic, copy) NSString *identifier; + +@property (nonatomic, readonly) NSString *name; +@property (nonatomic, copy) NSString *firstName; +@property (nonatomic, copy) NSString *lastName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTAccount.m b/AltSign/ALTAccount.m new file mode 100644 index 0000000..0278d73 --- /dev/null +++ b/AltSign/ALTAccount.m @@ -0,0 +1,73 @@ +// +// ALTAccount.m +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAccount.h" + +@implementation ALTAccount + +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary +{ + self = [super init]; + if (self) + { + NSString *appleID = responseDictionary[@"email"]; + NSNumber *identifier = responseDictionary[@"personId"]; + NSString *firstName = responseDictionary[@"firstName"] ?: responseDictionary[@"dsFirstName"]; + NSString *lastName = responseDictionary[@"lastName"] ?: responseDictionary[@"dsLastName"]; + + if (appleID == nil || identifier == nil || firstName == nil || lastName == nil) + { + return nil; + } + + _appleID = [appleID copy]; + _identifier = [identifier.description copy]; + _firstName = [firstName copy]; + _lastName = [lastName copy]; + } + + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, Name: %@, Apple ID: %@>", NSStringFromClass([self class]), self, self.name, self.appleID]; +} + +- (BOOL)isEqual:(id)object +{ + ALTAccount *account = (ALTAccount *)object; + if (![account isKindOfClass:[ALTAccount class]]) + { + return NO; + } + + BOOL isEqual = [self.identifier isEqualToString:account.identifier]; + return isEqual; +} + +- (NSUInteger)hash +{ + return self.identifier.hash; +} + +#pragma mark - Getters/Setters - + +- (NSString *)name +{ + NSPersonNameComponents *components = [[NSPersonNameComponents alloc] init]; + components.givenName = self.firstName; + components.familyName = self.lastName; + + NSString *name = [NSPersonNameComponentsFormatter localizedStringFromPersonNameComponents:components style:NSPersonNameComponentsFormatterStyleDefault options:0]; + return name; +} + +@end diff --git a/AltSign/ALTAnisetteData.h b/AltSign/ALTAnisetteData.h new file mode 100644 index 0000000..056f09f --- /dev/null +++ b/AltSign/ALTAnisetteData.h @@ -0,0 +1,44 @@ +// +// ALTAnisetteData.h +// AltSign +// +// Created by Riley Testut on 11/13/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAnisetteData : NSObject + +@property (nonatomic, copy) NSString *machineID; +@property (nonatomic, copy) NSString *oneTimePassword; +@property (nonatomic, copy) NSString *localUserID; +@property (nonatomic) unsigned long long routingInfo; + +@property (nonatomic, copy) NSString *deviceUniqueIdentifier; +@property (nonatomic, copy) NSString *deviceSerialNumber; +@property (nonatomic, copy) NSString *deviceDescription; + +@property (nonatomic, copy) NSDate *date; +@property (nonatomic, copy) NSLocale *locale; +@property (nonatomic, copy) NSTimeZone *timeZone; + +- (instancetype)initWithMachineID:(NSString *)machineID + oneTimePassword:(NSString *)oneTimePassword + localUserID:(NSString *)localUserID + routingInfo:(unsigned long long)routingInfo + deviceUniqueIdentifier:(NSString *)deviceUniqueIdentifier + deviceSerialNumber:(NSString *)deviceSerialNumber + deviceDescription:(NSString *)deviceDescription + date:(NSDate *)date + locale:(NSLocale *)locale + timeZone:(NSTimeZone *)timeZone; + +- (nullable instancetype)initWithJSON:(NSDictionary *)json; +- (NSDictionary *)json; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTAnisetteData.m b/AltSign/ALTAnisetteData.m new file mode 100644 index 0000000..5680244 --- /dev/null +++ b/AltSign/ALTAnisetteData.m @@ -0,0 +1,223 @@ +// +// ALTAnisetteData.m +// AltSign +// +// Created by Riley Testut on 11/13/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAnisetteData.h" + +@implementation ALTAnisetteData + +- (instancetype)initWithMachineID:(NSString *)machineID + oneTimePassword:(NSString *)oneTimePassword + localUserID:(NSString *)localUserID + routingInfo:(unsigned long long)routingInfo + deviceUniqueIdentifier:(NSString *)deviceUniqueIdentifier + deviceSerialNumber:(NSString *)deviceSerialNumber + deviceDescription:(NSString *)deviceDescription + date:(NSDate *)date + locale:(NSLocale *)locale + timeZone:(NSTimeZone *)timeZone +{ + self = [super init]; + if (self) + { + _machineID = [machineID copy]; + _oneTimePassword = [oneTimePassword copy]; + _localUserID = [localUserID copy]; + _routingInfo = routingInfo; + + _deviceUniqueIdentifier = [deviceUniqueIdentifier copy]; + _deviceSerialNumber = [deviceSerialNumber copy]; + _deviceDescription = [deviceDescription copy]; + + _date = [date copy]; + _locale = [locale copy]; + _timeZone = [timeZone copy]; + } + + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"Machine ID: %@\nOne-Time Password: %@\nLocal User ID: %@\nRouting Info: %@\nDevice UDID: %@\nDevice Serial Number: %@\nDevice Description: %@\nDate: %@\nLocale: %@\nTime Zone: %@", + self.machineID, self.oneTimePassword, self.localUserID, @(self.routingInfo), self.deviceUniqueIdentifier, self.deviceSerialNumber, self.deviceDescription, self.date, self.locale.localeIdentifier, self.timeZone]; +} + +- (BOOL)isEqual:(id)object +{ + ALTAnisetteData *anisetteData = (ALTAnisetteData *)object; + if (![anisetteData isKindOfClass:[ALTAnisetteData class]]) + { + return NO; + } + + BOOL isEqual = ([self.machineID isEqualToString:anisetteData.machineID] && + [self.oneTimePassword isEqualToString:anisetteData.oneTimePassword] && + [self.localUserID isEqualToString:anisetteData.localUserID] && + [@(self.routingInfo) isEqualToNumber:@(anisetteData.routingInfo)] && + [self.deviceUniqueIdentifier isEqualToString:anisetteData.deviceUniqueIdentifier] && + [self.deviceSerialNumber isEqualToString:anisetteData.deviceSerialNumber] && + [self.deviceDescription isEqualToString:anisetteData.deviceDescription] && + [self.date isEqualToDate:anisetteData.date] && + [self.locale isEqual:anisetteData.locale] && + [self.timeZone isEqualToTimeZone:anisetteData.timeZone]); + return isEqual; +} + +- (NSUInteger)hash +{ + return (self.machineID.hash ^ + self.oneTimePassword.hash ^ + self.localUserID.hash ^ + @(self.routingInfo).hash ^ + self.deviceUniqueIdentifier.hash ^ + self.deviceSerialNumber.hash ^ + self.deviceDescription.hash ^ + self.date.hash ^ + self.locale.hash ^ + self.timeZone.hash); + ; +} + +#pragma mark - - + +- (nonnull id)copyWithZone:(nullable NSZone *)zone +{ + ALTAnisetteData *copy = [[ALTAnisetteData alloc] initWithMachineID:self.machineID + oneTimePassword:self.oneTimePassword + localUserID:self.localUserID + routingInfo:self.routingInfo + deviceUniqueIdentifier:self.deviceUniqueIdentifier + deviceSerialNumber:self.deviceSerialNumber + deviceDescription:self.deviceDescription + date:self.date + locale:self.locale + timeZone:self.timeZone]; + + return copy; +} + +#pragma mark - - + +- (instancetype)initWithCoder:(NSCoder *)decoder +{ + NSString *machineID = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(machineID))]; + NSString *oneTimePassword = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(oneTimePassword))]; + NSString *localUserID = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(localUserID))]; + NSNumber *routingInfo = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(routingInfo))]; + + NSString *deviceUniqueIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(deviceUniqueIdentifier))]; + NSString *deviceSerialNumber = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(deviceSerialNumber))]; + NSString *deviceDescription = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(deviceDescription))]; + + NSDate *date = [decoder decodeObjectOfClass:[NSDate class] forKey:NSStringFromSelector(@selector(date))]; + NSLocale *locale = [decoder decodeObjectOfClass:[NSLocale class] forKey:NSStringFromSelector(@selector(locale))]; + NSTimeZone *timeZone = [decoder decodeObjectOfClass:[NSTimeZone class] forKey:NSStringFromSelector(@selector(timeZone))]; + + self = [self initWithMachineID:machineID + oneTimePassword:oneTimePassword + localUserID:localUserID + routingInfo:[routingInfo unsignedLongLongValue] + deviceUniqueIdentifier:deviceUniqueIdentifier + deviceSerialNumber:deviceSerialNumber + deviceDescription:deviceDescription + date:date + locale:locale + timeZone:timeZone]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:self.machineID forKey:NSStringFromSelector(@selector(machineID))]; + [encoder encodeObject:self.oneTimePassword forKey:NSStringFromSelector(@selector(oneTimePassword))]; + [encoder encodeObject:self.localUserID forKey:NSStringFromSelector(@selector(localUserID))]; + [encoder encodeObject:@(self.routingInfo) forKey:NSStringFromSelector(@selector(routingInfo))]; + + [encoder encodeObject:self.deviceUniqueIdentifier forKey:NSStringFromSelector(@selector(deviceUniqueIdentifier))]; + [encoder encodeObject:self.deviceSerialNumber forKey:NSStringFromSelector(@selector(deviceSerialNumber))]; + [encoder encodeObject:self.deviceDescription forKey:NSStringFromSelector(@selector(deviceDescription))]; + + [encoder encodeObject:self.date forKey:NSStringFromSelector(@selector(date))]; + [encoder encodeObject:self.locale forKey:NSStringFromSelector(@selector(locale))]; + [encoder encodeObject:self.timeZone forKey:NSStringFromSelector(@selector(timeZone))]; +} + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +#pragma mark - JSON - + +- (instancetype)initWithJSON:(NSDictionary *)json +{ + NSString *machineID = json[@"machineID"]; + NSString *oneTimePassword = json[@"oneTimePassword"]; + NSString *localUserID = json[@"localUserID"]; + NSString *routingInfo = json[@"routingInfo"]; + NSString *deviceUniqueIdentifier = json[@"deviceUniqueIdentifier"]; + NSString *deviceSerialNumber = json[@"deviceSerialNumber"]; + NSString *deviceDescription = json[@"deviceDescription"]; + NSString *dateString = json[@"date"]; + NSString *localeIdentifier = json[@"locale"]; + NSString *timeZoneIdentifier = json[@"timeZone"]; + + if (machineID == nil || oneTimePassword == nil || localUserID == nil || routingInfo == nil || deviceUniqueIdentifier == nil || + deviceSerialNumber == nil || deviceDescription == nil || dateString == nil || localeIdentifier == nil || timeZoneIdentifier == nil) + { + return nil; + } + + NSISO8601DateFormatter *dateFormatter = [[NSISO8601DateFormatter alloc] init]; + NSDate *date = [dateFormatter dateFromString:dateString]; + + NSLocale *locale = [NSLocale localeWithLocaleIdentifier:localeIdentifier]; + + // There is not a perfect mapping between NSTimeZone's and their identifiers, so it's possible timeZoneWithAbbreviation: will return nil. + // In this case, we'll default to the local time zone since that's most likely correct, and if not it shouldn't matter regardless. + NSTimeZone *timeZone = [NSTimeZone timeZoneWithAbbreviation:timeZoneIdentifier] ?: [NSTimeZone localTimeZone]; + + self = [self initWithMachineID:machineID + oneTimePassword:oneTimePassword + localUserID:localUserID + routingInfo:[routingInfo longLongValue] + deviceUniqueIdentifier:deviceUniqueIdentifier + deviceSerialNumber:deviceSerialNumber + deviceDescription:deviceDescription + date:date + locale:locale + timeZone:timeZone]; + return self; +} + +- (NSDictionary *)json +{ + NSISO8601DateFormatter *dateFormatter = [[NSISO8601DateFormatter alloc] init]; + + NSDictionary *json = @{ + @"machineID": self.machineID, + @"oneTimePassword": self.oneTimePassword, + @"localUserID": self.localUserID, + @"routingInfo": [@(self.routingInfo) description], + @"deviceUniqueIdentifier": self.deviceUniqueIdentifier, + @"deviceSerialNumber": self.deviceSerialNumber, + @"deviceDescription": self.deviceDescription, + @"date": [dateFormatter stringFromDate:self.date], + @"locale": self.locale.localeIdentifier, + + // NSTimeZone.abbreviation may be nil, so provide defaults. + @"timeZone": self.timeZone.abbreviation ?: NSTimeZone.localTimeZone.abbreviation ?: @"PST" + }; + + return json; +} + +@end diff --git a/AltSign/ALTAppGroup.h b/AltSign/ALTAppGroup.h new file mode 100644 index 0000000..6e07402 --- /dev/null +++ b/AltSign/ALTAppGroup.h @@ -0,0 +1,22 @@ +// +// ALTAppGroup.h +// AltSign +// +// Created by Riley Testut on 6/24/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAppGroup : NSObject + +@property (copy, nonatomic, readonly) NSString *name; +@property (copy, nonatomic, readonly) NSString *identifier; + +@property (copy, nonatomic, readonly) NSString *groupIdentifier; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTAppGroup.m b/AltSign/ALTAppGroup.m new file mode 100644 index 0000000..a4395c3 --- /dev/null +++ b/AltSign/ALTAppGroup.m @@ -0,0 +1,59 @@ +// +// ALTAppGroup.m +// AltSign +// +// Created by Riley Testut on 6/24/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAppGroup.h" + +@implementation ALTAppGroup + +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary +{ + self = [super init]; + if (self) + { + NSString *name = responseDictionary[@"name"]; + NSString *identifier = responseDictionary[@"applicationGroup"]; + NSString *groupIdentifier = responseDictionary[@"identifier"]; + + if (name == nil || identifier == nil || groupIdentifier == nil) + { + return nil; + } + + _name = [name copy]; + _identifier = [identifier copy]; + _groupIdentifier = [groupIdentifier copy]; + } + + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, ID: %@, GroupID: %@>", NSStringFromClass([self class]), self, self.identifier, self.groupIdentifier]; +} + +- (BOOL)isEqual:(id)object +{ + ALTAppGroup *group = (ALTAppGroup *)object; + if (![group isKindOfClass:[ALTAppGroup class]]) + { + return NO; + } + + BOOL isEqual = ([self.identifier isEqualToString:group.identifier] && [self.groupIdentifier isEqualToString:group.groupIdentifier]); + return isEqual; +} + +- (NSUInteger)hash +{ + return self.identifier.hash ^ self.groupIdentifier.hash; +} + +@end diff --git a/AltSign/ALTAppID.h b/AltSign/ALTAppID.h new file mode 100644 index 0000000..a33636f --- /dev/null +++ b/AltSign/ALTAppID.h @@ -0,0 +1,26 @@ +// +// ALTAppID.h +// AltSign +// +// Created by Riley Testut on 5/21/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +#import "ALTCapabilities.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAppID : NSObject + +@property (copy, nonatomic) NSString *name; +@property (copy, nonatomic) NSString *identifier; + +@property (copy, nonatomic) NSString *bundleIdentifier; + +@property (copy, nonatomic) NSDictionary *features; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTAppID.m b/AltSign/ALTAppID.m new file mode 100644 index 0000000..e4d92fc --- /dev/null +++ b/AltSign/ALTAppID.m @@ -0,0 +1,84 @@ +// +// ALTAppID.m +// AltSign +// +// Created by Riley Testut on 5/21/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAppID.h" + +@implementation ALTAppID + +- (instancetype)initWithName:(NSString *)name identifier:(NSString *)identifier bundleIdentifier:(NSString *)bundleIdentifier features:(NSDictionary *)features +{ + self = [super init]; + if (self) + { + _name = [name copy]; + _identifier = [identifier copy]; + _bundleIdentifier = [bundleIdentifier copy]; + _features = [features copy]; + } + + return self; +} + +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary +{ + NSString *name = responseDictionary[@"name"]; + NSString *identifier = responseDictionary[@"appIdId"]; + NSString *bundleIdentifier = responseDictionary[@"identifier"]; + + NSDictionary *allFeatures = responseDictionary[@"features"] ?: @{}; + NSArray *enabledFeatures = responseDictionary[@"enabledFeatures"] ?: @[]; + + if (name == nil || identifier == nil || bundleIdentifier == nil) + { + return nil; + } + + NSMutableDictionary *features = [NSMutableDictionary dictionary]; + for (ALTFeature feature in enabledFeatures) + { + id value = allFeatures[feature]; + features[feature] = value; + } + + self = [self initWithName:name identifier:identifier bundleIdentifier:bundleIdentifier features:features]; + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, Name: %@, ID: %@, BundleID: %@>", NSStringFromClass([self class]), self, self.name, self.identifier, self.bundleIdentifier]; +} + +- (BOOL)isEqual:(id)object +{ + ALTAppID *appID = (ALTAppID *)object; + if (![appID isKindOfClass:[ALTAppID class]]) + { + return NO; + } + + BOOL isEqual = ([self.identifier isEqualToString:appID.identifier] && [self.bundleIdentifier isEqualToString:appID.bundleIdentifier]); + return isEqual; +} + +- (NSUInteger)hash +{ + return self.identifier.hash ^ self.bundleIdentifier.hash; +} + +#pragma mark - - + +- (nonnull id)copyWithZone:(nullable NSZone *)zone +{ + ALTAppID *appID = [[ALTAppID alloc] initWithName:self.name identifier:self.identifier bundleIdentifier:self.bundleIdentifier features:self.features]; + return appID; +} + +@end diff --git a/AltSign/ALTAppleAPI+Authentication.h b/AltSign/ALTAppleAPI+Authentication.h new file mode 100644 index 0000000..c0c425e --- /dev/null +++ b/AltSign/ALTAppleAPI+Authentication.h @@ -0,0 +1,28 @@ +// +// ALTAppleAPI+Authentication.h +// AltSign +// +// Created by Riley Testut on 11/16/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +@class ALTAppleAPISession; + +#import + +@class ALTAppleAPISession; + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAppleAPI (Authentication) + +- (void)authenticateWithAppleID:(NSString *)appleID + password:(NSString *)password + anisetteData:(ALTAnisetteData *)anisetteData + verificationHandler:(nullable void (^)(void (^completionHandler)(NSString *_Nullable verificationCode)))verificationHandler + completionHandler:(void (^)(ALTAccount *_Nullable account, ALTAppleAPISession *_Nullable session, NSError *_Nullable error))completionHandler +NS_SWIFT_NAME(authenticate(appleID:password:anisetteData:verificationHandler:completionHandler:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTAppleAPI+Authentication.m b/AltSign/ALTAppleAPI+Authentication.m new file mode 100644 index 0000000..faeac70 --- /dev/null +++ b/AltSign/ALTAppleAPI+Authentication.m @@ -0,0 +1,764 @@ +// +// ALTAppleAPI+Authentication.m +// AltSign +// +// Created by Riley Testut on 11/16/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// +// Heavily based on sample code provided by Kabir Oberai (https://github.com/kabiroberai) +// + +#import "ALTAppleAPI+Authentication.h" +#import "ALTAppleAPI_Private.h" + +#import "ALTModel+Internal.h" + +// Core Crypto +#import +#import +#import +#import +#import +#import +#import +#import +#import + +static const char ALTHexCharacters[] = "0123456789abcdef"; + +struct ccrng_state *ccDRBGGetRngState(void); + +void ALTDigestUpdateString(const struct ccdigest_info *di_info, struct ccdigest_ctx *di_ctx, NSString *string) +{ + ccdigest_update(di_info, di_ctx, string.length, string.UTF8String); +} + +void ALTDigestUpdateData(const struct ccdigest_info *di_info, struct ccdigest_ctx *di_ctx, NSData *data) +{ + uint32_t data_len = (uint32_t)data.length; // 4 bytes for length + ccdigest_update(di_info, di_ctx, sizeof(data_len), &data_len); + ccdigest_update(di_info, di_ctx, data_len, data.bytes); +} + +NSData *ALTPBKDF2SRP(const struct ccdigest_info *di_info, BOOL isS2k, NSString *password, NSData *salt, int iterations) +{ + const struct ccdigest_info *password_di_info = ccsha256_di(); + char *digest_raw = (char *)malloc(password_di_info->output_size); + const char *passwordUTF8 = password.UTF8String; + ccdigest(password_di_info, strlen(passwordUTF8), passwordUTF8, digest_raw); + + size_t final_digest_len = password_di_info->output_size * (isS2k ? 1 : 2); + char *digest = (char *)malloc(final_digest_len); + + if (isS2k) + { + memcpy(digest, digest_raw, final_digest_len); + } + else + { + for (int i = 0; i < password_di_info->output_size; i++) + { + char byte = digest_raw[i]; + digest[i * 2 + 0] = ALTHexCharacters[(byte >> 4) & 0x0F]; + digest[i * 2 + 1] = ALTHexCharacters[(byte >> 0) & 0x0F]; + } + } + + NSMutableData *data = [NSMutableData dataWithLength:di_info->output_size]; + + if (ccpbkdf2_hmac(di_info, final_digest_len, digest, salt.length, salt.bytes, iterations, di_info->output_size, data.mutableBytes) != 0) + { + return nil; + } + + return data; +} + +NSData *ALTCreateSessionKey(ccsrp_ctx_t srp_ctx, const char *key_name) +{ + size_t key_len; + const void *session_key = ccsrp_get_session_key(srp_ctx, &key_len); + + const struct ccdigest_info *di_info = ccsha256_di(); + + size_t hmac_len = di_info->output_size; + unsigned char *hmac_bytes = (unsigned char *)malloc(hmac_len); + cchmac(di_info, key_len, session_key, strlen(key_name), key_name, hmac_bytes); + + NSData *sessionKey = [NSData dataWithBytes:hmac_bytes length:hmac_len]; + return sessionKey; +} + +NSData *ALTDecryptDataCBC(ccsrp_ctx_t srp_ctx, NSData *spd) +{ + NSData *extraDataKey = ALTCreateSessionKey(srp_ctx, "extra data key:"); + NSData *extraDataIV = ALTCreateSessionKey(srp_ctx, "extra data iv:"); + + NSMutableData *decryptedData = [NSMutableData dataWithLength:spd.length]; + + const struct ccmode_cbc *decrypt_mode = ccaes_cbc_decrypt_mode(); + + cccbc_iv *iv = (cccbc_iv *)malloc(decrypt_mode->block_size); + if (extraDataIV.bytes) + { + memcpy(iv, extraDataIV.bytes, decrypt_mode->block_size); + } + else + { + bzero(iv, decrypt_mode->block_size); + } + + cccbc_ctx *ctx_buf = (cccbc_ctx *)malloc(decrypt_mode->size); + decrypt_mode->init(decrypt_mode, ctx_buf, extraDataKey.length, extraDataKey.bytes); + + size_t length = ccpad_pkcs7_decrypt(decrypt_mode, ctx_buf, iv, spd.length, spd.bytes, decryptedData.mutableBytes); + if (length > spd.length) + { + return nil; + } + + return decryptedData; +} + +NSData *ALTDecryptDataGCM(NSData *sk, NSData *encryptedData) +{ + const struct ccmode_gcm *decrypt_mode = ccaes_gcm_decrypt_mode(); + + ccgcm_ctx *gcm_ctx = (ccgcm_ctx *)malloc(decrypt_mode->size); + decrypt_mode->init(decrypt_mode, gcm_ctx, sk.length, sk.bytes); + + if (encryptedData.length < 35) + { + NSLog(@"ERROR: Encrypted token too short."); + return nil; + } + + if (cc_cmp_safe(3, encryptedData.bytes, "XYZ")) + { + NSLog(@"ERROR: Encrypted token wrong version!"); + return nil; + } + + decrypt_mode->set_iv(gcm_ctx, 16, encryptedData.bytes + 3); + decrypt_mode->gmac(gcm_ctx, 3, encryptedData.bytes); + + size_t decrypted_len = encryptedData.length - 35; + NSMutableData *decryptedData = [NSMutableData dataWithLength:decrypted_len]; + + decrypt_mode->gcm(gcm_ctx, decrypted_len, encryptedData.bytes + 16 + 3, decryptedData.mutableBytes); + + char tag[16]; + decrypt_mode->finalize(gcm_ctx, 16, tag); + + if (cc_cmp_safe(16, encryptedData.bytes + decrypted_len + 19, tag)) + { + NSLog(@"Invalid tag version"); + return nil; + } + + return decryptedData; +} + +NSData *ALTCreateAppTokensChecksum(NSData *sk, NSString *adsid, NSArray *apps) +{ + const struct ccdigest_info *di_info = ccsha256_di(); + size_t hmac_size = cchmac_di_size(di_info); + struct cchmac_ctx *hmac_ctx = (struct cchmac_ctx *)malloc(hmac_size); + cchmac_init(di_info, hmac_ctx, sk.length, sk.bytes); + + const char *key = "apptokens"; + cchmac_update(di_info, hmac_ctx, strlen(key), key); + + const char *adsidUTF8 = adsid.UTF8String; + cchmac_update(di_info, hmac_ctx, strlen(adsidUTF8), adsidUTF8); + + for (NSString *app in apps) + { + cchmac_update(di_info, hmac_ctx, app.length, app.UTF8String); + } + + NSMutableData *checksum = [NSMutableData dataWithLength:di_info->output_size]; + cchmac_final(di_info, hmac_ctx, checksum.mutableBytes); + + return checksum; +} + +@implementation ALTAppleAPI (Authentication) + +- (void)authenticateWithAppleID:(NSString *)appleID + password:(NSString *)password + anisetteData:(ALTAnisetteData *)anisetteData + verificationHandler:(void (^)(void (^ _Nonnull)(NSString * _Nullable)))verificationHandler + completionHandler:(void (^)(ALTAccount * _Nullable, ALTAppleAPISession * _Nullable, NSError * _Nullable))completionHandler +{ + NSMutableDictionary *clientDictionary = [@{ + @"bootstrap": @YES, + @"icscrec": @YES, + @"loc": NSLocale.currentLocale.localeIdentifier, + @"pbe": @NO, + @"prkgen": @YES, + @"svct": @"iCloud", + @"X-Apple-I-Client-Time": [self.dateFormatter stringFromDate:anisetteData.date], + @"X-Apple-Locale": NSLocale.currentLocale.localeIdentifier, + @"X-Apple-I-TimeZone": NSTimeZone.localTimeZone.abbreviation, + @"X-Apple-I-MD": anisetteData.oneTimePassword, + @"X-Apple-I-MD-LU": anisetteData.localUserID, + @"X-Apple-I-MD-M": anisetteData.machineID, + @"X-Apple-I-MD-RINFO": @(anisetteData.routingInfo), + @"X-Mme-Device-Id": anisetteData.deviceUniqueIdentifier, + @"X-Apple-I-SRL-NO": anisetteData.deviceSerialNumber, + } mutableCopy]; + + /* Begin CoreCrypto Logic */ + ccsrp_const_gp_t gp = ccsrp_gp_rfc5054_2048(); + + const struct ccdigest_info *di_info = ccsha256_di(); + struct ccdigest_ctx *di_ctx = (struct ccdigest_ctx *)malloc(ccdigest_di_size(di_info)); + ccdigest_init(di_info, di_ctx); + + const struct ccdigest_info *srp_di = ccsha256_di(); + struct ccsrp_ctx_body *srp_ctx = (struct ccsrp_ctx_body *)malloc(ccsrp_sizeof_srp(di_info, gp)); + ccsrp_ctx_init(srp_ctx, srp_di, gp); + + srp_ctx->hdr.blinding_rng = ccrng(NULL); + srp_ctx->hdr.flags.noUsernameInX = true; + + NSArray *ps = @[@"s2k", @"s2k_fo"]; + ALTDigestUpdateString(di_info, di_ctx, ps[0]); + ALTDigestUpdateString(di_info, di_ctx, @","); + ALTDigestUpdateString(di_info, di_ctx, ps[1]); + + size_t A_size = ccsrp_exchange_size(srp_ctx); + char *A_bytes = (char *)malloc(A_size); + ccsrp_client_start_authentication(srp_ctx, ccDRBGGetRngState(), A_bytes); + + NSData *A_data = [NSData dataWithBytes:A_bytes length:A_size]; + + ALTDigestUpdateString(di_info, di_ctx, @"|"); + + NSDictionary *parameters = @{ + @"A2k": A_data, + @"ps": ps, + @"cpd": clientDictionary, + @"u": appleID, + @"o": @"init" + }; + + // 1st Request + [self sendAuthenticationRequestWithParameters:parameters anisetteData:anisetteData completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, nil, requestError); + return; + } + + size_t M_size = ccsrp_get_session_key_length(srp_ctx); + char *M_bytes = (char *)malloc(A_size); + NSData *M_data = [NSData dataWithBytes:M_bytes length:M_size]; + + NSString *sp = responseDictionary[@"sp"]; + BOOL isS2K = [sp isEqualToString:@"s2k"]; + + ALTDigestUpdateString(di_info, di_ctx, @"|"); + + if (sp) + { + ALTDigestUpdateString(di_info, di_ctx, sp); + } + + NSString *c = responseDictionary[@"c"]; + NSData *salt = responseDictionary[@"s"]; + NSNumber *iterations = responseDictionary[@"i"]; + NSData *B_data = responseDictionary[@"B"]; + + if (c == nil || salt == nil || iterations == nil || B_data == nil) + { + completionHandler(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]); + return; + } + + NSData *passwordKey = ALTPBKDF2SRP(di_info, isS2K, password, salt, [iterations intValue]); + if (passwordKey == nil) + { + completionHandler(nil, nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAuthenticationHandshakeFailed userInfo:nil]); + return; + } + + int result = ccsrp_client_process_challenge(srp_ctx, appleID.UTF8String, passwordKey.length, passwordKey.bytes, + salt.length, salt.bytes, B_data.bytes, (void *)M_data.bytes); + if (result != 0) + { + completionHandler(nil, nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAuthenticationHandshakeFailed userInfo:nil]); + return; + } + + NSDictionary *parameters = @{ + @"c": c, + @"M1": M_data, + @"cpd": clientDictionary, + @"u": appleID, + @"o": @"complete" + }; + + // 2nd Request + [self sendAuthenticationRequestWithParameters:parameters anisetteData:anisetteData completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, nil, requestError); + return; + } + + NSData *M2_data = responseDictionary[@"M2"]; + if (M2_data == nil) + { + NSLog(@"ERROR: M2 data not found!"); + + completionHandler(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]); + return; + } + + if (!ccsrp_client_verify_session(srp_ctx, M2_data.bytes)) + { + NSLog(@"ERROR: Failed to verify session."); + + completionHandler(nil, nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAuthenticationHandshakeFailed userInfo:nil]); + return; + } + + ALTDigestUpdateString(di_info, di_ctx, @"|"); + + NSData *spd = responseDictionary[@"spd"]; + if (spd) + { + ALTDigestUpdateData(di_info, di_ctx, spd); + } + + ALTDigestUpdateString(di_info, di_ctx, @"|"); + + NSData *sc = responseDictionary[@"sc"]; + if (sc) + { + ALTDigestUpdateData(di_info, di_ctx, sc); + } + + ALTDigestUpdateString(di_info, di_ctx, @"|"); + + NSData *np = responseDictionary[@"np"]; + if (np == nil) + { + NSLog(@"ERROR: Missing np dictionary."); + + completionHandler(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]); + return; + } + + size_t digest_len = di_info->output_size; + if (np.length != digest_len) + { + NSLog(@"ERROR: Neg proto hash is too short."); + + completionHandler(nil, nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAuthenticationHandshakeFailed userInfo:nil]); + return; + } + + unsigned char *digest = (unsigned char *)malloc(digest_len); + di_info->final(di_info, di_ctx, digest); + + NSData *hmacKey = ALTCreateSessionKey(srp_ctx, "HMAC key:"); + unsigned char *hmac_out = (unsigned char *)malloc(digest_len); + cchmac(di_info, hmacKey.length, hmacKey.bytes, digest_len, digest, hmac_out); + + if (cc_cmp_safe(digest_len, hmac_out, np.bytes)) + { + NSLog(@"ERROR: Invalid neg prot hmac."); + + completionHandler(nil, nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAuthenticationHandshakeFailed userInfo:nil]); + return; + } + + NSData *decryptedData = ALTDecryptDataCBC(srp_ctx, spd); + if (decryptedData == nil) + { + NSLog(@"ERROR: Could not decrypt login response."); + + completionHandler(nil, nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAuthenticationHandshakeFailed userInfo:nil]); + return; + } + + NSError *parseError = nil; + NSDictionary *decryptedDictionary = [NSPropertyListSerialization propertyListWithData:decryptedData options:0 format:nil error:&parseError]; + if (decryptedDictionary == nil) + { + NSLog(@"ERROR: Could not parse decrypted login response plist!"); + + completionHandler(nil, nil, parseError); + return; + } + + NSString *adsid = decryptedDictionary[@"adsid"]; + NSString *idmsToken = decryptedDictionary[@"GsIdmsToken"]; + + if (adsid == nil || idmsToken == nil) + { + NSLog(@"ERROR: adsid and/or idmsToken is nil. adsid: %@. idmsToken: %@", adsid, idmsToken); + + completionHandler(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]); + return; + } + + NSDictionary *statusDictionary = responseDictionary[@"Status"]; + + NSString *authType = statusDictionary[@"au"]; + if ([authType isEqualToString:@"trustedDeviceSecondaryAuth"]) + { + // Handle Two-Factor + + if (verificationHandler != nil) + { + [self requestTwoFactorCodeForDSID:adsid idmsToken:idmsToken anisetteData:anisetteData verificationHandler:verificationHandler completionHandler:^(BOOL success, NSError *error) { + if (success) + { + // We've successfully signed-in with two-factor, so restart authentication (which will now succeed). + [self authenticateWithAppleID:appleID password:password anisetteData:anisetteData verificationHandler:verificationHandler completionHandler:completionHandler]; + } + else + { + completionHandler(nil, nil, error); + } + }]; + } + else + { + completionHandler(nil, nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorRequiresTwoFactorAuthentication userInfo:nil]); + } + } + else + { + // Fetch Auth Token + + NSData *sk = decryptedDictionary[@"sk"]; + NSData *c = decryptedDictionary[@"c"]; + + if (sk == nil || c == nil) + { + NSLog(@"ERROR: No ak and/or c data."); + + completionHandler(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]); + return; + } + + NSArray *apps = @[@"com.apple.gs.xcode.auth"]; + NSData *checksum = ALTCreateAppTokensChecksum(sk, adsid, apps); + + NSDictionary *parameters = @{ + @"u": adsid, + @"app": apps, + @"c": c, + @"t": idmsToken, + @"checksum": checksum, + @"cpd": clientDictionary, + @"o": @"apptokens" + }; + + [self fetchAuthTokenWithParameters:parameters sk:sk anisetteData:anisetteData completionHandler:^(NSString *authToken, NSError *error) { + if (authToken == nil) + { + completionHandler(nil, nil, error); + return; + } + + ALTAppleAPISession *session = [[ALTAppleAPISession alloc] initWithDSID:adsid authToken:authToken anisetteData:anisetteData]; + [self fetchAccountForSession:session completionHandler:^(ALTAccount *account, NSError *error) { + if (account == nil) + { + completionHandler(nil, nil, error); + } + else + { + completionHandler(account, session, nil); + } + }]; + }]; + } + }]; + }]; +} + +- (void)fetchAuthTokenWithParameters:(NSDictionary *)parameters sk:(NSData *)sk anisetteData:(ALTAnisetteData *)anisetteData completionHandler:(void (^)(NSString *authToken, NSError *error))completionHandler +{ + [self sendAuthenticationRequestWithParameters:parameters anisetteData:anisetteData completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSData *encryptedToken = responseDictionary[@"et"]; + NSData *decryptedToken = ALTDecryptDataGCM(sk, encryptedToken); + + if (decryptedToken == nil) + { + NSLog(@"ERROR: Failed to decrypt apptoken."); + + completionHandler(nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]); + return; + } + + NSError *parseError = nil; + NSDictionary *decryptedTokenDictionary = [NSPropertyListSerialization propertyListWithData:decryptedToken options:0 format:nil error:&parseError]; + if (decryptedTokenDictionary == nil) + { + NSLog(@"ERROR: Could not parse decrypted apptoken plist."); + + completionHandler(nil, parseError); + return; + } + + NSString *app = [parameters[@"app"] firstObject]; + + NSDictionary *tokenDictionary = decryptedTokenDictionary[@"t"][app]; + NSString *token = tokenDictionary[@"token"]; + NSNumber *expirationDataMS = tokenDictionary[@"expiry"]; + + if (token == nil) + { + completionHandler(nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]); + return; + } + + NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:(double)expirationDataMS.integerValue / 1000]; + NSLog(@"Got token for %@!\nExpires: %@\nValue: %@\n", app, expirationDate, token); + + completionHandler(token, nil); + }]; +} + +- (void)requestTwoFactorCodeForDSID:(NSString *)dsid idmsToken:(NSString *)idmsToken anisetteData:(ALTAnisetteData *)anisetteData + verificationHandler:(nonnull void (^)(void (^ _Nonnull)(NSString * _Nonnull)))verificationHandler + completionHandler:(void (^)(BOOL success, NSError *error))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"https://gsa.apple.com/auth/verify/trusteddevice"]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + + NSString *identityToken = [NSString stringWithFormat:@"%@:%@", dsid, idmsToken]; + + NSData *identityTokenData = [identityToken dataUsingEncoding:NSUTF8StringEncoding]; + NSString *encodedIdentityToken = [identityTokenData base64EncodedStringWithOptions:0]; + + NSDictionary *httpHeaders = @{ + @"Content-Type": @"text/x-xml-plist", + @"User-Agent": @"Xcode", + @"Accept": @"text/x-xml-plist", + @"Accept-Language": @"en-us", + @"X-Apple-App-Info": @"com.apple.gs.xcode.auth", + @"X-Xcode-Version": @"11.2 (11B41)", + @"X-Apple-Identity-Token": encodedIdentityToken, + @"X-Apple-I-MD-M": anisetteData.machineID, + @"X-Apple-I-MD": anisetteData.oneTimePassword, + @"X-Apple-I-MD-LU": anisetteData.localUserID, + @"X-Apple-I-MD-RINFO": [@(anisetteData.routingInfo) description], + @"X-Mme-Device-Id": anisetteData.deviceUniqueIdentifier, + @"X-MMe-Client-Info": anisetteData.deviceDescription, + @"X-Apple-I-Client-Time": [self.dateFormatter stringFromDate:anisetteData.date], + @"X-Apple-Locale": anisetteData.locale.localeIdentifier, + @"X-Apple-I-TimeZone": anisetteData.timeZone.abbreviation + }; + + [httpHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + [request setValue:value forHTTPHeaderField:key]; + }]; + + NSURLSessionDataTask *requestCodeTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (data == nil || error != nil) + { + completionHandler(NO, error); + return; + } + + void (^responseHandler)(NSString *) = ^(NSString *_Nullable verificationCode) { + if (verificationCode == nil) + { + completionHandler(NO, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorRequiresTwoFactorAuthentication userInfo:nil]); + return; + } + + NSMutableDictionary *headers = [httpHeaders mutableCopy]; + headers[@"security-code"] = verificationCode; + + NSURL *URL = [NSURL URLWithString:@"https://gsa.apple.com/grandslam/GsService2/validate"]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + + [headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + [request setValue:value forHTTPHeaderField:key]; + }]; + + NSURLSessionDataTask *verifyCodeTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (data == nil || error != nil) + { + completionHandler(NO, error); + return; + } + + NSError *parseError = nil; + NSDictionary *responseDictionary = [NSPropertyListSerialization propertyListWithData:data options:0 format:nil error:&parseError]; + + if (responseDictionary == nil) + { + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:@{NSUnderlyingErrorKey: parseError}]; + completionHandler(NO, error); + return; + } + + NSInteger errorCode = [responseDictionary[@"ec"] integerValue]; // Same for NSString or NSNumber. + if (errorCode != 0) + { + NSError *error = nil; + switch (errorCode) + { + case -21669: + error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorIncorrectVerificationCode userInfo:nil]; + break; + + default: + break; + } + + if (error == nil) + { + NSString *errorDescription = responseDictionary[@"em"]; + NSString *localizedDescription = [NSString stringWithFormat:@"%@ (%@)", errorDescription, @(errorCode)]; + + error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorUnknown userInfo:@{NSLocalizedDescriptionKey: localizedDescription}]; + } + + completionHandler(NO, error); + } + else + { + completionHandler(YES, nil); + } + }]; + + [verifyCodeTask resume]; + }; + + verificationHandler(responseHandler); + }]; + + [requestCodeTask resume]; +} + +- (void)fetchAccountForSession:(ALTAppleAPISession *)session completionHandler:(void (^)(ALTAccount *account, NSError *error))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"viewDeveloper.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:nil session:session team:nil completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + ALTAccount *account = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSDictionary *dictionary = responseDictionary[@"developer"]; + if (dictionary == nil) + { + return nil; + } + + ALTAccount *account = [[ALTAccount alloc] initWithResponseDictionary:dictionary]; + return account; + } resultCodeHandler:nil error:&error]; + + completionHandler(account, error); + }]; +} + +- (void)sendAuthenticationRequestWithParameters:(NSDictionary *)requestDictionary anisetteData:(ALTAnisetteData *)anisetteData completionHandler:(void (^)(NSDictionary *responseDictionary, NSError *error))completionHandler +{ + NSURL *requestURL = [NSURL URLWithString:@"https://gsa.apple.com/grandslam/GsService2"]; + + NSDictionary *> *parameters = @{ + @"Header": @{ @"Version": @"1.0.1" }, + @"Request": requestDictionary + }; + + NSError *serializationError = nil; + NSData *bodyData = [NSPropertyListSerialization dataWithPropertyList:parameters format:NSPropertyListXMLFormat_v1_0 options:0 error:&serializationError]; + if (bodyData == nil) + { + NSError *error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidParameters userInfo:@{NSUnderlyingErrorKey: serializationError}]; + completionHandler(nil, error); + return; + } + + NSDictionary *httpHeaders = @{ + @"Content-Type": @"text/x-xml-plist", + @"X-MMe-Client-Info": anisetteData.deviceDescription, + @"Accept": @"*/*", + @"User-Agent": @"akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0" + }; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; + request.HTTPMethod = @"POST"; + request.HTTPBody = bodyData; + [httpHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + [request setValue:value forHTTPHeaderField:key]; + }]; + + NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (data == nil) + { + completionHandler(nil, error); + return; + } + + NSError *parseError = nil; + NSDictionary *responseDictionary = [NSPropertyListSerialization propertyListWithData:data options:0 format:nil error:&parseError]; + + if (responseDictionary == nil) + { + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:@{NSUnderlyingErrorKey: parseError}]; + completionHandler(nil, error); + return; + } + + NSDictionary *dictionary = responseDictionary[@"Response"]; + + NSDictionary *status = dictionary[@"Status"]; + + NSInteger errorCode = [status[@"ec"] integerValue]; + if (errorCode != 0) + { + NSError *error = nil; + switch (errorCode) + { + case -22406: + error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorIncorrectCredentials userInfo:nil]; + break; + + default: + break; + } + + if (error == nil) + { + NSString *errorDescription = status[@"em"]; + NSString *localizedDescription = [NSString stringWithFormat:@"%@ (%@)", errorDescription, @(errorCode)]; + + error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorUnknown userInfo:@{NSLocalizedDescriptionKey: localizedDescription}]; + } + + completionHandler(nil, error); + } + else + { + completionHandler(dictionary, nil); + } + }]; + + [dataTask resume]; +} + +@end diff --git a/AltSign/ALTAppleAPI.h b/AltSign/ALTAppleAPI.h new file mode 100644 index 0000000..cb7b923 --- /dev/null +++ b/AltSign/ALTAppleAPI.h @@ -0,0 +1,86 @@ +// +// ALTAppleAPI.h +// AltSign +// +// Created by Riley Testut on 5/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +#import "ALTCapabilities.h" + +@class ALTAppleAPISession; + +@class ALTAccount; +@class ALTAnisetteData; +@class ALTTeam; +@class ALTDevice; +@class ALTCertificate; +@class ALTAppID; +@class ALTAppGroup; +@class ALTProvisioningProfile; + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAppleAPI : NSObject + +@property (class, nonatomic, readonly) ALTAppleAPI *sharedAPI; + +/* Teams */ +- (void)fetchTeamsForAccount:(ALTAccount *)account session:(ALTAppleAPISession *)session + completionHandler:(void (^)(NSArray *_Nullable teams, NSError *_Nullable error))completionHandler; + +/* Devices */ +- (void)fetchDevicesForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(NSArray *_Nullable devices, NSError *_Nullable error))completionHandler; + +- (void)registerDeviceWithName:(NSString *)name identifier:(NSString *)identifier team:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(ALTDevice *_Nullable device, NSError *_Nullable error))completionHandler +NS_SWIFT_NAME(registerDevice(name:identifier:team:session:completionHandler:)); + +/* Certificates */ +- (void)fetchCertificatesForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(NSArray *_Nullable certificates, NSError *_Nullable error))completionHandler; + +- (void)addCertificateWithMachineName:(NSString *)name toTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(ALTCertificate *_Nullable certificate, NSError *_Nullable error))completionHandler +NS_SWIFT_NAME(addCertificate(machineName:to:session:completionHandler:)); + +- (void)revokeCertificate:(ALTCertificate *)certificate forTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler +NS_SWIFT_NAME(revoke(_:for:session:completionHandler:)); + +/* App IDs */ +- (void)fetchAppIDsForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(NSArray *_Nullable appIDs, NSError *_Nullable error))completionHandler; + +- (void)addAppIDWithName:(NSString *)name bundleIdentifier:(NSString *)bundleIdentifier team:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(ALTAppID *_Nullable appID, NSError *_Nullable error))completionHandler; + +- (void)updateAppID:(ALTAppID *)appID team:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(ALTAppID * _Nullable appID, NSError * _Nullable error))completionHandler; + +- (void)deleteAppID:(ALTAppID *)appID forTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; + +/* App Groups */ +- (void)fetchAppGroupsForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(NSArray *_Nullable groups, NSError *_Nullable error))completionHandler; + +- (void)addAppGroupWithName:(NSString *)name groupIdentifier:(NSString *)groupIdentifier team:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(ALTAppGroup *_Nullable group, NSError *_Nullable error))completionHandler; + +- (void)addAppID:(ALTAppID *)appID toGroup:(ALTAppGroup *)group team:(ALTTeam *)team session:(ALTAppleAPISession *)session +completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; + +/* Provisioning Profiles */ +- (void)fetchProvisioningProfileForAppID:(ALTAppID *)appID team:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(ALTProvisioningProfile *_Nullable provisioningProfile, NSError *_Nullable error))completionHandler; + +- (void)deleteProvisioningProfile:(ALTProvisioningProfile *)provisioningProfile forTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTAppleAPI.m b/AltSign/ALTAppleAPI.m new file mode 100644 index 0000000..6713070 --- /dev/null +++ b/AltSign/ALTAppleAPI.m @@ -0,0 +1,862 @@ +// +// ALTAppleAPI.m +// AltSign +// +// Created by Riley Testut on 5/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAppleAPI_Private.h" +#import "ALTAppleAPISession.h" + +#import "ALTAnisetteData.h" + +#import "ALTModel+Internal.h" + +#import + +NS_ASSUME_NONNULL_BEGIN + +NSString *const ALTAuthenticationProtocolVersion = @"A1234"; +NSString *const ALTProtocolVersion = @"QH65B2"; +NSString *const ALTAppIDKey = @"ba2ec180e6ca6e6c6a542255453b24d6e6e5b2be0cc48bc1b0d8ad64cfe0228f"; +NSString *const ALTClientID = @"XABBG36SBA"; + +NS_ASSUME_NONNULL_END + +@implementation ALTAppleAPI + ++ (instancetype)sharedAPI +{ + static ALTAppleAPI *_appleAPI = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _appleAPI = [[self alloc] init]; + }); + + return _appleAPI; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + _dateFormatter = [[NSISO8601DateFormatter alloc] init]; + + _baseURL = [[NSURL URLWithString:[NSString stringWithFormat:@"https://developerservices2.apple.com/services/%@/", ALTProtocolVersion]] copy]; + _servicesBaseURL = [[NSURL URLWithString:@"https://developerservices2.apple.com/services/v1/"] copy]; + } + + return self; +} + +#pragma mark - Teams - + +- (void)fetchTeamsForAccount:(ALTAccount *)account session:(ALTAppleAPISession *)session completionHandler:(void (^)(NSArray *teams, NSError *error))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"listTeams.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:nil session:session team:nil completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + NSArray *teams = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSArray *array = responseDictionary[@"teams"]; + if (array == nil) + { + return nil; + } + + NSMutableArray *teams = [NSMutableArray array]; + for (NSDictionary *dictionary in array) + { + ALTTeam *team = [[ALTTeam alloc] initWithAccount:account responseDictionary:dictionary]; + if (team == nil) + { + return nil; + } + + [teams addObject:team]; + } + return teams; + } resultCodeHandler:nil error:&error]; + + if (teams != nil && teams.count == 0) + { + completionHandler(nil, [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorNoTeams userInfo:nil]); + } + else + { + completionHandler(teams, error); + } + }]; +} + +#pragma mark - Devices - + +- (void)fetchDevicesForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(NSArray * _Nullable, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/listDevices.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:nil session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + NSArray *devices = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSArray *array = responseDictionary[@"devices"]; + if (array == nil) + { + return nil; + } + + NSMutableArray *devices = [NSMutableArray array]; + for (NSDictionary *dictionary in array) + { + ALTDevice *device = [[ALTDevice alloc] initWithResponseDictionary:dictionary]; + if (device == nil) + { + return nil; + } + + [devices addObject:device]; + } + return devices; + } resultCodeHandler:nil error:&error]; + + completionHandler(devices, error); + }]; +} + +- (void)registerDeviceWithName:(NSString *)name identifier:(NSString *)identifier team:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(ALTDevice * _Nullable, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/addDevice.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:@{@"deviceNumber": identifier, @"name": name} session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + ALTDevice *device = [self processResponse:responseDictionary parseHandler:^id () { + NSDictionary *dictionary = responseDictionary[@"device"]; + if (dictionary == nil) + { + return nil; + } + + ALTDevice *device = [[ALTDevice alloc] initWithResponseDictionary:dictionary]; + return device; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 35: + if ([[[responseDictionary objectForKey:@"userString"] lowercaseString] containsString:@"already exists"]) + { + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorDeviceAlreadyRegistered userInfo:nil]; + } + else + { + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidDeviceID userInfo:nil]; + } + + default: return nil; + } + } error:&error]; + + completionHandler(device, error); + }]; +} + +#pragma mark - Certificates - + +- (void)fetchCertificatesForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(NSArray * _Nullable, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"certificates" relativeToURL:self.servicesBaseURL]; + NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + + [self sendServicesRequest:request additionalParameters:@{@"filter[certificateType]": @"IOS_DEVELOPMENT"} session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + NSArray *certificates = [self processResponse:responseDictionary parseHandler:^id { + NSArray *array = responseDictionary[@"data"]; + if (array == nil) + { + return nil; + } + + NSMutableArray *certificates = [NSMutableArray array]; + for (NSDictionary *dictionary in array) + { + ALTCertificate *certificate = [[ALTCertificate alloc] initWithResponseDictionary:dictionary]; + if (certificate == nil) + { + return nil; + } + + [certificates addObject:certificate]; + } + return certificates; + } resultCodeHandler:nil error:&error]; + + completionHandler(certificates, error); + }]; +} + +- (void)addCertificateWithMachineName:(NSString *)machineName toTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(ALTCertificate * _Nullable, NSError * _Nullable))completionHandler +{ + ALTCertificateRequest *request = [[ALTCertificateRequest alloc] init]; + if (request == nil) + { + NSError *error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidCertificateRequest userInfo:nil]; + completionHandler(nil, error); + return; + } + + NSURL *URL = [NSURL URLWithString:@"ios/submitDevelopmentCSR.action" relativeToURL:self.baseURL]; + NSString *encodedCSR = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding]; + + [self sendRequestWithURL:URL additionalParameters:@{@"csrContent": encodedCSR, + @"machineId": [[NSUUID UUID] UUIDString], + @"machineName": machineName} + session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + ALTCertificate *certificate = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSDictionary *dictionary = responseDictionary[@"certRequest"]; + if (dictionary == nil) + { + return nil; + } + + ALTCertificate *certificate = [[ALTCertificate alloc] initWithResponseDictionary:dictionary]; + certificate.privateKey = request.privateKey; + return certificate; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 3250: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidCertificateRequest userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(certificate, error); + }]; +} + +- (void)revokeCertificate:(ALTCertificate *)certificate forTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"certificates/%@", certificate.identifier] relativeToURL:self.servicesBaseURL]; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + request.HTTPMethod = @"DELETE"; + + [self sendServicesRequest:request additionalParameters:nil session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(NO, requestError); + return; + } + + NSError *error = nil; + id result = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + return responseDictionary; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 7252: return nil; + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorCertificateDoesNotExist userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(result != nil, error); + }]; +} + +#pragma mark - App IDs - + +- (void)fetchAppIDsForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(NSArray * _Nullable, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/listAppIds.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:nil session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + NSArray *appIDs = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSArray *array = responseDictionary[@"appIds"]; + if (array == nil) + { + return nil; + } + + NSMutableArray *appIDs = [NSMutableArray array]; + for (NSDictionary *dictionary in array) + { + ALTAppID *appID = [[ALTAppID alloc] initWithResponseDictionary:dictionary]; + if (appID == nil) + { + return nil; + } + + [appIDs addObject:appID]; + } + return appIDs; + } resultCodeHandler:nil error:&error]; + + completionHandler(appIDs, error); + }]; +} + +- (void)addAppIDWithName:(NSString *)name bundleIdentifier:(NSString *)bundleIdentifier team:(ALTTeam *)team session:(ALTAppleAPISession *)session + completionHandler:(void (^)(ALTAppID *_Nullable appID, NSError *_Nullable error))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/addAppId.action" relativeToURL:self.baseURL]; + + NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedCharacters formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; + + NSString *sanitizedName = [name stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:nil]; + sanitizedName = [[sanitizedName componentsSeparatedByCharactersInSet:[allowedCharacters invertedSet]] componentsJoinedByString:@""]; + + [self sendRequestWithURL:URL additionalParameters:@{@"identifier": bundleIdentifier, @"name": sanitizedName} session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + ALTAppID *appID = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSDictionary *dictionary = responseDictionary[@"appId"]; + if (dictionary == nil) + { + return nil; + } + + ALTAppID *appID = [[ALTAppID alloc] initWithResponseDictionary:dictionary]; + return appID; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 35: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidAppIDName userInfo:nil]; + + case 9401: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorBundleIdentifierUnavailable userInfo:nil]; + + case 9412: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidBundleIdentifier userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(appID, error); + }]; +} + +- (void)updateAppID:(ALTAppID *)appID team:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(ALTAppID * _Nullable, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/updateAppId.action" relativeToURL:self.baseURL]; + + NSMutableDictionary *parameters = [@{@"appIdId": appID.identifier} mutableCopy]; + + for (ALTFeature feature in appID.features) + { + parameters[feature] = appID.features[feature]; + } + + [self sendRequestWithURL:URL additionalParameters:parameters + session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + ALTAppID *appID = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSDictionary *dictionary = responseDictionary[@"appId"]; + if (dictionary == nil) + { + return nil; + } + + ALTAppID *appID = [[ALTAppID alloc] initWithResponseDictionary:dictionary]; + return appID; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 35: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidAppIDName userInfo:nil]; + + case 9100: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAppIDDoesNotExist userInfo:nil]; + + case 9412: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidBundleIdentifier userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(appID, error); + }]; +} + +- (void)deleteAppID:(ALTAppID *)appID forTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/deleteAppId.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:@{@"appIdId": appID.identifier} session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(NO, requestError); + return; + } + + NSError *error = nil; + id value = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSNumber *result = responseDictionary[@"resultCode"]; + return [result integerValue] == 0 ? result : nil; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 9100: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAppIDDoesNotExist userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(value != nil, error); + }]; +} + +#pragma mark - App Groups - + +- (void)fetchAppGroupsForTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(NSArray *_Nullable appIDs, NSError *_Nullable error))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/listApplicationGroups.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:nil session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + NSArray *groups = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSArray *array = responseDictionary[@"applicationGroupList"]; + if (array == nil) + { + return nil; + } + + NSMutableArray *groups = [NSMutableArray array]; + for (NSDictionary *dictionary in array) + { + ALTAppGroup *group = [[ALTAppGroup alloc] initWithResponseDictionary:dictionary]; + if (group == nil) + { + return nil; + } + + [groups addObject:group]; + } + return groups; + } resultCodeHandler:nil error:&error]; + + completionHandler(groups, error); + }]; +} + +- (void)addAppGroupWithName:(NSString *)name groupIdentifier:(NSString *)groupIdentifier team:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(ALTAppGroup * _Nullable, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/addApplicationGroup.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:@{@"identifier": groupIdentifier, @"name": name} session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + ALTAppGroup *group = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSDictionary *dictionary = responseDictionary[@"applicationGroup"]; + if (dictionary == nil) + { + return nil; + } + + ALTAppGroup *group = [[ALTAppGroup alloc] initWithResponseDictionary:dictionary]; + return group; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 35: + // Doesn't distinguish between different validation failures via resultCode unfortunately. + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidAppGroup userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(group, error); + }]; +} + +- (void)addAppID:(ALTAppID *)appID toGroup:(ALTAppGroup *)group team:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/assignApplicationGroupToAppId.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:@{@"appIdId": appID.identifier, @"applicationGroups": group.identifier} + session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(NO, requestError); + return; + } + + NSError *error = nil; + id value = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSNumber *result = responseDictionary[@"resultCode"]; + return [result integerValue] == 0 ? result : nil; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 9115: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAppIDDoesNotExist userInfo:nil]; + + case 35: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAppGroupDoesNotExist userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(value != nil, error); + }]; +} + +#pragma mark - Provisioning Profiles - + +- (void)fetchProvisioningProfileForAppID:(ALTAppID *)appID team:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(ALTProvisioningProfile * _Nullable, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/downloadTeamProvisioningProfile.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:@{@"appIdId": appID.identifier} session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(nil, requestError); + return; + } + + NSError *error = nil; + ALTProvisioningProfile *provisioningProfile = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSDictionary *dictionary = responseDictionary[@"provisioningProfile"]; + if (dictionary == nil) + { + return nil; + } + + ALTProvisioningProfile *provisioningProfile = [[ALTProvisioningProfile alloc] initWithResponseDictionary:dictionary]; + return provisioningProfile; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 8201: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorAppIDDoesNotExist userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(provisioningProfile, error); + }]; +} + +- (void)deleteProvisioningProfile:(ALTProvisioningProfile *)provisioningProfile forTeam:(ALTTeam *)team session:(ALTAppleAPISession *)session completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler +{ + NSURL *URL = [NSURL URLWithString:@"ios/deleteProvisioningProfile.action" relativeToURL:self.baseURL]; + + [self sendRequestWithURL:URL additionalParameters:@{@"provisioningProfileId": provisioningProfile.identifier, + @"teamId": team.identifier} + session:session team:team completionHandler:^(NSDictionary *responseDictionary, NSError *requestError) { + if (responseDictionary == nil) + { + completionHandler(NO, requestError); + return; + } + + NSError *error = nil; + id value = [self processResponse:responseDictionary parseHandler:^id _Nullable{ + NSNumber *result = responseDictionary[@"resultCode"]; + return [result integerValue] == 0 ? result : nil; + } resultCodeHandler:^NSError * _Nullable(NSInteger resultCode) { + switch (resultCode) + { + case 35: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidProvisioningProfileIdentifier userInfo:nil]; + + case 8101: + return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorProvisioningProfileDoesNotExist userInfo:nil]; + + default: return nil; + } + } error:&error]; + + completionHandler(value != nil, error); + }]; +} + +#pragma mark - Requests - + +- (void)sendRequestWithURL:(NSURL *)requestURL additionalParameters:(nullable NSDictionary *)additionalParameters session:(ALTAppleAPISession *)session team:(nullable ALTTeam *)team completionHandler:(void (^)(NSDictionary *responseDictionary, NSError *error))completionHandler +{ + NSMutableDictionary *parameters = [@{ + @"clientId": ALTClientID, + @"protocolVersion": ALTProtocolVersion, + @"requestId": [[[NSUUID UUID] UUIDString] uppercaseString], + } mutableCopy]; + + if (team != nil) + { + parameters[@"teamId"] = team.identifier; + } + + [additionalParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + parameters[key] = value; + }]; + + NSError *serializationError = nil; + NSData *bodyData = [NSPropertyListSerialization dataWithPropertyList:parameters format:NSPropertyListXMLFormat_v1_0 options:0 error:&serializationError]; + if (bodyData == nil) + { + NSError *error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidParameters userInfo:@{NSUnderlyingErrorKey: serializationError}]; + completionHandler(nil, error); + return; + } + + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?clientId=%@", requestURL.absoluteString, ALTClientID]]; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + request.HTTPMethod = @"POST"; + request.HTTPBody = bodyData; + + NSDictionary *httpHeaders = @{ + @"Content-Type": @"text/x-xml-plist", + @"User-Agent": @"Xcode", + @"Accept": @"text/x-xml-plist", + @"Accept-Language": @"en-us", + @"X-Apple-App-Info": @"com.apple.gs.xcode.auth", + @"X-Xcode-Version": @"11.2 (11B41)", + @"X-Apple-I-Identity-Id": session.dsid, + @"X-Apple-GS-Token": session.authToken, + @"X-Apple-I-MD-M": session.anisetteData.machineID, + @"X-Apple-I-MD": session.anisetteData.oneTimePassword, + @"X-Apple-I-MD-LU": session.anisetteData.localUserID, + @"X-Apple-I-MD-RINFO": [@(session.anisetteData.routingInfo) description], + @"X-Mme-Device-Id": session.anisetteData.deviceUniqueIdentifier, + @"X-MMe-Client-Info": session.anisetteData.deviceDescription, + @"X-Apple-I-Client-Time": [self.dateFormatter stringFromDate:session.anisetteData.date], + @"X-Apple-Locale": session.anisetteData.locale.localeIdentifier, + @"X-Apple-I-Locale": session.anisetteData.locale.localeIdentifier, + @"X-Apple-I-TimeZone": session.anisetteData.timeZone.abbreviation + }; + + [httpHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + [request setValue:value forHTTPHeaderField:key]; + }]; + + NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (data == nil) + { + completionHandler(nil, error); + return; + } + + NSError *parseError = nil; + NSDictionary *responseDictionary = [NSPropertyListSerialization propertyListWithData:data options:0 format:nil error:&parseError]; + + if (responseDictionary == nil) + { + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:@{NSUnderlyingErrorKey: parseError}]; + completionHandler(nil, error); + return; + } + + completionHandler(responseDictionary, nil); + }]; + + [dataTask resume]; +} + +- (void)sendServicesRequest:(NSURLRequest *)originalRequest additionalParameters:(nullable NSDictionary *)additionalParameters session:(ALTAppleAPISession *)session team:(ALTTeam *)team completionHandler:(void (^)(NSDictionary *responseDictionary, NSError *error))completionHandler +{ + NSMutableURLRequest *request = [originalRequest mutableCopy]; + + NSMutableArray *queryItems = [@[[NSURLQueryItem queryItemWithName:@"teamId" value:team.identifier]] mutableCopy]; + [additionalParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:key value:value]]; + }]; + + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.queryItems = queryItems; + + NSString *queryString = components.query ?: @""; + + NSError *serializationError = nil; + NSData *bodyData = [NSJSONSerialization dataWithJSONObject:@{@"urlEncodedQueryParams": queryString} options:0 error:&serializationError]; + if (bodyData == nil) + { + NSError *error = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidParameters userInfo:@{NSUnderlyingErrorKey: serializationError}]; + completionHandler(nil, error); + return; + } + + request.HTTPBody = bodyData; + + NSString *HTTPMethodOverride = request.HTTPMethod; + request.HTTPMethod = @"POST"; + + NSDictionary *httpHeaders = @{ + @"Content-Type": @"application/vnd.api+json", + @"User-Agent": @"Xcode", + @"Accept": @"application/vnd.api+json", + @"Accept-Language": @"en-us", + @"X-Apple-App-Info": @"com.apple.gs.xcode.auth", + @"X-Xcode-Version": @"11.2 (11B41)", + @"X-HTTP-Method-Override": HTTPMethodOverride, + @"X-Apple-I-Identity-Id": session.dsid, + @"X-Apple-GS-Token": session.authToken, + @"X-Apple-I-MD-M": session.anisetteData.machineID, + @"X-Apple-I-MD": session.anisetteData.oneTimePassword, + @"X-Apple-I-MD-LU": session.anisetteData.localUserID, + @"X-Apple-I-MD-RINFO": [@(session.anisetteData.routingInfo) description], + @"X-Mme-Device-Id": session.anisetteData.deviceUniqueIdentifier, + @"X-MMe-Client-Info": session.anisetteData.deviceDescription, + @"X-Apple-I-Client-Time": [self.dateFormatter stringFromDate:session.anisetteData.date], + @"X-Apple-Locale": session.anisetteData.locale.localeIdentifier, + @"X-Apple-I-TimeZone": session.anisetteData.timeZone.abbreviation + }; + + [httpHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + [request setValue:value forHTTPHeaderField:key]; + }]; + + NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (data == nil) + { + completionHandler(nil, error); + return; + } + + NSDictionary *responseDictionary = nil; + + if (data.length == 0) + { + responseDictionary = @{}; + } + else + { + NSError *parseError = nil; + responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError]; + + if (responseDictionary == nil) + { + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:@{NSUnderlyingErrorKey: parseError}]; + completionHandler(nil, error); + return; + } + } + + completionHandler(responseDictionary, nil); + }]; + + [dataTask resume]; +} + +- (nullable id)processResponse:(NSDictionary *)responseDictionary + parseHandler:(id _Nullable (^_Nullable)(void))parseHandler + resultCodeHandler:(NSError *_Nullable (^_Nullable)(NSInteger resultCode))resultCodeHandler + error:(NSError **)error +{ + if (parseHandler != nil) + { + id value = parseHandler(); + if (value != nil) + { + return value; + } + } + + id result = responseDictionary[@"resultCode"]; + if (result == nil) + { + *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]; + return nil; + } + + NSInteger resultCode = [result integerValue]; // Works wether result is NSNumber or NSString. + if (resultCode == 0) + { + return nil; + } + else + { + NSError *tempError = nil; + if (resultCodeHandler) + { + tempError = resultCodeHandler(resultCode); + } + + if (tempError == nil) + { + NSString *errorDescription = [responseDictionary objectForKey:@"userString"] ?: [responseDictionary objectForKey:@"resultString"]; + NSString *localizedDescription = [NSString stringWithFormat:@"%@ (%@)", errorDescription, @(resultCode)]; + + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedDescriptionKey] = localizedDescription; + tempError = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorUnknown userInfo:userInfo]; + } + + *error = tempError; + + return nil; + } +} + +@end diff --git a/AltSign/ALTAppleAPISession.h b/AltSign/ALTAppleAPISession.h new file mode 100644 index 0000000..c718519 --- /dev/null +++ b/AltSign/ALTAppleAPISession.h @@ -0,0 +1,25 @@ +// +// ALTAppleAPISession.h +// AltSign +// +// Created by Riley Testut on 11/15/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +@class ALTAnisetteData; + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAppleAPISession : NSObject + +@property (nonatomic, copy) NSString *dsid; +@property (nonatomic, copy) NSString *authToken; +@property (nonatomic, copy) ALTAnisetteData *anisetteData; + +- (instancetype)initWithDSID:(NSString *)dsid authToken:(NSString *)authToken anisetteData:(ALTAnisetteData *)anisetteData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTAppleAPISession.m b/AltSign/ALTAppleAPISession.m new file mode 100644 index 0000000..ffa5636 --- /dev/null +++ b/AltSign/ALTAppleAPISession.m @@ -0,0 +1,35 @@ +// +// ALTAppleAPISession.m +// AltSign +// +// Created by Riley Testut on 11/15/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAppleAPISession.h" +#import "ALTAccount.h" +#import "ALTAnisetteData.h" + +@implementation ALTAppleAPISession + +- (instancetype)initWithDSID:(NSString *)dsid authToken:(NSString *)authToken anisetteData:(ALTAnisetteData *)anisetteData +{ + self = [super init]; + if (self) + { + _dsid = [dsid copy]; + _authToken = [authToken copy]; + _anisetteData = [anisetteData copy]; + } + + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, DSID: %@, Auth Token: %@, Anisette Data: %@>", NSStringFromClass([self class]), self, self.dsid, self.authToken, self.anisetteData]; +} + +@end diff --git a/AltSign/ALTAppleAPI_Private.h b/AltSign/ALTAppleAPI_Private.h new file mode 100644 index 0000000..0052d88 --- /dev/null +++ b/AltSign/ALTAppleAPI_Private.h @@ -0,0 +1,34 @@ +// +// ALTAppleAPI+Private.h +// AltSign +// +// Created by Riley Testut on 11/16/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAppleAPI.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAppleAPI () + +@property (nonatomic, readonly) NSURLSession *session; +@property (nonatomic, readonly) NSISO8601DateFormatter *dateFormatter; + +@property (nonatomic, copy, readonly) NSURL *baseURL; +@property (nonatomic, copy, readonly) NSURL *servicesBaseURL; + +- (void)sendRequestWithURL:(NSURL *)requestURL + additionalParameters:(nullable NSDictionary *)additionalParameters + session:(ALTAppleAPISession *)session + team:(nullable ALTTeam *)team + completionHandler:(void (^)(NSDictionary *responseDictionary, NSError *error))completionHandler; + +- (nullable id)processResponse:(NSDictionary *)responseDictionary + parseHandler:(id _Nullable (^_Nullable)(void))parseHandler + resultCodeHandler:(NSError *_Nullable (^_Nullable)(NSInteger resultCode))resultCodeHandler + error:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTApplication.h b/AltSign/ALTApplication.h new file mode 100644 index 0000000..52f3ddd --- /dev/null +++ b/AltSign/ALTApplication.h @@ -0,0 +1,43 @@ +// +// ALTApplication.h +// AltSign +// +// Created by Riley Testut on 6/24/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#endif + +#import "ALTCapabilities.h" + +@class ALTProvisioningProfile; + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTApplication : NSObject + +@property (nonatomic, copy, readonly) NSString *name; +@property (nonatomic, copy, readonly) NSString *bundleIdentifier; +@property (nonatomic, copy, readonly) NSString *version; + +#if TARGET_OS_IPHONE +@property (nonatomic, readonly) UIImage *icon; +#endif + +@property (nonatomic, readonly, nullable) ALTProvisioningProfile *provisioningProfile; + +@property (nonatomic, readonly) NSOperatingSystemVersion minimumiOSVersion; + +@property (nonatomic, copy, readonly) NSDictionary *entitlements; + +@property (nonatomic, copy, readonly) NSURL *fileURL; + +- (nullable instancetype)initWithFileURL:(NSURL *)fileURL; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTApplication.mm b/AltSign/ALTApplication.mm new file mode 100644 index 0000000..cc20699 --- /dev/null +++ b/AltSign/ALTApplication.mm @@ -0,0 +1,153 @@ +// +// ALTApplication.m +// AltSign +// +// Created by Riley Testut on 6/24/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTApplication.h" +#import "ALTProvisioningProfile.h" + +#include "ldid.hpp" + +@interface ALTApplication () + +@property (nonatomic, copy, nullable, readonly) NSString *iconName; + +@end + +@implementation ALTApplication +@synthesize entitlements = _entitlements; +@synthesize provisioningProfile = _provisioningProfile; + +- (instancetype)initWithFileURL:(NSURL *)fileURL +{ + self = [super init]; + if (self) + { + NSBundle *bundle = [NSBundle bundleWithURL:fileURL]; + if (bundle == nil) + { + return nil; + } + + // Load info dictionary directly from disk, since NSBundle caches values + // that might not reflect the updated values on disk (such as bundle identifier). + NSURL *infoPlistURL = [bundle.bundleURL URLByAppendingPathComponent:@"Info.plist"]; + NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfURL:infoPlistURL]; + if (infoDictionary == nil) + { + return nil; + } + + NSString *name = infoDictionary[@"CFBundleDisplayName"] ?: infoDictionary[(NSString *)kCFBundleNameKey]; + NSString *bundleIdentifier = infoDictionary[(NSString *)kCFBundleIdentifierKey]; + + if (name == nil || bundleIdentifier == nil) + { + return nil; + } + + NSString *version = infoDictionary[@"CFBundleShortVersionString"] ?: @"1.0"; + NSString *minimumVersionString = infoDictionary[@"MinimumOSVersion"] ?: @"1.0"; + + NSArray *versionComponents = [minimumVersionString componentsSeparatedByString:@"."]; + + NSInteger majorVersion = [versionComponents.firstObject integerValue]; + NSInteger minorVersion = (versionComponents.count > 1) ? [versionComponents[1] integerValue] : 0; + NSInteger patchVersion = (versionComponents.count > 2) ? [versionComponents[2] integerValue] : 0; + + NSOperatingSystemVersion minimumVersion; + minimumVersion.majorVersion = majorVersion; + minimumVersion.minorVersion = minorVersion; + minimumVersion.patchVersion = patchVersion; + + NSDictionary *icons = infoDictionary[@"CFBundleIcons"]; + NSDictionary *primaryIcon = icons[@"CFBundlePrimaryIcon"]; + + NSArray *iconFiles = primaryIcon[@"CFBundleIconFiles"]; + if (iconFiles == nil) + { + iconFiles = infoDictionary[@"CFBundleIconFiles"]; + } + + NSString *iconName = [iconFiles lastObject]; + if (iconName == nil) + { + iconName = infoDictionary[@"CFBundleIconFile"]; + } + + _fileURL = [fileURL copy]; + _name = [name copy]; + _bundleIdentifier = [bundleIdentifier copy]; + _version = [version copy]; + _minimumiOSVersion = minimumVersion; + _iconName = [iconName copy]; + } + + return self; +} + +#if TARGET_OS_IPHONE +- (UIImage *)icon +{ + NSBundle *bundle = [NSBundle bundleWithURL:self.fileURL]; + if (bundle == nil) + { + return nil; + } + + NSString *iconName = self.iconName; + if (iconName == nil) + { + return nil; + } + + UIImage *icon = [UIImage imageNamed:iconName inBundle:bundle compatibleWithTraitCollection:nil]; + return icon; +} +#endif + +- (NSDictionary *)entitlements +{ + if (_entitlements == nil) + { + NSDictionary *appEntitlements = @{}; + + std::string rawEntitlements = ldid::Entitlements(self.fileURL.fileSystemRepresentation); + if (rawEntitlements.size() != 0) + { + NSData *entitlementsData = [NSData dataWithBytes:rawEntitlements.c_str() length:rawEntitlements.size()]; + + NSError *error = nil; + NSDictionary *entitlements = [NSPropertyListSerialization propertyListWithData:entitlementsData options:0 format:nil error:&error]; + + if (entitlements != nil) + { + appEntitlements = entitlements; + } + else + { + NSLog(@"Error parsing entitlements: %@", error); + } + } + + _entitlements = appEntitlements; + } + + return _entitlements; +} + +- (ALTProvisioningProfile *)provisioningProfile +{ + if (_provisioningProfile == nil) + { + NSURL *provisioningProfileURL = [self.fileURL URLByAppendingPathComponent:@"embedded.mobileprovision"]; + _provisioningProfile = [[ALTProvisioningProfile alloc] initWithURL:provisioningProfileURL]; + } + + return _provisioningProfile; +} + +@end diff --git a/AltSign/ALTCapabilities.h b/AltSign/ALTCapabilities.h new file mode 100644 index 0000000..76f8296 --- /dev/null +++ b/AltSign/ALTCapabilities.h @@ -0,0 +1,31 @@ +// +// ALTCapabilities.h +// AltSign +// +// Created by Riley Testut on 6/25/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +// Entitlements +typedef NSString *ALTEntitlement NS_TYPED_EXTENSIBLE_ENUM; +extern ALTEntitlement const ALTEntitlementApplicationIdentifier; +extern ALTEntitlement const ALTEntitlementKeychainAccessGroups; +extern ALTEntitlement const ALTEntitlementAppGroups; +extern ALTEntitlement const ALTEntitlementGetTaskAllow; +extern ALTEntitlement const ALTEntitlementTeamIdentifier; +extern ALTEntitlement const ALTEntitlementInterAppAudio; + +// Features +typedef NSString *ALTFeature NS_TYPED_EXTENSIBLE_ENUM; +extern ALTFeature const ALTFeatureGameCenter; +extern ALTFeature const ALTFeatureAppGroups; +extern ALTFeature const ALTFeatureInterAppAudio; + +_Nullable ALTEntitlement ALTEntitlementForFeature(ALTFeature feature) NS_SWIFT_NAME(ALTEntitlement.init(feature:)); +_Nullable ALTFeature ALTFeatureForEntitlement(ALTEntitlement entitlement) NS_SWIFT_NAME(ALTFeature.init(entitlement:)); + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTCapabilities.m b/AltSign/ALTCapabilities.m new file mode 100644 index 0000000..302107a --- /dev/null +++ b/AltSign/ALTCapabilities.m @@ -0,0 +1,50 @@ +// +// ALTCapabilities.m +// AltSign +// +// Created by Riley Testut on 6/25/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTCapabilities.h" + +// Entitlements +ALTEntitlement const ALTEntitlementApplicationIdentifier = @"application-identifier"; +ALTEntitlement const ALTEntitlementKeychainAccessGroups = @"keychain-access-groups"; +ALTEntitlement const ALTEntitlementAppGroups = @"com.apple.security.application-groups"; +ALTEntitlement const ALTEntitlementGetTaskAllow = @"get-task-allow"; +ALTEntitlement const ALTEntitlementTeamIdentifier = @"com.apple.developer.team-identifier"; +ALTEntitlement const ALTEntitlementInterAppAudio = @"inter-app-audio"; + +// Features +ALTFeature const ALTFeatureGameCenter = @"gameCenter"; +ALTFeature const ALTFeatureAppGroups = @"APG3427HIY"; +ALTFeature const ALTFeatureInterAppAudio = @"IAD53UNK2F"; + +_Nullable ALTEntitlement ALTEntitlementForFeature(ALTFeature feature) +{ + if ([feature isEqualToString:ALTFeatureAppGroups]) + { + return ALTEntitlementAppGroups; + } + else if ([feature isEqualToString:ALTFeatureInterAppAudio]) + { + return ALTEntitlementInterAppAudio; + } + + return nil; +} + +_Nullable ALTFeature ALTFeatureForEntitlement(ALTEntitlement entitlement) +{ + if ([entitlement isEqualToString:ALTEntitlementAppGroups]) + { + return ALTFeatureAppGroups; + } + else if ([entitlement isEqualToString:ALTEntitlementInterAppAudio]) + { + return ALTFeatureInterAppAudio; + } + + return nil; +} diff --git a/AltSign/ALTCertificate.h b/AltSign/ALTCertificate.h new file mode 100644 index 0000000..04c1f0b --- /dev/null +++ b/AltSign/ALTCertificate.h @@ -0,0 +1,33 @@ +// +// ALTCertificate.h +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTCertificate : NSObject + +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSString *serialNumber; + +@property (nonatomic, copy, nullable) NSString *identifier; +@property (nonatomic, copy, nullable) NSString *machineName; +@property (nonatomic, copy, nullable) NSString *machineIdentifier; + +@property (nonatomic, copy, nullable) NSData *data; +@property (nonatomic, copy, nullable) NSData *privateKey; + +- (nullable instancetype)initWithData:(NSData *)data; +- (nullable instancetype)initWithP12Data:(NSData *)p12Data password:(nullable NSString *)password; + +- (nullable NSData *)p12Data; +- (nullable NSData *)encryptedP12DataWithPassword:(NSString *)password; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTCertificate.m b/AltSign/ALTCertificate.m new file mode 100644 index 0000000..82f67c9 --- /dev/null +++ b/AltSign/ALTCertificate.m @@ -0,0 +1,262 @@ +// +// ALTCertificate.m +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTCertificate.h" + +#include +#include + +NSString *ALTCertificatePEMPrefix = @"-----BEGIN CERTIFICATE-----"; +NSString *ALTCertificatePEMSuffix = @"-----END CERTIFICATE-----"; + +@implementation ALTCertificate + +- (instancetype)initWithName:(NSString *)name serialNumber:(NSString *)serialNumber data:(nullable NSData *)data +{ + self = [super init]; + if (self) + { + _name = [name copy]; + _serialNumber = [serialNumber copy]; + _data = [data copy]; + } + + return self; +} + +- (instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary +{ + NSString *identifier = responseDictionary[@"id"]; + + NSDictionary *attributesDictionary = responseDictionary[@"attributes"] ?: responseDictionary; + + NSData *data = nil; + if (attributesDictionary[@"certContent"] != nil) + { + data = attributesDictionary[@"certContent"]; + } + else if (attributesDictionary[@"certificateContent"] != nil) + { + NSString *encodedData = attributesDictionary[@"certificateContent"]; + data = [[NSData alloc] initWithBase64EncodedString:encodedData options:0]; + } + + NSString *machineName = attributesDictionary[@"machineName"]; + NSString *machineIdentifier = attributesDictionary[@"machineId"]; + + if (data != nil) + { + self = [self initWithData:data]; + } + else + { + NSString *name = attributesDictionary[@"name"]; + NSString *serialNumber = attributesDictionary[@"serialNumber"] ?: attributesDictionary[@"serialNum"]; + + self = [self initWithName:name serialNumber:serialNumber data:nil]; + } + + if (self) + { + _machineName = [machineName copy]; + _machineIdentifier = [machineIdentifier copy]; + _identifier = [identifier copy]; + } + + return self; +} + +- (nullable instancetype)initWithP12Data:(NSData *)p12Data password:(nullable NSString *)password +{ + BIO *inputP12Buffer = BIO_new(BIO_s_mem()); + BIO_write(inputP12Buffer, p12Data.bytes, (int)p12Data.length); + + PKCS12 *inputP12 = d2i_PKCS12_bio(inputP12Buffer, NULL); + + // Extract key + certificate from .p12. + EVP_PKEY *key; + X509 *certificate; + PKCS12_parse(inputP12, password.UTF8String, &key, &certificate, NULL); + + if (key == nil || certificate == nil) + { + return nil; + } + + BIO *pemBuffer = BIO_new(BIO_s_mem()); + PEM_write_bio_X509(pemBuffer, certificate); + + BIO *privateKeyBuffer = BIO_new(BIO_s_mem()); + PEM_write_bio_PrivateKey(privateKeyBuffer, key, NULL, NULL, 0, NULL, NULL); + + char *pemBytes = NULL; + NSUInteger pemSize = BIO_get_mem_data(pemBuffer, &pemBytes); + + char *privateKeyBytes = NULL; + NSUInteger privateKeySize = BIO_get_mem_data(privateKeyBuffer, &privateKeyBytes); + + NSData *pemData = [NSData dataWithBytes:pemBytes length:pemSize]; + NSData *privateKey = [NSData dataWithBytes:privateKeyBytes length:privateKeySize]; + + self = [self initWithData:pemData]; + if (self) + { + _privateKey = [privateKey copy]; + } + + return self; +} + +- (nullable instancetype)initWithData:(NSData *)data +{ + NSData *pemData = data; + + NSData *prefixData = [data subdataWithRange:NSMakeRange(0, MIN(data.length, ALTCertificatePEMPrefix.length))]; + NSString *prefix = [[NSString alloc] initWithData:prefixData encoding:NSUTF8StringEncoding]; + + if (![prefix isEqualToString:ALTCertificatePEMPrefix]) + { + // Convert to proper PEM format before storing. + NSString *base64Data = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + + NSString *content = [NSString stringWithFormat:@"%@\n%@\n%@", ALTCertificatePEMPrefix, base64Data, ALTCertificatePEMSuffix]; + pemData = [content dataUsingEncoding:NSUTF8StringEncoding]; + } + + BIO *certificateBuffer = BIO_new(BIO_s_mem()); + BIO_write(certificateBuffer, pemData.bytes, (int)pemData.length); + + X509 *certificate = nil; + PEM_read_bio_X509(certificateBuffer, &certificate, 0, 0); + if (certificate == nil) + { + return nil; + } + + /* Certificate Common Name */ + X509_NAME *subject = X509_get_subject_name(certificate); + int index = X509_NAME_get_index_by_NID(subject, NID_commonName, -1); + if (index == -1) + { + return nil; + } + + X509_NAME_ENTRY *nameEntry = X509_NAME_get_entry(subject, index); + ASN1_STRING *nameData = X509_NAME_ENTRY_get_data(nameEntry); + unsigned char *cName = ASN1_STRING_data(nameData); + + + /* Serial Number */ + ASN1_INTEGER *serialNumberData = X509_get_serialNumber(certificate); + BIGNUM *number = ASN1_INTEGER_to_BN(serialNumberData, NULL); + if (number == nil) + { + return nil; + } + + char *cSerialNumber = BN_bn2hex(number); + + if (cName == nil || cSerialNumber == nil) + { + return nil; + } + + NSString *name = [NSString stringWithFormat:@"%s", cName]; + NSString *serialNumber = [NSString stringWithFormat:@"%s", cSerialNumber]; + + NSInteger location = NSNotFound; + for (int i = 0; i < serialNumber.length; i++) + { + if ([serialNumber characterAtIndex:i] != '0') + { + location = i; + break; + } + } + + if (location == NSNotFound) + { + return nil; + } + + // Remove leading zeros. + NSString *trimmedSerialNumber = [serialNumber substringFromIndex:location]; + + self = [self initWithName:name serialNumber:trimmedSerialNumber data:pemData]; + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, Name: %@, SN: %@>", NSStringFromClass([self class]), self, self.name, self.serialNumber]; +} + +- (BOOL)isEqual:(id)object +{ + ALTCertificate *certificate = (ALTCertificate *)object; + if (![certificate isKindOfClass:[ALTCertificate class]]) + { + return NO; + } + + BOOL isEqual = [self.serialNumber isEqualToString:certificate.serialNumber]; + return isEqual; +} + +- (NSUInteger)hash +{ + return self.serialNumber.hash; +} + +#pragma mark - ALTCertificate - + +- (nullable NSData *)p12Data +{ + return [self encryptedP12DataWithPassword:@""]; +} + +- (nullable NSData *)encryptedP12DataWithPassword:(NSString *)password +{ + BIO *certificateBuffer = BIO_new(BIO_s_mem()); + BIO *privateKeyBuffer = BIO_new(BIO_s_mem()); + + BIO_write(certificateBuffer, self.data.bytes, (int)self.data.length); + BIO_write(privateKeyBuffer, self.privateKey.bytes, (int)self.privateKey.length); + + X509 *certificate = nil; + PEM_read_bio_X509(certificateBuffer, &certificate, 0, 0); + + EVP_PKEY *privateKey = nil; + PEM_read_bio_PrivateKey(privateKeyBuffer, &privateKey, 0, 0); + + char emptyString[] = ""; + PKCS12 *outputP12 = PKCS12_create((char *)password.UTF8String, emptyString, privateKey, certificate, NULL, 0, 0, 0, 0, 0); + + BIO *p12Buffer = BIO_new(BIO_s_mem()); + i2d_PKCS12_bio(p12Buffer, outputP12); + + char *buffer = NULL; + NSUInteger size = BIO_get_mem_data(p12Buffer, &buffer); + + NSData *p12Data = [NSData dataWithBytes:buffer length:size]; + + BIO_free(p12Buffer); + PKCS12_free(outputP12); + + EVP_PKEY_free(privateKey); + X509_free(certificate); + + BIO_free(privateKeyBuffer); + BIO_free(certificateBuffer); + + return p12Data; +} + +@end diff --git a/AltSign/ALTCertificateRequest.h b/AltSign/ALTCertificateRequest.h new file mode 100644 index 0000000..16cc43d --- /dev/null +++ b/AltSign/ALTCertificateRequest.h @@ -0,0 +1,22 @@ +// +// ALTCertificateRequest.h +// AltSign +// +// Created by Riley Testut on 5/21/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTCertificateRequest : NSObject + +@property (nonatomic, copy, readonly) NSData *data; +@property (nonatomic, copy, readonly) NSData *privateKey; + +- (nullable instancetype)init; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTCertificateRequest.m b/AltSign/ALTCertificateRequest.m new file mode 100644 index 0000000..cd21b8e --- /dev/null +++ b/AltSign/ALTCertificateRequest.m @@ -0,0 +1,151 @@ +// +// ALTCertificateRequest.m +// AltSign +// +// Created by Riley Testut on 5/21/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTCertificateRequest.h" +#include +#include +#include + +@implementation ALTCertificateRequest + +- (instancetype)init +{ + self = [super init]; + if (self) + { + NSData *data = nil; + NSData *privateKey = nil; + [self generateRequest:&data privateKey:&privateKey]; + + if (data == nil || privateKey == nil) + { + return nil; + } + + _data = [data copy]; + _privateKey = [privateKey copy]; + } + + return self; +} + +// Based on https://www.codepool.biz/how-to-use-openssl-to-generate-x-509-certificate-request.html +- (void)generateRequest:(NSData **)outputRequest privateKey:(NSData **)outputPrivateKey +{ + BIGNUM *bignum = NULL; + __block RSA *rsa = NULL; + + X509_REQ *request = NULL; + EVP_PKEY *publicKey = NULL; + + BIO *csr = NULL; + BIO *privateKey = NULL; + + void (^finish)(void) = ^{ + if (publicKey != NULL) + { + // Also frees rsa, so we check if non-nil to prevent double free. + EVP_PKEY_free(publicKey); + } + else + { + RSA_free(rsa); + } + + BN_free(bignum); + X509_REQ_free(request); + + BIO_free_all(csr); + BIO_free_all(privateKey); + }; + + /* Generate RSA Key */ + + bignum = BN_new(); + if (BN_set_word(bignum, RSA_F4) != 1) + { + finish(); + return; + } + + rsa = RSA_new(); + if (RSA_generate_key_ex(rsa, 2048, bignum, NULL) != 1) + { + finish(); + return; + } + + /* Generate request */ + + const char *country = "US"; + const char *state = "CA"; + const char *city = "Los Angeles"; + const char *organization = "AltSign"; + const char *commonName = "AltSign"; + + request = X509_REQ_new(); + if (X509_REQ_set_version(request, 1) != 1) + { + finish(); + return; + } + + // Subject + X509_NAME *subject = X509_REQ_get_subject_name(request); + X509_NAME_add_entry_by_txt(subject, "C", MBSTRING_ASC, (const unsigned char *)country, -1, -1, 0); + X509_NAME_add_entry_by_txt(subject, "ST", MBSTRING_ASC, (const unsigned char*)state, -1, -1, 0); + X509_NAME_add_entry_by_txt(subject, "L", MBSTRING_ASC, (const unsigned char*)city, -1, -1, 0); + X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC, (const unsigned char*)organization, -1, -1, 0); + X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (const unsigned char*)commonName, -1, -1, 0); + + // Public Key + publicKey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(publicKey, rsa); + + if (X509_REQ_set_pubkey(request, publicKey) != 1) + { + finish(); + return; + } + + // Sign request + if (X509_REQ_sign(request, publicKey, EVP_sha1()) <= 0) + { + finish(); + return; + } + + // Output + csr = BIO_new(BIO_s_mem()); + if (PEM_write_bio_X509_REQ(csr, request) != 1) + { + finish(); + return; + } + + privateKey = BIO_new(BIO_s_mem()); + if (PEM_write_bio_RSAPrivateKey(privateKey, rsa, NULL, NULL, 0, NULL, NULL) != 1) + { + finish(); + return; + } + + /* Return values */ + + char *csrData = NULL; + long csrLength = BIO_get_mem_data(csr, &csrData); + *outputRequest = [NSData dataWithBytes:csrData length:csrLength]; + + char *privateKeyData = NULL; + long privateKeyLength = BIO_get_mem_data(privateKey, &privateKeyData); + *outputPrivateKey = [NSData dataWithBytes:privateKeyData length:privateKeyLength]; + + finish(); +} + +@end diff --git a/AltSign/ALTDevice.h b/AltSign/ALTDevice.h new file mode 100644 index 0000000..72b251a --- /dev/null +++ b/AltSign/ALTDevice.h @@ -0,0 +1,23 @@ +// +// ALTDevice.h +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTDevice : NSObject + +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSString *identifier; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithName:(NSString *)name identifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTDevice.m b/AltSign/ALTDevice.m new file mode 100644 index 0000000..1d16a6c --- /dev/null +++ b/AltSign/ALTDevice.m @@ -0,0 +1,63 @@ +// +// ALTDevice.m +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTDevice.h" + +@implementation ALTDevice + +- (instancetype)initWithName:(NSString *)name identifier:(NSString *)identifier +{ + self = [super init]; + if (self) + { + _name = [name copy]; + _identifier = [identifier copy]; + } + + return self; +} + +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary +{ + NSString *name = responseDictionary[@"name"]; + NSString *identifier = responseDictionary[@"deviceNumber"]; + + if (name == nil || identifier == nil) + { + return nil; + } + + self = [self initWithName:name identifier:identifier]; + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, Name: %@, UDID: %@>", NSStringFromClass([self class]), self, self.name, self.identifier]; +} + +- (BOOL)isEqual:(id)object +{ + ALTDevice *device = (ALTDevice *)object; + if (![device isKindOfClass:[ALTDevice class]]) + { + return NO; + } + + BOOL isEqual = [self.identifier isEqualToString:device.identifier]; + return isEqual; +} + +- (NSUInteger)hash +{ + return self.identifier.hash; +} + +@end diff --git a/AltSign/ALTModel+Internal.h b/AltSign/ALTModel+Internal.h new file mode 100644 index 0000000..f58928c --- /dev/null +++ b/AltSign/ALTModel+Internal.h @@ -0,0 +1,49 @@ +// +// ALTModel+Internal.h +// AltSign +// +// Created by Riley Testut on 5/28/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTAccount.h" +#import "ALTTeam.h" +#import "ALTDevice.h" +#import "ALTCertificate.h" +#import "ALTCertificateRequest.h" +#import "ALTAppID.h" +#import "ALTAppGroup.h" +#import "ALTProvisioningProfile.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTAccount () +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary; +@end + +@interface ALTTeam () +- (nullable instancetype)initWithAccount:(ALTAccount *)account responseDictionary:(NSDictionary *)responseDictionary; +@end + +@interface ALTDevice () +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary; +@end + +@interface ALTCertificate () +- (instancetype)initWithName:(NSString *)name serialNumber:(NSString *)serialNumber data:(nullable NSData *)data NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary; +@end + +@interface ALTAppID () +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary; +@end + +@interface ALTAppGroup () +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary; +@end + +@interface ALTProvisioningProfile () +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary; +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTProvisioningProfile.h b/AltSign/ALTProvisioningProfile.h new file mode 100644 index 0000000..f4f2a10 --- /dev/null +++ b/AltSign/ALTProvisioningProfile.h @@ -0,0 +1,45 @@ +// +// ALTProvisioningProfile.h +// AltSign +// +// Created by Riley Testut on 5/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +#import "ALTCapabilities.h" + +@class ALTAppID; +@class ALTCertificate; + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTProvisioningProfile : NSObject + +@property (copy, nonatomic, readonly) NSString *name; +@property (copy, nonatomic, readonly, nullable) NSString *identifier; +@property (copy, nonatomic, readonly) NSUUID *UUID; + +@property (copy, nonatomic, readonly) NSString *bundleIdentifier; +@property (copy, nonatomic, readonly) NSString *teamIdentifier; + +@property (copy, nonatomic, readonly) NSDate *creationDate; +@property (copy, nonatomic, readonly) NSDate *expirationDate; + +@property (copy, nonatomic, readonly) NSDictionary *entitlements; +@property (copy, nonatomic, readonly) NSArray *certificates; +@property (copy, nonatomic, readonly) NSArray *deviceIDs; + +@property (readonly) BOOL isFreeProvisioningProfile; + +@property (copy, nonatomic, readonly) NSData *data; + +- (nullable instancetype)initWithData:(NSData *)data NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithURL:(NSURL *)fileURL; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTProvisioningProfile.m b/AltSign/ALTProvisioningProfile.m new file mode 100644 index 0000000..847b7cb --- /dev/null +++ b/AltSign/ALTProvisioningProfile.m @@ -0,0 +1,301 @@ +// +// ALTProvisioningProfile.m +// AltSign +// +// Created by Riley Testut on 5/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTProvisioningProfile.h" +#import "ALTCertificate.h" + +#define ASN1_SEQUENCE 0x30 +#define ASN1_CONTAINER 0xA0 +#define ASN1_OBJECT_IDENTIFIER 0x06 +#define ASN1_OCTET_STRING 0x04 + +@implementation ALTProvisioningProfile + +- (nullable instancetype)initWithResponseDictionary:(NSDictionary *)responseDictionary +{ + NSString *identifier = responseDictionary[@"provisioningProfileId"]; + if (identifier == nil) + { + return nil; + } + + NSData *data = responseDictionary[@"encodedProfile"]; + if (data == nil) + { + return nil; + } + + self = [self initWithData:data]; + _identifier = [identifier copy]; + + return self; +} + +- (nullable instancetype)initWithURL:(NSURL *)fileURL +{ + NSData *data = [NSData dataWithContentsOfURL:fileURL]; + if (data == nil) + { + return nil; + } + + self = [self initWithData:data]; + return self; +} + +- (nullable instancetype)initWithData:(NSData *)data +{ + self = [super init]; + if (self) + { + NSDictionary *dictionary = [ALTProvisioningProfile dictionaryFromEncodedData:data]; + if (dictionary == nil) + { + return nil; + } + + NSString *name = dictionary[@"Name"]; + NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:dictionary[@"UUID"]]; + + NSString *teamIdentifier = [dictionary[@"TeamIdentifier"] firstObject]; + + NSDate *creationDate = dictionary[@"CreationDate"]; + NSDate *expirationDate = dictionary[@"ExpirationDate"]; + + NSDictionary *entitlements = dictionary[@"Entitlements"]; + NSArray *deviceIDs = dictionary[@"ProvisionedDevices"]; + + if (name == nil || UUID == nil || teamIdentifier == nil || creationDate == nil || expirationDate == nil || entitlements == nil || deviceIDs == nil) + { + return nil; + } + + BOOL isFreeProvisioningProfile = [dictionary[@"LocalProvision"] boolValue]; + + _data = [data copy]; + + _name = [name copy]; + _UUID = [UUID copy]; + + _teamIdentifier = [teamIdentifier copy]; + + _creationDate = [creationDate copy]; + _expirationDate = [expirationDate copy]; + + _entitlements = [entitlements copy]; + _deviceIDs = [deviceIDs copy]; + + _isFreeProvisioningProfile = isFreeProvisioningProfile; + + [entitlements enumerateKeysAndObjectsUsingBlock:^(ALTEntitlement entitlement, id value, BOOL *stop) { + if (![entitlement isEqualToString:ALTEntitlementApplicationIdentifier]) + { + return; + } + + NSUInteger location = [(NSString *)value rangeOfString:@"."].location; + if (location == NSNotFound) + { + return; + } + + NSString *bundleIdentifier = [value substringFromIndex:location + 1]; + self->_bundleIdentifier = [bundleIdentifier copy]; + + *stop = YES; + }]; + + if (_bundleIdentifier == nil) + { + return nil; + } + + NSMutableArray *certificates = [NSMutableArray array]; + + NSArray *certificatesArray = dictionary[@"DeveloperCertificates"]; + for (NSData *data in certificatesArray) + { + ALTCertificate *certificate = [[ALTCertificate alloc] initWithData:data]; + if (certificate != nil) + { + [certificates addObject:certificate]; + } + } + + _certificates = [certificates copy]; + } + + return self; +} + +// Heavily inspired by libimobiledevice/ideviceprovision.c +// https://github.com/libimobiledevice/libimobiledevice/blob/ddba0b5efbcab483e80be10130c5c797f9ac8d08/tools/ideviceprovision.c#L98 ++ (nullable NSDictionary *)dictionaryFromEncodedData:(NSData *)encodedData +{ + // Helper blocks + size_t (^itemSize)(unsigned char *) = ^size_t(unsigned char *pointer) { + size_t size = -1; + + char bsize = *(pointer + 1); + if (bsize & 0x80) + { + switch (bsize & 0xF) + { + case 2: + { + uint16_t value = *(uint16_t *)(pointer + 2); + size = ntohs(value); + break; + } + + case 3: + { + uint32_t value = *(uint32_t *)(pointer + 2); + size = ntohl(value) >> 8; + break; + } + + case 4: + { + uint32_t value = *(uint32_t *)(pointer + 2); + size = ntohl(value); + break; + } + + default: + break; + } + } + else + { + size = (size_t)bsize; + } + + return size; + }; + + unsigned char * (^advanceToNextItem)(unsigned char *) = ^unsigned char *(unsigned char *pointer) { + unsigned char *nextItem = pointer; + + char bsize = *(pointer + 1); + if (bsize & 0x80) + { + nextItem += 2 + (bsize & 0xF); + } + else + { + nextItem += 3; + } + + return nextItem; + }; + + unsigned char * (^skipNextItem)(unsigned char *) = ^unsigned char *(unsigned char *pointer) { + size_t size = itemSize(pointer); + + unsigned char *nextItem = pointer + 2 + size; + return nextItem; + }; + + + /* Start parsing */ + unsigned char *pointer = (unsigned char *)encodedData.bytes; + if (*pointer != ASN1_SEQUENCE) + { + return nil; + } + + pointer = advanceToNextItem(pointer); + if (*pointer != ASN1_OBJECT_IDENTIFIER) + { + return nil; + } + + pointer = skipNextItem(pointer); + if (*pointer != ASN1_CONTAINER) + { + return nil; + } + + pointer = advanceToNextItem(pointer); + if (*pointer != ASN1_SEQUENCE) + { + return nil; + } + + pointer = advanceToNextItem(pointer); + + // Skip 2 items. + for (int i = 0; i < 2; i++) + { + pointer = skipNextItem(pointer); + } + + if (*pointer != ASN1_SEQUENCE) + { + return nil; + } + + pointer = advanceToNextItem(pointer); + if (*pointer != ASN1_OBJECT_IDENTIFIER) + { + return nil; + } + + pointer = skipNextItem(pointer); + if (*pointer != ASN1_CONTAINER) + { + return nil; + } + + pointer = advanceToNextItem(pointer); + if (*pointer != ASN1_OCTET_STRING) + { + return nil; + } + + size_t length = itemSize(pointer); + pointer = advanceToNextItem(pointer); + + NSData *data = [NSData dataWithBytes:(const void *)pointer length:length]; + + NSError *error = nil; + NSDictionary *dictionary = [NSPropertyListSerialization propertyListWithData:data options:0 format:nil error:&error]; + if (dictionary == nil) + { + NSLog(@"Failed to parse provisioning profile from data. %@", error); + } + + return dictionary; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, Name: %@, UUID: %@, App BundleID: %@>", NSStringFromClass([self class]), self, self.name, self.UUID, self.bundleIdentifier]; +} + +- (BOOL)isEqual:(id)object +{ + ALTProvisioningProfile *profile = (ALTProvisioningProfile *)object; + if (![profile isKindOfClass:[ALTProvisioningProfile class]]) + { + return NO; + } + + BOOL isEqual = ([self.UUID isEqual:profile.UUID] && [self.data isEqualToData:profile.data]); + return isEqual; +} + +- (NSUInteger)hash +{ + return self.UUID.hash ^ self.data.hash; +} + +@end diff --git a/AltSign/ALTSigner.h b/AltSign/ALTSigner.h new file mode 100644 index 0000000..1d2663a --- /dev/null +++ b/AltSign/ALTSigner.h @@ -0,0 +1,29 @@ +// +// ALTSigner.h +// AltSign +// +// Created by Riley Testut on 5/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +@class ALTAppID; +@class ALTTeam; +@class ALTCertificate; +@class ALTProvisioningProfile; + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTSigner : NSObject + +@property (nonatomic) ALTTeam *team; +@property (nonatomic) ALTCertificate *certificate; + +- (instancetype)initWithTeam:(ALTTeam *)team certificate:(ALTCertificate *)certificate; + +- (NSProgress *)signAppAtURL:(NSURL *)appURL provisioningProfiles:(NSArray *)profiles completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTSigner.mm b/AltSign/ALTSigner.mm new file mode 100644 index 0000000..5164497 --- /dev/null +++ b/AltSign/ALTSigner.mm @@ -0,0 +1,312 @@ +// +// ALTSigner.m +// AltSign +// +// Created by Riley Testut on 5/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTSigner.h" +#import "ALTAppID.h" +#import "ALTTeam.h" +#import "ALTCertificate.h" +#import "ALTProvisioningProfile.h" +#import "ALTApplication.h" + +#import "NSFileManager+Apps.h" +#import "NSError+ALTErrors.h" + +#include "ldid.hpp" + +#include + +#include +#include + +std::string CertificatesContent(ALTCertificate *altCertificate) +{ + NSURL *pemURL = [NSBundle.mainBundle URLForResource:@"apple" withExtension:@"pem"]; + NSLog(@"pem: %@", pemURL); + + NSData *altCertificateP12Data = [altCertificate p12Data]; + + BIO *inputP12Buffer = BIO_new(BIO_s_mem()); + BIO_write(inputP12Buffer, altCertificateP12Data.bytes, (int)altCertificateP12Data.length); + + auto inputP12 = d2i_PKCS12_bio(inputP12Buffer, NULL); + + // Extract key + certificate from .p12. + EVP_PKEY *key; + X509 *certificate; + PKCS12_parse(inputP12, "", &key, &certificate, NULL); + + // Open .pem from file. + auto pemFile = fopen(pemURL.path.fileSystemRepresentation, "r"); + + // Extract certificates from .pem. + auto *certificates = sk_X509_new(NULL); + while (auto certificate = PEM_read_X509(pemFile, NULL, NULL, NULL)) + { + sk_X509_push(certificates, certificate); + } + + // Create new .p12 in memory with private key and certificate chain. + char emptyString[] = ""; + auto outputP12 = PKCS12_create(emptyString, emptyString, key, certificate, certificates, 0, 0, 0, 0, 0); + + BIO *outputP12Buffer = BIO_new(BIO_s_mem()); + i2d_PKCS12_bio(outputP12Buffer, outputP12); + + char *buffer = NULL; + NSUInteger size = BIO_get_mem_data(outputP12Buffer, &buffer); + + NSData *p12Data = [NSData dataWithBytes:buffer length:size]; + + // Free .p12 structures + PKCS12_free(inputP12); + PKCS12_free(outputP12); + + BIO_free(inputP12Buffer); + BIO_free(outputP12Buffer); + + // Close files + fclose(pemFile); + + std::string output((const char *)p12Data.bytes, (size_t)p12Data.length); + return output; +} + +@implementation ALTSigner + ++ (void)load +{ + OpenSSL_add_all_algorithms(); +} + +- (instancetype)initWithTeam:(ALTTeam *)team certificate:(ALTCertificate *)certificate +{ + self = [super init]; + if (self) + { + _team = team; + _certificate = certificate; + } + + return self; +} + +- (NSProgress *)signAppAtURL:(NSURL *)appURL provisioningProfiles:(NSArray *)profiles completionHandler:(void (^)(BOOL success, NSError *error))completionHandler +{ + NSProgress *progress = [NSProgress discreteProgressWithTotalUnitCount:1]; + + NSURL *ipaURL = nil; + NSURL *appBundleURL = nil; + + void (^finish)(BOOL, NSError *) = ^(BOOL success, NSError *error) { + if (ipaURL != nil) + { + NSError *removeError = nil; + if (![[NSFileManager defaultManager] removeItemAtURL:[ipaURL URLByDeletingLastPathComponent] error:&removeError]) + { + NSLog(@"Failed to clean up after resigning. %@", removeError); + } + } + + completionHandler(success, error); + }; + + __block NSError *error = nil; + + if ([appURL.pathExtension.lowercaseString isEqualToString:@"ipa"]) + { + ipaURL = appURL; + + NSURL *outputDirectoryURL = [[appURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:[[NSUUID UUID] UUIDString] isDirectory:YES]; + if (![[NSFileManager defaultManager] createDirectoryAtURL:outputDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error]) + { + finish(NO, error); + return progress; + } + + appBundleURL = [[NSFileManager defaultManager] unzipAppBundleAtURL:appURL toDirectory:outputDirectoryURL error:&error]; + if (appBundleURL == nil) + { + finish(NO, [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorMissingAppBundle userInfo:@{NSUnderlyingErrorKey: error}]); + return progress; + } + } + else + { + appBundleURL = appURL; + } + + NSBundle *appBundle = [NSBundle bundleWithURL:appBundleURL]; + if (appBundle == nil) + { + finish(NO, [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorInvalidApp userInfo:nil]); + return progress; + } + + ALTApplication *application = [[ALTApplication alloc] initWithFileURL:appBundleURL]; + if (application == nil) + { + finish(NO, [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorInvalidApp userInfo:nil]); + return progress; + } + + NSDirectoryEnumerator *countEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:appURL + includingPropertiesForKeys:@[NSURLIsDirectoryKey] + options:0 + errorHandler:^BOOL(NSURL * _Nonnull url, NSError * _Nonnull error) { + if (error) { + NSLog(@"[Error] %@ (%@)", error, url); + return NO; + } + + return YES; + }]; + + NSInteger totalCount = 0; + for (NSURL *__unused fileURL in countEnumerator) + { + NSNumber *isDirectory = nil; + if (![fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] || [isDirectory boolValue]) + { + continue; + } + + // Ignore CodeResources files. + if ([[fileURL lastPathComponent] isEqualToString:@"CodeResources"]) + { + continue; + } + + totalCount++; + } + + progress.totalUnitCount = totalCount; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + NSMutableDictionary *entitlementsByFileURL = [NSMutableDictionary dictionary]; + + ALTProvisioningProfile *(^profileForApp)(ALTApplication *) = ^ALTProvisioningProfile *(ALTApplication *app) { + // Assume for now that apps don't have 100s of app extensions 🤷‍♂️ + for (ALTProvisioningProfile *profile in profiles) + { + if ([profile.bundleIdentifier isEqualToString:app.bundleIdentifier]) + { + return profile; + } + } + + return profiles.firstObject; + }; + + NSError * (^prepareApp)(ALTApplication *) = ^NSError *(ALTApplication *app) { + ALTProvisioningProfile *profile = profileForApp(app); + if (profile == nil) + { + return [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorMissingProvisioningProfile userInfo:nil]; + } + + NSURL *profileURL = [app.fileURL URLByAppendingPathComponent:@"embedded.mobileprovision"]; + [profile.data writeToURL:profileURL atomically:YES]; + + NSData *entitlementsData = [NSPropertyListSerialization dataWithPropertyList:profile.entitlements format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]; + if (entitlementsData == nil) + { + return error; + } + + NSString *entitlements = [[NSString alloc] initWithData:entitlementsData encoding:NSUTF8StringEncoding]; + entitlementsByFileURL[app.fileURL] = entitlements; + + return nil; + }; + + NSError *prepareError = prepareApp(application); + if (prepareError != nil) + { + finish(NO, prepareError); + return; + } + + NSURL *pluginsURL = [appBundle builtInPlugInsURL]; + + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:pluginsURL + includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil]; + + for (NSURL *extensionURL in enumerator) + { + ALTApplication *appExtension = [[ALTApplication alloc] initWithFileURL:extensionURL]; + if (appExtension == nil) + { + prepareError = [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorInvalidApp userInfo:nil]; + break; + } + + NSError *error = prepareApp(appExtension); + if (error != nil) + { + prepareError = error; + break; + } + } + + if (prepareError != nil) + { + finish(NO, prepareError); + return; + } + + + // Sign application + ldid::DiskFolder appBundle(application.fileURL.fileSystemRepresentation); + std::string key = CertificatesContent(self.certificate); + + ldid::Sign("", appBundle, key, "", + ldid::fun([&](const std::string &path, const std::string &binaryEntitlements) -> std::string { + NSString *filename = [NSString stringWithCString:path.c_str() encoding:NSUTF8StringEncoding]; + + NSURL *fileURL = nil; + + if (filename.length == 0) + { + fileURL = application.fileURL; + } + else + { + fileURL = [application.fileURL URLByAppendingPathComponent:filename isDirectory:YES]; + } + + NSString *entitlements = entitlementsByFileURL[fileURL]; + return entitlements.UTF8String; + }), + ldid::fun([&](const std::string &string) { + progress.completedUnitCount += 1; + }), + ldid::fun([&](const double signingProgress) { + })); + + + // Dispatch after to allow time to finish signing binary. + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (ipaURL != nil) + { + NSURL *resignedIPAURL = [[NSFileManager defaultManager] zipAppBundleAtURL:appBundleURL error:&error]; + + if (![[NSFileManager defaultManager] replaceItemAtURL:ipaURL withItemAtURL:resignedIPAURL backupItemName:nil options:0 resultingItemURL:nil error:&error]) + { + finish(NO, error); + } + } + + finish(YES, nil); + }); + }); + + return progress; +} + +@end diff --git a/AltSign/ALTTeam.h b/AltSign/ALTTeam.h new file mode 100644 index 0000000..311cc68 --- /dev/null +++ b/AltSign/ALTTeam.h @@ -0,0 +1,36 @@ +// +// ALTTeam.h +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +@class ALTAccount; + +typedef NS_ENUM(int16_t, ALTTeamType) +{ + ALTTeamTypeUnknown = 0, + ALTTeamTypeFree = 1, + ALTTeamTypeIndividual = 2, + ALTTeamTypeOrganization = 3, +}; + +NS_ASSUME_NONNULL_BEGIN + +@interface ALTTeam : NSObject + +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSString *identifier; +@property (nonatomic) ALTTeamType type; + +@property (nonatomic) ALTAccount *account; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithName:(NSString *)name identifier:(NSString *)identifier type:(ALTTeamType)type account:(ALTAccount *)account NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/ALTTeam.m b/AltSign/ALTTeam.m new file mode 100644 index 0000000..543b579 --- /dev/null +++ b/AltSign/ALTTeam.m @@ -0,0 +1,93 @@ +// +// ALTTeam.m +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "ALTTeam.h" + +@implementation ALTTeam + +- (instancetype)initWithName:(NSString *)name identifier:(NSString *)identifier type:(ALTTeamType)type account:(ALTAccount *)account +{ + self = [super init]; + if (self) + { + _name = [name copy]; + _identifier = [identifier copy]; + _type = type; + _account = account; + } + + return self; +} + +- (nullable instancetype)initWithAccount:(ALTAccount *)account responseDictionary:(NSDictionary *)responseDictionary +{ + NSString *name = responseDictionary[@"name"]; + NSString *identifier = responseDictionary[@"teamId"]; + NSString *teamType = responseDictionary[@"type"]; + + if (name == nil || identifier == nil || teamType == nil) + { + return nil; + } + + ALTTeamType type = ALTTeamTypeUnknown; + + if ([teamType isEqualToString:@"Company/Organization"]) + { + type = ALTTeamTypeOrganization; + } + else if ([teamType isEqualToString:@"Individual"]) + { + NSArray *memberships = responseDictionary[@"memberships"]; + + NSDictionary *membership = memberships.firstObject; + NSString *name = membership[@"name"]; + + if (memberships.count == 1 && [name.lowercaseString containsString:@"free"]) + { + type = ALTTeamTypeFree; + } + else + { + type = ALTTeamTypeIndividual; + } + } + else + { + type = ALTTeamTypeUnknown; + } + + self = [self initWithName:name identifier:identifier type:type account:account]; + return self; +} + +#pragma mark - NSObject - + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, Name: %@>", NSStringFromClass([self class]), self, self.name]; +} + +- (BOOL)isEqual:(id)object +{ + ALTTeam *team = (ALTTeam *)object; + if (![team isKindOfClass:[ALTTeam class]]) + { + return NO; + } + + BOOL isEqual = [self.identifier isEqualToString:team.identifier]; + return isEqual; +} + +- (NSUInteger)hash +{ + return self.identifier.hash; +} + +@end diff --git a/AltSign/AltSign.h b/AltSign/AltSign.h new file mode 100644 index 0000000..c18fa50 --- /dev/null +++ b/AltSign/AltSign.h @@ -0,0 +1,39 @@ +// +// AltSign.h +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +// Apple API +#import +#import +#import + +// Signing +#import + +// Model +#import +#import +#import +#import +#import +#import +#import +#import +#import + +// Categories +#import +#import + +// Capabilities +#import + +//! Project version number for AltSign. +FOUNDATION_EXPORT double AltSignVersionNumber; + +//! Project version string for AltSign. +FOUNDATION_EXPORT const unsigned char AltSignVersionString[]; diff --git a/AltSign/NSError+ALTErrors.h b/AltSign/NSError+ALTErrors.h new file mode 100644 index 0000000..0a664e2 --- /dev/null +++ b/AltSign/NSError+ALTErrors.h @@ -0,0 +1,60 @@ +// +// NSError+ALTErrors.h +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +extern NSErrorDomain const AltSignErrorDomain; +typedef NS_ERROR_ENUM(AltSignErrorDomain, ALTError) +{ + ALTErrorUnknown, + ALTErrorInvalidApp, + ALTErrorMissingAppBundle, + ALTErrorMissingInfoPlist, + ALTErrorMissingProvisioningProfile, +}; + +extern NSErrorDomain const ALTAppleAPIErrorDomain; +typedef NS_ERROR_ENUM(ALTAppleAPIErrorDomain, ALTAppleAPIError) +{ + ALTAppleAPIErrorUnknown, + ALTAppleAPIErrorInvalidParameters, + + ALTAppleAPIErrorIncorrectCredentials, + ALTAppleAPIErrorAppSpecificPasswordRequired, + + ALTAppleAPIErrorNoTeams, + + ALTAppleAPIErrorInvalidDeviceID, + ALTAppleAPIErrorDeviceAlreadyRegistered, + + ALTAppleAPIErrorInvalidCertificateRequest, + ALTAppleAPIErrorCertificateDoesNotExist, + + ALTAppleAPIErrorInvalidAppIDName, + ALTAppleAPIErrorInvalidBundleIdentifier, + ALTAppleAPIErrorBundleIdentifierUnavailable, + ALTAppleAPIErrorAppIDDoesNotExist, + + ALTAppleAPIErrorInvalidAppGroup, + ALTAppleAPIErrorAppGroupDoesNotExist, + + ALTAppleAPIErrorInvalidProvisioningProfileIdentifier, + ALTAppleAPIErrorProvisioningProfileDoesNotExist, + + ALTAppleAPIErrorRequiresTwoFactorAuthentication, + ALTAppleAPIErrorIncorrectVerificationCode, + ALTAppleAPIErrorAuthenticationHandshakeFailed, +}; + +NS_ASSUME_NONNULL_BEGIN + +@interface NSError (ALTError) + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/NSError+ALTErrors.m b/AltSign/NSError+ALTErrors.m new file mode 100644 index 0000000..7d1f7a6 --- /dev/null +++ b/AltSign/NSError+ALTErrors.m @@ -0,0 +1,128 @@ +// +// NSError+ALTError.m +// AltSign +// +// Created by Riley Testut on 5/10/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "NSError+ALTErrors.h" + +NSErrorDomain const AltSignErrorDomain = @"com.rileytestut.AltSign"; +NSErrorDomain const ALTAppleAPIErrorDomain = @"com.rileytestut.ALTAppleAPI"; + +@implementation NSError (ALTError) + ++ (void)load +{ + [NSError setUserInfoValueProviderForDomain:AltSignErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) { + if ([userInfoKey isEqualToString:NSLocalizedFailureReasonErrorKey]) + { + return [error alt_localizedFailureReason]; + } + + return nil; + }]; + + [NSError setUserInfoValueProviderForDomain:ALTAppleAPIErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) { + if ([userInfoKey isEqualToString:NSLocalizedDescriptionKey]) + { + return [error alt_appleapi_localizedDescription]; + } + + return nil; + }]; +} + +- (nullable NSString *)alt_localizedFailureReason +{ + switch ((ALTError)self.code) + { + case ALTErrorUnknown: + return NSLocalizedString(@"An unknown error occured.", @""); + + case ALTErrorInvalidApp: + return NSLocalizedString(@"The app is invalid.", @""); + + case ALTErrorMissingAppBundle: + return NSLocalizedString(@"The provided .ipa does not contain an app bundle.", @""); + + case ALTErrorMissingInfoPlist: + return NSLocalizedString(@"The provided app is missing its Info.plist.", @""); + + case ALTErrorMissingProvisioningProfile: + return NSLocalizedString(@"Could not find matching provisioning profile.", @""); + } + + return nil; +} + +- (nullable NSString *)alt_appleapi_localizedDescription +{ + switch ((ALTAppleAPIError)self.code) + { + case ALTAppleAPIErrorUnknown: + return NSLocalizedString(@"An unknown error occured.", @""); + + case ALTAppleAPIErrorInvalidParameters: + return NSLocalizedString(@"The provided parameters are invalid.", @""); + + case ALTAppleAPIErrorIncorrectCredentials: + return NSLocalizedString(@"Incorrect Apple ID or password.", @""); + + case ALTAppleAPIErrorNoTeams: + return NSLocalizedString(@"You are not a member of any development teams.", @""); + + case ALTAppleAPIErrorAppSpecificPasswordRequired: + return NSLocalizedString(@"An app-specific password is required. You can create one at appleid.apple.com.", @""); + + case ALTAppleAPIErrorInvalidDeviceID: + return NSLocalizedString(@"This device's UDID is invalid.", @""); + + case ALTAppleAPIErrorDeviceAlreadyRegistered: + return NSLocalizedString(@"This device is already registered with this team.", @""); + + case ALTAppleAPIErrorInvalidCertificateRequest: + return NSLocalizedString(@"The certificate request is invalid.", @""); + + case ALTAppleAPIErrorCertificateDoesNotExist: + return NSLocalizedString(@"There is no certificate with the requested serial number for this team.", @""); + + case ALTAppleAPIErrorInvalidAppIDName: + return NSLocalizedString(@"The name for this app is invalid.", @""); + + case ALTAppleAPIErrorInvalidBundleIdentifier: + return NSLocalizedString(@"The bundle identifier for this app is invalid.", @""); + + case ALTAppleAPIErrorBundleIdentifierUnavailable: + return NSLocalizedString(@"The bundle identifier for this app has already been registered.", @""); + + case ALTAppleAPIErrorAppIDDoesNotExist: + return NSLocalizedString(@"There is no App ID with the requested identifier on this team.", @""); + + case ALTAppleAPIErrorInvalidAppGroup: + return NSLocalizedString(@"The provided app group is invalid.", @""); + + case ALTAppleAPIErrorAppGroupDoesNotExist: + return NSLocalizedString(@"App group does not exist", @""); + + case ALTAppleAPIErrorInvalidProvisioningProfileIdentifier: + return NSLocalizedString(@"The identifier for the requested provisioning profile is invalid.", @""); + + case ALTAppleAPIErrorProvisioningProfileDoesNotExist: + return NSLocalizedString(@"There is no provisioning profile with the requested identifier on this team.", @""); + + case ALTAppleAPIErrorRequiresTwoFactorAuthentication: + return NSLocalizedString(@"This account requires signing in with two-factor authentication.", @""); + + case ALTAppleAPIErrorIncorrectVerificationCode: + return NSLocalizedString(@"Incorrect verification code.", @""); + + case ALTAppleAPIErrorAuthenticationHandshakeFailed: + return NSLocalizedString(@"Failed to perform authentication handshake with server.", @""); + } + + return nil; +} + +@end diff --git a/AltSign/NSFileManager+Apps.h b/AltSign/NSFileManager+Apps.h new file mode 100644 index 0000000..488b003 --- /dev/null +++ b/AltSign/NSFileManager+Apps.h @@ -0,0 +1,20 @@ +// +// NSFileManager+Apps.h +// AltSign +// +// Created by Riley Testut on 5/28/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSFileManager (Apps) + +- (nullable NSURL *)unzipAppBundleAtURL:(NSURL *)ipaURL toDirectory:(NSURL *)directoryURL error:(NSError **)error; +- (nullable NSURL *)zipAppBundleAtURL:(NSURL *)appBundleURL error:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AltSign/NSFileManager+Apps.m b/AltSign/NSFileManager+Apps.m new file mode 100644 index 0000000..d2da4cf --- /dev/null +++ b/AltSign/NSFileManager+Apps.m @@ -0,0 +1,415 @@ +// +// NSFileManager+Apps.m +// AltSign +// +// Created by Riley Testut on 5/28/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +#import "NSFileManager+Apps.h" + +#import "NSError+ALTErrors.h" + +#include "zip.h" +#include "unzip.h" + +int ALTReadBufferSize = 8192; +int ALTMaxFilenameLength = 512; +char ALTDirectoryDeliminator = '/'; + +#define READ_BUFFER_SIZE 8192 +#define MAX_FILENAME 512 + +@implementation NSFileManager (Apps) + +- (nullable NSURL *)unzipAppBundleAtURL:(NSURL *)ipaURL toDirectory:(NSURL *)directoryURL error:(NSError **)error +{ + unzFile zipFile = unzOpen(ipaURL.fileSystemRepresentation); + if (zipFile == NULL) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileNoSuchFileError userInfo:@{NSURLErrorKey: ipaURL}]; + return nil; + } + + FILE *outputFile = nil; + + void (^finish)(void) = ^{ + if (outputFile != nil) + { + fclose(outputFile); + } + + unzCloseCurrentFile(zipFile); + unzClose(zipFile); + }; + + unz_global_info zipInfo; + if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadCorruptFileError userInfo:@{NSURLErrorKey: ipaURL}]; + + finish(); + return nil; + } + + NSProgress *progress = [NSProgress progressWithTotalUnitCount:zipInfo.number_entry]; + + char buffer[ALTReadBufferSize]; + + for (int i = 0; i < zipInfo.number_entry; i++) + { + unz_file_info info; + char cFilename[ALTMaxFilenameLength]; + + if (unzGetCurrentFileInfo(zipFile, &info, cFilename, ALTMaxFilenameLength, NULL, 0, NULL, 0) != UNZ_OK) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:@{NSURLErrorKey: ipaURL}]; + + finish(); + return nil; + } + + NSString *filename = [[NSString alloc] initWithCString:cFilename encoding:NSUTF8StringEncoding]; + if ([filename hasPrefix:@"__MACOSX"]) + { + if (i + 1 < zipInfo.number_entry) + { + if (unzGoToNextFile(zipFile) != UNZ_OK) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:@{NSFilePathErrorKey: filename}]; + + finish(); + return nil; + } + } + + continue; + } + + NSError *(^createDirectory)(NSURL *) = ^NSError *(NSURL *directoryURL) { + NSError *error = nil; + if (![self createDirectoryAtURL:directoryURL withIntermediateDirectories:YES attributes:nil error:&error]) + { + return error; + } + + return nil; + }; + + NSURL *fileURL = [directoryURL URLByAppendingPathComponent:filename]; + + if ([filename characterAtIndex:filename.length - 1] == ALTDirectoryDeliminator) + { + // Directory + + NSError *directoryError = createDirectory(fileURL); + if (directoryError != nil) + { + *error = directoryError; + return nil; + } + } + else + { + // File + if (unzOpenCurrentFile(zipFile) != UNZ_OK) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:@{NSURLErrorKey: fileURL}]; + + finish(); + return nil; + } + + NSURL *parentDirectory = [fileURL URLByDeletingLastPathComponent]; + if (![[NSFileManager defaultManager] fileExistsAtPath:parentDirectory.path]) + { + NSError *directoryError = createDirectory(parentDirectory); + if (directoryError != nil) + { + *error = directoryError; + return nil; + } + } + + outputFile = fopen(fileURL.fileSystemRepresentation, "wb"); + if (outputFile == NULL) + { + NSError *underlyingError = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:@{NSURLErrorKey: fileURL}]; + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSURLErrorKey: fileURL, NSUnderlyingErrorKey: underlyingError}]; + + finish(); + return nil; + } + + int result = UNZ_OK; + + do + { + result = unzReadCurrentFile(zipFile, buffer, ALTReadBufferSize); + + if (result < 0) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:@{NSURLErrorKey: fileURL}]; + + finish(); + return nil; + } + + size_t count = fwrite(buffer, result, 1, outputFile); + if (result > 0 && count != 1) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSURLErrorKey: fileURL}]; + + finish(); + return nil; + } + + } while (result > 0); + + short permissions = (info.external_fa >> 16) & 0x01FF; + if (![self setAttributes:@{NSFilePosixPermissions: @(permissions)} ofItemAtPath:fileURL.path error:error]) + { + finish(); + return nil; + } + + fclose(outputFile); + outputFile = NULL; + } + + unzCloseCurrentFile(zipFile); + + progress.completedUnitCount += 1; + + if (i + 1 < zipInfo.number_entry) + { + if (unzGoToNextFile(zipFile) != UNZ_OK) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:@{NSURLErrorKey: fileURL}]; + + finish(); + return nil; + } + } + } + + finish(); + + NSURL *payloadDirectory = [directoryURL URLByAppendingPathComponent:@"Payload"]; + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:payloadDirectory.path error:error]; + if (contents == nil) + { + finish(); + return nil; + } + + for (NSString *filename in contents) + { + if ([filename.pathExtension.lowercaseString isEqualToString:@"app"]) + { + NSURL *appBundleURL = [payloadDirectory URLByAppendingPathComponent:filename]; + NSURL *outputURL = [directoryURL URLByAppendingPathComponent:filename]; + + if (![[NSFileManager defaultManager] moveItemAtURL:appBundleURL toURL:outputURL error:error]) + { + finish(); + return nil; + } + + NSError *deleteError = nil; + if (![[NSFileManager defaultManager] removeItemAtURL:payloadDirectory error:&deleteError]) + { + *error = deleteError; + + finish(); + return nil; + } + + return outputURL; + } + } + + *error = [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorMissingAppBundle userInfo:@{NSURLErrorKey: ipaURL}]; + return nil; +} + +- (NSURL *)zipAppBundleAtURL:(NSURL *)appBundleURL error:(NSError **)error +{ + NSString *appBundleFilename = [appBundleURL lastPathComponent]; + NSString *appName = [appBundleFilename stringByDeletingPathExtension]; + + NSString *ipaName = [NSString stringWithFormat:@"%@.ipa", appName]; + NSURL *ipaURL = [[appBundleURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:ipaName]; + + if ([self fileExistsAtPath:ipaURL.path]) + { + if (![self removeItemAtURL:ipaURL error:error]) + { + return nil; + } + } + + zipFile zipFile = zipOpen(ipaURL.fileSystemRepresentation, APPEND_STATUS_CREATE); + if (zipFile == nil) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSURLErrorKey: ipaURL}]; + return nil; + } + + NSURL *payloadDirectory = [NSURL fileURLWithPath:@"Payload" isDirectory:YES]; + NSURL *appBundleDirectory = [payloadDirectory URLByAppendingPathComponent:appBundleFilename isDirectory:YES]; + + NSDirectoryEnumerator *countEnumerator = [self enumeratorAtURL:appBundleURL + includingPropertiesForKeys:@[] + options:0 + errorHandler:^BOOL(NSURL * _Nonnull url, NSError * _Nonnull error) { + if (error) { + NSLog(@"[Error] %@ (%@)", error, url); + return NO; + } + + return YES; + }]; + + NSInteger totalCount = 0; + for (NSURL *__unused fileURL in countEnumerator) + { + totalCount++; + } + + NSProgress *progress = [NSProgress progressWithTotalUnitCount:totalCount + 2]; // We add two extra entries at the end. + + NSDirectoryEnumerator *enumerator = [self enumeratorAtURL:appBundleURL + includingPropertiesForKeys:@[NSURLIsDirectoryKey] + options:0 + errorHandler:^BOOL(NSURL * _Nonnull url, NSError * _Nonnull error) { + if (error) { + NSLog(@"[Error] %@ (%@)", error, url); + return NO; + } + + return YES; + }]; + + BOOL success = YES; + + for (NSURL *fileURL in enumerator) + { + NSNumber *isDirectory = nil; + if (![fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:error]) + { + success = NO; + break; + } + + if (![self writeItemAtURL:fileURL toZipFile:&zipFile depth:enumerator.level relativeURL:appBundleDirectory isDirectory:[isDirectory boolValue] error:error]) + { + success = NO; + break; + } + + progress.completedUnitCount += 1; + } + + if (success) + { + if (![self writeItemAtURL:payloadDirectory toZipFile:&zipFile depth:1 relativeURL:nil isDirectory:YES error:error]) + { + success = NO; + } + + progress.completedUnitCount += 1; + + if (![self writeItemAtURL:appBundleDirectory toZipFile:&zipFile depth:2 relativeURL:nil isDirectory:YES error:error]) + { + success = NO; + } + + progress.completedUnitCount += 1; + } + + zipClose(zipFile, NULL); + + return success ? ipaURL : nil; +} + +- (BOOL)writeItemAtURL:(NSURL *)fileURL toZipFile:(zipFile *)zipFile depth:(NSInteger)depth relativeURL:(nullable NSURL *)relativeURL isDirectory:(BOOL)isDirectory error:(NSError **)error +{ + NSArray *components = fileURL.pathComponents; + NSArray *relativeComponents = [components subarrayWithRange:NSMakeRange(components.count - depth, depth)]; + + NSString *relativePath = [relativeComponents componentsJoinedByString:@"/"]; + NSString *filename = nil; + + if (relativeURL != nil) + { + NSURL *relatedURL = [relativeURL URLByAppendingPathComponent:relativePath]; + filename = relatedURL.relativePath; + } + else + { + filename = relativePath; + } + + NSData *data = nil; + zip_fileinfo fileInfo = {}; + + if (isDirectory) + { + if ([filename hasPrefix:@"/"]) + { + filename = [filename stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; + } + + if (![filename hasSuffix:@"/"]) + { + filename = [filename stringByAppendingString:@"/"]; + } + } + else + { + NSDictionary *attributes = [self attributesOfItemAtPath:fileURL.path error:error]; + if (attributes == nil) + { + return NO; + } + + NSNumber *permissionsValue = attributes[NSFilePosixPermissions]; + if (permissionsValue == nil) + { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:@{NSURLErrorKey: fileURL}]; + return NO; + } + + short permissions = permissionsValue.shortValue; + NSInteger shiftedPermissions = 0100000 + permissions; + uLong permissionsLong = @(shiftedPermissions).unsignedLongValue; + + fileInfo.external_fa = (unsigned int)(permissionsLong << 16L); + + data = [NSData dataWithContentsOfURL:fileURL options:0 error:error]; + if (data == nil) + { + return NO; + } + } + + if (zipOpenNewFileInZip(*zipFile, filename.fileSystemRepresentation, &fileInfo, + NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) + { + zipCloseFileInZip(*zipFile); + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSFilePathErrorKey: filename}]; + return NO; + } + + if (zipWriteInFileInZip(*zipFile, data.bytes, (unsigned int)data.length) != ZIP_OK) + { + zipCloseFileInZip(*zipFile); + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:@{NSFilePathErrorKey: filename}]; + return NO; + } + + return YES; +} + +@end diff --git a/AltSign/ldid/ldid.cpp b/AltSign/ldid/ldid.cpp new file mode 100644 index 0000000..e91a1e9 --- /dev/null +++ b/AltSign/ldid/ldid.cpp @@ -0,0 +1,119 @@ +// +// ldid.cpp +// websign +// +// ldid implentation file wrapper used to add our own logic without modifying ldid source. +// +// Created by Riley Testut on 3/12/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +// Redefine ldid's main function to ldid_main to prevent duplicate main declarations. +#define main ldid_main + +#include + +// Undefine our hacky main redefinition. +#undef main + +namespace ldid +{ + // Based heavily on ldid::Sign executable locating logic. + std::string ExecutablePath(std::string bundlePath) + { + auto folder = ldid::DiskFolder(bundlePath); + + std::string executable; + + bool mac(false); + + std::string info("Info.plist"); + if (!folder.Look(info) && folder.Look("Resources/" + info)) { + mac = true; + info = "Resources/" + info; + } + + folder.Open(info, fun([&](std::streambuf &buffer, size_t length, const void *flag) { + plist_d(buffer, length, fun([&](plist_t node) { + executable = plist_s(plist_dict_get_item(node, "CFBundleExecutable")); + })); + })); + + if (!mac && folder.Look("MacOS/" + executable)) { + executable = "MacOS/" + executable; + mac = true; + } + + return executable; + } + + // Based heavily on ldid's -e argument logic. + std::string Entitlements(std::string path) + { + struct stat info; + _syscall(stat(path.c_str(), &info)); + + if (S_ISDIR(info.st_mode)) + { + path += "/" + ExecutablePath(path); + } + + std::stringstream stringstream; + + Map mapping(path, false); + FatHeader fat_header(mapping.data(), mapping.size()); + + _foreach (mach_header, fat_header.GetMachHeaders()) + { + struct linkedit_data_command *signature(NULL); + + _foreach (load_command, mach_header.GetLoadCommands()) + { + uint32_t cmd(mach_header.Swap(load_command->cmd)); + if (cmd == LC_CODE_SIGNATURE) + { + signature = reinterpret_cast(load_command); + } + } + + if (signature != NULL) + { + uint32_t data = mach_header.Swap(signature->dataoff); + + uint8_t *top = reinterpret_cast(mach_header.GetBase()); + uint8_t *blob = top + data; + struct SuperBlob *super = reinterpret_cast(blob); + + for (size_t index(0); index != Swap(super->count); ++index) + { + if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) + { + uint32_t begin = Swap(super->index[index].offset); + struct Blob *entitlements = reinterpret_cast(blob + begin); + + char *bytes = (char *)(entitlements + 1); + int size = Swap(entitlements->length) - sizeof(*entitlements); + + for (int i = 0; i < size; i++) + { + char byte = bytes[i]; + stringstream << byte; + } + + if (size > 0) + { + auto entitlementsString = stringstream.str(); + + // One valid mach_header is all we need to retrieve entitlements, so return to stop iterating over the next ones. + return entitlementsString; + } + } + } + } + } + + // No entitlements found in any mach_header, so return empty string. + return ""; + } + +} diff --git a/AltSign/ldid/ldid.hpp b/AltSign/ldid/ldid.hpp new file mode 100644 index 0000000..0a148ec --- /dev/null +++ b/AltSign/ldid/ldid.hpp @@ -0,0 +1,18 @@ +// +// ldid.hpp +// websign +// +// ldid header file wrapper used to add our own logic without modifying ldid source. +// +// Created by Riley Testut on 3/12/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +#pragma once + +#include + +namespace ldid +{ + std::string Entitlements(std::string path); +} diff --git a/Dependencies/Individual/libcrypto.a b/Dependencies/Individual/libcrypto.a new file mode 100644 index 0000000..9de1bb8 Binary files /dev/null and b/Dependencies/Individual/libcrypto.a differ diff --git a/Dependencies/Individual/libimobiledevice.a b/Dependencies/Individual/libimobiledevice.a new file mode 100644 index 0000000..f8bd4f6 Binary files /dev/null and b/Dependencies/Individual/libimobiledevice.a differ diff --git a/Dependencies/Individual/libplist.a b/Dependencies/Individual/libplist.a new file mode 100644 index 0000000..c632911 Binary files /dev/null and b/Dependencies/Individual/libplist.a differ diff --git a/Dependencies/Individual/libssl.a b/Dependencies/Individual/libssl.a new file mode 100644 index 0000000..7d01bea Binary files /dev/null and b/Dependencies/Individual/libssl.a differ diff --git a/Dependencies/Individual/libusbmuxd.a b/Dependencies/Individual/libusbmuxd.a new file mode 100644 index 0000000..ccfc3b4 Binary files /dev/null and b/Dependencies/Individual/libusbmuxd.a differ diff --git a/Dependencies/README.md b/Dependencies/README.md new file mode 100644 index 0000000..28bc811 --- /dev/null +++ b/Dependencies/README.md @@ -0,0 +1,7 @@ +# Dependencies + +**Q:** Why are these precompiled? +**A:** I tried to add them as a dependency in the code. I tried for hours. I couldn't. These precompiled libraries come from brew.sh since I just wasn't able to compile them myself. + +**Q:** What's "Individual" and what's "dependencies.deb"? +**A:** When I individually linked the libraries, Xcode always linked the dynamic libraries as well, which I didn't want. So I packed all of the objects inside of one archive and linked that instead, which worked diff --git a/Dependencies/dependencies.a b/Dependencies/dependencies.a new file mode 100644 index 0000000..843a961 Binary files /dev/null and b/Dependencies/dependencies.a differ diff --git a/SAMKeychain/LICENSE b/SAMKeychain/LICENSE new file mode 100644 index 0000000..21fe4ef --- /dev/null +++ b/SAMKeychain/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2010-2016 Sam Soffes, http://soff.es + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/SAMKeychain/SAMKeychain.h b/SAMKeychain/SAMKeychain.h new file mode 100644 index 0000000..2af305d --- /dev/null +++ b/SAMKeychain/SAMKeychain.h @@ -0,0 +1,203 @@ +// +// SAMKeychain.h +// SAMKeychain +// +// Created by Sam Soffes on 5/19/10. +// Copyright (c) 2010-2014 Sam Soffes. All rights reserved. +// + +#if __has_feature(modules) + @import Foundation; +#else + #import +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** + Error code specific to SAMKeychain that can be returned in NSError objects. + For codes returned by the operating system, refer to SecBase.h for your + platform. + */ +typedef NS_ENUM(OSStatus, SAMKeychainErrorCode) { + /** Some of the arguments were invalid. */ + SAMKeychainErrorBadArguments = -1001, +}; + +/** SAMKeychain error domain */ +extern NSString *const kSAMKeychainErrorDomain; + +/** Account name. */ +extern NSString *const kSAMKeychainAccountKey; + +/** + Time the item was created. + + The value will be a string. + */ +extern NSString *const kSAMKeychainCreatedAtKey; + +/** Item class. */ +extern NSString *const kSAMKeychainClassKey; + +/** Item description. */ +extern NSString *const kSAMKeychainDescriptionKey; + +/** Item label. */ +extern NSString *const kSAMKeychainLabelKey; + +/** Time the item was last modified. + + The value will be a string. + */ +extern NSString *const kSAMKeychainLastModifiedKey; + +/** Where the item was created. */ +extern NSString *const kSAMKeychainWhereKey; + +/** + Simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system + Keychain on Mac OS X and iOS. + + This was originally inspired by EMKeychain and SDKeychain (both of which are now gone). Thanks to the authors. + SAMKeychain has since switched to a simpler implementation that was abstracted from [SSToolkit](http://sstoolk.it). + */ +@interface SAMKeychain : NSObject + +#pragma mark - Classic methods + +/** + Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a + password for the given parameters. + + @param serviceName The service for which to return the corresponding password. + + @param account The account for which to return the corresponding password. + + @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't + have a password for the given parameters. + */ ++ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account; ++ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none))); + +/** + Returns a nsdata containing the password for a given account and service, or `nil` if the Keychain doesn't have a + password for the given parameters. + + @param serviceName The service for which to return the corresponding password. + + @param account The account for which to return the corresponding password. + + @return Returns a nsdata containing the password for a given account and service, or `nil` if the Keychain doesn't + have a password for the given parameters. + */ ++ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account; ++ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none))); + + +/** + Deletes a password from the Keychain. + + @param serviceName The service for which to delete the corresponding password. + + @param account The account for which to delete the corresponding password. + + @return Returns `YES` on success, or `NO` on failure. + */ ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account; ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none))); + + +/** + Sets a password in the Keychain. + + @param password The password to store in the Keychain. + + @param serviceName The service for which to set the corresponding password. + + @param account The account for which to set the corresponding password. + + @return Returns `YES` on success, or `NO` on failure. + */ ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account; ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none))); + +/** + Sets a password in the Keychain. + + @param password The password to store in the Keychain. + + @param serviceName The service for which to set the corresponding password. + + @param account The account for which to set the corresponding password. + + @return Returns `YES` on success, or `NO` on failure. + */ ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account; ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none))); + +/** + Returns an array containing the Keychain's accounts, or `nil` if the Keychain has no accounts. + + See the `NSString` constants declared in SAMKeychain.h for a list of keys that can be used when accessing the + dictionaries returned by this method. + + @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any + accounts. The order of the objects in the array isn't defined. + */ ++ (nullable NSArray *> *)allAccounts; ++ (nullable NSArray *> *)allAccounts:(NSError *__autoreleasing *)error __attribute__((swift_error(none))); + + +/** + Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any + accounts for the given service. + + See the `NSString` constants declared in SAMKeychain.h for a list of keys that can be used when accessing the + dictionaries returned by this method. + + @param serviceName The service for which to return the corresponding accounts. + + @return An array of dictionaries containing the Keychain's accounts for a given `serviceName`, or `nil` if the Keychain + doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined. + */ ++ (nullable NSArray *> *)accountsForService:(nullable NSString *)serviceName; ++ (nullable NSArray *> *)accountsForService:(nullable NSString *)serviceName error:(NSError *__autoreleasing *)error __attribute__((swift_error(none))); + + +#pragma mark - Configuration + +#if __IPHONE_4_0 && TARGET_OS_IPHONE +/** + Returns the accessibility type for all future passwords saved to the Keychain. + + @return Returns the accessibility type. + + The return value will be `NULL` or one of the "Keychain Item Accessibility + Constants" used for determining when a keychain item should be readable. + + @see setAccessibilityType + */ ++ (CFTypeRef)accessibilityType; + +/** + Sets the accessibility type for all future passwords saved to the Keychain. + + @param accessibilityType One of the "Keychain Item Accessibility Constants" + used for determining when a keychain item should be readable. + + If the value is `NULL` (the default), the Keychain default will be used which + is highly insecure. You really should use at least `kSecAttrAccessibleAfterFirstUnlock` + for background applications or `kSecAttrAccessibleWhenUnlocked` for all + other applications. + + @see accessibilityType + */ ++ (void)setAccessibilityType:(CFTypeRef)accessibilityType; +#endif + +@end + +NS_ASSUME_NONNULL_END + +#import diff --git a/SAMKeychain/SAMKeychain.m b/SAMKeychain/SAMKeychain.m new file mode 100644 index 0000000..6d01d3d --- /dev/null +++ b/SAMKeychain/SAMKeychain.m @@ -0,0 +1,130 @@ +// +// SAMKeychain.m +// SAMKeychain +// +// Created by Sam Soffes on 5/19/10. +// Copyright (c) 2010-2014 Sam Soffes. All rights reserved. +// + +#import "SAMKeychain.h" +#import "SAMKeychainQuery.h" + +NSString *const kSAMKeychainErrorDomain = @"com.samsoffes.samkeychain"; +NSString *const kSAMKeychainAccountKey = @"acct"; +NSString *const kSAMKeychainCreatedAtKey = @"cdat"; +NSString *const kSAMKeychainClassKey = @"labl"; +NSString *const kSAMKeychainDescriptionKey = @"desc"; +NSString *const kSAMKeychainLabelKey = @"labl"; +NSString *const kSAMKeychainLastModifiedKey = @"mdat"; +NSString *const kSAMKeychainWhereKey = @"svce"; + +#if __IPHONE_4_0 && TARGET_OS_IPHONE + static CFTypeRef SAMKeychainAccessibilityType = NULL; +#endif + +@implementation SAMKeychain + ++ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account { + return [self passwordForService:serviceName account:account error:nil]; +} + + ++ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError *__autoreleasing *)error { + SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init]; + query.service = serviceName; + query.account = account; + [query fetch:error]; + return query.password; +} + ++ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account { + return [self passwordDataForService:serviceName account:account error:nil]; +} + ++ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error { + SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init]; + query.service = serviceName; + query.account = account; + [query fetch:error]; + + return query.passwordData; +} + + ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account { + return [self deletePasswordForService:serviceName account:account error:nil]; +} + + ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError *__autoreleasing *)error { + SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init]; + query.service = serviceName; + query.account = account; + return [query deleteItem:error]; +} + + ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account { + return [self setPassword:password forService:serviceName account:account error:nil]; +} + + ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError *__autoreleasing *)error { + SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init]; + query.service = serviceName; + query.account = account; + query.password = password; + return [query save:error]; +} + ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account { + return [self setPasswordData:password forService:serviceName account:account error:nil]; +} + + ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error { + SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init]; + query.service = serviceName; + query.account = account; + query.passwordData = password; + return [query save:error]; +} + ++ (nullable NSArray *)allAccounts { + return [self allAccounts:nil]; +} + + ++ (nullable NSArray *)allAccounts:(NSError *__autoreleasing *)error { + return [self accountsForService:nil error:error]; +} + + ++ (nullable NSArray *)accountsForService:(nullable NSString *)serviceName { + return [self accountsForService:serviceName error:nil]; +} + + ++ (nullable NSArray *)accountsForService:(nullable NSString *)serviceName error:(NSError *__autoreleasing *)error { + SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init]; + query.service = serviceName; + return [query fetchAll:error]; +} + + +#if __IPHONE_4_0 && TARGET_OS_IPHONE ++ (CFTypeRef)accessibilityType { + return SAMKeychainAccessibilityType; +} + + ++ (void)setAccessibilityType:(CFTypeRef)accessibilityType { + CFRetain(accessibilityType); + if (SAMKeychainAccessibilityType) { + CFRelease(SAMKeychainAccessibilityType); + } + SAMKeychainAccessibilityType = accessibilityType; +} +#endif + +@end diff --git a/SAMKeychain/SAMKeychainQuery.h b/SAMKeychain/SAMKeychainQuery.h new file mode 100644 index 0000000..f1b20f7 --- /dev/null +++ b/SAMKeychain/SAMKeychainQuery.h @@ -0,0 +1,147 @@ +// +// SAMKeychainQuery.h +// SAMKeychain +// +// Created by Caleb Davenport on 3/19/13. +// Copyright (c) 2013-2014 Sam Soffes. All rights reserved. +// + +#if __has_feature(modules) + @import Foundation; + @import Security; +#else + #import + #import +#endif + +NS_ASSUME_NONNULL_BEGIN + +#if __IPHONE_7_0 || __MAC_10_9 + // Keychain synchronization available at compile time + #define SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE 1 +#endif + +#if __IPHONE_3_0 || __MAC_10_9 + // Keychain access group available at compile time + #define SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE 1 +#endif + +#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE +typedef NS_ENUM(NSUInteger, SAMKeychainQuerySynchronizationMode) { + SAMKeychainQuerySynchronizationModeAny, + SAMKeychainQuerySynchronizationModeNo, + SAMKeychainQuerySynchronizationModeYes +}; +#endif + +/** + Simple interface for querying or modifying keychain items. + */ +@interface SAMKeychainQuery : NSObject + +/** kSecAttrAccount */ +@property (nonatomic, copy, nullable) NSString *account; + +/** kSecAttrService */ +@property (nonatomic, copy, nullable) NSString *service; + +/** kSecAttrLabel */ +@property (nonatomic, copy, nullable) NSString *label; + +#ifdef SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE +/** kSecAttrAccessGroup (only used on iOS) */ +@property (nonatomic, copy, nullable) NSString *accessGroup; +#endif + +#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE +/** kSecAttrSynchronizable */ +@property (nonatomic) SAMKeychainQuerySynchronizationMode synchronizationMode; +#endif + +/** Root storage for password information */ +@property (nonatomic, copy, nullable) NSData *passwordData; + +/** + This property automatically transitions between an object and the value of + `passwordData` using NSKeyedArchiver and NSKeyedUnarchiver. + */ +@property (nonatomic, copy, nullable) id passwordObject; + +/** + Convenience accessor for setting and getting a password string. Passes through + to `passwordData` using UTF-8 string encoding. + */ +@property (nonatomic, copy, nullable) NSString *password; + + +///------------------------ +/// @name Saving & Deleting +///------------------------ + +/** + Save the receiver's attributes as a keychain item. Existing items with the + given account, service, and access group will first be deleted. + + @param error Populated should an error occur. + + @return `YES` if saving was successful, `NO` otherwise. + */ +- (BOOL)save:(NSError **)error; + +/** + Delete keychain items that match the given account, service, and access group. + + @param error Populated should an error occur. + + @return `YES` if saving was successful, `NO` otherwise. + */ +- (BOOL)deleteItem:(NSError **)error; + + +///--------------- +/// @name Fetching +///--------------- + +/** + Fetch all keychain items that match the given account, service, and access + group. The values of `password` and `passwordData` are ignored when fetching. + + @param error Populated should an error occur. + + @return An array of dictionaries that represent all matching keychain items or + `nil` should an error occur. + The order of the items is not determined. + */ +- (nullable NSArray *> *)fetchAll:(NSError **)error; + +/** + Fetch the keychain item that matches the given account, service, and access + group. The `password` and `passwordData` properties will be populated unless + an error occurs. The values of `password` and `passwordData` are ignored when + fetching. + + @param error Populated should an error occur. + + @return `YES` if fetching was successful, `NO` otherwise. + */ +- (BOOL)fetch:(NSError **)error; + + +///----------------------------- +/// @name Synchronization Status +///----------------------------- + +#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE +/** + Returns a boolean indicating if keychain synchronization is available on the device at runtime. The #define + SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE is only for compile time. If you are checking for the presence of synchronization, + you should use this method. + + @return A value indicating if keychain synchronization is available + */ ++ (BOOL)isSynchronizationAvailable; +#endif + +@end + +NS_ASSUME_NONNULL_END diff --git a/SAMKeychain/SAMKeychainQuery.m b/SAMKeychain/SAMKeychainQuery.m new file mode 100644 index 0000000..00ecb80 --- /dev/null +++ b/SAMKeychain/SAMKeychainQuery.m @@ -0,0 +1,316 @@ +// +// SAMKeychainQuery.m +// SAMKeychain +// +// Created by Caleb Davenport on 3/19/13. +// Copyright (c) 2013-2014 Sam Soffes. All rights reserved. +// + +#import "SAMKeychainQuery.h" +#import "SAMKeychain.h" + +@implementation SAMKeychainQuery + +@synthesize account = _account; +@synthesize service = _service; +@synthesize label = _label; +@synthesize passwordData = _passwordData; + +#ifdef SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE +@synthesize accessGroup = _accessGroup; +#endif + +#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE +@synthesize synchronizationMode = _synchronizationMode; +#endif + +#pragma mark - Public + +- (BOOL)save:(NSError *__autoreleasing *)error { + OSStatus status = SAMKeychainErrorBadArguments; + if (!self.service || !self.account || !self.passwordData) { + if (error) { + *error = [[self class] errorWithCode:status]; + } + return NO; + } + NSMutableDictionary *query = nil; + NSMutableDictionary * searchQuery = [self query]; + status = SecItemCopyMatching((__bridge CFDictionaryRef)searchQuery, nil); + if (status == errSecSuccess) {//item already exists, update it! + query = [[NSMutableDictionary alloc]init]; + [query setObject:self.passwordData forKey:(__bridge id)kSecValueData]; +#if __IPHONE_4_0 && TARGET_OS_IPHONE + CFTypeRef accessibilityType = [SAMKeychain accessibilityType]; + if (accessibilityType) { + [query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible]; + } +#endif + status = SecItemUpdate((__bridge CFDictionaryRef)(searchQuery), (__bridge CFDictionaryRef)(query)); + }else if(status == errSecItemNotFound){//item not found, create it! + query = [self query]; + if (self.label) { + [query setObject:self.label forKey:(__bridge id)kSecAttrLabel]; + } + [query setObject:self.passwordData forKey:(__bridge id)kSecValueData]; +#if __IPHONE_4_0 && TARGET_OS_IPHONE + CFTypeRef accessibilityType = [SAMKeychain accessibilityType]; + if (accessibilityType) { + [query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible]; + } +#endif + status = SecItemAdd((__bridge CFDictionaryRef)query, NULL); + } + if (status != errSecSuccess && error != NULL) { + *error = [[self class] errorWithCode:status]; + } + return (status == errSecSuccess);} + + +- (BOOL)deleteItem:(NSError *__autoreleasing *)error { + OSStatus status = SAMKeychainErrorBadArguments; + if (!self.service || !self.account) { + if (error) { + *error = [[self class] errorWithCode:status]; + } + return NO; + } + + NSMutableDictionary *query = [self query]; +#if TARGET_OS_IPHONE + status = SecItemDelete((__bridge CFDictionaryRef)query); +#else + // On Mac OS, SecItemDelete will not delete a key created in a different + // app, nor in a different version of the same app. + // + // To replicate the issue, save a password, change to the code and + // rebuild the app, and then attempt to delete that password. + // + // This was true in OS X 10.6 and probably later versions as well. + // + // Work around it by using SecItemCopyMatching and SecKeychainItemDelete. + CFTypeRef result = NULL; + [query setObject:@YES forKey:(__bridge id)kSecReturnRef]; + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); + if (status == errSecSuccess) { + status = SecKeychainItemDelete((SecKeychainItemRef)result); + CFRelease(result); + } +#endif + + if (status != errSecSuccess && error != NULL) { + *error = [[self class] errorWithCode:status]; + } + + return (status == errSecSuccess); +} + + +- (nullable NSArray *)fetchAll:(NSError *__autoreleasing *)error { + NSMutableDictionary *query = [self query]; + [query setObject:@YES forKey:(__bridge id)kSecReturnAttributes]; + [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit]; +#if __IPHONE_4_0 && TARGET_OS_IPHONE + CFTypeRef accessibilityType = [SAMKeychain accessibilityType]; + if (accessibilityType) { + [query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible]; + } +#endif + + CFTypeRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); + if (status != errSecSuccess && error != NULL) { + *error = [[self class] errorWithCode:status]; + return nil; + } + + return (__bridge_transfer NSArray *)result; +} + + +- (BOOL)fetch:(NSError *__autoreleasing *)error { + OSStatus status = SAMKeychainErrorBadArguments; + if (!self.service || !self.account) { + if (error) { + *error = [[self class] errorWithCode:status]; + } + return NO; + } + + CFTypeRef result = NULL; + NSMutableDictionary *query = [self query]; + [query setObject:@YES forKey:(__bridge id)kSecReturnData]; + [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); + + if (status != errSecSuccess) { + if (error) { + *error = [[self class] errorWithCode:status]; + } + return NO; + } + + self.passwordData = (__bridge_transfer NSData *)result; + return YES; +} + + +#pragma mark - Accessors + +- (void)setPasswordObject:(id)object { + self.passwordData = [NSKeyedArchiver archivedDataWithRootObject:object]; +} + + +- (id)passwordObject { + if ([self.passwordData length]) { + return [NSKeyedUnarchiver unarchiveObjectWithData:self.passwordData]; + } + return nil; +} + + +- (void)setPassword:(NSString *)password { + self.passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; +} + + +- (NSString *)password { + if ([self.passwordData length]) { + return [[NSString alloc] initWithData:self.passwordData encoding:NSUTF8StringEncoding]; + } + return nil; +} + + +#pragma mark - Synchronization Status + +#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE ++ (BOOL)isSynchronizationAvailable { +#if TARGET_OS_IPHONE + // Apple suggested way to check for 7.0 at runtime + // https://developer.apple.com/library/ios/documentation/userexperience/conceptual/transitionguide/SupportingEarlieriOS.html + return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1; +#else + return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4; +#endif +} +#endif + + +#pragma mark - Private + +- (NSMutableDictionary *)query { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3]; + [dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; + + if (self.service) { + [dictionary setObject:self.service forKey:(__bridge id)kSecAttrService]; + } + + if (self.account) { + [dictionary setObject:self.account forKey:(__bridge id)kSecAttrAccount]; + } + +#ifdef SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE +#if !TARGET_IPHONE_SIMULATOR + if (self.accessGroup) { + [dictionary setObject:self.accessGroup forKey:(__bridge id)kSecAttrAccessGroup]; + } +#endif +#endif + +#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE + if ([[self class] isSynchronizationAvailable]) { + id value; + + switch (self.synchronizationMode) { + case SAMKeychainQuerySynchronizationModeNo: { + value = @NO; + break; + } + case SAMKeychainQuerySynchronizationModeYes: { + value = @YES; + break; + } + case SAMKeychainQuerySynchronizationModeAny: { + value = (__bridge id)(kSecAttrSynchronizableAny); + break; + } + } + + [dictionary setObject:value forKey:(__bridge id)(kSecAttrSynchronizable)]; + } +#endif + + return dictionary; +} + + ++ (NSError *)errorWithCode:(OSStatus) code { + static dispatch_once_t onceToken; + static NSBundle *resourcesBundle = nil; + dispatch_once(&onceToken, ^{ + NSURL *url = [[NSBundle bundleForClass:[SAMKeychainQuery class]] URLForResource:@"SAMKeychain" withExtension:@"bundle"]; + resourcesBundle = [NSBundle bundleWithURL:url]; + }); + + NSString *message = nil; + switch (code) { + case errSecSuccess: return nil; + case SAMKeychainErrorBadArguments: message = NSLocalizedStringFromTableInBundle(@"SAMKeychainErrorBadArguments", @"SAMKeychain", resourcesBundle, nil); break; + +#if TARGET_OS_IPHONE + case errSecUnimplemented: { + message = NSLocalizedStringFromTableInBundle(@"errSecUnimplemented", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecParam: { + message = NSLocalizedStringFromTableInBundle(@"errSecParam", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecAllocate: { + message = NSLocalizedStringFromTableInBundle(@"errSecAllocate", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecNotAvailable: { + message = NSLocalizedStringFromTableInBundle(@"errSecNotAvailable", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecDuplicateItem: { + message = NSLocalizedStringFromTableInBundle(@"errSecDuplicateItem", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecItemNotFound: { + message = NSLocalizedStringFromTableInBundle(@"errSecItemNotFound", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecInteractionNotAllowed: { + message = NSLocalizedStringFromTableInBundle(@"errSecInteractionNotAllowed", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecDecode: { + message = NSLocalizedStringFromTableInBundle(@"errSecDecode", @"SAMKeychain", resourcesBundle, nil); + break; + } + case errSecAuthFailed: { + message = NSLocalizedStringFromTableInBundle(@"errSecAuthFailed", @"SAMKeychain", resourcesBundle, nil); + break; + } + default: { + message = NSLocalizedStringFromTableInBundle(@"errSecDefault", @"SAMKeychain", resourcesBundle, nil); + } +#else + default: + message = (__bridge_transfer NSString *)SecCopyErrorMessageString(code, NULL); +#endif + } + + NSDictionary *userInfo = nil; + if (message) { + userInfo = @{ NSLocalizedDescriptionKey : message }; + } + return [NSError errorWithDomain:kSAMKeychainErrorDomain code:code userInfo:userInfo]; +} + +@end diff --git a/corecrypto/cc.h b/corecrypto/cc.h new file mode 100644 index 0000000..df98a5f --- /dev/null +++ b/corecrypto/cc.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CC_H_ +#define _CORECRYPTO_CC_H_ + +#include +#include +#include + +/* Provide a general purpose macro concat method. */ +#define cc_concat_(a, b) a##b +#define cc_concat(a, b) cc_concat_(a, b) + +/* Manage asserts here because a few functions in header public files do use asserts */ +#define cc_assert(x) assert(x) +#if CC_KERNEL +#include +#elif CC_USE_S3 +#define assert(args) // No assert in S3 +#else +#include +#endif + +/* Provide a static assert that can be used to create compile-type failures. */ +#define cc_static_assert(e,m) \ + ;enum { cc_concat(static_assert_, __COUNTER__) = 1/(int)(!!(e)) } + +/* Declare a struct element with a guarenteed alignment of _alignment_. + The resulting struct can be used to create arrays that are aligned by + a certain amount. */ +#define cc_aligned_struct(_alignment_) \ +typedef struct { \ +uint8_t b[_alignment_]; \ +} CC_ALIGNED(_alignment_) + +/* number of array elements used in a cc_ctx_decl */ +#define cc_ctx_n(_type_, _size_) ((_size_ + sizeof(_type_) - 1) / sizeof(_type_)) + +/* sizeof of a context declared with cc_ctx_decl */ +#define cc_ctx_sizeof(_type_, _size_) sizeof(_type_[cc_ctx_n(_type_, _size_)]) + +/* + 1. _alloca cannot be removed becasue this header file is compiled with both MSVC++ and with clang. + 2. The _MSC_VER version of cc_ctx_decl() is not compatible with the way *_decl macros as used in CommonCrypto, AppleKeyStore and SecurityFrameworks. To observe the incompatibilities and errors, use below definition. Corecrypto itself, accepts both deinitions + #define cc_ctx_decl(_type_, _size_, _name_) _type_ _name_ ## _array[cc_ctx_n(_type_, (_size_))]; _type_ *_name_ = _name_ ## _array + 3. Never use sizeof() operator for the variables declared with cc_ctx_decl(), because it is not be compatible with the _MSC_VER version of cc_ctx_decl(). + */ +#if defined(_MSC_VER) +#define cc_ctx_decl(_type_, _size_, _name_) _type_ * _name_ = (_type_ *) _alloca(sizeof(_type_) * cc_ctx_n(_type_, _size_) ) +#else +#define cc_ctx_decl(_type_, _size_, _name_) _type_ _name_ [cc_ctx_n(_type_, _size_)] +#endif + +/* bzero is deprecated. memset is the way to go */ +/* FWIW, L4, HEXAGON and ARMCC even with gnu compatibility mode don't have bzero */ +#define cc_zero(_size_,_data_) memset((_data_),0 ,(_size_)) + +/*! + @brief cc_clear(len, dst) zeroizes array dst and it will not be optimized out. + @discussion It is used to clear sensitive data, particularly when the are defined in the stack + @param len number of bytes to be cleared in dst + @param dst input array + */ +CC_NONNULL2 +void cc_clear(size_t len, void *dst); + +#define cc_copy(_size_, _dst_, _src_) memcpy(_dst_, _src_, _size_) + +CC_INLINE CC_NONNULL2 CC_NONNULL3 CC_NONNULL4 +void cc_xor(size_t size, void *r, const void *s, const void *t) { + uint8_t *_r=(uint8_t *)r; + const uint8_t *_s=(const uint8_t *)s; + const uint8_t *_t=(const uint8_t *)t; + while (size--) { + _r[size] = _s[size] ^ _t[size]; + } +} + +/*! + @brief cc_cmp_safe(num, pt1, pt2) compares two array ptr1 and ptr2 of num bytes. + @discussion The execution time/cycles is independent of the data and therefore guarantees no leak about the data. However, the execution time depends on num. + @param num number of bytes in each array + @param ptr1 input array + @param ptr2 input array + @return returns 0 if the num bytes starting at ptr1 are identical to the num bytes starting at ptr2 and 1 if they are different or if num is 0 (empty arrays). + */ +CC_NONNULL2 CC_NONNULL3 +int cc_cmp_safe (size_t num, const void * ptr1, const void * ptr2); + +/* Exchange S and T of any type. NOTE: Both and S and T are evaluated + mutliple times and MUST NOT be expressions. */ +#define CC_SWAP(S,T) do { \ + __typeof__(S) _cc_swap_tmp = S; S = T; T = _cc_swap_tmp; \ +} while(0) + +/* Return the maximum value between S and T. */ +#define CC_MAX(S, T) ({__typeof__(S) _cc_max_s = S; __typeof__(T) _cc_max_t = T; _cc_max_s > _cc_max_t ? _cc_max_s : _cc_max_t;}) + +/* Return the minimum value between S and T. */ +#define CC_MIN(S, T) ({__typeof__(S) _cc_min_s = S; __typeof__(T) _cc_min_t = T; _cc_min_s <= _cc_min_t ? _cc_min_s : _cc_min_t;}) + +#endif /* _CORECRYPTO_CC_H_ */ diff --git a/corecrypto/cc_config.h b/corecrypto/cc_config.h new file mode 100644 index 0000000..2c7733c --- /dev/null +++ b/corecrypto/cc_config.h @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CC_CONFIG_H_ +#define _CORECRYPTO_CC_CONFIG_H_ + +/* A word about configuration macros: + + Conditional configuration macros specific to corecrypto should be named CORECRYPTO_xxx + or CCxx_yyy and be defined to be either 0 or 1 in this file. You can add an + #ifndef #error construct at the end of this file to make sure it's always defined. + + They should always be tested using the #if directive, never the #ifdef directive. + + No other conditional macros shall ever be used (except in this file) + + Configuration Macros that are defined outside of corecrypto (eg: KERNEL, DEBUG, ...) + shall only be used in this file to define CCxxx macros. + + External macros should be assumed to be either undefined, defined with no value, + or defined as true or false. We shall strive to build with -Wundef whenever possible, + so the following construct should be used to test external macros in this file: + + #if defined(DEBUG) && (DEBUG) + #define CORECRYPTO_DEBUG 1 + #else + #define CORECRYPTO_DEBUG 0 + #endif + + + It is acceptable to define a conditional CC_xxxx macro in an implementation file, + to be used only in this file. + + The current code is not guaranteed to follow those rules, but should be fixed to. + + Corecrypto requires GNU and C99 compatibility. + Typically enabled by passing --gnu --c99 to the compiler (eg. armcc) + +*/ + +#define CORECRYPTO_PUBLIC_SDK 1 + +//Do not set this macros to 1, unless you are developing/testing for Linux under macOS +#define CORECRYPTO_SIMULATE_POSIX_ENVIRONMENT 0 + +//Do not set these macros to 1, unless you are developing/testing for Windows under macOS +#define CORECRYPTO_SIMULATE_WINDOWS_ENVIRONMENT 0 +#define CORECRYPTO_HACK_FOR_WINDOWS_DEVELOPMENT 0 + +//this macro is used to turn on/off usage of transparent union in corecrypto +//it should be commented out in corecrypto and be used only by the software that use corecrypto +//#define CORECRYPTO_DONOT_USE_TRANSPARENT_UNION +#if defined(__cplusplus) +#define CORECRYPTO_USE_TRANSPARENT_UNION 0 +#elif defined(CORECRYPTO_DONOT_USE_TRANSPARENT_UNION) + #define CORECRYPTO_USE_TRANSPARENT_UNION !CORECRYPTO_DONOT_USE_TRANSPARENT_UNION +#else + #define CORECRYPTO_USE_TRANSPARENT_UNION 1 +#endif + +#if (defined(DEBUG) && (DEBUG)) || defined(_DEBUG) //MSVC defines _DEBUG +/* CC_DEBUG is already used in CommonCrypto */ + #define CORECRYPTO_DEBUG 1 +#else + #define CORECRYPTO_DEBUG 0 +#endif + +// This macro can be used to enable prints when a condition in the macro "cc_require" +// is false. This is especially useful to confirm that negative testing fails +// at the intended location +#define CORECRYPTO_DEBUG_ENABLE_CC_REQUIRE_PRINTS 0 + +#if defined(KERNEL) && (KERNEL) + #define CC_KERNEL 1 // KEXT, XNU repo or kernel components such as AppleKeyStore +#else + #define CC_KERNEL 0 +#endif + +#if defined(__linux__) || CORECRYPTO_SIMULATE_POSIX_ENVIRONMENT + #define CC_LINUX 1 +#else + #define CC_LINUX 0 +#endif + +#if defined(USE_L4) && (USE_L4) + #define CC_USE_L4 1 +#else + #define CC_USE_L4 0 +#endif + +#if defined(USE_SEPROM) && (USE_SEPROM) + #define CC_USE_SEPROM 1 +#else + #define CC_USE_SEPROM 0 +#endif + +#if defined(USE_S3) && (USE_S3) + #define CC_USE_S3 1 +#else + #define CC_USE_S3 0 +#endif + +#if (defined(ICE_FEATURES_ENABLED)) || (defined(MAVERICK) && (MAVERICK)) + #define CC_BASEBAND 1 +#else + #define CC_BASEBAND 0 +#endif + +#if defined(EFI) && (EFI) + #define CC_EFI 1 +#else + #define CC_EFI 0 +#endif + +#if defined(IBOOT) && (IBOOT) + #define CC_IBOOT 1 +#else + #define CC_IBOOT 0 +#endif + +// Defined by the XNU build scripts +// Applies to code embedded in XNU but NOT to the kext +#if defined(XNU_KERNEL_PRIVATE) + #define CC_XNU_KERNEL_PRIVATE 1 +#else + #define CC_XNU_KERNEL_PRIVATE 0 +#endif + +// handle unaligned data, if the cpu cannot. Currently for gladman AES and the C version of the SHA256 +#define CC_HANDLE_UNALIGNED_DATA CC_BASEBAND + +// BaseBand configuration +#if CC_BASEBAND + +// -- ENDIANESS +#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) + #if defined(ENDIAN_LITTLE) || (defined(__arm__) && !defined(__BIG_ENDIAN)) + #define __LITTLE_ENDIAN__ + #elif !defined(ENDIAN_BIG) && !defined(__BIG_ENDIAN) + #error Baseband endianess not defined. + #endif + #define AESOPT_ENDIAN_NO_FILE +#endif + +// -- Architecture + #define CCN_UNIT_SIZE 4 // 32 bits + +// -- External function + #define assert ASSERT // sanity + +// -- Warnings +// Ignore irrelevant warnings after verification +// #1254-D: arithmetic on pointer to void or function type +// #186-D: pointless comparison of unsigned integer with zero +// #546-D: transfer of control bypasses initialization of + #ifdef __arm__ + #pragma diag_suppress 186, 1254,546 + #elif defined(__GNUC__) +// warning: pointer of type 'void *' used in arithmetic + #pragma GCC diagnostic ignored "-Wpointer-arith" + #endif // __arm__ +#endif // CC_BASEBAND + +//CC_XNU_KERNEL_AVAILABLE indicates the availibity of XNU kernel functions, +//like what we have on OSX, iOS, tvOS, Watch OS +#if defined(__APPLE__) && defined(__MACH__) + #define CC_XNU_KERNEL_AVAILABLE 1 +#else + #define CC_XNU_KERNEL_AVAILABLE 0 +#endif + +//arm arch64 definition for gcc +#if defined(__GNUC__) && defined(__aarch64__) && !defined(__arm64__) + #define __arm64__ +#endif + +#if !defined(CCN_UNIT_SIZE) + #if defined(__arm64__) || defined(__x86_64__) || defined(_WIN64) + #define CCN_UNIT_SIZE 8 + #elif defined(__arm__) || defined(__i386__) || defined(_WIN32) + #define CCN_UNIT_SIZE 4 + #else + #error undefined architecture + #endif +#endif /* !defined(CCN_UNIT_SIZE) */ + + +//this allows corecrypto Windows development using xcode +#if defined(CORECRYPTO_SIMULATE_WINDOWS_ENVIRONMENT) + #if CORECRYPTO_SIMULATE_WINDOWS_ENVIRONMENT && CC_XNU_KERNEL_AVAILABLE && CORECRYPTO_DEBUG + #define CC_USE_ASM 0 + #define CC_USE_HEAP_FOR_WORKSPACE 1 + #if (CCN_UNIT_SIZE==8) + #define CCN_UINT128_SUPPORT_FOR_64BIT_ARCH 0 + #else + #define CCN_UINT128_SUPPORT_FOR_64BIT_ARCH 1 + #endif + #endif +#endif + +#if !defined(CCN_UINT128_SUPPORT_FOR_64BIT_ARCH) + #if defined(_WIN64) && defined(_WIN32) && (CCN_UNIT_SIZE==8) + #define CCN_UINT128_SUPPORT_FOR_64BIT_ARCH 0 + #elif defined(_WIN32) + #define CCN_UINT128_SUPPORT_FOR_64BIT_ARCH 1//should not be a problem + #else + #define CCN_UINT128_SUPPORT_FOR_64BIT_ARCH 1 + #endif +#endif + +#if defined(_MSC_VER) + #if defined(__clang__) + #define CC_ALIGNED(x) __attribute__ ((aligned(x))) //clang compiler + #else + #define CC_ALIGNED(x) __declspec(align(x)) //MS complier + #endif +#else + #if __clang__ || CCN_UNIT_SIZE==8 + #define CC_ALIGNED(x) __attribute__ ((aligned(x))) + #else + #define CC_ALIGNED(x) __attribute__ ((aligned((x)>8?8:(x)))) + #endif +#endif + +#if defined(__arm__) +//this is copied from , because is not available on SEPROM environment + #if defined (__ARM_ARCH_7A__) || defined (__ARM_ARCH_7S__) || defined (__ARM_ARCH_7F__) || defined (__ARM_ARCH_7K__) + #define _ARM_ARCH_7 + #endif + + #if defined(__ARM_ARCH_6M__) || defined(__TARGET_ARCH_6S_M) || defined (__armv6m__) + #define _ARM_ARCH_6M + #endif +#endif + +#if defined(__arm64__) || defined(__arm__) + #define CCN_IOS 1 + #define CCN_OSX 0 +#elif defined(__x86_64__) || defined(__i386__) + #define CCN_IOS 0 + #define CCN_OSX 1 +#endif + +#if CC_USE_L4 || CC_USE_S3 +/* No dynamic linking allowed in L4, e.g. avoid nonlazy symbols */ +/* For corecrypto kext, CC_STATIC should be undefined */ + #define CC_STATIC 1 +#endif + +#if !defined(CC_USE_HEAP_FOR_WORKSPACE) + #if CC_USE_S3 || CC_USE_SEPROM + #define CC_USE_HEAP_FOR_WORKSPACE 0 + #else + #define CC_USE_HEAP_FOR_WORKSPACE 1 + #endif +#endif + +/* memset_s is only available in few target */ +#if CC_USE_SEPROM || defined(__CC_ARM) \ + || defined(__hexagon__) || CC_EFI + #define CC_HAS_MEMSET_S 0 +#else + #define CC_HAS_MEMSET_S 1 +#endif + +// Include target conditionals if available. +#if defined(__has_include) /* portability */ +#if __has_include() +#include +#endif /* __has_include() */ +#endif /* defined(__has_include) */ + +// Disable RSA Keygen on iBridge +#if defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE && CC_KERNEL +#define CC_DISABLE_RSAKEYGEN 1 /* for iBridge */ +#else +#define CC_DISABLE_RSAKEYGEN 0 /* default */ +#endif + +//- functions implemented in assembly ------------------------------------------ +//this the list of corecrypto clients that use assembly and the clang compiler +#if !(CC_XNU_KERNEL_AVAILABLE || CC_KERNEL || CC_USE_L4 || CC_IBOOT || CC_USE_SEPROM || CC_USE_S3) && !defined(_WIN32) && CORECRYPTO_DEBUG + #warning "You are using the default corecrypto configuration, assembly optimizations may not be available for your platform" +#endif + +// Use this macro to strictly disable assembly regardless of cpu/os/compiler/etc. +// Our assembly code is not gcc compatible. Clang defines the __GNUC__ macro as well. +#if !defined(CC_USE_ASM) + #if defined(_WIN32) || CC_EFI || CC_BASEBAND || CC_XNU_KERNEL_PRIVATE || (defined(__GNUC__) && !defined(__clang__)) + #define CC_USE_ASM 0 + #else + #define CC_USE_ASM 1 + #endif +#endif + +//-(1) ARM V7 +#if defined(_ARM_ARCH_7) && __clang__ && CC_USE_ASM + #define CCN_DEDICATED_SQR 1 + #define CCN_MUL_KARATSUBA 0 // no performance improvement + #define CCN_ADD_ASM 1 + #define CCN_SUB_ASM 1 + #define CCN_MUL_ASM 0 + #define CCN_ADDMUL1_ASM 1 + #define CCN_MUL1_ASM 1 + #define CCN_CMP_ASM 1 + #define CCN_ADD1_ASM 0 + #define CCN_SUB1_ASM 0 + #define CCN_N_ASM 1 + #define CCN_SET_ASM 1 + #define CCN_SHIFT_RIGHT_ASM 1 + #define CCAES_ARM_ASM 1 + #define CCAES_INTEL_ASM 0 + #if CC_KERNEL || CC_USE_L4 || CC_IBOOT || CC_USE_SEPROM || CC_USE_S3 + #define CCAES_MUX 0 + #else + #define CCAES_MUX 1 + #endif + #define CCN_USE_BUILTIN_CLZ 1 + #define CCSHA1_VNG_INTEL 0 + #define CCSHA2_VNG_INTEL 0 + + #if defined(__ARM_NEON__) || CC_KERNEL + #define CCSHA1_VNG_ARMV7NEON 1 + #define CCSHA2_VNG_ARMV7NEON 1 + #else /* !defined(__ARM_NEON__) */ + #define CCSHA1_VNG_ARMV7NEON 0 + #define CCSHA2_VNG_ARMV7NEON 0 + #endif /* !defined(__ARM_NEON__) */ + #define CCSHA256_ARMV6M_ASM 0 + +//-(2) ARM 64 +#elif defined(__arm64__) && __clang__ && CC_USE_ASM + #define CCN_DEDICATED_SQR 1 + #define CCN_MUL_KARATSUBA 1 // 4*n CCN_UNIT extra memory required. + #define CCN_ADD_ASM 1 + #define CCN_SUB_ASM 1 + #define CCN_MUL_ASM 1 + #define CCN_ADDMUL1_ASM 0 + #define CCN_MUL1_ASM 0 + #define CCN_CMP_ASM 1 + #define CCN_ADD1_ASM 0 + #define CCN_SUB1_ASM 0 + #define CCN_N_ASM 1 + #define CCN_SET_ASM 0 + #define CCN_SHIFT_RIGHT_ASM 1 + #define CCAES_ARM_ASM 1 + #define CCAES_INTEL_ASM 0 + #define CCAES_MUX 0 // On 64bit SoC, asm is much faster than HW + #define CCN_USE_BUILTIN_CLZ 1 + #define CCSHA1_VNG_INTEL 0 + #define CCSHA2_VNG_INTEL 0 + #define CCSHA1_VNG_ARMV7NEON 1 // reused this to avoid making change to xcode project, put arm64 assembly code with armv7 code + #define CCSHA2_VNG_ARMV7NEON 1 + #define CCSHA256_ARMV6M_ASM 0 + +//-(3) Intel 32/64 +#elif (defined(__x86_64__) || defined(__i386__)) && __clang__ && CC_USE_ASM + #define CCN_DEDICATED_SQR 1 + #define CCN_MUL_KARATSUBA 1 // 4*n CCN_UNIT extra memory required. + /* These assembly routines only work for a single CCN_UNIT_SIZE. */ + #if (defined(__x86_64__) && CCN_UNIT_SIZE == 8) || (defined(__i386__) && CCN_UNIT_SIZE == 4) + #define CCN_ADD_ASM 1 + #define CCN_SUB_ASM 1 + #define CCN_MUL_ASM 1 + #else + #define CCN_ADD_ASM 0 + #define CCN_SUB_ASM 0 + #define CCN_MUL_ASM 0 + #endif + + #if (defined(__x86_64__) && CCN_UNIT_SIZE == 8) + #define CCN_CMP_ASM 1 + #define CCN_N_ASM 1 + #define CCN_SHIFT_RIGHT_ASM 1 + #else + #define CCN_CMP_ASM 0 + #define CCN_N_ASM 0 + #define CCN_SHIFT_RIGHT_ASM 0 + #endif + + #define CCN_ADDMUL1_ASM 0 + #define CCN_MUL1_ASM 0 + #define CCN_ADD1_ASM 0 + #define CCN_SUB1_ASM 0 + #define CCN_SET_ASM 0 + #define CCAES_ARM_ASM 0 + #define CCAES_INTEL_ASM 1 + #define CCAES_MUX 0 + #define CCN_USE_BUILTIN_CLZ 0 + #define CCSHA1_VNG_INTEL 1 + #define CCSHA2_VNG_INTEL 1 + #define CCSHA1_VNG_ARMV7NEON 0 + #define CCSHA2_VNG_ARMV7NEON 0 + #define CCSHA256_ARMV6M_ASM 0 + +//-(4) disable assembly +#else + #if CCN_UINT128_SUPPORT_FOR_64BIT_ARCH + #define CCN_DEDICATED_SQR 1 + #else + #define CCN_DEDICATED_SQR 0 //when assembly is off and 128-bit integers are not supported, dedicated square is off. This is the case on Windows + #endif + #define CCN_MUL_KARATSUBA 1 // 4*n CCN_UNIT extra memory required. + #define CCN_ADD_ASM 0 + #define CCN_SUB_ASM 0 + #define CCN_MUL_ASM 0 + #define CCN_ADDMUL1_ASM 0 + #define CCN_MUL1_ASM 0 + #define CCN_CMP_ASM 0 + #define CCN_ADD1_ASM 0 + #define CCN_SUB1_ASM 0 + #define CCN_N_ASM 0 + #define CCN_SET_ASM 0 + #define CCN_SHIFT_RIGHT_ASM 0 + #define CCAES_ARM_ASM 0 + #define CCAES_INTEL_ASM 0 + #define CCAES_MUX 0 + #define CCN_USE_BUILTIN_CLZ 0 + #define CCSHA1_VNG_INTEL 0 + #define CCSHA2_VNG_INTEL 0 + #define CCSHA1_VNG_ARMV7NEON 0 + #define CCSHA2_VNG_ARMV7NEON 0 + #define CCSHA256_ARMV6M_ASM 0 + +#endif + +#define CC_INLINE static inline + +#if CORECRYPTO_USE_TRANSPARENT_UNION +// Non null for transparent unions is ambiguous and cause problems +// for most tools (GCC and others: 23919290). + #define CC_NONNULL_TU(N) +#else + #define CC_NONNULL_TU(N) CC_NONNULL(N) +#endif + +#ifdef __GNUC__ + #define CC_NORETURN __attribute__((__noreturn__)) + #define CC_NOTHROW __attribute__((__nothrow__)) + #define CC_NONNULL(N) __attribute__((__nonnull__ N)) + #define CC_NONNULL1 __attribute__((__nonnull__(1))) + #define CC_NONNULL2 __attribute__((__nonnull__(2))) + #define CC_NONNULL3 __attribute__((__nonnull__(3))) + #define CC_NONNULL4 __attribute__((__nonnull__(4))) + #define CC_NONNULL5 __attribute__((__nonnull__(5))) + #define CC_NONNULL6 __attribute__((__nonnull__(6))) + #define CC_NONNULL7 __attribute__((__nonnull__(7))) + #define CC_NONNULL_ALL __attribute__((__nonnull__)) + #define CC_SENTINEL __attribute__((__sentinel__)) + #define CC_CONST __attribute__((__const__)) + #define CC_PURE __attribute__((__pure__)) + #define CC_WARN_RESULT __attribute__((__warn_unused_result__)) + #define CC_MALLOC __attribute__((__malloc__)) + #define CC_UNUSED __attribute__((unused)) +#else /* !__GNUC__ */ +/*! @parseOnly */ + #define CC_UNUSED +/*! @parseOnly */ + #define CC_NONNULL(N) +/*! @parseOnly */ + #define CC_NORETURN +/*! @parseOnly */ + #define CC_NOTHROW +/*! @parseOnly */ + #define CC_NONNULL1 +/*! @parseOnly */ + #define CC_NONNULL2 +/*! @parseOnly */ + #define CC_NONNULL3 +/*! @parseOnly */ + #define CC_NONNULL4 +/*! @parseOnly */ + #define CC_NONNULL5 +/*! @parseOnly */ + #define CC_NONNULL6 +/*! @parseOnly */ + #define CC_NONNULL7 +/*! @parseOnly */ + #define CC_NONNULL_ALL +/*! @parseOnly */ + #define CC_SENTINEL +/*! @parseOnly */ + #define CC_CONST +/*! @parseOnly */ + #define CC_PURE +/*! @parseOnly */ + #define CC_WARN_RESULT +/*! @parseOnly */ + #define CC_MALLOC +#endif /* !__GNUC__ */ + +// Enable FIPSPOST function tracing only when supported. */ +#ifdef CORECRYPTO_POST_TRACE +#define CC_FIPSPOST_TRACE 1 +#else +#define CC_FIPSPOST_TRACE 0 +#endif + +#endif /* _CORECRYPTO_CC_CONFIG_H_ */ diff --git a/corecrypto/cc_debug.h b/corecrypto/cc_debug.h new file mode 100644 index 0000000..5a5f1b9 --- /dev/null +++ b/corecrypto/cc_debug.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2012,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +//debug configuration header file +#ifndef _CORECRYPTO_CCN_DEBUG_H_ +#define _CORECRYPTO_CCN_DEBUG_H_ + +#include + +// DO NOT INCLUDE this HEADER file in CoreCrypto files added for XNU project or headers +// included by external clients. + +// ======================== +// Printf for corecrypto +// ======================== +#if CC_KERNEL + #include + #define cc_printf(x...) kprintf(x) + #if !CONFIG_EMBEDDED + extern int printf(const char *format, ...) __printflike(1,2); + #endif +#elif CC_USE_S3 || CC_IBOOT + #include + #define cc_printf(x...) printf(x) +#else + #include + #define cc_printf(x...) fprintf(stderr, x) +#endif + +// ======================== +// Integer types +// ======================== + +#if CC_KERNEL +/* Those are not defined in libkern */ +#define PRIx64 "llx" +#define PRIx32 "x" +#define PRIx16 "hx" +#define PRIx8 "hhx" +#else +#include +#endif + +#if CCN_UNIT_SIZE == 8 +#define CCPRIx_UNIT ".016" PRIx64 +#elif CCN_UNIT_SIZE == 4 +#define CCPRIx_UNIT ".08" PRIx32 +#elif CCN_UNIT_SIZE == 2 +#define CCPRIx_UNIT ".04" PRIx16 +#elif CCN_UNIT_SIZE == 1 +#define CCPRIx_UNIT ".02" PRIx8 +#else +#error invalid CCN_UNIT_SIZE +#endif + +// ======================== +// Print utilities for corecrypto +// ======================== + +#include + +/* Print a byte array of arbitrary size */ +void cc_print(const char *label, size_t count, const uint8_t *s); + +#endif /* _CORECRYPTO_CCN_DEBUG_H_ */ diff --git a/corecrypto/cc_memory.h b/corecrypto/cc_memory.h new file mode 100644 index 0000000..4a0712b --- /dev/null +++ b/corecrypto/cc_memory.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_cc_memory_h +#define corecrypto_cc_memory_h + +#if CORECRYPTO_DEBUG +extern void *g_ws_start; +#endif + +#include +#include "cc_debug.h" +#include + + +CC_INLINE void cc_alloc_debug(CC_UNUSED void *p) { +#if CORECRYPTO_DEBUG + // Contract for some client is to have a single malloc at a time + cc_assert(g_ws_start==NULL); + g_ws_start=p; +#endif +} + +CC_INLINE void cc_free_debug(CC_UNUSED void *p) { +#if CORECRYPTO_DEBUG + // Contract for some client is to have a single malloc at a time + cc_assert(g_ws_start==p); // Free the address we allocated + g_ws_start=NULL; +#endif +} + +// Add specific error for memory allocation failure +// which does not overlap with others +#define CCERR_MEMORY_ALLOC_FAIL -200 + +// ============================================================================= +// Declare workspace with memory in STACK +// This is the least preferred option since most corecrypto client have +// small stack. It is still useful when needing small allocations and errors +// can't be easily propagated +// ============================================================================= + +// Declare a variable in stack and use its address +// Only uses this when we don't have a way to propagate error +#define CC_DECL_WORKSPACE_STACK(ws,n) \ + cc_unit tmp_##__FILE__##__LINE__[(n)]; \ + cc_ws _ws={&tmp_##__FILE__##__LINE__[0],&tmp_##__FILE__##__LINE__[(n)]}; \ + cc_ws_t ws=&_ws; \ + cc_alloc_debug(ws->start); + +// Reset pointers to avoid future reference +#define CC_FREE_WORKSPACE_STACK(_ws) \ + cc_free_debug(ws->start); \ + ws->start=NULL; \ + ws->end=NULL; + +#define CC_CLEAR_AND_FREE_WORKSPACE_STACK(ws) { \ + cc_assert(ws->startend); \ + ccn_clear(ws->end - ws->start,ws->start); \ + CC_FREE_WORKSPACE_STACK(ws);} + +// ============================================================================= +// Declare workspace in the region correspding to HEAP or STACK +// depending on the setting of CC_USE_HEAP_FOR_WORKSPACE +// This should be the preference for large memory allocations but it requires +// to propagate error in case of allocation failure +// ============================================================================= +#if CC_USE_HEAP_FOR_WORKSPACE + +// Malloc/free functions to be used +#if CC_KERNEL +#include +CC_INLINE void *cc_malloc(size_t s) +{ + return IOMalloc(s); +} +CC_INLINE void cc_free(void *p,size_t size) +{ + IOFree(p,size); +} +#else +#include +CC_INLINE void *cc_malloc(size_t s) +{ + return malloc(s); +} +CC_INLINE void cc_free(void *p,size_t size CC_UNUSED) +{ + free(p); +} + +#endif + +#define CC_DECL_WORKSPACE_OR_FAIL(ws,n) \ + cc_unit* tmp_##__FILE__##__LINE__=cc_malloc(ccn_sizeof_n((n))); \ + cc_ws _ws={&tmp_##__FILE__##__LINE__[0],&tmp_##__FILE__##__LINE__[(n)]}; \ + cc_ws_t ws=&_ws; \ + if (NULL == ws->start) return CCERR_MEMORY_ALLOC_FAIL; \ + cc_alloc_debug(ws->start); + +// Free and reset pointers to avoid future references +#define CC_FREE_WORKSPACE(ws) \ + cc_free_debug(ws->start); \ + cc_free(ws->start,(ws->end - ws->start)*sizeof(ws->start[0])); \ + ws->start=NULL; \ + ws->end=NULL; + +#else // not CC_USE_HEAP_FOR_WORKSPACE + +// Declare a variable in stack and use its address +// Could use alloca but alloca is not so portable, and not secure. +#define CC_DECL_WORKSPACE_OR_FAIL CC_DECL_WORKSPACE_STACK + +// Reset pointers to avoid future reference +#define CC_FREE_WORKSPACE CC_FREE_WORKSPACE_STACK + +#endif // CC_USE_HEAP_FOR_WORKSPACE + +// ============================================================================= +// Common +// ============================================================================= + +#define CC_CLEAR_AND_FREE_WORKSPACE(ws) { \ + cc_assert(ws->startend); \ + ccn_clear(ws->end - ws->start,ws->start); \ + CC_FREE_WORKSPACE(ws);} + +#endif // corecrypto_cc_memory_h diff --git a/corecrypto/cc_priv.h b/corecrypto/cc_priv.h new file mode 100644 index 0000000..2065c44 --- /dev/null +++ b/corecrypto/cc_priv.h @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CC_PRIV_H_ +#define _CORECRYPTO_CC_PRIV_H_ + +#include +#include + +/* defines the following macros : + + CC_MEMCPY : optimized memcpy. + CC_MEMMOVE : optimized memmove. + CC_MEMSET : optimized memset. + + CC_STORE32_BE : store 32 bit value in big endian in unaligned buffer. + CC_STORE32_LE : store 32 bit value in little endian in unaligned buffer. + CC_STORE64_BE : store 64 bit value in big endian in unaligned buffer. + CC_STORE64_LE : store 64 bit value in little endian in unaligned buffer. + + CC_LOAD32_BE : load 32 bit value in big endian from unaligned buffer. + CC_LOAD32_LE : load 32 bit value in little endian from unaligned buffer. + CC_LOAD64_BE : load 64 bit value in big endian from unaligned buffer. + CC_LOAD64_LE : load 64 bit value in little endian from unaligned buffer. + + CC_ROR : Rotate Right 32 bits. Rotate count can be a variable. + CC_ROL : Rotate Left 32 bits. Rotate count can be a variable. + CC_RORc : Rotate Right 32 bits. Rotate count must be a constant. + CC_ROLc : Rotate Left 32 bits. Rotate count must be a constant. + + CC_ROR64 : Rotate Right 64 bits. Rotate count can be a variable. + CC_ROL64 : Rotate Left 64 bits. Rotate count can be a variable. + CC_ROR64c : Rotate Right 64 bits. Rotate count must be a constant. + CC_ROL64c : Rotate Left 64 bits. Rotate count must be a constant. + + CC_BSWAP : byte swap a 32 bits variable. + + CC_H2BE32 : convert a 32 bits value between host and big endian order. + CC_H2LE32 : convert a 32 bits value between host and little endian order. + +The following are not defined yet... define them if needed. + + CC_BSWAPc : byte swap a 32 bits constant + + CC_BSWAP64 : byte swap a 64 bits variable + CC_BSWAP64c : byte swap a 64 bits constant + + CC_READ_LE32 : read a 32 bits little endian value + + CC_WRITE_LE32 : write a 32 bits little endian value + CC_WRITE_LE64 : write a 64 bits little endian value + + CC_H2BE64 : convert a 64 bits value between host and big endian order + CC_H2LE64 : convert a 64 bits value between host and little endian order + +*/ + +/* TODO: optimized versions */ +#define CC_MEMCPY(D,S,L) memcpy((D),(S),(L)) +#define CC_MEMMOVE(D,S,L) memmove((D),(S),(L)) +#define CC_MEMSET(D,V,L) memset((D),(V),(L)) + +// MARK: - Loads and Store + +// MARK: -- 32 bits - little endian + +// MARK: --- Default version + +#define CC_STORE32_LE(x, y) do { \ + ((unsigned char *)(y))[3] = (unsigned char)(((x)>>24)&255); \ + ((unsigned char *)(y))[2] = (unsigned char)(((x)>>16)&255); \ + ((unsigned char *)(y))[1] = (unsigned char)(((x)>>8)&255); \ + ((unsigned char *)(y))[0] = (unsigned char)((x)&255); \ +} while(0) + +#define CC_LOAD32_LE(x, y) do { \ +x = ((uint32_t)(((const unsigned char *)(y))[3] & 255)<<24) | \ + ((uint32_t)(((const unsigned char *)(y))[2] & 255)<<16) | \ + ((uint32_t)(((const unsigned char *)(y))[1] & 255)<<8) | \ + ((uint32_t)(((const unsigned char *)(y))[0] & 255)); \ +} while(0) + +// MARK: -- 64 bits - little endian + +#define CC_STORE64_LE(x, y) do { \ + ((unsigned char *)(y))[7] = (unsigned char)(((x)>>56)&255); \ + ((unsigned char *)(y))[6] = (unsigned char)(((x)>>48)&255); \ + ((unsigned char *)(y))[5] = (unsigned char)(((x)>>40)&255); \ + ((unsigned char *)(y))[4] = (unsigned char)(((x)>>32)&255); \ + ((unsigned char *)(y))[3] = (unsigned char)(((x)>>24)&255); \ + ((unsigned char *)(y))[2] = (unsigned char)(((x)>>16)&255); \ + ((unsigned char *)(y))[1] = (unsigned char)(((x)>>8)&255); \ + ((unsigned char *)(y))[0] = (unsigned char)((x)&255); \ +} while(0) + +#define CC_LOAD64_LE(x, y) do { \ +x = (((uint64_t)(((const unsigned char *)(y))[7] & 255))<<56) | \ + (((uint64_t)(((const unsigned char *)(y))[6] & 255))<<48) | \ + (((uint64_t)(((const unsigned char *)(y))[5] & 255))<<40) | \ + (((uint64_t)(((const unsigned char *)(y))[4] & 255))<<32) | \ + (((uint64_t)(((const unsigned char *)(y))[3] & 255))<<24) | \ + (((uint64_t)(((const unsigned char *)(y))[2] & 255))<<16) | \ + (((uint64_t)(((const unsigned char *)(y))[1] & 255))<<8) | \ + (((uint64_t)(((const unsigned char *)(y))[0] & 255))); \ +} while(0) + +// MARK: -- 32 bits - big endian +// MARK: --- intel version + +#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER) + +#define CC_STORE32_BE(x, y) \ + __asm__ __volatile__ ( \ + "bswapl %0 \n\t" \ + "movl %0,(%1)\n\t" \ + "bswapl %0 \n\t" \ + ::"r"(x), "r"(y)) + +#define CC_LOAD32_BE(x, y) \ + __asm__ __volatile__ ( \ + "movl (%1),%0\n\t" \ + "bswapl %0\n\t" \ + :"=r"(x): "r"(y)) + +#else +// MARK: --- default version +#define CC_STORE32_BE(x, y) do { \ + ((unsigned char *)(y))[0] = (unsigned char)(((x)>>24)&255); \ + ((unsigned char *)(y))[1] = (unsigned char)(((x)>>16)&255); \ + ((unsigned char *)(y))[2] = (unsigned char)(((x)>>8)&255); \ + ((unsigned char *)(y))[3] = (unsigned char)((x)&255); \ +} while(0) + +#define CC_LOAD32_BE(x, y) do { \ +x = ((uint32_t)(((const unsigned char *)(y))[0] & 255)<<24) | \ + ((uint32_t)(((const unsigned char *)(y))[1] & 255)<<16) | \ + ((uint32_t)(((const unsigned char *)(y))[2] & 255)<<8) | \ + ((uint32_t)(((const unsigned char *)(y))[3] & 255)); \ +} while(0) + +#endif + +// MARK: -- 64 bits - big endian + +// MARK: --- intel 64 bits version + +#if defined(__x86_64__) && !defined (_MSC_VER) + +#define CC_STORE64_BE(x, y) \ +__asm__ __volatile__ ( \ +"bswapq %0 \n\t" \ +"movq %0,(%1)\n\t" \ +"bswapq %0 \n\t" \ +::"r"(x), "r"(y)) + +#define CC_LOAD64_BE(x, y) \ +__asm__ __volatile__ ( \ +"movq (%1),%0\n\t" \ +"bswapq %0\n\t" \ +:"=r"(x): "r"(y)) + +#else + +// MARK: --- default version + +#define CC_STORE64_BE(x, y) do { \ + ((unsigned char *)(y))[0] = (unsigned char)(((x)>>56)&255); \ + ((unsigned char *)(y))[1] = (unsigned char)(((x)>>48)&255); \ + ((unsigned char *)(y))[2] = (unsigned char)(((x)>>40)&255); \ + ((unsigned char *)(y))[3] = (unsigned char)(((x)>>32)&255); \ + ((unsigned char *)(y))[4] = (unsigned char)(((x)>>24)&255); \ + ((unsigned char *)(y))[5] = (unsigned char)(((x)>>16)&255); \ + ((unsigned char *)(y))[6] = (unsigned char)(((x)>>8)&255); \ + ((unsigned char *)(y))[7] = (unsigned char)((x)&255); \ +} while(0) + +#define CC_LOAD64_BE(x, y) do { \ +x = (((uint64_t)(((const unsigned char *)(y))[0] & 255))<<56) | \ + (((uint64_t)(((const unsigned char *)(y))[1] & 255))<<48) | \ + (((uint64_t)(((const unsigned char *)(y))[2] & 255))<<40) | \ + (((uint64_t)(((const unsigned char *)(y))[3] & 255))<<32) | \ + (((uint64_t)(((const unsigned char *)(y))[4] & 255))<<24) | \ + (((uint64_t)(((const unsigned char *)(y))[5] & 255))<<16) | \ + (((uint64_t)(((const unsigned char *)(y))[6] & 255))<<8) | \ + (((uint64_t)(((const unsigned char *)(y))[7] & 255))); \ +} while(0) + +#endif + +// MARK: - 32-bit Rotates + +#if defined(_MSC_VER) +// MARK: -- MSVC version + +#include +#if !defined(__clang__) + #pragma intrinsic(_lrotr,_lrotl) +#endif +#define CC_ROR(x,n) _lrotr(x,n) +#define CC_ROL(x,n) _lrotl(x,n) +#define CC_RORc(x,n) _lrotr(x,n) +#define CC_ROLc(x,n) _lrotl(x,n) + +#elif (defined(__i386__) || defined(__x86_64__)) +// MARK: -- intel asm version + +CC_INLINE uint32_t CC_ROL(uint32_t word, int i) +{ + __asm__ ("roll %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +CC_INLINE uint32_t CC_ROR(uint32_t word, int i) +{ + __asm__ ("rorl %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +/* Need to be a macro here, because 'i' is an immediate (constant) */ +#define CC_ROLc(word, i) \ +({ uint32_t _word=(word); \ + __asm__ __volatile__ ("roll %2,%0" \ + :"=r" (_word) \ + :"0" (_word),"I" (i)); \ + _word; \ +}) + + +#define CC_RORc(word, i) \ +({ uint32_t _word=(word); \ + __asm__ __volatile__ ("rorl %2,%0" \ + :"=r" (_word) \ + :"0" (_word),"I" (i)); \ + _word; \ +}) + +#else + +// MARK: -- default version + +CC_INLINE uint32_t CC_ROL(uint32_t word, int i) +{ + return ( (word<<(i&31)) | (word>>(32-(i&31))) ); +} + +CC_INLINE uint32_t CC_ROR(uint32_t word, int i) +{ + return ( (word>>(i&31)) | (word<<(32-(i&31))) ); +} + +#define CC_ROLc(x, y) CC_ROL(x, y) +#define CC_RORc(x, y) CC_ROR(x, y) + +#endif + +// MARK: - 64 bits rotates + +#if defined(__x86_64__) && !defined(_MSC_VER) //clang _MSVC doesn't support GNU-style inline assembly +// MARK: -- intel 64 asm version + +CC_INLINE uint64_t CC_ROL64(uint64_t word, int i) +{ + __asm__("rolq %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +CC_INLINE uint64_t CC_ROR64(uint64_t word, int i) +{ + __asm__("rorq %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +/* Need to be a macro here, because 'i' is an immediate (constant) */ +#define CC_ROL64c(word, i) \ +({ \ + uint64_t _word=(word); \ + __asm__("rolq %2,%0" \ + :"=r" (_word) \ + :"0" (_word),"J" (i)); \ + _word; \ +}) + +#define CC_ROR64c(word, i) \ +({ \ + uint64_t _word=(word); \ + __asm__("rorq %2,%0" \ + :"=r" (_word) \ + :"0" (_word),"J" (i)); \ + _word; \ +}) + + +#else /* Not x86_64 */ + +// MARK: -- default C version + +CC_INLINE uint64_t CC_ROL64(uint64_t word, int i) +{ + return ( (word<<(i&63)) | (word>>(64-(i&63))) ); +} + +CC_INLINE uint64_t CC_ROR64(uint64_t word, int i) +{ + return ( (word>>(i&63)) | (word<<(64-(i&63))) ); +} + +#define CC_ROL64c(x, y) CC_ROL64(x, y) +#define CC_ROR64c(x, y) CC_ROR64(x, y) + +#endif + + +// MARK: - Byte Swaps + +CC_INLINE uint32_t CC_BSWAP(uint32_t x) +{ + return ( + ((x>>24)&0x000000FF) | + ((x<<24)&0xFF000000) | + ((x>>8) &0x0000FF00) | + ((x<<8) &0x00FF0000) + ); +} + +#define CC_BSWAP64(x) \ +((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \ +(((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ +(((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ +(((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ +(((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ +(((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ +(((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ +(((uint64_t)(x) & 0x00000000000000ffULL) << 56))) + +#ifdef __LITTLE_ENDIAN__ +#define CC_H2BE32(x) CC_BSWAP(x) +#define CC_H2LE32(x) (x) +#else +#define CC_H2BE32(x) (x) +#define CC_H2LE32(x) CC_BSWAP(x) +#endif + +#define CC_READ_LE32(ptr) \ +( (uint32_t)( \ +((uint32_t)((const uint8_t *)(ptr))[0]) | \ +(((uint32_t)((const uint8_t *)(ptr))[1]) << 8) | \ +(((uint32_t)((const uint8_t *)(ptr))[2]) << 16) | \ +(((uint32_t)((const uint8_t *)(ptr))[3]) << 24))) + +#define CC_WRITE_LE32(ptr, x) \ +do { \ +((uint8_t *)(ptr))[0] = (uint8_t)( (x) & 0xFF); \ +((uint8_t *)(ptr))[1] = (uint8_t)(((x) >> 8) & 0xFF); \ +((uint8_t *)(ptr))[2] = (uint8_t)(((x) >> 16) & 0xFF); \ +((uint8_t *)(ptr))[3] = (uint8_t)(((x) >> 24) & 0xFF); \ +} while(0) + +#define CC_WRITE_LE64(ptr, x) \ +do { \ +((uint8_t *)(ptr))[0] = (uint8_t)( (x) & 0xFF); \ +((uint8_t *)(ptr))[1] = (uint8_t)(((x) >> 8) & 0xFF); \ +((uint8_t *)(ptr))[2] = (uint8_t)(((x) >> 16) & 0xFF); \ +((uint8_t *)(ptr))[3] = (uint8_t)(((x) >> 24) & 0xFF); \ +((uint8_t *)(ptr))[4] = (uint8_t)(((x) >> 32) & 0xFF); \ +((uint8_t *)(ptr))[5] = (uint8_t)(((x) >> 40) & 0xFF); \ +((uint8_t *)(ptr))[6] = (uint8_t)(((x) >> 48) & 0xFF); \ +((uint8_t *)(ptr))[7] = (uint8_t)(((x) >> 56) & 0xFF); \ +} while(0) + +/* extract a byte portably */ +#ifdef _MSC_VER +#define cc_byte(x, n) ((unsigned char)((x) >> (8 * (n)))) +#else +#define cc_byte(x, n) (((x) >> (8 * (n))) & 255) +#endif + +/* HEAVISIDE_STEP (shifted by one) + function f(x): x->0, when x=0 + x->1, when x>0 + Can also be seen as a bitwise operation: + f(x): x -> y + y[0]=(OR x[i]) for all i (all bits) + y[i]=0 for all i>0 + Run in constant time (log2()) + Useful to run constant time checks +*/ +#define HEAVISIDE_STEP_UINT64(r,s) {uint64_t _t=s; \ + _t=(((_t)>>32) | (_t)); \ + _t=(0xFFFFFFFF + (_t & 0xFFFFFFFF)); \ + r=_t >> 32;} + +#define HEAVISIDE_STEP_UINT32(r,s) {uint32_t _t=s; \ + _t=(((_t)>>16) | (_t)); \ + _t=(0xFFFF + (_t & 0xFFFF)); \ + r=_t >> 16;} + +#define HEAVISIDE_STEP_UINT16(r,s) {uint32_t _t=s; \ + _t=(0xFFFF + ((_t) & 0xFFFF)); \ + r=_t >> 16;} + +#define HEAVISIDE_STEP_UINT8(r,s) {uint16_t _t=s; \ + _t=(0xFF + ((_t) & 0xFF)); \ + r=_t >> 8;} + +#define CC_HEAVISIDE_STEP(r,s) { \ + if (sizeof(s) == 1) {HEAVISIDE_STEP_UINT8(r,s);} \ + else if (sizeof(s) == 2) {HEAVISIDE_STEP_UINT16(r,s);} \ + else if (sizeof(s) == 4) {HEAVISIDE_STEP_UINT32(r,s);} \ + else if (sizeof(s) == 8) {HEAVISIDE_STEP_UINT64(r,s);} \ + else {r=(((s)==0)?0:1);} \ + } + +/* Return 1 if x mod 4 =1,2,3, 0 otherwise */ +#define CC_CARRY_2BITS(x) (((x>>1) | x) & 0x1) +#define CC_CARRY_3BITS(x) (((x>>2) | (x>>1) | x) & 0x1) + +/* Set a variable to the biggest power of 2 which can be represented */ +#define MAX_POWER_OF_2(x) ((__typeof__(x))1<<(8*sizeof(x)-1)) +#define cc_ceiling(a,b) (((a)+((b)-1))/(b)) +#define CC_BITLEN_TO_BYTELEN(x) cc_ceiling((x), 8) + +//cc_try_abort() is implemented to comply with FIPS 140-2. +void cc_try_abort(const char * msg , ...); + +/*! + @brief cc_muxp(s, a, b) is equivalent to z = s ? a : b, but it executes in constant time + @param a input pointer + @param b input pointer + @param s The selection parameter s must be 0 or 1. if s is integer 1 a is returned. If s is integer 0, b is returned. Otherwise, the output is undefined. + @return Returns a, if s is 1 and b if s is 0 + */ +void *cc_muxp(int s, const void *a, const void *b); + +/*! + @brief cc_mux2p + @param a input pointer + @param b input pointer + @param r_true output pointer: if s is integer 1 r_true=a is returned, otherwise r_true=b + @param r_false output pointer: if s is integer 1 r_false=b is returned, otherwise r_false=a + @param s The selection parameter s must be 0 or 1. + @discussion Executes in constant time + */ +void cc_mux2p(int s, void **r_true, void **r_false, const void *a, const void *b); + +/*! + @brief CC_MUXU(s, a, b) is equivalent to z = s ? a : b, but it executes in constant time + @param a input unsigned type + @param b input unsigned type + @param s The selection parameter s must be 0 or 1. if s is integer 1 a is returned. If s is integer 0, b is returned. Otherwise, the output is undefined. + @param r output + @return r = a, if s is 1 and b if s is 0 + */ +#define CC_MUXU(r, s, a, b) \ +{ \ + __typeof__(r) _cond = ((__typeof__(r))(s)-(__typeof__(r))1); \ + r = (~_cond&(a))|(_cond&(b)); \ +} + +int cc_is_compiled_with_tu(void); + +#endif /* _CORECRYPTO_CC_PRIV_H_ */ diff --git a/corecrypto/cc_runtime_config.h b/corecrypto/cc_runtime_config.h new file mode 100644 index 0000000..c7b82a2 --- /dev/null +++ b/corecrypto/cc_runtime_config.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef CORECRYPTO_CC_RUNTIME_CONFIG_H_ +#define CORECRYPTO_CC_RUNTIME_CONFIG_H_ + +#include + +/* Only intel systems have these runtime switches today. */ +#if (CCSHA1_VNG_INTEL || CCSHA2_VNG_INTEL || CCAES_INTEL_ASM) \ + && (defined(__x86_64__) || defined(__i386__)) + +#if CC_KERNEL + #include + #define CC_HAS_AESNI() ((cpuid_features() & CPUID_FEATURE_AES) != 0) + #define CC_HAS_SupplementalSSE3() ((cpuid_features() & CPUID_FEATURE_SSSE3) != 0) + #define CC_HAS_AVX1() ((cpuid_features() & CPUID_FEATURE_AVX1_0) != 0) + #define CC_HAS_AVX2() ((cpuid_info()->cpuid_leaf7_features & CPUID_LEAF7_FEATURE_AVX2) != 0) + +#elif CC_XNU_KERNEL_AVAILABLE && !CORECRYPTO_PUBLIC_SDK + #include + + #ifndef kHasAVX2_0 /* 10.8 doesn't have kHasAVX2_0 defined */ + #define kHasAVX2_0 0 + #endif + + extern int _cpu_capabilities; + #define CC_HAS_AESNI() (_cpu_capabilities & kHasAES) + #define CC_HAS_SupplementalSSE3() (_cpu_capabilities & kHasSupplementalSSE3) + #define CC_HAS_AVX1() (_cpu_capabilities & kHasAVX1_0) + #define CC_HAS_AVX2() (_cpu_capabilities & kHasAVX2_0) +#else + #define CC_HAS_AESNI() 0 + #define CC_HAS_SupplementalSSE3() 0 + #define CC_HAS_AVX1() 0 + #define CC_HAS_AVX2() 0 +#endif + +#endif /* !(defined(__x86_64__) || defined(__i386__)) */ + +#endif /* CORECRYPTO_CC_RUNTIME_CONFIG_H_ */ diff --git a/corecrypto/ccaes.h b/corecrypto/ccaes.h new file mode 100644 index 0000000..8070eb6 --- /dev/null +++ b/corecrypto/ccaes.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2010,2011,2012,2013,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef _CORECRYPTO_CCAES_H_ +#define _CORECRYPTO_CCAES_H_ + +#include +#include + +#define CCAES_BLOCK_SIZE 16 +#define CCAES_KEY_SIZE_128 16 +#define CCAES_KEY_SIZE_192 24 +#define CCAES_KEY_SIZE_256 32 + +#define CCAES_CTR_MAX_PARALLEL_NBLOCKS 8 + +extern const struct ccmode_ecb ccaes_ltc_ecb_decrypt_mode; +extern const struct ccmode_ecb ccaes_ltc_ecb_encrypt_mode; + +extern const struct ccmode_cbc ccaes_gladman_cbc_encrypt_mode; +extern const struct ccmode_cbc ccaes_gladman_cbc_decrypt_mode; + +#if CCAES_ARM_ASM +extern const struct ccmode_ecb ccaes_arm_ecb_encrypt_mode; +extern const struct ccmode_ecb ccaes_arm_ecb_decrypt_mode; + +extern const struct ccmode_cbc ccaes_arm_cbc_encrypt_mode; +extern const struct ccmode_cbc ccaes_arm_cbc_decrypt_mode; + +extern const struct ccmode_xts ccaes_arm_xts_encrypt_mode; +extern const struct ccmode_xts ccaes_arm_xts_decrypt_mode; + +extern const struct ccmode_cfb ccaes_arm_cfb_encrypt_mode; +extern const struct ccmode_cfb ccaes_arm_cfb_decrypt_mode; + +extern const struct ccmode_ofb ccaes_arm_ofb_crypt_mode; + +#endif + +#if CCAES_MUX +extern const struct ccmode_cbc ccaes_ios_hardware_cbc_encrypt_mode; +extern const struct ccmode_cbc ccaes_ios_hardware_cbc_decrypt_mode; + +extern const struct ccmode_ctr ccaes_ios_hardware_ctr_crypt_mode; + +extern const struct ccmode_cbc *ccaes_ios_mux_cbc_encrypt_mode(void); +extern const struct ccmode_cbc *ccaes_ios_mux_cbc_decrypt_mode(void); + +extern const struct ccmode_ctr *ccaes_ios_mux_ctr_crypt_mode(void); + +#endif + +#if CCAES_INTEL_ASM +//extern const struct ccmode_ecb ccaes_intel_ecb_encrypt_mode; +//extern const struct ccmode_ecb ccaes_intel_ecb_decrypt_mode; + +extern const struct ccmode_ecb ccaes_intel_ecb_encrypt_opt_mode; +extern const struct ccmode_ecb ccaes_intel_ecb_encrypt_aesni_mode; + +extern const struct ccmode_ecb ccaes_intel_ecb_decrypt_opt_mode; +extern const struct ccmode_ecb ccaes_intel_ecb_decrypt_aesni_mode; + +//extern const struct ccmode_cbc ccaes_intel_cbc_encrypt_mode; +//extern const struct ccmode_cbc ccaes_intel_cbc_decrypt_mode; + +extern const struct ccmode_cbc ccaes_intel_cbc_encrypt_opt_mode; +extern const struct ccmode_cbc ccaes_intel_cbc_encrypt_aesni_mode; + +extern const struct ccmode_cbc ccaes_intel_cbc_decrypt_opt_mode; +extern const struct ccmode_cbc ccaes_intel_cbc_decrypt_aesni_mode; + +//extern const struct ccmode_xts ccaes_intel_xts_encrypt_mode; +//extern const struct ccmode_xts ccaes_intel_xts_decrypt_mode; + +extern const struct ccmode_xts ccaes_intel_xts_encrypt_opt_mode; +extern const struct ccmode_xts ccaes_intel_xts_encrypt_aesni_mode; + +extern const struct ccmode_xts ccaes_intel_xts_decrypt_opt_mode; +extern const struct ccmode_xts ccaes_intel_xts_decrypt_aesni_mode; +#endif + +#if CC_USE_L4 +extern const struct ccmode_cbc ccaes_skg_cbc_encrypt_mode; +extern const struct ccmode_cbc ccaes_skg_cbc_decrypt_mode; + +extern const struct ccmode_ecb ccaes_skg_ecb_encrypt_mode; +extern const struct ccmode_ecb ccaes_skg_ecb_decrypt_mode; + +extern const struct ccmode_ecb ccaes_trng_ecb_encrypt_mode; +#endif + +/* Implementation Selectors: */ +const struct ccmode_ecb *ccaes_ecb_encrypt_mode(void); +const struct ccmode_cbc *ccaes_cbc_encrypt_mode(void); +const struct ccmode_cfb *ccaes_cfb_encrypt_mode(void); +const struct ccmode_cfb8 *ccaes_cfb8_encrypt_mode(void); +const struct ccmode_xts *ccaes_xts_encrypt_mode(void); +const struct ccmode_gcm *ccaes_gcm_encrypt_mode(void); +const struct ccmode_ccm *ccaes_ccm_encrypt_mode(void); + +const struct ccmode_ecb *ccaes_ecb_decrypt_mode(void); +const struct ccmode_cbc *ccaes_cbc_decrypt_mode(void); +const struct ccmode_cfb *ccaes_cfb_decrypt_mode(void); +const struct ccmode_cfb8 *ccaes_cfb8_decrypt_mode(void); +const struct ccmode_xts *ccaes_xts_decrypt_mode(void); +const struct ccmode_gcm *ccaes_gcm_decrypt_mode(void); +const struct ccmode_ccm *ccaes_ccm_decrypt_mode(void); + +const struct ccmode_ctr *ccaes_ctr_crypt_mode(void); +const struct ccmode_ofb *ccaes_ofb_crypt_mode(void); + +const struct ccmode_siv *ccaes_siv_encrypt_mode(void); +const struct ccmode_siv *ccaes_siv_decrypt_mode(void); + +#endif /* _CORECRYPTO_CCAES_H_ */ diff --git a/corecrypto/ccansikdf.h b/corecrypto/ccansikdf.h new file mode 100644 index 0000000..97f0ed5 --- /dev/null +++ b/corecrypto/ccansikdf.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef corecrypto_ccansikdf_h +#define corecrypto_ccansikdf_h + +#include +#include + +/* + ANSI x9.63 KDF as per x9.63-2011 specification. + with granularity in bytes. + + Input: The input to the key derivation function is: + 1. A byte string Z that is the shared secret value, of byte length lenZ. + 2. An integer keydatalen that is the length in byte of the keying data to be generated. keydatalen shall be less than (2^32–1) hashlen + 3. A byte string SharedInfo that consists of some data shared by the two entities intended to share the secret value Z. The total byte length of Z and SharedInfo must be at most maxhashlen – 4. + + Approved digest functions are for output >= 224bit that is SHA-224 and beyond. + SHA-1 is not forbidden but should only be used for interroperability requirements. + */ + +CC_NONNULL((1, 3, 7)) +int ccansikdf_x963(const struct ccdigest_info *di, + const size_t Z_len, const unsigned char *Z, + const size_t sharedinfo_byte_len, const void *sharedinfo, + const size_t key_len, uint8_t *key); + +#endif diff --git a/corecrypto/ccasn1.h b/corecrypto/ccasn1.h new file mode 100644 index 0000000..a8316a7 --- /dev/null +++ b/corecrypto/ccasn1.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010,2011,2012,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef _CORECRYPTO_CCASN1_H_ +#define _CORECRYPTO_CCASN1_H_ + +#include +#include +#include + +/* ASN.1 types for on the fly ASN.1 BER/DER encoding/decoding. Don't use + these with the ccder interface, use the CCDER_ types instead. */ +enum { + CCASN1_EOL = 0x00, + CCASN1_BOOLEAN = 0x01, + CCASN1_INTEGER = 0x02, + CCASN1_BIT_STRING = 0x03, + CCASN1_OCTET_STRING = 0x04, + CCASN1_NULL = 0x05, + CCASN1_OBJECT_IDENTIFIER = 0x06, + CCASN1_OBJECT_DESCRIPTOR = 0x07, + /* External or instance-of 0x08 */ + CCASN1_REAL = 0x09, + CCASN1_ENUMERATED = 0x0a, + CCASN1_EMBEDDED_PDV = 0x0b, + CCASN1_UTF8_STRING = 0x0c, + /* 0x0d */ + /* 0x0e */ + /* 0x0f */ + CCASN1_SEQUENCE = 0x10, + CCASN1_SET = 0x11, + CCASN1_NUMERIC_STRING = 0x12, + CCASN1_PRINTABLE_STRING = 0x13, + CCASN1_T61_STRING = 0x14, + CCASN1_VIDEOTEX_STRING = 0x15, + CCASN1_IA5_STRING = 0x16, + CCASN1_UTC_TIME = 0x17, + CCASN1_GENERALIZED_TIME = 0x18, + CCASN1_GRAPHIC_STRING = 0x19, + CCASN1_VISIBLE_STRING = 0x1a, + CCASN1_GENERAL_STRING = 0x1b, + CCASN1_UNIVERSAL_STRING = 0x1c, + /* 0x1d */ + CCASN1_BMP_STRING = 0x1e, + CCASN1_HIGH_TAG_NUMBER = 0x1f, + CCASN1_TELETEX_STRING = CCASN1_T61_STRING, + + CCASN1_TAG_MASK = 0xff, + CCASN1_TAGNUM_MASK = 0x1f, + + CCASN1_METHOD_MASK = 0x20, + CCASN1_PRIMITIVE = 0x00, + CCASN1_CONSTRUCTED = 0x20, + + CCASN1_CLASS_MASK = 0xc0, + CCASN1_UNIVERSAL = 0x00, + CCASN1_APPLICATION = 0x40, + CCASN1_CONTEXT_SPECIFIC = 0x80, + CCASN1_PRIVATE = 0xc0, + + CCASN1_CONSTRUCTED_SET = CCASN1_SET | CCASN1_CONSTRUCTED, + CCASN1_CONSTRUCTED_SEQUENCE = CCASN1_SEQUENCE | CCASN1_CONSTRUCTED, +}; + +#if CORECRYPTO_USE_TRANSPARENT_UNION +typedef union { + const unsigned char * oid; +} __attribute__((transparent_union)) ccoid_t; +#define CCOID(x) ((x).oid) +#else + typedef const unsigned char * ccoid_t; +#define CCOID(oid) (oid) +#endif + +/* Returns *der iff *der points to a DER encoded oid that fits within *der_len. */ +ccoid_t ccoid_for_der(size_t *der_len, const uint8_t **der); + +/* Returns the size of an oid including it's tag and length. */ +CC_INLINE CC_PURE CC_NONNULL_TU((1)) +size_t ccoid_size(ccoid_t oid) { + return 2 + CCOID(oid)[1]; +} + +CC_INLINE CC_PURE CC_NONNULL_TU((1)) CC_NONNULL_TU((2)) +bool ccoid_equal(ccoid_t oid1, ccoid_t oid2) { + return (ccoid_size(oid1) == ccoid_size(oid2) + && memcmp(CCOID(oid1), CCOID(oid2), ccoid_size(oid1))== 0); +} + +#endif /* _CORECRYPTO_CCASN1_H_ */ diff --git a/corecrypto/ccblowfish.h b/corecrypto/ccblowfish.h new file mode 100644 index 0000000..bcfafef --- /dev/null +++ b/corecrypto/ccblowfish.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010,2012,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef _CORECRYPTO_CCBLOWFISH_H_ +#define _CORECRYPTO_CCBLOWFISH_H_ + +#include + +#define CCBLOWFISH_BLOCK_SIZE 8 + +#define CCBLOWFISH_KEY_SIZE_MIN 8 +#define CCBLOWFISH_KEY_SIZE_MAX 56 + +extern const struct ccmode_ecb ccblowfish_ltc_ecb_decrypt_mode; +extern const struct ccmode_ecb ccblowfish_ltc_ecb_encrypt_mode; + + + +const struct ccmode_ecb *ccblowfish_ecb_decrypt_mode(void); +const struct ccmode_ecb *ccblowfish_ecb_encrypt_mode(void); + +const struct ccmode_cbc *ccblowfish_cbc_decrypt_mode(void); +const struct ccmode_cbc *ccblowfish_cbc_encrypt_mode(void); + +const struct ccmode_cfb *ccblowfish_cfb_decrypt_mode(void); +const struct ccmode_cfb *ccblowfish_cfb_encrypt_mode(void); + +const struct ccmode_cfb8 *ccblowfish_cfb8_decrypt_mode(void); +const struct ccmode_cfb8 *ccblowfish_cfb8_encrypt_mode(void); + +const struct ccmode_ctr *ccblowfish_ctr_crypt_mode(void); + +const struct ccmode_ofb *ccblowfish_ofb_crypt_mode(void); + + +#endif /* _CORECRYPTO_CCBLOWFISH_H_ */ diff --git a/corecrypto/cccast.h b/corecrypto/cccast.h new file mode 100644 index 0000000..71b5fd6 --- /dev/null +++ b/corecrypto/cccast.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011,2012,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCCAST_H_ +#define _CORECRYPTO_CCCAST_H_ + +#include + +#define CCCAST_BLOCK_SIZE 8 /* block size in bytes */ +#define CCCAST_KEY_LENGTH 16 /* MAX key size in bytes */ +#define CCCAST_MIN_KEY_LENGTH 5 /* MIN key size in bytes */ + +/* Selectors: */ +const struct ccmode_ecb *cccast_ecb_decrypt_mode(void); +const struct ccmode_ecb *cccast_ecb_encrypt_mode(void); + +const struct ccmode_cbc *cccast_cbc_decrypt_mode(void); +const struct ccmode_cbc *cccast_cbc_encrypt_mode(void); + +const struct ccmode_cfb *cccast_cfb_decrypt_mode(void); +const struct ccmode_cfb *cccast_cfb_encrypt_mode(void); + +const struct ccmode_cfb8 *cccast_cfb8_decrypt_mode(void); +const struct ccmode_cfb8 *cccast_cfb8_encrypt_mode(void); + +const struct ccmode_ctr *cccast_ctr_crypt_mode(void); + +const struct ccmode_ofb *cccast_ofb_crypt_mode(void); + +/* Implementations: */ +extern const struct ccmode_ecb cccast_eay_ecb_decrypt_mode; +extern const struct ccmode_ecb cccast_eay_ecb_encrypt_mode; + + +#endif /* _CORECRYPTO_CCCAST_H_ */ diff --git a/corecrypto/ccchacha20poly1305.h b/corecrypto/ccchacha20poly1305.h new file mode 100644 index 0000000..a496abe --- /dev/null +++ b/corecrypto/ccchacha20poly1305.h @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCCHACHA20POLY1305_H_ +#define _CORECRYPTO_CCCHACHA20POLY1305_H_ + +#include +#include +#include + +#define CCCHACHA20_KEY_NBYTES 32 +#define CCCHACHA20_BLOCK_NBYTES 64 +#define CCCHACHA20_BLOCK_NBITS (CCCHACHA20_BLOCK_NBYTES * 8) +#define CCCHACHA20_NONCE_NBYTES 12 + +typedef struct { + uint32_t state[16]; + uint8_t buffer[CCCHACHA20_BLOCK_NBYTES]; + size_t leftover; +} ccchacha20_ctx; + +#define CCPOLY1305_TAG_NBYTES 16 + +typedef struct { + uint32_t r0, r1, r2, r3, r4; + uint32_t s1, s2, s3, s4; + uint32_t h0, h1, h2, h3, h4; + uint8_t buf[16]; + size_t buf_used; + uint8_t key[16]; +} ccpoly1305_ctx; + + +/*! + @group ccchacha20poly1305 + @abstract Encrypts and authenticates or decrypts and verifies data. + @discussion See RFC 7539 for details. + + @warning The key-nonce pair must be unique per encryption. + + @warning A single message can be at most (2^38 - 64) bytes in length. + + The correct sequence of calls to encrypt is: + + @code ccchacha20poly1305_init(...) + ccchacha20poly1305_setnonce(...) + ccchacha20poly1305_aad(...) (may be called zero or more times) + ccchacha20poly1305_encrypt(...) (may be called zero or more times) + ccchacha20poly1305_finalize(...) + + To reuse the context for additional encryptions, follow this sequence: + + @code ccchacha20poly1305_reset(...) + ccchacha20poly1305_setnonce(...) + ccchacha20poly1305_aad(...) (may be called zero or more times) + ccchacha20poly1305_encrypt(...) (may be called zero or more times) + ccchacha20poly1305_finalize(...) + + To decrypt, follow this call sequence: + + @code ccchacha20poly1305_init(...) + ccchacha20poly1305_setnonce(...) + ccchacha20poly1305_aad(...) (may be called zero or more times) + ccchacha20poly1305_decrypt(...) (may be called zero or more times) + ccchacha20poly1305_verify(...) (returns zero on successful decryption) + + To reuse the context for additional encryptions, follow this sequence: + + @code ccchacha20poly1305_reset(...) + ccchacha20poly1305_setnonce(...) + ccchacha20poly1305_aad(...) (may be called zero or more times) + ccchacha20poly1305_decrypt(...) (may be called zero or more times) + ccchacha20poly1305_verify(...) (returns zero on successful decryption) +*/ + +#define CCCHACHA20POLY1305_KEY_NBYTES (CCCHACHA20_KEY_NBYTES) +#define CCCHACHA20POLY1305_NONCE_NBYTES (CCCHACHA20_NONCE_NBYTES) +#define CCCHACHA20POLY1305_TAG_NBYTES (CCPOLY1305_TAG_NBYTES) + +/* (2^32 - 1) blocks */ +/* (2^38 - 64) bytes */ +/* (2^41 - 512) bits */ +/* Exceeding this figure breaks confidentiality and authenticity. */ +#define CCCHACHA20POLY1305_TEXT_MAX_NBYTES ((1ULL << 38) - 64ULL) + +#define CCCHACHA20POLY1305_STATE_SETNONCE 1 +#define CCCHACHA20POLY1305_STATE_AAD 2 +#define CCCHACHA20POLY1305_STATE_ENCRYPT 3 +#define CCCHACHA20POLY1305_STATE_DECRYPT 4 +#define CCCHACHA20POLY1305_STATE_FINAL 5 + +typedef struct { + ccchacha20_ctx chacha20_ctx; + ccpoly1305_ctx poly1305_ctx; + uint64_t aad_nbytes; + uint64_t text_nbytes; + uint8_t state; +} ccchacha20poly1305_ctx; + +// This is just a stub right now. +// Eventually we will optimize by platform. +struct ccchacha20poly1305_info { + +}; + +extern const struct ccchacha20poly1305_info ccchacha20poly1305_info_default; + +const struct ccchacha20poly1305_info *ccchacha20poly1305_info(void); + +/*! + @function ccchacha20poly1305_init + @abstract Initialize a chacha20poly1305 context. + + @param info Implementation descriptor + @param ctx Context for this instance + @param key Secret chacha20 key + + @result 0 iff successful. + + @discussion The key is 32 bytes in length. + + @warning The key-nonce pair must be unique per encryption. + */ +int ccchacha20poly1305_init(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, const uint8_t *key); + +/*! + @function ccchacha20poly1305_reset + @abstract Reset a chacha20poly1305 context for reuse. + + @param info Implementation descriptor + @param ctx Context for this instance + + @result 0 iff successful. + */ +int ccchacha20poly1305_reset(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx); + +/*! + @function ccchacha20poly1305_setnonce + @abstract Set the nonce for encryption or decryption. + + @param info Implementation descriptor + @param ctx Context for this instance + @param nonce Unique nonce per encryption + + @result 0 iff successful. + + @discussion The nonce is 12 bytes in length. + + @warning The key-nonce pair must be unique per encryption. + */ +int ccchacha20poly1305_setnonce(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, const uint8_t *nonce); +int ccchacha20poly1305_incnonce(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, uint8_t *nonce); + +/*! + @function ccchacha20poly1305_aad + @abstract Authenticate additional data. + + @param info Descriptor for the mode + @param ctx Context for this instance + @param nbytes Length of the additional data in bytes + @param aad Additional data to authenticate + + @result 0 iff successful. + + @discussion This is typically used to authenticate data that cannot be encrypted (e.g. packet headers). + + This function may be called zero or more times. + */ +int ccchacha20poly1305_aad(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, size_t nbytes, const void *aad); + +/*! + @function ccchacha20poly1305_encrypt + @abstract Encrypt data. + + @param info Descriptor for the mode + @param ctx Context for this instance + @param nbytes Length of the plaintext in bytes + @param ptext Input plaintext + @param ctext Output ciphertext + + @result 0 iff successful. + + @discussion In-place processing is supported. + + This function may be called zero or more times. + */ +int ccchacha20poly1305_encrypt(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, size_t nbytes, const void *ptext, void *ctext); + +/*! + @function ccchacha20poly1305_finalize + @abstract Finalize encryption. + + @param info Descriptor for the mode + @param ctx Context for this instance + @param tag Generated authentication tag + + @result 0 iff successful. + + @discussion The generated tag is 16 bytes in length. + */ +int ccchacha20poly1305_finalize(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, uint8_t *tag); + +/*! + @function ccchacha20poly1305_decrypt + @abstract Decrypt data. + + @param info Descriptor for the mode + @param ctx Context for this instance + @param nbytes Length of the ciphertext in bytes + @param ctext Input ciphertext + @param ptext Output plaintext + + @result 0 iff successful. + + @discussion In-place processing is supported. + + This function may be called zero or more times. + */ +int ccchacha20poly1305_decrypt(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, size_t nbytes, const void *ctext, void *ptext); + +/*! + @function ccchacha20poly1305_verify + @abstract Verify authenticity. + + @param info Descriptor for the mode + @param ctx Context for this instance + @param tag Expected authentication tag + + @result 0 iff authentic and otherwise successful. + + @discussion The expected tag is 16 bytes in length. + */ +int ccchacha20poly1305_verify(const struct ccchacha20poly1305_info *info, ccchacha20poly1305_ctx *ctx, const uint8_t *tag); + +/*! + @function ccchacha20poly1305_encrypt_oneshot + @abstract Encrypt with chacha20poly1305. + + @param info Descriptor for the mode + @param key Secret chacha20 key + @param nonce Unique nonce per encryption + @param aad_nbytes Length of the additional data in bytes + @param aad Additional data to authenticate + @param ptext_nbytes Length of the plaintext in bytes + @param ptext Input plaintext + @param ctext Output ciphertext + @param tag Generated authentication tag + + @discussion See RFC 7539 for details. + + The key is 32 bytes in length. + + The nonce is 12 bytes in length. + + The generated tag is 16 bytes in length. + + In-place processing is supported. + + @warning The key-nonce pair must be unique per encryption. + + @warning A single message can be at most (2^38 - 64) bytes in length. + */ +int ccchacha20poly1305_encrypt_oneshot(const struct ccchacha20poly1305_info *info, const uint8_t *key, const uint8_t *nonce, size_t aad_nbytes, const void *aad, size_t ptext_nbytes, const void *ptext, void *ctext, uint8_t *tag); + +/*! + @function ccchacha20poly1305_decrypt_oneshot + @abstract Decrypt with chacha20poly1305. + + @param info Descriptor for the mode + @param key Secret chacha20 key + @param nonce Unique nonce per encryption + @param aad_nbytes Length of the additional data in bytes + @param aad Additional data to authenticate + @param ctext_nbytes Length of the ciphertext in bytes + @param ctext Input ciphertext + @param ptext Output plaintext + @param tag Expected authentication tag + + @discussion See RFC 7539 for details. + + The key is 32 bytes in length. + + The nonce is 12 bytes in length. + + The generated tag is 16 bytes in length. + + In-place processing is supported. + */ +int ccchacha20poly1305_decrypt_oneshot(const struct ccchacha20poly1305_info *info, const uint8_t *key, const uint8_t *nonce, size_t aad_nbytes, const void *aad, size_t ctext_nbytes, const void *ctext, void *ptext, const uint8_t *tag); + +#endif diff --git a/corecrypto/ccchacha20poly1305_priv.h b/corecrypto/ccchacha20poly1305_priv.h new file mode 100644 index 0000000..d030db9 --- /dev/null +++ b/corecrypto/ccchacha20poly1305_priv.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCCHACHA20POLY1305_PRIV_H_ +#define _CORECRYPTO_CCCHACHA20POLY1305_PRIV_H_ + +/*! @group ccchacha20 + @abstract Encrypts/decrypts N bytes of data with a 32-byte key and 8-byte nonce starting from an 8-byte counter. + @discussion See DJB's page on ChaCha20 . + */ + +int ccchacha20_init(ccchacha20_ctx *ctx, const uint8_t *key); +int ccchacha20_reset(ccchacha20_ctx *ctx); +int ccchacha20_setnonce(ccchacha20_ctx *ctx, const uint8_t *nonce); +int ccchacha20_setcounter(ccchacha20_ctx *ctx, uint32_t counter); +int ccchacha20_update(ccchacha20_ctx *ctx, size_t nbytes, const void *in, void *out); +int ccchacha20_final(ccchacha20_ctx *ctx); +int ccchacha20(const uint8_t *key, const uint8_t *nonce, uint32_t counter, size_t nbytes, const void *in, void *out); + +/*! @group poly1305 + @abstract Generates a 16-byte Poly1305 Message Authentication Code from N bytes of data and a 32-byte key. + @discussion See DJB's paper on Poly1305 for details. + */ + +int ccpoly1305_init(ccpoly1305_ctx *ctx, const uint8_t *key); +int ccpoly1305_update(ccpoly1305_ctx *ctx, size_t nbytes, const uint8_t *data); +int ccpoly1305_final(ccpoly1305_ctx *ctx, uint8_t *tag); +int ccpoly1305(const uint8_t *key, size_t nbytes, const uint8_t *data, uint8_t *tag); + +#endif /* _CORECRYPTO_CCCHACHA20POLY1305_PRIV_H_ */ diff --git a/corecrypto/cccmac.h b/corecrypto/cccmac.h new file mode 100644 index 0000000..7ff7a0c --- /dev/null +++ b/corecrypto/cccmac.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2013,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_cccmac_H_ +#define _CORECRYPTO_cccmac_H_ + +#include +#include +#include + +#define CMAC_BLOCKSIZE 16 + +#if CORECRYPTO_USE_TRANSPARENT_UNION +struct cccmac_ctx { + uint8_t b[8]; +} CC_ALIGNED(8); + +typedef struct cccmac_ctx_hdr { + uint8_t k1[CMAC_BLOCKSIZE]; + uint8_t k2[CMAC_BLOCKSIZE]; + uint8_t block[CMAC_BLOCKSIZE]; + size_t block_nbytes; // Number of byte occupied in block buf + size_t cumulated_nbytes; // Total size processed + const struct ccmode_cbc *cbc; + uint8_t ctx[8]; +} CC_ALIGNED(8) cccmac_ctx_hdr; + + +typedef union { + struct cccmac_ctx *b; + cccmac_ctx_hdr *hdr; +} cccmac_ctx_t __attribute__((transparent_union)); +#define cccmac_hdr_size sizeof(struct cccmac_ctx_hdr) + +#else + +struct cccmac_ctx { + uint8_t k1[CMAC_BLOCKSIZE]; + uint8_t k2[CMAC_BLOCKSIZE]; + uint8_t block[CMAC_BLOCKSIZE]; + size_t block_nbytes; // Number of byte occupied in block + size_t cumulated_nbytes; // Total size processed + const struct ccmode_cbc *cbc; + uint8_t ctx[8]; +} CC_ALIGNED(8);// cccmac_ctx_hdr; + +typedef struct cccmac_ctx* cccmac_ctx_t; + +#define cccmac_hdr_size sizeof(struct cccmac_ctx) + +#endif + + +#define cccmac_iv_size(_mode_) ((_mode_)->block_size) +#define cccmac_cbc_size(_mode_) ((_mode_)->size) + +#define cccmac_ctx_size(_mode_) (cccmac_hdr_size + cccmac_iv_size(_mode_) + cccmac_cbc_size(_mode_)) +#define cccmac_ctx_n(_mode_) ccn_nof_size(cccmac_ctx_size(_mode_)) + +#define cccmac_mode_decl(_mode_, _name_) cc_ctx_decl(struct cccmac_ctx, cccmac_ctx_size(_mode_), _name_) +#define cccmac_mode_clear(_mode_, _name_) cc_clear(cccmac_ctx_size(_mode_), _name_) + +#if CORECRYPTO_USE_TRANSPARENT_UNION +/* Return a cccbc_ctx * which can be accesed with the macros in ccmode.h */ +#define cccmac_mode_ctx_start(_mode_, HC) (((HC).hdr)->ctx) +#define CCCMAC_HDR(HC) (((cccmac_ctx_t)(HC)).hdr) +#else +/* Return a cccbc_ctx * which can be accesed with the macros in ccmode.h */ +#define cccmac_mode_ctx_start(_mode_, HC) (HC->ctx) +#define CCCMAC_HDR(HC) (HC) +#endif + +#define cccmac_mode_sym_ctx(_mode_, HC) (cccbc_ctx *)(cccmac_mode_ctx_start(_mode_, HC)) +#define cccmac_mode_iv(_mode_, HC) (cccbc_iv *)(cccmac_mode_ctx_start(_mode_, HC)+cccmac_cbc_size(_mode_)) +#define cccmac_k1(HC) (CCCMAC_HDR(HC)->k1) +#define cccmac_k2(HC) (CCCMAC_HDR(HC)->k2) +#define cccmac_block(HC) (CCCMAC_HDR(HC)->block) +#define cccmac_cbc(HC) (CCCMAC_HDR(HC)->cbc) +#define cccmac_block_nbytes(HC) (CCCMAC_HDR(HC)->block_nbytes) +#define cccmac_cumulated_nbytes(HC) (CCCMAC_HDR(HC)->cumulated_nbytes) + + +/* CMAC as defined in NIST SP800-38B - 2005 */ + +/* ============================================================================= + + ONE SHOT + + ==============================================================================*/ + +/*! + @function cccmac_one_shot_generate + @abstract CMAC generation in one call + + @param cbc CBC and block cipher specification + @param key_nbytes Length of the key in bytes + @param key Pointer to the key of length key_nbytes + @param data_nbytes Length of the data in bytes + @param data Pointer to the data in bytes + @param mac_nbytes Length in byte of the mac, > 0 + @param mac Output of length cbc->block_size + + @result 0 iff successful. + + @discussion Only supports CMAC_BLOCKSIZE block ciphers + */ +int cccmac_one_shot_generate(const struct ccmode_cbc *cbc, + size_t key_nbytes, const void *key, + size_t data_nbytes, const void *data, + size_t mac_nbytes, void *mac); + +/*! + @function cccmac_one_shot_verify + @abstract CMAC verification in one call + + @param cbc CBC and block cipher specification + @param key_nbytes Length of the key in bytes + @param key Pointer to the key of length key_nbytes + @param data_nbytes Length of the data in bytes + @param data Pointer to the data in bytes + @param expected_mac_nbytes Length in byte of the mac, > 0 + @param expected_mac Mac value expected + + @result 0 iff successful. + + @discussion Only supports CMAC_BLOCKSIZE block ciphers + */ +int cccmac_one_shot_verify(const struct ccmode_cbc *cbc, + size_t key_nbytes, const void *key, + size_t data_nbytes, const void *data, + size_t expected_mac_nbytes, const void *expected_mac); + +/* ============================================================================= + + STREAMING + + Init - Update - Final + +==============================================================================*/ + +/*! + @function cccmac_init + @abstract Init CMAC context with CBC mode and key + + @param cbc CBC and block cipher specification + @param ctx Context use to store internal state + @param key_nbytes Length of the key in bytes + @param key Full key + + @result 0 iff successful. + + @discussion Only supports CMAC_BLOCKSIZE block ciphers + */ + +int cccmac_init(const struct ccmode_cbc *cbc, + cccmac_ctx_t ctx, + size_t key_nbytes, const void *key); + +/*! + @function cccmac_update + @abstract Process data + + @param ctx Context use to store internal state + @param data_nbytes Length in byte of the data + @param data Data to process + + @result 0 iff successful. + + @discussion Only supports CMAC_BLOCKSIZE block ciphers + */ + +int cccmac_update(cccmac_ctx_t ctx, + size_t data_nbytes, const void *data); + +/*! + @function cccmac_final_generate + @abstract Final step for generation + + @param ctx Context use to store internal state + @param mac_nbytes Length in byte of the mac, > 0 + @param mac Output of length mac_nbytes + + @result 0 iff successful. + + @discussion Only supports CMAC_BLOCKSIZE block ciphers + */ +int cccmac_final_generate(cccmac_ctx_t ctx, + size_t mac_nbytes, void *mac); + +/*! + @function cccmac_final_verify + @abstract Final step and verification + + @param ctx Context use to store internal state + @param expected_mac_nbytes Length in byte of the mac, > 0 + @param expected_mac Mac value expected + + @result 0 iff successful. + + @discussion Only supports CMAC_BLOCKSIZE block ciphers + */ +int cccmac_final_verify(cccmac_ctx_t ctx, + size_t expected_mac_nbytes, const void *expected_mac); + +#endif /* _CORECRYPTO_cccmac_H_ */ diff --git a/corecrypto/ccder.h b/corecrypto/ccder.h new file mode 100644 index 0000000..1971a8d --- /dev/null +++ b/corecrypto/ccder.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2012,2013,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef _CORECRYPTO_CCDER_H_ +#define _CORECRYPTO_CCDER_H_ + +#include +#include + +#define CCDER_MULTIBYTE_TAGS 1 + +#ifdef CCDER_MULTIBYTE_TAGS +typedef unsigned long ccder_tag; +#else +typedef uint8_t ccder_tag; +#endif + +/* DER types to be used with ccder_decode and ccder_encode functions. */ +#define CCDER_EOL CCASN1_EOL +#define CCDER_BOOLEAN CCASN1_BOOLEAN +#define CCDER_INTEGER CCASN1_INTEGER +#define CCDER_BIT_STRING CCASN1_BIT_STRING +#define CCDER_OCTET_STRING CCASN1_OCTET_STRING +#define CCDER_NULL CCASN1_NULL +#define CCDER_OBJECT_IDENTIFIER CCASN1_OBJECT_IDENTIFIER +#define CCDER_OBJECT_DESCRIPTOR CCASN1_OBJECT_DESCRIPTOR + /* External or instance-of 0x08 */ +#define CCDER_REAL CCASN1_REAL +#define CCDER_ENUMERATED CCASN1_ENUMERATED +#define CCDER_EMBEDDED_PDV CCASN1_EMBEDDED_PDV +#define CCDER_UTF8_STRING CCASN1_UTF8_STRING + /* 0x0d */ + /* 0x0e */ + /* 0x0f */ +#define CCDER_SEQUENCE CCASN1_SEQUENCE +#define CCDER_SET CCASN1_SET +#define CCDER_NUMERIC_STRING CCASN1_NUMERIC_STRING +#define CCDER_PRINTABLE_STRING CCASN1_PRINTABLE_STRING +#define CCDER_T61_STRING CCASN1_T61_STRING +#define CCDER_VIDEOTEX_STRING CCASN1_VIDEOTEX_STRING +#define CCDER_IA5_STRING CCASN1_IA5_STRING +#define CCDER_UTC_TIME CCASN1_UTC_TIME +#define CCDER_GENERALIZED_TIME CCASN1_GENERALIZED_TIME +#define CCDER_GRAPHIC_STRING CCASN1_GRAPHIC_STRING +#define CCDER_VISIBLE_STRING CCASN1_VISIBLE_STRING +#define CCDER_GENERAL_STRING CCASN1_GENERAL_STRING +#define CCDER_UNIVERSAL_STRING CCASN1_UNIVERSAL_STRING + /* 0x1d */ +#define CCDER_BMP_STRING CCASN1_BMP_STRING +#define CCDER_HIGH_TAG_NUMBER CCASN1_HIGH_TAG_NUMBER +#define CCDER_TELETEX_STRING CCDER_T61_STRING + +#ifdef CCDER_MULTIBYTE_TAGS +#define CCDER_TAG_MASK ((ccder_tag)~0) +#define CCDER_TAGNUM_MASK ((ccder_tag)~((ccder_tag)7 << (sizeof(ccder_tag) * 8 - 3))) + +#define CCDER_METHOD_MASK ((ccder_tag)1 << (sizeof(ccder_tag) * 8 - 3)) +#define CCDER_PRIMITIVE ((ccder_tag)0 << (sizeof(ccder_tag) * 8 - 3)) +#define CCDER_CONSTRUCTED ((ccder_tag)1 << (sizeof(ccder_tag) * 8 - 3)) + +#define CCDER_CLASS_MASK ((ccder_tag)3 << (sizeof(ccder_tag) * 8 - 2)) +#define CCDER_UNIVERSAL ((ccder_tag)0 << (sizeof(ccder_tag) * 8 - 2)) +#define CCDER_APPLICATION ((ccder_tag)1 << (sizeof(ccder_tag) * 8 - 2)) +#define CCDER_CONTEXT_SPECIFIC ((ccder_tag)2 << (sizeof(ccder_tag) * 8 - 2)) +#define CCDER_PRIVATE ((ccder_tag)3 << (sizeof(ccder_tag) * 8 - 2)) +#else /* !CCDER_MULTIBYTE_TAGS */ +#define CCDER_TAG_MASK CCASN1_TAG_MASK +#define CCDER_TAGNUM_MASK CCASN1_TAGNUM_MASK + +#define CCDER_METHOD_MASK CCASN1_METHOD_MASK +#define CCDER_PRIMITIVE CCASN1_PRIMITIVE +#define CCDER_CONSTRUCTED CCASN1_CONSTRUCTED + +#define CCDER_CLASS_MASK CCASN1_CLASS_MASK +#define CCDER_UNIVERSAL CCASN1_UNIVERSAL +#define CCDER_APPLICATION CCASN1_APPLICATION +#define CCDER_CONTEXT_SPECIFIC CCASN1_CONTEXT_SPECIFIC +#define CCDER_PRIVATE CCASN1_PRIVATE +#endif /* !CCDER_MULTIBYTE_TAGS */ +#define CCDER_CONSTRUCTED_SET (CCDER_SET | CCDER_CONSTRUCTED) +#define CCDER_CONSTRUCTED_SEQUENCE (CCDER_SEQUENCE | CCDER_CONSTRUCTED) + + +// MARK: ccder_sizeof_ functions + +/* Returns the size of an asn1 encoded item of length l in bytes. */ +CC_CONST +size_t ccder_sizeof(ccder_tag tag, size_t len); + +CC_PURE +size_t ccder_sizeof_implicit_integer(ccder_tag implicit_tag, + cc_size n, const cc_unit *s); + +CC_PURE +size_t ccder_sizeof_implicit_octet_string(ccder_tag implicit_tag, + cc_size n, const cc_unit *s); + +CC_CONST +size_t ccder_sizeof_implicit_raw_octet_string(ccder_tag implicit_tag, + size_t s_size); +CC_CONST +size_t ccder_sizeof_implicit_uint64(ccder_tag implicit_tag, uint64_t value); + +CC_PURE +size_t ccder_sizeof_integer(cc_size n, const cc_unit *s); + +CC_CONST +size_t ccder_sizeof_len(size_t len); + +CC_PURE +size_t ccder_sizeof_octet_string(cc_size n, const cc_unit *s); + +CC_PURE +size_t ccder_sizeof_oid(ccoid_t oid); + +CC_CONST +size_t ccder_sizeof_raw_octet_string(size_t s_size); + +CC_CONST +size_t ccder_sizeof_tag(ccder_tag tag); + +CC_CONST +size_t ccder_sizeof_uint64(uint64_t value); + +// MARK: ccder_encode_ functions. + +/* Encode a tag backwards, der_end should point to one byte past the end of + destination for the tag, returns a pointer to the first byte of the tag. + Returns NULL if there is an encoding error. */ +CC_NONNULL2 +uint8_t *ccder_encode_tag(ccder_tag tag, const uint8_t *der, uint8_t *der_end); + +/* Returns a pointer to the start of the len field. returns NULL if there + is an encoding error. */ +CC_NONNULL2 +uint8_t * +ccder_encode_len(size_t len, const uint8_t *der, uint8_t *der_end); + +/* der_end should point to the first byte of the content of this der item. */ +CC_NONNULL3 +uint8_t * +ccder_encode_tl(ccder_tag tag, size_t len, const uint8_t *der, uint8_t *der_end); + +CC_PURE CC_NONNULL2 +uint8_t * +ccder_encode_body_nocopy(size_t size, const uint8_t *der, uint8_t *der_end); + +/* Encode the tag and length of a constructed object. der is the lower + bound, der_end is one byte paste where we want to write the length and + body_end is one byte past the end of the body of the der object we are + encoding the tag and length of. */ +CC_NONNULL((2, 3)) +uint8_t * +ccder_encode_constructed_tl(ccder_tag tag, const uint8_t *body_end, + const uint8_t *der, uint8_t *der_end); + +/* Encodes oid into der and returns + der + ccder_sizeof_oid(oid). */ +CC_NONNULL_TU((1)) CC_NONNULL2 +uint8_t *ccder_encode_oid(ccoid_t oid, const uint8_t *der, uint8_t *der_end); + +CC_NONNULL((3, 4)) +uint8_t *ccder_encode_implicit_integer(ccder_tag implicit_tag, + cc_size n, const cc_unit *s, + const uint8_t *der, uint8_t *der_end); + +CC_NONNULL((2, 3)) +uint8_t *ccder_encode_integer(cc_size n, const cc_unit *s, + const uint8_t *der, uint8_t *der_end); + +CC_NONNULL3 +uint8_t *ccder_encode_implicit_uint64(ccder_tag implicit_tag, + uint64_t value, + const uint8_t *der, uint8_t *der_end); + +CC_NONNULL2 +uint8_t *ccder_encode_uint64(uint64_t value, + const uint8_t *der, uint8_t *der_end); + +CC_NONNULL((3, 4)) +uint8_t *ccder_encode_implicit_octet_string(ccder_tag implicit_tag, + cc_size n, const cc_unit *s, + const uint8_t *der, + uint8_t *der_end); + +CC_NONNULL((2, 3)) +uint8_t *ccder_encode_octet_string(cc_size n, const cc_unit *s, + const uint8_t *der, uint8_t *der_end); + +CC_NONNULL((3, 4)) +uint8_t *ccder_encode_implicit_raw_octet_string(ccder_tag implicit_tag, + size_t s_size, const uint8_t *s, + const uint8_t *der, + uint8_t *der_end); + +CC_NONNULL((2, 3)) +uint8_t *ccder_encode_raw_octet_string(size_t s_size, const uint8_t *s, + const uint8_t *der, uint8_t *der_end); + +size_t ccder_encode_eckey_size(size_t priv_size, ccoid_t oid, size_t pub_size); + +CC_NONNULL2 CC_NONNULL5 CC_NONNULL6 CC_NONNULL7 +uint8_t *ccder_encode_eckey(size_t priv_size, const uint8_t *priv_key, + ccoid_t oid, + size_t pub_size, const uint8_t *pub_key, + uint8_t *der, uint8_t *der_end); + +/* ccder_encode_body COPIES the body into the der. + It's inefficient – especially when you already have to convert to get to + the form for the body. + see encode integer for the right way to unify conversion and insertion */ +CC_NONNULL3 +uint8_t * +ccder_encode_body(size_t size, const uint8_t* body, + const uint8_t *der, uint8_t *der_end); + +// MARK: ccder_decode_ functions. + +/* Returns a pointer to the start of the length field, and returns the decoded tag in tag. + returns NULL if there is a decoding error. */ +CC_NONNULL((1, 3)) +const uint8_t *ccder_decode_tag(ccder_tag *tagp, const uint8_t *der, const uint8_t *der_end); + +CC_NONNULL((1, 3)) +const uint8_t *ccder_decode_len(size_t *lenp, const uint8_t *der, const uint8_t *der_end); + +/* Returns a pointer to the start of the der object, and returns the length in len. + returns NULL if there is a decoding error. */ +CC_NONNULL((2, 4)) +const uint8_t *ccder_decode_tl(ccder_tag expected_tag, size_t *lenp, + const uint8_t *der, const uint8_t *der_end); + +CC_NONNULL((2, 4)) +const uint8_t * +ccder_decode_constructed_tl(ccder_tag expected_tag, const uint8_t **body_end, + const uint8_t *der, const uint8_t *der_end); + +CC_NONNULL((1, 3)) +const uint8_t * +ccder_decode_sequence_tl(const uint8_t **body_end, + const uint8_t *der, const uint8_t *der_end); + +/*! + @function ccder_decode_uint_n + @abstract length in cc_unit of a der unsigned integer after skipping the leading zeroes + + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + @param n Output the number of cc_unit required to represent the number + + @result First byte after the parsed integer or + NULL if the integer is not valid (negative) or reach der_end when reading the integer + */ + +CC_NONNULL((3)) +const uint8_t *ccder_decode_uint_n(cc_size *n, + const uint8_t *der, const uint8_t *der_end); + +/*! + @function ccder_decode_uint + @abstract Represent in cc_unit a der unsigned integer after skipping the leading zeroes + + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + @param n Number of cc_unit allocated for r + @param r Allocated array of cc_unit to copy the integer into. + + @result First byte after the parsed integer or + NULL if the integer is not valid (negative) + reach der_end when reading the integer + n cc_unit is not enough to represent the integer + */ +CC_NONNULL((4)) +const uint8_t *ccder_decode_uint(cc_size n, cc_unit *r, + const uint8_t *der, const uint8_t *der_end); + +CC_NONNULL((3)) +const uint8_t *ccder_decode_uint64(uint64_t* r, + const uint8_t *der, const uint8_t *der_end); + +/* Decode SEQUENCE { r, s -- (unsigned)integer } in der into r and s. + Returns NULL on decode errors, returns pointer just past the end of the + sequence of integers otherwise. */ +CC_NONNULL((2, 3, 5)) +const uint8_t *ccder_decode_seqii(cc_size n, cc_unit *r, cc_unit *s, + const uint8_t *der, const uint8_t *der_end); +CC_NONNULL_TU((1)) CC_NONNULL((3)) +const uint8_t *ccder_decode_oid(ccoid_t *oidp, + const uint8_t *der, const uint8_t *der_end); + +CC_NONNULL((1,2,4)) +const uint8_t *ccder_decode_bitstring(const uint8_t **bit_string, + size_t *bit_length, + const uint8_t *der, const uint8_t *der_end); + +CC_NONNULL_TU((4)) CC_NONNULL((1,2,3,5,6,8)) +const uint8_t *ccder_decode_eckey(uint64_t *version, + size_t *priv_size, const uint8_t **priv_key, + ccoid_t *oid, + size_t *pub_size, const uint8_t **pub_key, + const uint8_t *der, const uint8_t *der_end); + +#define CC_EC_OID_SECP192R1 {((unsigned char *)"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x01")} +#define CC_EC_OID_SECP256R1 {((unsigned char *)"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07")} +#define CC_EC_OID_SECP224R1 {((unsigned char *)"\x06\x05\x2B\x81\x04\x00\x21")} +#define CC_EC_OID_SECP384R1 {((unsigned char *)"\x06\x05\x2B\x81\x04\x00\x22")} +#define CC_EC_OID_SECP521R1 {((unsigned char *)"\x06\x05\x2B\x81\x04\x00\x23")} + + +#endif /* _CORECRYPTO_CCDER_H_ */ diff --git a/corecrypto/ccder_decode_eckey.h b/corecrypto/ccder_decode_eckey.h new file mode 100644 index 0000000..891bb7e --- /dev/null +++ b/corecrypto/ccder_decode_eckey.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDER_DECODE_ECKEY_H_ +#define _CORECRYPTO_CCDER_DECODE_ECKEY_H_ + +// This header is used by a few external clients. +// Clients all need to move to + +#include + +#endif /* _CORECRYPTO_CCDER_DECODE_ECKEY_H_ */ diff --git a/corecrypto/ccder_encode_eckey.h b/corecrypto/ccder_encode_eckey.h new file mode 100644 index 0000000..88f8890 --- /dev/null +++ b/corecrypto/ccder_encode_eckey.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef _CORECRYPTO_CCDER_ENCODE_ECKEY_H_ +#define _CORECRYPTO_CCDER_ENCODE_ECKEY_H_ + +// This header is used by a few external clients. +// Clients all need to move to + +#include + +#endif /* _CORECRYPTO_CCDER_ENCODE_ECKEY_H_ */ diff --git a/corecrypto/ccder_priv.h b/corecrypto/ccder_priv.h new file mode 100644 index 0000000..cf0331d --- /dev/null +++ b/corecrypto/ccder_priv.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef ccder_priv_h +#define ccder_priv_h + +/*! + @function ccder_decode_uint_skip_leading_zeroes + @abstract Return the pointer on the most significant byte + Caller must ensure there is no overread (der + *len < der_end) prior + to calling this. + Per ITU-T Rec. X.690 (07/2002), section 8.3 "If the contents octets of an integer value + encoding consist of more than one octet, then the bits of the first octet + and bit 8 of the second octet, Shall not all be ones and shall not be zero". + Here we only allow unsigned integers. + + @param der Beginning of input DER buffer + @param len Pointer to the length. Update to the number of remaining byte + it may contain 0 as input/output. + + @result Pointer on the most significant byte + NULL is too many leading zeroes + */ + +CC_NONNULL((1, 2)) +CC_INLINE const uint8_t *ccder_decode_uint_skip_leading_zeroes( + size_t *len, + const uint8_t *der) +{ + if (!(*len)) { + // ISO/IEC 8825-1:2003 (E) 8.3.1 The encoding of an integer value shall be primitive + // The contents octets shall consist of one or more octets. + return NULL; + } + // Sign + if (der[0] & 0x80) { + // Negative value, not authorized for unsigned integer + return NULL; + } + // Leading byte + if (der[0] == 0) { + (*len)--; + der++; + + // At this point, we expect the most significant bit set + if ((*len) + && !(der[0] & 0x80)) return NULL; + } + + return der; +} + +#endif /* ccder_priv_h */ diff --git a/corecrypto/ccder_rsa.h b/corecrypto/ccder_rsa.h new file mode 100644 index 0000000..1955601 --- /dev/null +++ b/corecrypto/ccder_rsa.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_ccder_rsa_h +#define corecrypto_ccder_rsa_h + +#include +#include + +CC_INLINE uint8_t * +ccder_encode_cczp_as_integer(cczp_t zp, const uint8_t *der, uint8_t *der_end) { + return ccder_encode_integer(cczp_n(zp), cczp_prime(zp), der, der_end); +} + + +#endif diff --git a/corecrypto/ccdes.h b/corecrypto/ccdes.h new file mode 100644 index 0000000..9550a6c --- /dev/null +++ b/corecrypto/ccdes.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010,2012,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDES_H_ +#define _CORECRYPTO_CCDES_H_ + +#include + +#define CCDES_BLOCK_SIZE 8 +#define CCDES_KEY_SIZE 8 + +extern const struct ccmode_ecb ccdes_ltc_ecb_decrypt_mode; +extern const struct ccmode_ecb ccdes_ltc_ecb_encrypt_mode; + +extern const struct ccmode_ecb ccdes3_ltc_ecb_decrypt_mode; +extern const struct ccmode_ecb ccdes3_ltc_ecb_encrypt_mode; +extern const struct ccmode_ecb ccdes168_ltc_ecb_encrypt_mode; + +const struct ccmode_ecb *ccdes_ecb_decrypt_mode(void); +const struct ccmode_ecb *ccdes_ecb_encrypt_mode(void); + +const struct ccmode_cbc *ccdes_cbc_decrypt_mode(void); +const struct ccmode_cbc *ccdes_cbc_encrypt_mode(void); + +const struct ccmode_cfb *ccdes_cfb_decrypt_mode(void); +const struct ccmode_cfb *ccdes_cfb_encrypt_mode(void); + +const struct ccmode_cfb8 *ccdes_cfb8_decrypt_mode(void); +const struct ccmode_cfb8 *ccdes_cfb8_encrypt_mode(void); + +const struct ccmode_ctr *ccdes_ctr_crypt_mode(void); + +const struct ccmode_ofb *ccdes_ofb_crypt_mode(void); + + +const struct ccmode_ecb *ccdes3_ecb_decrypt_mode(void); +const struct ccmode_ecb *ccdes3_ecb_encrypt_mode(void); + +const struct ccmode_cbc *ccdes3_cbc_decrypt_mode(void); +const struct ccmode_cbc *ccdes3_cbc_encrypt_mode(void); + +const struct ccmode_cfb *ccdes3_cfb_decrypt_mode(void); +const struct ccmode_cfb *ccdes3_cfb_encrypt_mode(void); + +const struct ccmode_cfb8 *ccdes3_cfb8_decrypt_mode(void); +const struct ccmode_cfb8 *ccdes3_cfb8_encrypt_mode(void); + +const struct ccmode_ctr *ccdes3_ctr_crypt_mode(void); + +const struct ccmode_ofb *ccdes3_ofb_crypt_mode(void); + +int ccdes_key_is_weak( void *key, size_t length); +void ccdes_key_set_odd_parity(void *key, size_t length); + +uint32_t +ccdes_cbc_cksum(void *in, void *out, size_t length, + void *key, size_t keylen, void *ivec); + + +#endif /* _CORECRYPTO_CCDES_H_ */ diff --git a/corecrypto/ccdh.h b/corecrypto/ccdh.h new file mode 100644 index 0000000..fdb5360 --- /dev/null +++ b/corecrypto/ccdh.h @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2011,2012,2013,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDH_H_ +#define _CORECRYPTO_CCDH_H_ + +#include +#include +#include + +/* Error codes */ +#define CCDH_ERROR_DEFAULT -1 +#define CCDH_GENERATE_KEY_TOO_MANY_TRIES -2 +#define CCDH_NOT_SUPPORTED_CONFIGURATION -3 +#define CCDH_SAFETY_CHECK -4 +#define CCDH_PUBLIC_KEY_MISSING -5 +#define CCDH_INVALID_DOMAIN_PARAMETER -6 +#define CCDH_INVALID_INPUT -7 +#define CCDH_DOMAIN_PARAMETER_MISMATCH -8 +#define CCDH_GENERATE_KEY_CONSISTENCY -9 + +#if CORECRYPTO_USE_TRANSPARENT_UNION + +cc_aligned_struct(16) ccdh_gp; + +/* A ccdh_gp_t is a pointer to a set of DH parameters. + The first entry is a (short) prime field. */ +typedef union { + cczp_t zp; + ccdh_gp *gp; +} __attribute__((transparent_union)) ccdh_gp_t; + +/* A ccdh_const_gp_t is a const pointer to a set of DH parameters. + The first entry is a const prime field. */ +typedef union { + cczp_const_t zp; + const ccdh_gp *gp; + ccdh_gp_t _ncgp; // Non const variant +} __attribute__((transparent_union)) ccdh_const_gp_t; + + +/* Every dh context (a public or private key) starts with this. */ +struct ccdh_ctx_header { + ccdh_const_gp_t gp; + uint8_t pad[16 - sizeof(ccdh_const_gp_t *)]; +} CC_ALIGNED(16); + +struct ccdh_ctx_body { + struct ccdh_ctx_header hdr; + cc_unit xy[]; +} CC_ALIGNED(16); + +struct ccdh_ctx_public { + struct ccdh_ctx_header hdr; + cc_unit pub[]; +} CC_ALIGNED(16); + +/* The ccdh_full_ctx_decl macro allocates an array of ccdh_full_ctx */ +typedef struct ccdh_full_ctx { + struct ccdh_ctx_header hdr; +} CC_ALIGNED(16) ccdh_full_ctx; + +/* The ccdh_pub_ctx_decl macro allocates an array of ccdh_pub_ctx */ +typedef struct ccdh_pub_ctx { + struct ccdh_ctx_header hdr; +} CC_ALIGNED(16) ccdh_pub_ctx; + +/* A ccdh_full_ctx_t is a pointer to a dh key pair. It should be + allocated to be sizeof(ccdh_full_ctx_decl()) bytes. Each of the + ccns within a dh key is always ccdh_ctx_n() cc_units long. */ +typedef union { + ccdh_full_ctx *_full; // Constructor + struct ccdh_ctx_header *hdr; + struct ccdh_ctx_body *body; + struct ccdh_ctx_public *pub; +} __attribute__((transparent_union)) ccdh_full_ctx_t; + +typedef union { + ccdh_pub_ctx *_pub; // Constructor + ccdh_full_ctx *_full; // Constructor + struct ccdh_ctx_header *hdr; + struct ccdh_ctx_body *body; + struct ccdh_ctx_public *pub; + ccdh_full_ctx_t fullt; // Conversion constructor fk->pk +} __attribute__((transparent_union)) ccdh_pub_ctx_t; + +#else //================================================= NO transparent union + +struct ccdh_gp { + __CCZP_ELEMENTS_DEFINITIONS() +} CC_ALIGNED(CCN_UNIT_SIZE); + +/* A ccdh_gp_t is a pointer to a set of DH parameters. + The first entry is a (short) prime field. */ +typedef struct ccdh_gp *ccdh_gp_t; + +/* A ccdh_const_gp_t is a const pointer to a set of DH parameters. + The first entry is a const prime field. */ +typedef const struct ccdh_gp *ccdh_const_gp_t; + +/* The ccdh_full_ctx_decl macro allocates an array of ccdh_full_ctx */ +struct ccdh_full_ctx { + ccdh_const_gp_t gp; + uint8_t pad[16 - sizeof(ccdh_const_gp_t *)]; + cc_unit xy[]; +} CC_ALIGNED(16) ; + +/* The ccdh_pub_ctx_decl macro allocates an array of ccdh_pub_ctx */ +struct ccdh_pub_ctx { + ccdh_const_gp_t gp; + uint8_t pad[16 - sizeof(ccdh_const_gp_t *)]; + cc_unit xy[]; +} CC_ALIGNED(16) ; + +/* A ccdh_full_ctx_t is a pointer to a dh key pair. It should be + allocated to be sizeof(ccdh_full_ctx_decl()) bytes. Each of the + ccns within a dh key is always ccdh_ctx_n() cc_units long. */ + +typedef struct ccdh_full_ctx *ccdh_full_ctx_t; +typedef struct ccdh_pub_ctx *ccdh_pub_ctx_t; + +#endif //================================================= NO transparent union + +#if CORECRYPTO_USE_TRANSPARENT_UNION + /* Return the size of an ccdh_full_ctx where each ccn is _size_ bytes. */ + /* Full has x and y */ + #define ccdh_full_ctx_size(_size_) (sizeof(struct ccdh_ctx_header) + 2 * (_size_)) + /* Pub has only y */ + #define ccdh_pub_ctx_size(_size_) (sizeof(struct ccdh_ctx_header) + 1 * (_size_)) + + /* Declare a fully scheduled dh key. Size is the size in bytes each ccn in + the key. For example to declare (on the stack or in a struct) a 1024 bit + dh public key named foo use ccdh_pub_ctx_decl(ccn_sizeof(1024), foo). */ + #define ccdh_full_ctx_decl(_size_, _name_) cc_ctx_decl(ccdh_full_ctx, ccdh_full_ctx_size(_size_), _name_) + #define ccdh_pub_ctx_decl(_size_, _name_) cc_ctx_decl(ccdh_pub_ctx, ccdh_pub_ctx_size(_size_), _name_) +#else + /* Return the size of an ccdh_full_ctx where each ccn is _size_ bytes. */ + /* Full has x and y */ + #define ccdh_full_ctx_size(_size_) (sizeof(struct ccdh_full_ctx) + 2 * (_size_)) + /* Pub has only y */ + #define ccdh_pub_ctx_size(_size_) (sizeof(struct ccdh_pub_ctx) + 1 * (_size_)) + + /* Declare a fully scheduled dh key. Size is the size in bytes each ccn in + the key. For example to declare (on the stack or in a struct) a 1024 bit + dh public key named foo use ccdh_pub_ctx_decl(ccn_sizeof(1024), foo). */ + #define ccdh_full_ctx_decl(_size_, _name_) cc_ctx_decl(struct ccdh_full_ctx, ccdh_full_ctx_size(_size_), _name_) + #define ccdh_pub_ctx_decl(_size_, _name_) cc_ctx_decl(struct ccdh_pub_ctx, ccdh_pub_ctx_size(_size_), _name_) +#endif + +#define ccdh_pub_ctx_clear(_size_, _name_) cc_clear(ccdh_pub_ctx_size(_size_), _name_) +#define ccdh_full_ctx_clear(_size_, _name_) cc_clear(ccdh_full_ctx_size(_size_), _name_) +/* Declare storage for a fully scheduled dh key for a given set of dh parameters. */ +#define ccdh_full_ctx_decl_gp(_gp_, _name_) ccdh_full_ctx_decl(ccdh_ccn_size(_gp_), _name_) +#define ccdh_pub_ctx_decl_gp(_gp_, _name_) ccdh_pub_ctx_decl(ccdh_ccn_size(_gp_), _name_) + +/* Return the length of the prime for gp in bits. */ +#define ccdh_gp_prime_bitlen(GP) (ccn_bitlen(ccdh_gp_n(GP), ccdh_gp_prime(GP))) + +/* Return the sizeof the prime for gp. */ +#define ccdh_gp_prime_size(GP) (ccdh_ccn_size(GP)) + +#if CORECRYPTO_USE_TRANSPARENT_UNION +/* Group parameters accessors */ +/* If you set the structure manually, you must set it to zero to be + future proof */ +#define CCDH_GP_N(_gp_) (CCZP_N((_gp_).zp)) +#define CCDH_GP_PRIME(_gp_) (CCZP_PRIME((_gp_).zp)) +#define CCDH_GP_ZP(_gp_) ((_gp_).zp) +static inline cczp_const_t ccdh_gp_zp(ccdh_const_gp_t gp) { return gp.zp;} +#define CCDH_GP_RECIP(_gp_) (CCZP_RECIP((_gp_).zp)) +/* l must be chosen wisely to avoid the private key to be recoverable with the Pohlig-Hellman algorithm for example. "Small" l is only possible for special groups for example when p is a safe prime. */ +#else +/* Group parameters accessors */ +/* If you set the structure manually, you must set it to zero to be + future proof */ +#define CCDH_GP_N(_gp_) (CCZP_N(_gp_)) +#define CCDH_GP_PRIME(_gp_) (CCZP_PRIME(_gp_)) +#define CCDH_GP_ZP(_gp_) ((cczp_t)(_gp_)) +static inline cczp_const_t ccdh_gp_zp(ccdh_const_gp_t gp) { return (cczp_const_t) gp;} +#define CCDH_GP_RECIP(_gp_) (CCZP_RECIP((_gp_))) +#endif + +#define CCDH_GP_G(_gp_) (CCDH_GP_RECIP(_gp_) + 1 + ccdh_gp_n(_gp_)) // recip size is n+1 +#define CCDH_GP_L(_gp_) (*((CCDH_GP_Q(_gp_) + ccdh_gp_n(_gp_)))) // Size of the private key in bit. +#define CCDH_GP_Q(_gp_) (CCDH_GP_G(_gp_) + ccdh_gp_n(_gp_)) // generator size is n +/* l must be chosen wisely to avoid the private key to be recoverable with the Pohlig-Hellman algorithm for example. "Small" l is only possible for special groups for example when p is a safe prime. */ + +/* Return the size of a ccdh_gp where the prime is of _size_ bytes. */ +#define ccdh_gp_size(_size_) (cczp_size(_size_) + 2 * (_size_) + ccn_sizeof_n(1)) + +#if CORECRYPTO_USE_TRANSPARENT_UNION + +/* Declare a gp */ +#define ccdh_gp_decl(_size_, _name_) cc_ctx_decl(ccdh_gp, ccdh_gp_size(_size_), _name_) + +/* lvalue accessors to ccdh_ctx fields. (only a ccdh_full_ctx_t has y). */ +/* gp: group parameter */ +#define ccdh_ctx_gp(KEY) (((ccdh_pub_ctx_t)(KEY)).hdr->gp) +//we do not call ccdh_ctx_public(), because ccdh_ctx_gp may be called with ccdh_pub_ctx_t KEY +/* n: size of group */ +#define ccdh_ctx_n(KEY) (ccdh_gp_n(ccdh_ctx_gp(KEY))) +/* prime: group prime */ +#define ccdh_ctx_prime(KEY) (ccdh_gp_prime(ccdh_ctx_gp(KEY))) +/* y: the public key */ +#define ccdh_ctx_y(KEY) (((ccdh_pub_ctx_t)(KEY)).body->xy) +/* x: the private key */ +#define ccdh_ctx_x(KEY) (((ccdh_full_ctx_t)(KEY)).body->xy + 1 * ccdh_ctx_n(KEY)) +#else + +/* Declare a gp */ +#define ccdh_gp_decl(_size_, _name_) cc_ctx_decl(struct ccdh_gp, ccdh_gp_size(_size_), _name_) + +/* lvalue accessors to ccdh_ctx fields. (only a ccdh_full_ctx_t has y). */ +/* gp: group parameter */ +#define ccdh_ctx_gp(KEY) (((ccdh_pub_ctx_t)(KEY))->gp) +/* n: size of group */ +#define ccdh_ctx_n(KEY) (ccdh_gp_n(ccdh_ctx_gp(KEY))) +/* prime: group prime */ +#define ccdh_ctx_prime(KEY) (ccdh_gp_prime(ccdh_ctx_gp(KEY))) +/* y: the public key */ +#define ccdh_ctx_y(KEY) ((KEY)->xy) +/* x: the private key */ +#define ccdh_ctx_x(KEY) (ccdh_ctx_y(KEY) + 1 * ccdh_ctx_n(KEY)) + +#endif + +CC_INLINE +ccdh_pub_ctx_t ccdh_ctx_public(ccdh_full_ctx_t key) { + return (ccdh_pub_ctx_t)key; +} + +#if CORECRYPTO_USE_TRANSPARENT_UNION + +/* Callers must call this function to initialze a ccdh_full_ctx or + ccdh_pub_ctx before using most of the macros in this file. */ +CC_INLINE CC_NONNULL_TU((1)) +void ccdh_ctx_init(ccdh_const_gp_t gp, ccdh_pub_ctx_t key) { + key.hdr->gp = gp; +} + +/* rvalue accessors to ccdh_ctx fields. */ + +/* Return count (n) of a ccn for gp. */ +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +cc_size ccdh_gp_n(ccdh_const_gp_t gp) { + return cczp_n(gp.zp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_prime(ccdh_const_gp_t gp) { + return cczp_prime(gp.zp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_recip(ccdh_const_gp_t gp) { + return cczp_recip(gp.zp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit ccdh_gp_options(ccdh_const_gp_t gp) { + return cczp_options(gp.zp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_g(ccdh_const_gp_t gp) { + return CCDH_GP_G(gp._ncgp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_order(ccdh_const_gp_t gp) { + return CCDH_GP_Q(gp._ncgp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +cc_size ccdh_gp_l(ccdh_const_gp_t gp) { + return CCDH_GP_L(gp._ncgp); +} +/* Return sizeof a ccn for gp. */ +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +size_t ccdh_ccn_size(ccdh_const_gp_t gp) { + return ccn_sizeof_n(cczp_n(gp.zp)); +} + +#else //================================================================================= +/* Callers must call this function to initialze a ccdh_full_ctx or + ccdh_pub_ctx before using most of the macros in this file. */ +CC_INLINE CC_NONNULL_TU((1)) +void ccdh_ctx_init(ccdh_const_gp_t gp, ccdh_pub_ctx_t key) { + key->gp = gp; +} + +/* rvalue accessors to ccdh_ctx fields. */ + +/* Return count (n) of a ccn for gp. */ +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +cc_size ccdh_gp_n(ccdh_const_gp_t gp) { + return cczp_n((cczp_const_t)gp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_prime(ccdh_const_gp_t gp) { + return cczp_prime((cczp_const_t)gp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_recip(ccdh_const_gp_t gp) { + return cczp_recip((cczp_const_t)gp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit ccdh_gp_options(ccdh_const_gp_t gp) { + return cczp_options((cczp_const_t)gp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_g(ccdh_const_gp_t gp) { + return CCDH_GP_G(gp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +const cc_unit *ccdh_gp_order(ccdh_const_gp_t gp) { + return CCDH_GP_Q(gp); +} + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +cc_size ccdh_gp_l(ccdh_const_gp_t gp) { + return CCDH_GP_L((ccdh_const_gp_t)gp); +} + +/* Return sizeof a ccn for gp. */ +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +size_t ccdh_ccn_size(ccdh_const_gp_t gp) { + return ccn_sizeof_n(CCZP_N(gp)); +} + +#endif//================================================================================= + +CC_INLINE CC_NONNULL_TU((1)) +size_t ccdh_gp_order_bitlen(ccdh_const_gp_t gp) { + return ccn_bitlen(ccdh_gp_n(gp),ccdh_gp_order(gp)); +} + + + +/* DH group parameter initialization */ + +/* + * Group paramters must be well chosen to avoid serious security issues. + * a) ccdh_init_gp with l>0 is to be used for group parameter where p is a safe prime. + * l should be at least twice the security level desired (128bit security => l=256). + * If you are not sure, set l=0, it is slow but it is safe against attacks using the + * Pohlig-Hellman algorithm for example. + * b) ccdh_init_gp_with_order is to be used when the group prime is not a safe prime: + * the order is necessary to avoid small subgroup attacks and generate the private key + * efficiently + * c) ccdh_init_gp_with_order to set the group from byte. + * If the group prime is not a safe prime, the order MUST be provided to avoid small subgroup attacks + * If the group prime is a safe prime, l should be at least twice the security level desired (128bit security => l=256). + * If you are not sure, set l=0, it is slow but it is safe against attacks using the + * Pohlig-Hellman algorithm for example. + */ +CC_NONNULL_TU((1)) CC_NONNULL((3, 4)) +int ccdh_init_gp(ccdh_gp_t gp, cc_size n, + const cc_unit *p, + const cc_unit *g, + cc_size l); + +CC_NONNULL_TU((1)) CC_NONNULL((3, 4, 5)) +int ccdh_init_gp_with_order(ccdh_gp_t gp, cc_size n, + const cc_unit *p, + const cc_unit *g, + const cc_unit *q); + +CC_NONNULL_TU((1)) CC_NONNULL((4, 6)) +int ccdh_init_gp_from_bytes(ccdh_gp_t gp, cc_size n, + size_t p_len, const uint8_t *p, + size_t g_len, const uint8_t *g, + size_t q_len, const uint8_t *q, + cc_size l); + +/* + * Generate a DH private/public key pair from the group parameter + */ +CC_NONNULL_TU((1)) CC_NONNULL2 +int ccdh_generate_key(ccdh_const_gp_t gp, struct ccrng_state *rng, + ccdh_full_ctx_t key); + +/* + * Compute an DH shared secret between private_key and public_key after validation the public key. + * Returns the result in computed_key, which must be an array of ccdh_ctx_n(private_key) cc_units + * DEPRECATED - use ccdh_compute_key + */ + +CC_NONNULL_TU((1,2)) CC_NONNULL3 +int ccdh_compute_key(ccdh_full_ctx_t private_key, ccdh_pub_ctx_t public_key, + cc_unit *computed_key); + +/* Leading bytes of computed_shared_secret (a.k.a. Z) that contain all zero bits + are stripped before it is used as the shared secret. Match common specs such as TLS */ +CC_NONNULL_TU((1,2)) CC_NONNULL4 +int ccdh_compute_shared_secret(ccdh_full_ctx_t private_key, + ccdh_pub_ctx_t public_key, + size_t *computed_shared_secret_len, + uint8_t *computed_shared_secret, + struct ccrng_state *blinding_rng); + + +/* Import a public key. The imported key is an Octet String, as defined in PKCS#3 */ +CC_NONNULL_TU((1)) CC_NONNULL3 +int ccdh_import_pub(ccdh_const_gp_t gp, size_t in_len, const uint8_t *in, + ccdh_pub_ctx_t key); + +/* Import a private key. The imported key is an Octet String, as defined in PKCS#3 */ +CC_NONNULL_TU((1)) CC_NONNULL3 +int ccdh_import_priv(ccdh_const_gp_t gp, size_t in_len, const uint8_t *in, + ccdh_full_ctx_t key); + +/* Import a private key. The imported key is an Octet String, as defined in PKCS#3 */ +CC_NONNULL_TU((1)) CC_NONNULL3 +int ccdh_import_full(ccdh_const_gp_t gp, + size_t in_priv_len, const uint8_t *in_priv, + size_t in_pub_len, const uint8_t *in_pub, + ccdh_full_ctx_t key); + +/* Return the sizeof a buffer needed to exported public key to. */ +CC_INLINE CC_CONST CC_NONNULL_TU((1)) +size_t ccdh_export_pub_size(ccdh_pub_ctx_t key) { + return ccdh_gp_prime_size(ccdh_ctx_gp(key)); +} + +/* Export public key to out. Out must be ccdh_export_pub_size(key) bytes long. + The key is exported as an Octet String, as defined in PKCS#3 */ +CC_NONNULL_TU((1)) CC_NONNULL2 +void ccdh_export_pub(ccdh_pub_ctx_t key, void *out); + +/* + * ASN.1/DER glue from PKCS #3 : + * prime p, generator g, and optional privateValueLength l + */ + +CC_NONNULL_TU((1)) +size_t ccder_encode_dhparams_size(const ccdh_const_gp_t gp); + +CC_NONNULL_TU((1)) CC_NONNULL((2)) CC_NONNULL((3)) +uint8_t * ccder_encode_dhparams(const ccdh_const_gp_t gp, uint8_t *der, uint8_t *der_end); + +/* CCZP_N(gpfoo.zp) must be set before decoding */ +CC_NONNULL_TU((1)) CC_NONNULL((2)) +const uint8_t *ccder_decode_dhparams(ccdh_gp_t gp, const uint8_t *der, const uint8_t *der_end); + +/* returns the n needed for ccdh_gp_decl/heap allocation of a ccdh_gp_t, can be larger then the actual size used */ +CC_NONNULL((1)) +cc_size ccder_decode_dhparam_n(const uint8_t *der, const uint8_t *der_end); + +#endif /* _CORECRYPTO_CCDH_H_ */ diff --git a/corecrypto/ccdh_gp.h b/corecrypto/ccdh_gp.h new file mode 100644 index 0000000..e84885d --- /dev/null +++ b/corecrypto/ccdh_gp.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +/* Autogenerated file - Use scheme ccdh_gen_gp to regenerate */ +#ifndef _CORECRYPTO_CCDH_GP_H_ +#define _CORECRYPTO_CCDH_GP_H_ + +#include + +ccdh_const_gp_t ccdh_gp_apple768(void); +ccdh_const_gp_t ccdh_gp_rfc5114_MODP_1024_160(void); +ccdh_const_gp_t ccdh_gp_rfc5114_MODP_2048_224(void); +ccdh_const_gp_t ccdh_gp_rfc5114_MODP_2048_256(void); +ccdh_const_gp_t ccdh_gp_rfc2409group02(void); +ccdh_const_gp_t ccdh_gp_rfc3526group05(void); +ccdh_const_gp_t ccdh_gp_rfc3526group14(void); +ccdh_const_gp_t ccdh_gp_rfc3526group15(void); +ccdh_const_gp_t ccdh_gp_rfc3526group16(void); +ccdh_const_gp_t ccdh_gp_rfc3526group17(void); +ccdh_const_gp_t ccdh_gp_rfc3526group18(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_1024(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_2048(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_3072(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_4096(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_8192(void); + +#endif /* _CORECRYPTO_CCDH_GP_H_ */ diff --git a/corecrypto/ccdh_priv.h b/corecrypto/ccdh_priv.h new file mode 100644 index 0000000..f054738 --- /dev/null +++ b/corecrypto/ccdh_priv.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2011,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDH_PRIV_H_ +#define _CORECRYPTO_CCDH_PRIV_H_ + +#include + +#define ccdh_gp_decl_n(_n_) \ +struct { \ + struct cczp_hd hp; \ + cc_unit p[(_n_)]; /* Prime */ \ + cc_unit recip[((_n_)+1)]; /* precomp for field ops */ \ + cc_unit g[(_n_)]; /* Generator */ \ + cc_unit q[(_n_)]; /* Order */ \ + cc_size l; /* Size of the private key */ \ +} + +#define ccdh_gp_decl_static(_bits_) ccdh_gp_decl_n(ccn_nof(_bits_)) + +int ccdh_generate_private_key(ccdh_const_gp_t gp, cc_unit *x, + struct ccrng_state *rng); + +int ccdh_check_pub(ccdh_const_gp_t gp, ccdh_pub_ctx_t public_key); + +int ccdh_power_blinded(struct ccrng_state *blinding_rng, + ccdh_const_gp_t gp, + cc_unit *r, const cc_unit *s, const cc_unit *e) ; + +/*! + @function ccdh_pairwise_consistency_check + @abstract Does a DH with a constant key to confirm the newly generated key is + correct. + @param gp Group parameters + @param rng For key generation and internal countermeasures + @param key DH key pair + @return true if no error, false otherwise. + */ +bool ccdh_pairwise_consistency_check(ccdh_const_gp_t gp, + struct ccrng_state *rng, + ccdh_full_ctx_t key); + + +#endif /* _CORECRYPTO_CCDH_GP_PRIV_H_ */ diff --git a/corecrypto/ccdigest.h b/corecrypto/ccdigest.h new file mode 100644 index 0000000..5177a96 --- /dev/null +++ b/corecrypto/ccdigest.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDIGEST_H_ +#define _CORECRYPTO_CCDIGEST_H_ + +#include +#include + +/* To malloc a digest context for a given di, use malloc(ccdigest_di_size(di)) + and assign the result to a pointer to a struct ccdigest_ctx. */ +#if CORECRYPTO_USE_TRANSPARENT_UNION +struct ccdigest_ctx { + union { + uint8_t u8; + uint32_t u32; + uint64_t u64; + cc_unit ccn; + } state; +} CC_ALIGNED(8); + +typedef union { + struct ccdigest_ctx *hdr; +} ccdigest_ctx_t __attribute__((transparent_union)); + +struct ccdigest_state { + union { + uint8_t u8; + uint32_t u32; + uint64_t u64; + cc_unit ccn; + } state; +} CC_ALIGNED(8); + +typedef union { + struct ccdigest_state *hdr; + struct ccdigest_ctx *_ctx; + ccdigest_ctx_t _ctxt; +} ccdigest_state_t __attribute__((transparent_union)); +#else //======================================================= +struct ccdigest_ctx { + union { + uint8_t u8; + uint32_t u32; + uint64_t u64; + cc_unit ccn; + } state; +} CC_ALIGNED(8); + +typedef struct ccdigest_ctx *ccdigest_ctx_t ; + +struct ccdigest_state { + union { + uint8_t u8; + uint32_t u32; + uint64_t u64; + cc_unit ccn; + } state; +} CC_ALIGNED(8); + +typedef struct ccdigest_state *ccdigest_state_t; +#endif //======================================================= + + +struct ccdigest_info { + size_t output_size; + size_t state_size; + size_t block_size; + size_t oid_size; + const unsigned char *oid; + const void *initial_state; + void(*compress)(ccdigest_state_t state, size_t nblocks, + const void *data); + void(*final)(const struct ccdigest_info *di, ccdigest_ctx_t ctx, + unsigned char *digest); +}; + +/* Return sizeof a ccdigest_ctx for a given size_t _state_size_ and + size_t _block_size_. */ +#define ccdigest_ctx_size(_state_size_, _block_size_) ((_state_size_) + sizeof(uint64_t) + (_block_size_) + sizeof(unsigned int)) +/* Return sizeof a ccdigest_ctx for a given struct ccdigest_info *_di_. */ +#define ccdigest_di_size(_di_) (ccdigest_ctx_size((_di_)->state_size, (_di_)->block_size)) + +/* Declare a ccdigest_ctx for a given size_t _state_size_ and + size_t _block_size_, named _name_. Can be used in structs or on the + stack. */ +#define ccdigest_ctx_decl(_state_size_, _block_size_, _name_) cc_ctx_decl(struct ccdigest_ctx, ccdigest_ctx_size(_state_size_, _block_size_), _name_) +#define ccdigest_ctx_clear(_state_size_, _block_size_, _name_) cc_clear(ccdigest_ctx_size(_state_size_, _block_size_), _name_) +/* Declare a ccdigest_ctx for a given size_t _state_size_ and + size_t _block_size_, named _name_. Can be used on the stack. */ +#define ccdigest_di_decl(_di_, _name_) cc_ctx_decl(struct ccdigest_ctx, ccdigest_di_size(_di_), _name_) +#define ccdigest_di_clear(_di_, _name_) cc_clear(ccdigest_di_size(_di_), _name_) + +/* Digest context field accessors. Consider the implementation private. */ +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define ccdigest_state(_di_, _ctx_) ((struct ccdigest_state *)(&((ccdigest_ctx_t)(_ctx_)).hdr->state.u8 + sizeof(uint64_t))) +#else +#define ccdigest_state(_di_, _ctx_) ((struct ccdigest_state *)(&((ccdigest_ctx_t)(_ctx_))->state.u8 + sizeof(uint64_t))) +#endif + +#define ccdigest_state_u8(_di_, _ctx_) ccdigest_u8(ccdigest_state((_di_), (_ctx_))) +#define ccdigest_state_u32(_di_, _ctx_) ccdigest_u32(ccdigest_state((_di_), (_ctx_))) +#define ccdigest_state_u64(_di_, _ctx_) ccdigest_u64(ccdigest_state((_di_), (_ctx_))) +#define ccdigest_state_ccn(_di_, _ctx_) ccdigest_ccn(ccdigest_state((_di_), (_ctx_))) + +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define ccdigest_nbits(_di_, _ctx_) (((uint64_t *)(&((ccdigest_ctx_t)(_ctx_)).hdr->state.u8))[0]) +#define ccdigest_data(_di_, _ctx_) (&((ccdigest_ctx_t)(_ctx_)).hdr->state.u8 + (_di_)->state_size + sizeof(uint64_t)) +#define ccdigest_num(_di_, _ctx_) (((unsigned int *)(&((ccdigest_ctx_t)(_ctx_)).hdr->state.u8 + (_di_)->state_size + sizeof(uint64_t) + (_di_)->block_size))[0]) +#else +#define ccdigest_nbits(_di_, _ctx_) (((uint64_t *)(&((ccdigest_ctx_t)(_ctx_))->state.u8))[0]) +#define ccdigest_data(_di_, _ctx_) (&((ccdigest_ctx_t)(_ctx_))->state.u8 + (_di_)->state_size + sizeof(uint64_t)) +#define ccdigest_num(_di_, _ctx_) (((unsigned int *)(&((ccdigest_ctx_t)(_ctx_))->state.u8 + (_di_)->state_size + sizeof(uint64_t) + (_di_)->block_size))[0]) +#endif + +#if CORECRYPTO_USE_TRANSPARENT_UNION +/* Digest state field accessors. Consider the implementation private. */ +#define ccdigest_u8(_state_) (&((ccdigest_state_t)(_state_)).hdr->state.u8) +#define ccdigest_u32(_state_) (&((ccdigest_state_t)(_state_)).hdr->state.u32) +#define ccdigest_u64(_state_) (&((ccdigest_state_t)(_state_)).hdr->state.u64) +#define ccdigest_ccn(_state_) (&((ccdigest_state_t)(_state_)).hdr->state.ccn) +#else +/* Digest state field accessors. Consider the implementation private. */ +#define ccdigest_u8(_state_) (&((ccdigest_state_t)(_state_))->state.u8) +#define ccdigest_u32(_state_) (&((ccdigest_state_t)(_state_))->state.u32) +#define ccdigest_u64(_state_) (&((ccdigest_state_t)(_state_))->state.u64) +#define ccdigest_ccn(_state_) (&((ccdigest_state_t)(_state_))->state.ccn) +#endif + +/* We could just use memcpy instead of this special macro, but this allows us + to use the optimized ccn_set() assembly routine if we have one, which for + 32 bit arm is about 200% quicker than generic memcpy(). */ +#if CCN_SET_ASM && CCN_UNIT_SIZE <= 4 +#define ccdigest_copy_state(_di_, _dst_, _src_) ccn_set((_di_)->state_size / CCN_UNIT_SIZE, _dst_, _src_) +#else +#define ccdigest_copy_state(_di_, _dst_, _src_) CC_MEMCPY(_dst_, _src_, (_di_)->state_size) +#endif + +void ccdigest_init(const struct ccdigest_info *di, ccdigest_ctx_t ctx); +void ccdigest_update(const struct ccdigest_info *di, ccdigest_ctx_t ctx, + size_t len, const void *data); + +CC_INLINE +void ccdigest_final(const struct ccdigest_info *di, ccdigest_ctx_t ctx, unsigned char *digest) +{ + di->final(di,ctx,digest); +} + +void ccdigest(const struct ccdigest_info *di, size_t len, + const void *data, void *digest); + +/* test functions */ +int ccdigest_test(const struct ccdigest_info *di, size_t len, + const void *data, const void *digest); + +int ccdigest_test_chunk(const struct ccdigest_info *di, size_t len, + const void *data, const void *digest, size_t chunk); + +struct ccdigest_vector { + size_t len; + const void *message; + const void *digest; +}; + +int ccdigest_test_vector(const struct ccdigest_info *di, const struct ccdigest_vector *v); +int ccdigest_test_chunk_vector(const struct ccdigest_info *di, const struct ccdigest_vector *v, size_t chunk); + + +#define OID_DEF(_VALUE_) ((const unsigned char *)_VALUE_) + +#define CC_DIGEST_OID_MD2 OID_DEF("\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02\x02") +#define CC_DIGEST_OID_MD4 OID_DEF("\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02\x04") +#define CC_DIGEST_OID_MD5 OID_DEF("\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02\x05") +#define CC_DIGEST_OID_SHA1 OID_DEF("\x06\x05\x2b\x0e\x03\x02\x1a") +#define CC_DIGEST_OID_SHA224 OID_DEF("\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04") +#define CC_DIGEST_OID_SHA256 OID_DEF("\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01") +#define CC_DIGEST_OID_SHA384 OID_DEF("\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02") +#define CC_DIGEST_OID_SHA512 OID_DEF("\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03") +#define CC_DIGEST_OID_RMD128 OID_DEF("\x06\x06\x28\xCF\x06\x03\x00\x32") +#define CC_DIGEST_OID_RMD160 OID_DEF("\x06\x05\x2B\x24\x03\x02\x01") +#define CC_DIGEST_OID_RMD256 OID_DEF("\x06\x05\x2B\x24\x03\x02\x03") +#define CC_DIGEST_OID_RMD320 OID_DEF(NULL) + +#endif /* _CORECRYPTO_CCDIGEST_H_ */ diff --git a/corecrypto/ccdigest_priv.h b/corecrypto/ccdigest_priv.h new file mode 100644 index 0000000..63632f4 --- /dev/null +++ b/corecrypto/ccdigest_priv.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010,2011,2012,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDIGEST_PRIV_H_ +#define _CORECRYPTO_CCDIGEST_PRIV_H_ + +#include +#include + +void ccdigest_final_common(const struct ccdigest_info *di, + ccdigest_ctx_t ctx, void *digest); +void ccdigest_final_64be(const struct ccdigest_info *di, ccdigest_ctx_t, + unsigned char *digest); +void ccdigest_final_64le(const struct ccdigest_info *di, ccdigest_ctx_t, + unsigned char *digest); + +CC_INLINE CC_NONNULL_TU((1)) +bool ccdigest_oid_equal(const struct ccdigest_info *di, ccoid_t oid) { + if(di->oid == NULL && CCOID(oid) == NULL) return true; + if(di->oid == NULL || CCOID(oid) == NULL) return false; + return ccoid_equal(di->oid, oid); +} + +typedef const struct ccdigest_info *(ccdigest_lookup)(ccoid_t oid); + +#include +const struct ccdigest_info *ccdigest_oid_lookup(ccoid_t oid, ...); + +#endif /* _CORECRYPTO_CCDIGEST_PRIV_H_ */ diff --git a/corecrypto/ccdrbg.h b/corecrypto/ccdrbg.h new file mode 100644 index 0000000..9692e9c --- /dev/null +++ b/corecrypto/ccdrbg.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +/*! + @header corecrypto/ccdrbg.h + @abstract The functions provided in ccdrbg.h implement high-level accessors + to cryptographically secure random numbers. + + */ + +#ifndef _CORECRYPTO_CCDRBG_H_ +#define _CORECRYPTO_CCDRBG_H_ + +#include +#include + +/* error codes */ +#define CCDRBG_STATUS_OK 0 +#define CCDRBG_STATUS_ERROR (-1) +#define CCDRBG_STATUS_NEED_RESEED (-2) +#define CCDRBG_STATUS_PARAM_ERROR (-3) +// If this value is returned, the caller must abort or panic the process for security reasons. +// for example in the case of catastrophic error in +// http://csrc.nist.gov/publications/drafts/800-90/sp800_90a_r1_draft.pdf +// ccdrbg calls abort() or panic(), if they are available in the system. +#define CCDRBG_STATUS_ABORT (-4) +/* + * The maximum length of the entropy_input, additional_input (max_additional_input_length) , personalization string + * (max_personalization_string_length) and max_number_of_bits_per_request are implementation dependent + * but shall fit in a 32 bit register and be be less than or equal to the specified maximum length for the + * selected DRBG mechanism (NIST 800-90A Section 10). + */ + +#define CCDRBG_MAX_ENTROPY_SIZE ((uint32_t)1<<16) +#define CCDRBG_MAX_ADDITIONALINPUT_SIZE ((uint32_t)1<<16) +#define CCDRBG_MAX_PSINPUT_SIZE ((uint32_t)1<<16) +#define CCDRBG_MAX_REQUEST_SIZE ((uint32_t)1<<16) //this is the absolute maximum in NIST 800-90A +#define CCDRBG_RESEED_INTERVAL ((uint64_t)1<<30) // must be able to fit the NIST maximum of 2^48 + + +/* + * The entropyLength is forced to be greater or equal than the security strength. + * Nonce is not forced. It either needs to have 0.5*security strength entropy. Or, a vale that is repeated + * less than a 0.5*security strength bit random string. + * see below or NIST 800-90A for the definition of security strength + */ + +CC_INLINE int ccdrbg_init(const struct ccdrbg_info *info, + struct ccdrbg_state *drbg, + size_t entropyLength, const void* entropy, + size_t nonceLength, const void* nonce, + size_t psLength, const void* ps) +{ + return info->init(info, drbg, entropyLength, entropy, nonceLength, nonce, psLength, ps); +} + +/* + * The entropyLength is forced to be greater or equal than the security strength. + */ +CC_INLINE int ccdrbg_reseed(const struct ccdrbg_info *info, + struct ccdrbg_state *drbg, + size_t entropyLength, const void *entropy, + size_t additionalLength, const void *additional) +{ + return info->reseed(drbg, entropyLength, entropy, additionalLength, additional); +} + + +CC_INLINE int ccdrbg_generate(const struct ccdrbg_info *info, + struct ccdrbg_state *drbg, + size_t dataOutLength, void *dataOut, + size_t additionalLength, const void *additional) +{ + return info->generate(drbg, dataOutLength, dataOut, additionalLength, additional); +} + +CC_INLINE void ccdrbg_done(const struct ccdrbg_info *info, + struct ccdrbg_state *drbg) +{ + info->done(drbg); +} + +CC_INLINE size_t ccdrbg_context_size(const struct ccdrbg_info *info) +{ + return info->size; +} + + +/* + * NIST SP 800-90 CTR_DRBG + * the maximum security strengh of drbg equals to the block size of the corresponding ECB. + */ +struct ccdrbg_nistctr_custom { + const struct ccmode_ctr *ctr_info; + size_t keylen; + int strictFIPS; + int use_df; +}; + +void ccdrbg_factory_nistctr(struct ccdrbg_info *info, const struct ccdrbg_nistctr_custom *custom); + +/* + * NIST SP 800-90 HMAC_DRBG + * the maximum security strengh of drbg is half of output size of the input hash function and it internally is limited to 256 bits + */ +extern struct ccdrbg_info ccdrbg_nistdigest_info; + +struct ccdrbg_nisthmac_custom { + const struct ccdigest_info *di; + int strictFIPS; +}; + +void ccdrbg_factory_nisthmac(struct ccdrbg_info *info, const struct ccdrbg_nisthmac_custom *custom); + +/* + * NIST SP 800-90 TRNG DRBG + * + * Call into the SEP DRBG and perform a SP 800-90 test operation. + */ +void ccdrbg_factory_trng(struct ccdrbg_info *info); + +/* Required length of the various TRNG entropy and personalization inputs. */ +#define CCDRBG_TRNG_VECTOR_LEN 48 + +/* + * Dummy DRBG + */ +extern struct ccdrbg_info ccdrbg_dummy_info; + +#endif /* _CORECRYPTO_CCDRBG_H_ */ diff --git a/corecrypto/ccdrbg_factory.h b/corecrypto/ccdrbg_factory.h new file mode 100644 index 0000000..226164d --- /dev/null +++ b/corecrypto/ccdrbg_factory.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDRBG_FACTORY_H_ +#define _CORECRYPTO_CCDRBG_FACTORY_H_ + +#endif /* _CORECRYPTO_CCDRBG_FACTORY_H_ */ diff --git a/corecrypto/ccdrbg_impl.h b/corecrypto/ccdrbg_impl.h new file mode 100644 index 0000000..64506b8 --- /dev/null +++ b/corecrypto/ccdrbg_impl.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCDRBG_IMPL_H_ +#define _CORECRYPTO_CCDRBG_IMPL_H_ + +/* opaque drbg structure */ +struct ccdrbg_state; + +struct ccdrbg_info { + /*! Size of the DRBG state in bytes **/ + size_t size; + + /*! Instantiate the PRNG + @param prng The PRNG state + @param entropylen Length of entropy + @param entropy Entropy bytes + @param inlen Length of additional input + @param in Additional input bytes + @return 0 if successful + */ + int (*init)(const struct ccdrbg_info *info, struct ccdrbg_state *drbg, + size_t entropyLength, const void* entropy, + size_t nonceLength, const void* nonce, + size_t psLength, const void* ps); + + /*! Add entropy to the PRNG + @param prng The PRNG state + @param entropylen Length of entropy + @param entropy Entropy bytes + @param inlen Length of additional input + @param in Additional input bytes + @return 0 if successful + */ + int (*reseed)(struct ccdrbg_state *prng, + size_t entropylen, const void *entropy, + size_t inlen, const void *in); + + /*! Read from the PRNG in a FIPS Testing compliant manor + @param prng The PRNG state to read from + @param out [out] Where to store the data + @param outlen Length of data desired (octets) + @param inlen Length of additional input + @param in Additional input bytes + @return 0 if successfull + */ + int (*generate)(struct ccdrbg_state *prng, + size_t outlen, void *out, + size_t inlen, const void *in); + + /*! Terminate a PRNG state + @param prng The PRNG state to terminate + */ + void (*done)(struct ccdrbg_state *prng); + + /** private parameters */ + const void *custom; +}; + + + +#endif // _CORECRYPTO_CCDRBG_IMPL_H_ diff --git a/corecrypto/ccec.h b/corecrypto/ccec.h new file mode 100644 index 0000000..54d056a --- /dev/null +++ b/corecrypto/ccec.h @@ -0,0 +1,888 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCEC_H_ +#define _CORECRYPTO_CCEC_H_ +#include +#include +#include +#include +#include +#include + + +/* An ec_point. A ccec_projective_point_t is a point with x,y and z. + A ccec_affine_point_t only has x and y. */ + +struct ccec_projective_point { + cc_unit xyz[1]; +} CC_ALIGNED(8); +typedef struct ccec_projective_point ccec_projective_point; + +struct ccec_cp { + __CCZP_ELEMENTS_DEFINITIONS() +} CC_ALIGNED(CCN_UNIT_SIZE); + +#if CORECRYPTO_USE_TRANSPARENT_UNION + struct ccec_point_hdr { + cc_unit x; + }; + + typedef union { + struct ccec_point_hdr *hdr; + ccec_projective_point *_p; + } __attribute__((transparent_union)) ccec_projective_point_t; + + typedef union { + const struct ccec_point_hdr *hdr; + ccec_projective_point_t point; + ccec_projective_point *_p; + const ccec_projective_point *_cp; + const cc_unit *x; + } __attribute__((transparent_union)) ccec_const_projective_point_t; + + #define ccec_affine_point_t ccec_projective_point_t + #define ccec_affine_point ccec_projective_point + #define ccec_const_affine_point_t ccec_const_projective_point_t + + typedef union { + const struct ccec_cp *just_a_filler; + const struct cczp *zp; //security framework wants it this way + } __attribute__((transparent_union)) ccec_const_cp_t; +#else + + struct ccec_affine_point { + cc_unit xyz[1]; + } CC_ALIGNED(8); + typedef struct ccec_affine_point ccec_affine_point; + typedef ccec_projective_point* ccec_projective_point_t; + typedef ccec_affine_point* ccec_affine_point_t; + + typedef const struct ccec_affine_point* ccec_const_affine_point_t; + typedef const struct ccec_projective_point* ccec_const_projective_point_t; + + typedef const struct ccec_cp* ccec_const_cp_t; + +#endif + +/* Use ccec_full_ctx_decl to declare full ecc context */ +struct ccec_full_ctx { + ccec_const_cp_t cp; + uint8_t pad[16 - sizeof(ccec_const_cp_t *)]; + struct ccec_projective_point point[]; +} CC_ALIGNED(16) ; + +struct ccec_pub_ctx { + ccec_const_cp_t cp; + uint8_t pad[16 - sizeof(ccec_const_cp_t *)]; + struct ccec_projective_point point[]; +} CC_ALIGNED(16) ; + +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define ccec_ctx_public ccec_pub_ctx //this is just for compatibility + typedef union { + struct ccec_pub_ctx* pub; + struct ccec_pub_ctx* _pub; + struct ccec_pub_ctx* body; + struct ccec_full_ctx *_full; + struct ccec_full_ctx *full; + struct ccec_full_ctx *fullt; + struct ccec_full_ctx *hdr; + } ccec_full_ctx_t __attribute__((transparent_union)); + #define ccec_full(x) ((x).full) + typedef struct ccec_full_ctx ccec_full_ctx; + + typedef ccec_full_ctx_t ccec_pub_ctx_t; + typedef struct ccec_pub_ctx ccec_pub_ctx; +#else + typedef struct ccec_full_ctx* ccec_full_ctx_t; + typedef struct ccec_pub_ctx* ccec_pub_ctx_t; + CC_INLINE + ccec_pub_ctx_t ccec_ctx_public(ccec_full_ctx_t fk) { + return (ccec_pub_ctx_t) fk; + } +#endif + + +/* Return the size of an ccec_full_ctx where each ccn is _size_ bytes. */ +#define ccec_full_ctx_size(_size_) (sizeof(struct ccec_full_ctx) + 4 * (_size_)) +#define ccec_pub_ctx_size(_size_) (sizeof(struct ccec_pub_ctx) + 3 * (_size_)) + +/* declare full and public context, when curve paramters cp are not known and will be assigned later*/ +#define ccec_full_ctx_decl(_size_, _name_) cc_ctx_decl( struct ccec_full_ctx, ccec_full_ctx_size(_size_), _name_) +#define ccec_full_ctx_clear(_size_, _name_) cc_clear(ccec_full_ctx_size(_size_), _name_) +#define ccec_pub_ctx_decl(_size_, _name_) cc_ctx_decl( struct ccec_pub_ctx, ccec_pub_ctx_size(_size_), _name_) +#define ccec_pub_ctx_clear(_size_, _name_) cc_clear(ccec_pub_ctx_size(_size_), _name_) + +/* declare full and public context, when curve paramters cp are known */ +#define ccec_full_ctx_decl_cp(_cp_, _name_) ccec_full_ctx_decl(ccec_ccn_size(_cp_), _name_) +#define ccec_full_ctx_clear_cp(_cp_, _name_) ccec_full_ctx_clear(ccec_ccn_size(_cp_), _name_) +#define ccec_pub_ctx_decl_cp(_cp_, _name_) ccec_pub_ctx_decl(ccec_ccn_size(_cp_), _name_) +#define ccec_pub_ctx_clear_cp(_cp_, _name_) ccec_pub_ctx_clear(ccec_ccn_size(_cp_), _name_) + +/* Declare storage for a projected or affine point respectively. */ +#define ccec_point_size_n(_cp_) (3 * ccec_cp_n(cp)) +#define ccec_point_sizeof(_cp_) ccn_sizeof_n(ccec_point_size_n(cp)) +#define ccec_point_decl_cp(_cp_, _name_) cc_ctx_decl(struct ccec_projective_point, ccec_point_sizeof(_cp_), _name_) +#define ccec_point_clear_cp(_cp_, _name_) cc_clear(ccec_point_sizeof(_cp_), _name_) +#define ccec_affine_decl_cp(_cp_, _name_) cc_ctx_decl(struct ccec_affine_point, 2 * ccec_ccn_size(_cp_), _name_) +#define ccec_affine_clear_cp(_cp_, _name_) cc_clear(2 * ccec_ccn_size(_cp_), _name_) + +/* lvalue accessors to ccec_ctx fields. (only a ccec_full_ctx_t has K). */ +#if CORECRYPTO_USE_TRANSPARENT_UNION + #define ccec_ctx_cp(KEY) (((ccec_pub_ctx_t)(KEY)).hdr->cp) + CC_INLINE void ccec_ctx_init(ccec_const_cp_t cp, ccec_full_ctx_t key) {(key.full)->cp = cp;} + //CC_INLINE struct ccec_projective_point *ccec_ctx_point(ccec_full_ctx_t key){return key.full->point;} // The public key as a projected point on the curve + #define ccec_ctx_point(KEY) ((ccec_projective_point_t)(((ccec_full_ctx_t)KEY).full->point)) + #define ccec_ctx_n(KEY) (ccec_ctx_cp(KEY).zp->n) + #define ccec_ctx_prime(KEY) (ccec_ctx_cp(KEY).zp->ccn) + + CC_INLINE cc_size ccec_cp_n(ccec_const_cp_t cp) { return cp.zp->n; } + //CC_INLINE cczp_const_t ccec_cp_zp(ccec_const_cp_t cp){ return cp.zp; } + #define ccec_cp_zp(_cp_) ((_cp_).zp) + +#define ccec_ctx_x(KEY) (ccec_ctx_point(KEY)._p->xyz) // The x, y and z of the public key as a projected point on the curve. +#define ccec_ctx_y(KEY) (ccec_ctx_point(KEY)._p->xyz+ 1 * ccec_ctx_n(KEY)) +#define ccec_ctx_z(KEY) (ccec_ctx_point(KEY)._p->xyz+ 2 * ccec_ctx_n(KEY)) + +#else + /* Callers must use this macro to initialze a ccec_full_ctx or + ccec_pub_ctx before using most of the macros in this file. */ + #define ccec_ctx_cp(KEY) ((KEY)->cp) + #define ccec_ctx_init(_cp_, _key_) ((_key_)->cp = (_cp_)) + #define ccec_ctx_point(KEY) ((KEY)->point) // The public key as a projected point on the curve. + #define ccec_ctx_n(KEY) (ccec_ctx_cp(KEY)->n) // Return count (n) of a ccn for cp. + #define ccec_ctx_prime(KEY) (ccec_ctx_cp(KEY)->ccn) + + CC_CONST CC_INLINE cc_size ccec_cp_n(ccec_const_cp_t cp) { return cp->n; } + CC_CONST CC_INLINE cczp_const_t ccec_cp_zp(ccec_const_cp_t cp){ return (cczp_const_t)cp; } + + #define ccec_ctx_x(KEY) (ccec_ctx_point(KEY)->xyz) // The x, y and z of the public key as a projected point on the curve. + #define ccec_ctx_y(KEY) (ccec_ctx_point(KEY)->xyz+ 1 * ccec_ctx_n(KEY)) + #define ccec_ctx_z(KEY) (ccec_ctx_point(KEY)->xyz+ 2 * ccec_ctx_n(KEY)) +#endif + + +/***************************************************************************/ +/* EC Sizes */ +/***************************************************************************/ +/* Return the length of the prime for cp in bits. */ +#if CORECRYPTO_USE_TRANSPARENT_UNION + #define ccec_cp_prime_bitlen(CP) (ccn_bitlen((CP).zp->n, (CP).zp->ccn)) +#else + #define ccec_cp_prime_bitlen(CP) (ccn_bitlen((CP)->n, (CP)->ccn)) +#endif +/* Return the sizeof the prime for cp. */ +#define ccec_cp_prime_size(CP) ((ccec_cp_prime_bitlen(CP)+7)/8) +/* Return the ec keysize in bits. */ +#define ccec_ctx_bitlen(KEY) (ccec_cp_prime_bitlen(ccec_ctx_cp(KEY))) +/* Return the ec keysize in bytes. */ +#define ccec_ctx_size(KEY) (ccec_cp_prime_size(ccec_ctx_cp(KEY))) + + + + +/* The k of a full key which makes up the private key. + It is only accessible through full key + */ +CC_INLINE +cc_unit *ccec_ctx_k( ccec_full_ctx_t key) { + return (ccec_ctx_x(key)+ 3 * ccec_ctx_n(key)); +} + +CC_INLINE +ccec_pub_ctx_t ccec_ctx_pub( ccec_full_ctx_t key) { + return (ccec_pub_ctx_t) key; +} + + +/* Return sizeof a ccn for cp. */ +CC_CONST CC_INLINE +size_t ccec_ccn_size(ccec_const_cp_t cp) { + return ccn_sizeof_n(ccec_cp_n(cp)); +} + +/***************************************************************************/ +/* EC Curve Parameters */ +/***************************************************************************/ + +CC_CONST ccec_const_cp_t ccec_cp_192(void); +CC_CONST ccec_const_cp_t ccec_cp_224(void); +CC_CONST ccec_const_cp_t ccec_cp_256(void); +CC_CONST ccec_const_cp_t ccec_cp_384(void); +CC_CONST ccec_const_cp_t ccec_cp_521(void); + +/***************************************************************************/ +/* EC Wrap Params */ +/***************************************************************************/ + +struct ccec_rfc6637_curve; +struct ccec_rfc6637_wrap; +struct ccec_rfc6637_unwrap; + +extern struct ccec_rfc6637_wrap ccec_rfc6637_wrap_sha256_kek_aes128; +extern struct ccec_rfc6637_wrap ccec_rfc6637_wrap_sha512_kek_aes256; +extern struct ccec_rfc6637_unwrap ccec_rfc6637_unwrap_sha256_kek_aes128; +extern struct ccec_rfc6637_unwrap ccec_rfc6637_unwrap_sha512_kek_aes256; +extern struct ccec_rfc6637_curve ccec_rfc6637_dh_curve_p256; +extern struct ccec_rfc6637_curve ccec_rfc6637_dh_curve_p521; + +/***************************************************************************/ +/* EC Key Generation */ +/***************************************************************************/ + +/*! + @function ccec_generate_key + @abstract Default - Currently invokes the FIPS version + The behavior this function is not deterministic, + the number of random bytes it consumes may vary + @param cp Curve Parameters + @param rng Random for the key generation as well as consistency signature + @param key Full key containing the newly generated key pair + @returns 0 if no error, an error code otherwise. + */ + +CC_NONNULL_TU((1,3)) CC_NONNULL2 +int ccec_generate_key(ccec_const_cp_t cp, struct ccrng_state *rng, + ccec_full_ctx_t key); + +/*! + @function ccec_generate_key_legacy + @abstract NOT recommended: For legacy purposes in order to re-generate + deterministic keys previously generated. + 2 * ccn_sizeof(ccec_cp_order_bitlen(cp)) of random bytes needed + @param cp Curve Parameters + @param rng Random for the key generation as well as consistency signature + @param key Full key containing the newly generated key pair + @returns 0 if no error, an error code otherwise. + */ + +CC_NONNULL_TU((1,3)) CC_NONNULL2 +int ccec_generate_key_legacy(ccec_const_cp_t cp, struct ccrng_state *rng, + ccec_full_ctx_t key); + +/*! + @function ccec_generate_key_fips + @abstract Guarantees FIPS compliant key pair. RECOMMENDED + Use a non deterministic amount of random bytes + @param cp Curve Parameters + @param rng Random for the key generation as well as consistency signature + @param key Full key containing the newly generated key pair + @returns 0 if no error, an error code otherwise. + */ + +CC_NONNULL_TU((1,3)) CC_NONNULL2 +int ccec_generate_key_fips(ccec_const_cp_t cp, struct ccrng_state *rng, + ccec_full_ctx_t key); + +/*! + @function ccec_compact_generate_key + @abstract Generate a compact key pair according to + https://tools.ietf.org/html/draft-jivsov-ecc-compact-05 and follows FIPS guideline + @param cp Curve Parameters + @param rng Random for the key generation as well as consistency signature + @param key Full key containing the newly generated key pair + @returns 0 if no error, an error code otherwise. + */ + +/* Based on FIPS compliant version. Output a compact key */ +/* Use a non deterministic amount of random bytes */ +CC_NONNULL_TU((1,3)) CC_NONNULL2 +int ccec_compact_generate_key(ccec_const_cp_t cp, struct ccrng_state *rng, + ccec_full_ctx_t key); + +/*! + @function ccec_generate_key_deterministic + @abstract Generate a key pair from the provided entropy buffer. + requires cryptographic DRBG/KDF prior to calling + @param cp Curve Parameters + @param entropy_len Length in byte of the entropy buffer + @param entropy Pointer to the entropy buffer of size entropy_len + @param rng Real random for the signature and internal countermeasures + @param flag Bitmask: options as explained below + @param key Full key containing the newly generated key pair + @returns 0 if no error, an error code otherwise. + */ + +#define CCEC_GENKEY_DETERMINISTIC_FIPS (1<<0) +/* FIPS consumes all of the entropy and requires a minimum of ceiling(qbitlen+64 / 8) bytes of entropy. + It computes the secret key in [1,q-1] as (("entropy" mod (q-1)) + 1). "Entropy" is processed as a big endian number. + Provided the entropy is FIPS compliant and no other option is set this method is FIPS compliant. + If COMPACT option is used, the key is not strictly FIPS compliant */ + +#define CCEC_GENKEY_DETERMINISTIC_PKA (1<<1) +/* RAW consumes all of the entropy and requires a minimum of ceiling(qbitlen+64 / 8) bytes of entropy. + It computes the secret key in [2,q-1] as (("entropy" mod (q-2)) + 2). "Entropy" is processed as a big endian number. + Provided the entropy is FIPS compliant, this method is FIPS compliant. */ + +#define CCEC_GENKEY_DETERMINISTIC_LEGACY (1<<2) +/* LEGACY requires a minimum of ccn_sizeof_n(n) byte of entropy, but ignores bytes after ccn_sizeof_n(n) */ +/* Use them in the same sequence as the output of ccrng_generate that is used in ccec_generate_legacy */ + +#define CCEC_GENKEY_DETERMINISTIC_COMPACT ((1<<3) | CCEC_GENKEY_DETERMINISTIC_FIPS) +/* generate key that is compatible with compact export format. Compatible with all of the options above */ + +#define CCEC_GENKEY_DETERMINISTIC_SECBKP ((1<<4) | CCEC_GENKEY_DETERMINISTIC_COMPACT) +/* Compatibility flag for Secure Backup generated keys */ + +CC_NONNULL_TU((1,6)) CC_NONNULL((3,4)) +int ccec_generate_key_deterministic(ccec_const_cp_t cp, + size_t entropy_len, const uint8_t *entropy, + struct ccrng_state *rng, // For masking and signature + uint32_t flags, + ccec_full_ctx_t key); // Revisioning of the DRBG + + +/* Implementation per FIPS186-4 */ +#define CCEC_GENERATE_KEY_DEFAULT_ERR -1 +#define CCEC_GENERATE_KEY_TOO_MANY_TRIES -10 +#define CCEC_GENERATE_KEY_MULT_FAIL -11 +#define CCEC_GENERATE_KEY_AFF_FAIL -12 +#define CCEC_GENERATE_KEY_CONSISTENCY -13 +#define CCEC_GENERATE_NOT_ON_CURVE -14 +#define CCEC_GENERATE_NOT_ENOUGH_ENTROPY -15 +#define CCEC_GENERATE_NOT_SUPPORTED -16 +#define CCEC_GENERATE_INVALID_INPUT -17 + +/***************************************************************************/ +/* EC SIGN/VERIFY (ECDSA) */ +/***************************************************************************/ + +/* Return the maximum buffer size needed to hold a signature for key. */ +CC_INLINE CC_PURE CC_NONNULL_TU((1)) +size_t ccec_sign_max_size(ccec_const_cp_t cp) { + /* tag + 2 byte len + 2 * (tag + 1 byte len + optional leading zero + ccec_cp_prime_size) */ + return 3 + 2 * (3 + ccec_cp_prime_size(cp)); +} + +/* + Signature in DER format +*/ +CC_NONNULL_TU((1)) CC_NONNULL((3, 4, 5, 6)) +int ccec_sign(ccec_full_ctx_t key, size_t digest_len, const uint8_t *digest, + size_t *sig_len, uint8_t *sig, struct ccrng_state *rng); +CC_NONNULL_TU((1)) CC_NONNULL((3, 5, 6)) +int ccec_verify(ccec_pub_ctx_t key, size_t digest_len, const uint8_t *digest, + size_t sig_len, const uint8_t *sig, bool *valid); + + +/* + Raw signature, big endian, padded to the key size. + */ +CC_NONNULL_TU((1)) +size_t +ccec_signature_r_s_size(ccec_pub_ctx_t key); + +CC_NONNULL_TU((1)) CC_NONNULL((3, 4, 5, 6)) +int ccec_sign_composite(ccec_full_ctx_t key, size_t digest_len, const uint8_t *digest, + uint8_t *sig_r, uint8_t *sig_s, struct ccrng_state *rng); + +CC_NONNULL_TU((1)) CC_NONNULL((3, 4, 5, 6)) +int ccec_verify_composite(ccec_pub_ctx_t key, size_t digest_len, const uint8_t *digest, + uint8_t *sig_r, uint8_t *sig_s, bool *valid); + +/***************************************************************************/ +/* EC Diffie-Hellman */ +/***************************************************************************/ + +/* + Deprecated. Do not use. + Migrate existing calls to ccecdh_compute_shared_secret + */ + +/*! + @function ccec_compute_key + @abstract DEPRECATED. Use ccecdh_compute_shared_secret. + */ + +CC_NONNULL_TU((1,2)) CC_NONNULL((3, 4)) +int ccec_compute_key(ccec_full_ctx_t private_key, ccec_pub_ctx_t public_key, + size_t *computed_key_len, uint8_t *computed_key); + +/*! + @function ccecdh_compute_shared_secret + @abstract Elliptic Curve Diffie-Hellman + from ANSI X9.63 and NIST SP800-56A, section 5.7.1.2 + + @param private_key Input: EC private key + @param public_key Input: EC public key + @param computed_shared_secret_len Input: Size of allocation for computed_shared_secret. + Output: Effective size of data in computed_shared_secret + @param computed_shared_secret Output: DH shared secret + @param masking_rng Input: Handle on RNG to be used for the randomization of the computation + + @result 0 iff successful + + @discussion The shared secret MUST be transformed with a KDF function or at + least Hash (SHA-256 or above) before being used. + It shall not be used directly as a key. + */ + +CC_NONNULL_TU((1,2)) CC_NONNULL((3, 4)) +int ccecdh_compute_shared_secret(ccec_full_ctx_t private_key, + ccec_pub_ctx_t public_key, + size_t *computed_shared_secret_len, uint8_t *computed_shared_secret, + struct ccrng_state *masking_rng); + +/***************************************************************************/ +/* EC WRAP/UNWRAP */ +/***************************************************************************/ + +/* + * Use rfc6637 style PGP wrapping for using EC keys + */ + +CC_NONNULL_TU((1)) +size_t ccec_rfc6637_wrap_key_size(ccec_pub_ctx_t public_key, + unsigned long flags, + size_t key_len); + +/* + * When CCEC_RFC6637_COMPACT_KEYS flag is used, the wrapping is NOT + * compatible with RFC6637 so make sure the peer supports this mode + * before using it. It currently saves half of the public key size + * which for P256 is 32 bytes which end up being about 1/4 of the + * wrapping size. + * Macros are bit masks + */ +#define CCEC_RFC6637_COMPACT_KEYS 1 +#define CCEC_RFC6637_DEBUG_KEYS 2 +#define CCEC_EXPORT_COMPACT_DIVERSIFIED_KEYS 4 + +/*! + @function ccec_rfc6637_wrap_key + @abstract Key wraping based on rfc6637 + + @param public_key Input: EC public key + @param wrapped_key Output: Buffer for the wrapped key of length ccec_rfc6637_wrap_key_size + @param flags Input: Option flags + @param algid Input: Algorithm id + @param keylen Input: Length of the key to wrap (<=37 bytes) + @param key Input: Pointer to the key to wrap + @param curve Input: Definiton of the curve + @param curve Input: Definiton of the wrap + @param fingerprint Input: Point to a 20byte buffer used as fingerprint during wrapping. + @param rng Input: Handle on a RNG for ephemeral key generation and computation randomization + + @result 0 iff successful + + @discussion + This implementation hides the length of the key to wrap. + It only supports wrapping keys up to 37bytes. + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 6, 7, 8, 9, 10)) +int +ccec_rfc6637_wrap_key(ccec_pub_ctx_t public_key, + void *wrapped_key, + unsigned long flags, + uint8_t algid, + size_t key_len, + const void *key, + const struct ccec_rfc6637_curve *curve, + const struct ccec_rfc6637_wrap *wrap, + const uint8_t *fingerprint, + struct ccrng_state *rng); + +/*! + @function ccec_diversify_pub + @abstract diversified public key with scalar r. + r = entropy mod (q-1)) + 1, where entropy is interpreted as big endian. + + entropy_len must be greater or equal to ccec_diversify_min_entropy_len + the entropy must be a well uniformly distributed number, such as random byte, + output of a DRBG or output of a KDF. + + @param cp Input: Curve parameter + @param pub_key Input: Original public key P. + @param entropy_len Input: byte length of the entropy + @param entropy Input: point to the entropy + @param masking_rng Input: Random for randomizing the computation + @param diversified_generator Output: New generator (r.G). + @param diversified_pub_key Output: New public key (r.P). + + @result 0 iff unwrapping was successful + + @discussion + Diversified keys is the process of multiplying the generator and the public key + by a same random number. + This does not preserve properties of the key with respect to compact format + However, this method is valid with compact points when using ECDH and when only X coordinate is used + Therefore this is valid with ccec_rfc6637 wrap / unwrap. + + Compact here refers to https://datatracker.ietf.org/doc/draft-jivsov-ecc-compact/ + */ +int ccec_diversify_pub(ccec_const_cp_t cp, + ccec_pub_ctx_t pub_key, + size_t entropy_len, const uint8_t *entropy, + struct ccrng_state *masking_rng, + ccec_pub_ctx_t diversified_generator, + ccec_pub_ctx_t diversified_pub_key + ); + +/*! + @function ccec_diversify_min_entropy_len + @abstract Minimum length of entropy to be passed to ccec_diversify_pub + + @param cp Input: Curve parameter + + @result Minimal entropy length in bytes to be used in ccec_diversify_pub + + */ +size_t ccec_diversify_min_entropy_len(ccec_const_cp_t cp); + +/*! + @function ccec_rfc6637_wrap_key_diversified + @abstract Key wraping based on rfc6637 + + @param generator Input: Generator, represented as a public key + @param public_key Input: EC public key + @param wrapped_key Output: Buffer for the wrapped key of length ccec_rfc6637_wrap_key_size + @param flags Input: Option flags + @param algid Input: Algorithm id + @param keylen Input: Length of the key to wrap (<=38 bytes) + @param key Input: Pointer to the key to wrap + @param curve Input: Definiton of the curve + @param wrap Input: Definiton of the wrap + @param fingerprint Input: Point to a 20byte buffer used as fingerprint during wrapping. + @param rng Input: Handle on a RNG for ephemeral key generation and computation randomization + + @result 0 iff successful + + @discussion + Diversified keys is the process of multiplying the generator and the public key + by a same number. + This implementation hides the length of the key to wrap. + It only supports wrapping keys up to 37bytes. + */ + +CC_NONNULL_TU((1,2)) CC_NONNULL((3, 7, 8, 9, 10, 11)) +int +ccec_rfc6637_wrap_key_diversified(ccec_pub_ctx_t generator, + ccec_pub_ctx_t public_key, + void *wrapped_key, + unsigned long flags, + uint8_t symm_alg_id, + size_t key_len, + const void *key, + const struct ccec_rfc6637_curve *curve, + const struct ccec_rfc6637_wrap *wrap, + const uint8_t *fingerprint, /* 20 bytes */ + struct ccrng_state *rng); + +/*! + @function ccec_rfc6637_unwrap_key + @abstract Key unwraping based on rfc6637 + + @param private_key Input: Private key to unwrap the key + @param key_len Input/Output: Size of the allocated buffer / size of the key + @param key Output: Buffer for the unwrapped key + @param flags Input: Option flags + @param symm_key_alg Output: Algorithm id + @param curve Input: Definiton of the curve + @param wrap Input: Definiton of the unwrap + @param fingerprint Input: Point to a 20byte buffer used as fingerprint during wrapping. + @param wrapped_key_len Input: Size in byte of the wrapped key + @param wrapped_key Input: Pointer to the wrapped key + + @result 0 iff successful + + @discussion + Diversified keys is the process of multiplying the generator and the public key + by a same number. + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 5, 6, 7, 8, 10)) +int +ccec_rfc6637_unwrap_key(ccec_full_ctx_t private_key, + size_t *key_len, + void *key, + unsigned long flags, + uint8_t *symm_key_alg, + const struct ccec_rfc6637_curve *curve, + const struct ccec_rfc6637_unwrap *unwrap, + const uint8_t *fingerprint, + size_t wrapped_key_len, + const void *wrapped_key); + +/***************************************************************************/ +/* EC Import/Export */ +/***************************************************************************/ + +CC_NONNULL_TU((1,4)) CC_NONNULL((3)) +int ccec_import_pub(ccec_const_cp_t cp, size_t in_len, const uint8_t *in, ccec_pub_ctx_t key); + +/* Return the sizeof a buffer needed to exported public key to. */ +CC_INLINE CC_CONST CC_NONNULL_TU((1)) +size_t ccec_export_pub_size(ccec_pub_ctx_t key) { + return 1 + 2 * ccec_cp_prime_size(ccec_ctx_cp(key)); +} + +/* Export key to out. Out must be ccec_export_pub_size(key) bytes long. */ +CC_NONNULL_TU((1)) CC_NONNULL2 +void ccec_export_pub(ccec_pub_ctx_t key, void *out); + +/* ---------------------------------*/ +/* x963 */ +/* ---------------------------------*/ + +/* Export 9.63 */ +CC_INLINE CC_CONST CC_NONNULL_TU((2)) +size_t ccec_x963_export_size(const int fullkey, ccec_pub_ctx_t key){ + return (((ccec_ctx_bitlen(key)+7)/8) * ((fullkey == 1) + 2)) + 1; +} + +CC_NONNULL_TU((3)) CC_NONNULL2 +void ccec_x963_export(const int fullkey, void *out, ccec_full_ctx_t key); + +/* Import 9.63 */ +size_t ccec_x963_import_pub_size(size_t in_len); + +CC_NONNULL_TU((1,4)) CC_NONNULL3 +/* Import an EC public key with x9.63 format */ +int ccec_x963_import_pub(ccec_const_cp_t cp, size_t in_len, const uint8_t *in, ccec_pub_ctx_t key); + +size_t ccec_x963_import_priv_size(size_t in_len); + +CC_NONNULL_TU((1,4)) CC_NONNULL3 +/* Import the full key (private and public part of the key) with x9.63 format */ +int ccec_x963_import_priv(ccec_const_cp_t cp, size_t in_len, const uint8_t *in, ccec_full_ctx_t key); +/* ---------------------------------*/ +/* Compact */ +/* ---------------------------------*/ + +/* Compact here refers to https://datatracker.ietf.org/doc/draft-jivsov-ecc-compact/ */ + +/* Export Compact + Output as the same bitlen than p */ +CC_NONNULL_TU((3)) CC_NONNULL2 +void ccec_compact_export(const int fullkey, void *out, ccec_full_ctx_t key); + +CC_INLINE CC_CONST CC_NONNULL_TU((2)) +size_t ccec_compact_export_size(const int fullkey, ccec_pub_ctx_t key){ + return (((ccec_ctx_bitlen(key)+7)/8) * ((fullkey == 1) + 1)); +} + +/* Import Compact + The public key is the x coordinate, in big endian, of length the byte length of p + No preambule byte */ + +size_t ccec_compact_import_pub_size(size_t in_len); + +CC_NONNULL_TU((1,4)) CC_NONNULL3 +int ccec_compact_import_pub(ccec_const_cp_t cp, size_t in_len, const uint8_t *in, ccec_pub_ctx_t key); + +size_t ccec_compact_import_priv_size(size_t in_len); + +CC_NONNULL_TU((1,4)) CC_NONNULL3 +int ccec_compact_import_priv(ccec_const_cp_t cp, size_t in_len, const uint8_t *in, ccec_full_ctx_t key); + +/* ---------------------------------*/ +/* DER (RFC 5915) */ +/* ---------------------------------*/ + +/* Export EC priv to DER (RFC 5915) */ +CC_NONNULL_TU((1)) +size_t +ccec_der_export_priv_size(ccec_full_ctx_t key, ccoid_t key_oid, int includePublic); + +CC_NONNULL_TU((1)) CC_NONNULL5 +int +ccec_der_export_priv(ccec_full_ctx_t key, ccoid_t key_oid, int includePublic, size_t out_len, void *out); + +/* import EC priv from DER (RFC 5915) */ + +CC_NONNULL((2,4)) +int ccec_der_import_priv_keytype(size_t len, const uint8_t * data, ccoid_t *oid, size_t *n); + +CC_NONNULL_TU((1,4)) CC_NONNULL((3)) +int ccec_der_import_priv(ccec_const_cp_t cp, size_t length, const uint8_t *data, ccec_full_ctx_t full_key); + +/* ---------------------------------*/ +/* DER (custom) for diversified keys*/ +/* ---------------------------------*/ + +/*! + @function ccec_der_export_diversified_pub_size + @abstract DER export of a diversified public key + + @param diversified_generator Input: Generator, represented as a public key + @param diversified_key Input: EC public key + @param flags Input: Option flags (compact keys) + + @result sizeof a buffer needed to exported public key if successful, 0 otherwise. + + @discussion + Diversified keys is the process of multiplying the generator and the public key + by a same number. + + Compact here refers to https://datatracker.ietf.org/doc/draft-jivsov-ecc-compact/ + + */ +size_t ccec_der_export_diversified_pub_size( + ccec_pub_ctx_t diversified_generator, + ccec_pub_ctx_t diversified_key, + unsigned long flags); +/*! + @function ccec_der_export_diversified_pub + @abstract DER export of a diversified public key + + @param diversified_generator Input: Generator, represented as a public key + @param diversified_key Input: EC public key + @param flags Input: Option flags (compact keys) + @param der_len Input: Size of the destination buffer + @param der Output: Pointer to the destination buffer, must be ccec_export_pub_size(key) bytes long. + + @result NULL is error, pointer in the der buffer otherwise. + + @discussion + Diversified keys is the process of multiplying the generator and the public key + by a same number. + + Compact here refers to https://datatracker.ietf.org/doc/draft-jivsov-ecc-compact/ + */ +uint8_t *ccec_der_export_diversified_pub( + ccec_pub_ctx_t diversified_generator, + ccec_pub_ctx_t diversified_key, + unsigned long flags, + size_t der_len, uint8_t *der); + +/*! + @function ccec_der_export_diversified_pub + @abstract DER export of a diversified public key + + @param diversified_generator Output: Diversified generator, represented as a public key + @param diversified_key Output: Diversified EC public key + @param outflags Output: Output flags telling how the data was parsed. + @param der_len Input: Size of the destination buffer + @param der Output: Pointer to the destination buffer, must be ccec_export_pub_size(key) bytes long. + + @result 0 iff unwrapping was successful + + @discussion + Diversified keys is the process of multiplying the generator and the public key + by a same number. Currently the only valid output flag is CCEC_EXPORT_COMPACT_DIVERSIFIED_KEYS. + The generator and the public point a required to be encoded in the same format, either standard + or compact format. Mixing form is not allowed and that output is never generated + by ccec_der_export_diversified_pub. + + Compact here refers to https://datatracker.ietf.org/doc/draft-jivsov-ecc-compact/ + */ +int ccec_der_import_diversified_pub( + ccec_const_cp_t cp, + size_t length, const uint8_t *data, + int *outflags, + ccec_pub_ctx_t diversified_generator, + ccec_pub_ctx_t diversified_key); + +#define CCEC_IMPORT_DIVERSIFIED_KEYS_SUPPORT_FLAGS 1 + +/***************************************************************************/ +/* EC Construction and Validation */ +/***************************************************************************/ + +CC_NONNULL_TU((1)) +int ccec_get_pubkey_components(ccec_pub_ctx_t key, size_t *nbits, + uint8_t *x, size_t *xsize, + uint8_t *y, size_t *ysize); + +CC_NONNULL_TU((1)) +int ccec_get_fullkey_components(ccec_full_ctx_t key, size_t *nbits, + uint8_t *x, size_t *xsize, + uint8_t *y, size_t *ysize, + uint8_t *d, size_t *dsize); + +CC_NONNULL_TU((6)) +int ccec_make_pub(size_t nbits, + size_t xlength, const uint8_t *x, + size_t ylength, const uint8_t *y, + ccec_pub_ctx_t key); + +CC_NONNULL_TU((8)) +int ccec_make_priv(size_t nbits, + size_t xlength, const uint8_t *x, + size_t ylength, const uint8_t *y, + size_t klength, const uint8_t *k, + ccec_full_ctx_t key); + +/*! + @function ccec_validate_pub + @abstract Perform validation of the public key + @param key elliptic curve public key + @result true if the key is valid + @discussion + Perform the public key validation from FIPS: x,y are within range and + the point is on the curve. Point at infinity is considered as invalid here. + */ +CC_NONNULL_TU((1)) +bool ccec_validate_pub(ccec_pub_ctx_t key); + +int ccec_keysize_is_supported(size_t keysize); + +ccec_const_cp_t ccec_get_cp(size_t keysize); + +CC_NONNULL_TU((1)) CC_NONNULL2 +bool ccec_pairwise_consistency_check(const ccec_full_ctx_t full_key, struct ccrng_state *rng); + +ccec_const_cp_t ccec_curve_for_length_lookup(size_t keylen, ...); + +#endif /* _CORECRYPTO_CCEC_H_ */ diff --git a/corecrypto/ccec25519.h b/corecrypto/ccec25519.h new file mode 100644 index 0000000..7b71c8f --- /dev/null +++ b/corecrypto/ccec25519.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2014,2015,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCEC25519_H_ +#define _CORECRYPTO_CCEC25519_H_ + +#include +#include +#include + +typedef uint8_t ccec25519key[32]; +typedef ccec25519key ccec25519secretkey; +typedef ccec25519key ccec25519pubkey; +typedef ccec25519key ccec25519base; + +typedef uint8_t ccec25519signature[64]; + +/*! + @function cccurve25519 + @abstract Perform Curve25519 Diffie-Hellman. + http://cr.yp.to/ecdh.html + + @param out Output shared secret or public key. + @param sk Input secret key. + @param base Input basepoint (for computing a shared secret) + or NULL (for computing a public key). + */ + +void cccurve25519(ccec25519key out, + const ccec25519secretkey sk, + const ccec25519base base); + +/*! + @function cccurve25519_make_priv + @abstract Generates a random, montgomery curve 25519 private key. + + @param rng An initialized random number generator + @param sk Receives 32-byte secret key. + */ + +CC_INLINE void cccurve25519_make_priv(struct ccrng_state *rng, + ccec25519secretkey sk) { + ccrng_generate(rng,32,sk); + sk[0] &= 248; + sk[31] &= 127; + sk[31] |= 64; +} + +/*! + @function cccurve25519_make_pub + @abstract Creates a montgomery curve 25519 public key from a private key. + + @param pk Receives 32-byte public key. + @param sk Receives 32-byte secret key. + */ + +CC_INLINE void cccurve25519_make_pub(ccec25519pubkey pk, + const ccec25519secretkey sk) { + cccurve25519(pk, sk, NULL); +} + +/*! + @function cccurve25519_make_key_pair + @abstract Generates a random, montgomery curve 25519 key pair. + + @param rng An initialized random number generator + @param pk Receives 32-byte public key. + @param sk Receives 32-byte secret key. + */ + +CC_INLINE void cccurve25519_make_key_pair(struct ccrng_state *rng, + ccec25519pubkey pk, + ccec25519secretkey sk) { + cccurve25519_make_priv(rng, sk); + cccurve25519_make_pub(pk, sk); +} + + +/*! + @function cced25519_make_key_pair + @abstract Generates a random, Ed25519 key pair. + + @param di A valid descriptor for a 512 bit hash function for the platform + @param rng An initialized random number generator + @param pk Receives 32-byte public key. + @param sk Receives 32-byte secret key. + */ +void cced25519_make_key_pair(const struct ccdigest_info *di, + struct ccrng_state *rng, + ccec25519pubkey pk, + ccec25519secretkey sk); + +/*! + @function cced25519_sign + @abstract Signs a message using a secret key. + + @param di A valid descriptor for a 512 bit hash function for the platform + @param sig Receives the 64-byte signature. + @param len Number of bytes to sign. + @param msg Data to sign. + @param pk 32-byte public key as generated by cced25519_make_key_pair(). + @param sk 32-byte secret key as generated by cced25519_make_key_pair(). +*/ +void cced25519_sign(const struct ccdigest_info *di, + ccec25519signature sig, + size_t len, const void *msg, + const ccec25519pubkey pk, + const ccec25519secretkey sk); + +/*! + @function cced25519_verify + @abstract Verifies a signed message using a public key. + + @param di A valid descriptor for a 512 bit hash function for the platform + @param len Number of bytes of data to verify. + @param msg Data to verify. + @param sig 64-byte signature to verify data against. + @param pk 32-byte public key. Should have been generated by the peer using + cced25519_make_key_pair(). + + @result 0=Signed message is valid. Non-zero=Bad message. +*/ +int cced25519_verify(const struct ccdigest_info *di, + size_t len, const void *msg, + const ccec25519signature sig, + const ccec25519pubkey pk); + +#endif /* _CORECRYPTO_CCEC25519_H_ */ diff --git a/corecrypto/ccec25519_priv.h b/corecrypto/ccec25519_priv.h new file mode 100644 index 0000000..72e3abd --- /dev/null +++ b/corecrypto/ccec25519_priv.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCEC25519_PRIV_H_ +#define _CORECRYPTO_CCEC25519_PRIV_H_ + +/*! + @function cced25519_make_pub + @abstract Creates a montgomery curve 25519 public key from a private key. + + @param di A valid descriptor for a 512 bit hash function for the platform + @param pk Output 32-byte public key. + @param sk Input 32-byte secret key. + + @discussion Not safe for general use. For internal use only (eg. FIPS CAVS): + - Public key must be stored along side the private key, private key should not + be stored alone. + - It may be unsafe to use a same private key with different digests + */ + +int cced25519_make_pub(const struct ccdigest_info *di, + ccec25519pubkey pk, + const ccec25519secretkey sk); + +#endif /* _CORECRYPTO_CCEC25519_PRIV_H_ */ diff --git a/corecrypto/ccec_priv.h b/corecrypto/ccec_priv.h new file mode 100644 index 0000000..78ca717 --- /dev/null +++ b/corecrypto/ccec_priv.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2010,2011,2013,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCEC_PRIV_H_ +#define _CORECRYPTO_CCEC_PRIV_H_ + +#include +#include +#include +#include + +/* Configuration */ +#define CCEC_MASKING 1 + +/* Define this to 1 to use ccec_twin_mult for ccec_verify. This gives you a + big speedup for about 1500-2000 bytes of extra code. */ +#define CCEC_USE_TWIN_MULT 1 + +/* Define the condition for Montgomery arithmetic support */ +#define CCEC_ZP_IS_MONTGOMERY(cp) (cczp_is_montgomery(ccec_cp_zp(cp))) + +#define CCEC_DEBUG 0 + +/* Low level ec functions and types. */ + +/* Macros for accessing X and Y in an ccec_affine_point and X Y and Z in + an ccec_projective_point. */ + +#if CORECRYPTO_USE_TRANSPARENT_UNION + #define ccec_const_point_x(EP, _cp_) (&((ccec_const_affine_point_t)(EP)).hdr->x) + #define ccec_const_point_y(EP, _cp_) ((&((ccec_const_affine_point_t)(EP)).hdr->x) + ccec_cp_n(_cp_)) + #define ccec_const_point_z(EP, _cp_) ((&((ccec_const_projective_point_t)(EP)).hdr->x) + ccec_cp_n(_cp_) * 2) + + #define ccec_point_x(EP, _cp_) (&((ccec_affine_point_t)(EP)).hdr->x) + #define ccec_point_y(EP, _cp_) ((&((ccec_affine_point_t)(EP)).hdr->x) + ccec_cp_n(_cp_)) + #define ccec_point_z(EP, _cp_) ((&((ccec_projective_point_t)(EP)).hdr->x) + ccec_cp_n(_cp_) * 2) +#else + #define ccec_const_point_x(EP, _cp_) ((const cc_unit *)((EP)->xyz + ccec_cp_n(_cp_) * 0)) + #define ccec_const_point_y(EP, _cp_) ((const cc_unit *)((EP)->xyz + ccec_cp_n(_cp_) * 1)) + #define ccec_const_point_z(EP, _cp_) ((const cc_unit *)((EP)->xyz + ccec_cp_n(_cp_) * 2)) + + #define ccec_point_x(EP, _cp_) ((EP)->xyz + ccec_cp_n(_cp_) * 0) + #define ccec_point_y(EP, _cp_) ((EP)->xyz + ccec_cp_n(_cp_) * 1) + #define ccec_point_z(EP, _cp_) ((EP)->xyz + ccec_cp_n(_cp_) * 2) +#endif + +/* Macro to define a struct for a ccec_cp of _n_ units. This is + only to be used for static initializers of curve parameters. + Note that _n_ is evaluated multiple times. */ +#define ccec_cp_decl_n(_n_) struct { \ + struct cczp_hd hp; \ + cc_unit p[(_n_)]; \ + cc_unit pr[(_n_) + 1]; \ + cc_unit b[(_n_)]; \ + cc_unit gx[(_n_)]; \ + cc_unit gy[(_n_)]; \ + struct cczp_hd hq; \ + cc_unit q[(_n_)];\ + cc_unit qr[(_n_) + 1];\ +} + +/* Macro to define a struct for a ccec_cp of _bits_ bits. This is + only to be used for static initializers of curve parameters. */ +#define ccec_cp_decl(_bits_) ccec_cp_decl_n(ccn_nof(_bits_)) + +#if CORECRYPTO_USE_TRANSPARENT_UNION + #define ccec_cp_p(_cp_) ((_cp_).zp->ccn) + #define ccec_cp_b(_cp_) ((_cp_).zp->ccn + 1 + 2 * ccec_cp_n(_cp_)) + #define ccec_cp_g(_cp_) ((ccec_const_affine_point_t)(const ccec_affine_point *)((_cp_).zp->ccn + 1 + ccec_cp_n(_cp_) * 3)) + #define ccec_cp_zq(_cp_) ((cczp_const_t)((_cp_).zp->ccn + 1 + ccec_cp_n(_cp_) * 5)) + #define ccec_cp_options(_cp_) (*(ccec_cp_zq(_cp_).zp->ccn + 1 + 2 * ccec_cp_n(_cp_))) +#else + #define ccec_cp_p(_cp_) ((_cp_)->ccn) + #define ccec_cp_b(_cp_) ((_cp_)->ccn + 1 + 2 * ccec_cp_n(_cp_)) + #define ccec_cp_g(_cp_) ((const ccec_affine_point *)((_cp_)->ccn + 1 + ccec_cp_n(_cp_) * 3)) + #define ccec_cp_zq(_cp_) ((cczp_const_t)((_cp_)->ccn + 1 + ccec_cp_n(_cp_) * 5)) + #define ccec_cp_options(_cp_) (*(ccec_cp_zq(_cp_)->ccn + 1 + 2 * ccec_cp_n(_cp_))) +#endif + +/* Return the length of the order for cp in bits. */ +#define ccec_cp_order_bitlen(CP) (ccn_bitlen(cczp_n(ccec_cp_zq(cp)), cczp_prime(ccec_cp_zq(cp)))) +/* Return the length of the order for cp in bytes. */ +#define ccec_cp_order_size(cp) ((ccec_cp_order_bitlen(cp)+7)/8) + +/* accept an affine point S and set R equal to its projective representation. */ +int ccec_projectify(ccec_const_cp_t cp, ccec_projective_point_t r, ccec_const_affine_point_t s, + struct ccrng_state *masking_rng); + +/* accept a projective point S and set R equal to its affine representation. */ +int ccec_affinify(ccec_const_cp_t cp, ccec_affine_point_t r, ccec_const_projective_point_t s); + +/* accept a projective point S and output the x coordinate only of its affine representation. */ +int ccec_affinify_x_only(ccec_const_cp_t cp, cc_unit* sx, ccec_const_projective_point_t s, int secure) ; + +/* Take a x coordinate a recompute the point. No particular convention for y */ +int ccec_affine_point_from_x(ccec_const_cp_t cp, ccec_affine_point_t r, cc_unit *x, cc_unit *work2n); + +/* Return true if the point is on the curve. Requires curve with a=-3 */ +/* Z must be initialized. Set to 1 for points in affine representation */ +bool ccec_is_point(ccec_const_cp_t cp, ccec_const_projective_point_t s); + +/* accept an affine point S = (Sx,Sy) and return true if it is on the curve, (i.e., if SY2 = SX3 − 3SX.SZ^4 + bSZ^6 (mod p)), otherwise return false. */ +bool ccec_is_point_projective(ccec_const_cp_t cp, ccec_const_projective_point_t s); + +/* Validate the public key with respect to the curve information */ +int ccec_validate_pub_and_projectify(ccec_const_cp_t cp, + ccec_projective_point_t r, + ccec_const_affine_point_t public_point, + struct ccrng_state *masking_rng); + +/* Validate the private scalar with respect to the curve information */ +int ccec_validate_scalar(ccec_const_cp_t cp, const cc_unit* k); + +/* accept a projective point S and set R equal to the projective point 2S. Routine 2.2.6 performs no checks on its inputs. */ +#define CCEC_DOUBLE_WORKSPACE_SIZE(n)(6*(n)) +void ccec_double_ws(cc_ws_t ws, ccec_const_cp_t cp, ccec_projective_point_t r, ccec_const_projective_point_t s); + +/* accept two projective points S, T and set R equal to the projective point S + T. S and T must not be point at infinity. + Require r!=t. Ok with r==s */ +#define T_NORMALIZED 1 // expect T to be normalized (Z=1) +#define T_NEGATIVE 2 // use -T (point substration) +#define CCEC_ADD_SUB_WORKSPACE_SIZE(n) (7*(n)) +void ccec_add_ws(cc_ws_t ws, ccec_const_cp_t cp, + ccec_projective_point_t r, + ccec_const_projective_point_t s, + ccec_const_projective_point_t t, + uint32_t t_flags); + +/* accept two projective points S, T and set R equal to the projective point S + T . Routine 2.2.8 checks whether one of S or T is the point at infinity or whether S == T, and if so, takes the appropriate action. + + Require r!=t. Ok with r==s */ +void ccec_full_add_ws(cc_ws_t ws, ccec_const_cp_t cp, + ccec_projective_point_t r, + ccec_const_projective_point_t s, + ccec_const_projective_point_t t); + +/* accept two projective points S, T and set R equal to the projective point S + T . Routine 2.2.8 checks whether one of S or T is the point at infinity or whether S == T, and if so, takes the appropriate action. + T is required to be the neutral element (1 or R if Montgomery) */ +void ccec_full_add_normalized_ws(cc_ws_t ws, ccec_const_cp_t cp, + ccec_projective_point_t r, + ccec_const_projective_point_t s, + ccec_const_projective_point_t t); + +/* accept two projective points S, T and set R equal to the projective point S − T . Routine 2.2.9 checks whether one of S or T is the point at infinity or whether S == T, and if so, takes the appropriate action. */ +void ccec_full_sub_ws(cc_ws_t ws, ccec_const_cp_t cp, + ccec_projective_point_t r, + ccec_const_projective_point_t s, + ccec_const_projective_point_t t); + +/* accept two projective points S, T and set R equal to the projective point S − T . Routine 2.2.9 checks whether one of S or T is the point at infinity or whether S == T, and if so, takes the appropriate action. + T is required to be the neutral element (1 or R if Montgomery)*/ +void ccec_full_sub_normalized_ws(cc_ws_t ws, ccec_const_cp_t cp, + ccec_projective_point_t r, + ccec_const_projective_point_t s, + ccec_const_projective_point_t t); + + +/* accept a projective point S, an integer 1 ≤ d < q and 2 set R equal to the projective point dS. + Requires the point s to have been generated by "ccec_projectify" */ +int ccec_mult(ccec_const_cp_t cp, ccec_projective_point_t r, const cc_unit *d, + ccec_const_projective_point_t s, + struct ccrng_state *masking_rng); + +/* accept two projective points S, T , two integers 0 ≤ d0, d1 < p, and set R equal to the projective point d0S + d1T. */ +int ccec_twin_mult(ccec_const_cp_t cp, ccec_projective_point_t r, const cc_unit *d0, + ccec_const_projective_point_t s, + const cc_unit *d1, + ccec_const_projective_point_t t); + +/* Debugging */ +void ccec_alprint(ccec_const_cp_t cp, const char *label, ccec_const_affine_point_t s); +void ccec_plprint(ccec_const_cp_t cp, const char *label, ccec_const_projective_point_t s); + +void ccec_print_full_key(const char *label, ccec_full_ctx_t key); +void ccec_print_public_key(const char *label, ccec_pub_ctx_t key); +void ccec_print_sig(const char *label, size_t count, const uint8_t *s); + +/* + * EC key generation + */ + +/*! + @function ccec_generate_scalar_fips + @abstract Generate a random scalar k (private key) per FIPS "TestingCandidates" methodology + Faster than the extra bit generation + + @param cp Curve parameters + @param rng For the scalar k + @param k scalar of size ccec_cp_n(cp) + @param tmp buffer of size ccec_cp_n(cp) for intermediate values + @returns 0 if no error, an error code otherwise. + */ +int +ccec_generate_scalar_fips_retry(ccec_const_cp_t cp, struct ccrng_state *rng, cc_unit *k, cc_unit *tmp); + +/*! + @function ccec_generate_scalar_legacy + @abstract Generate a random scalar k (private key) with legacy method + Used for legacy purpose to reconstruct existing keys. + Behavior can not be changed + + @param cp Curve parameters + @param entropy_len Byte length of entropy + @param entropy Entropy for the scalar k + @param k scalar of size ccec_cp_n(cp) + @returns 0 if no error, an error code otherwise. + */ +int +ccec_generate_scalar_legacy(ccec_const_cp_t cp, + size_t entropy_len, const uint8_t *entropy, + cc_unit *k); + +/*! + @function ccec_generate_scalar_fips_extrabits + @abstract Generate a random scalar k (private key) per FIPS methodology + Slower than the "TestingCandidates" method + Behavior can not be changed + + @param cp Curve parameters + @param entropy_len Byte length of entropy + @param entropy Entropy for the scalar k + @param k scalar of size ccec_cp_n(cp) + @param tmp buffer of size ccec_cp_n(cp) for intermediate values + @returns 0 if no error, an error code otherwise. + */ +int +ccec_generate_scalar_fips_extrabits(ccec_const_cp_t cp, + size_t entropy_len, const uint8_t *entropy, + cc_unit *k, cc_unit *tmp); + +/*! + @function ccec_scalar_fips_extrabits_min_entropy_len + @abstract Return the minimum size of the entropy to be passed to + ccec_generate_scalar_fips_extrabits + + @param cp Curve parameters + @returns minimal value for entropy_len + */ +size_t ccec_scalar_fips_extrabits_min_entropy_len(ccec_const_cp_t cp); + +/*! + @function ccec_generate_scalar_pka + @abstract Generate a random scalar k (private key) per FIPS methodology + Similar to PKA behavior + Behavior can not be changed + + @param cp Curve parameters + @param entropy_len Byte length of entropy + @param entropy Entropy for the scalar k + @param k scalar of size ccec_cp_n(cp) + @param tmp buffer of size ccec_cp_n(cp) for intermediate values + @returns 0 if no error, an error code otherwise. + */ +int +ccec_generate_scalar_pka(ccec_const_cp_t cp, + size_t entropy_len, const uint8_t *entropy, + cc_unit *k, cc_unit *tmp); + +/*! + @function ccec_make_pub_from_priv + @abstract The public key from the input scalar k (private key) + This internal function does not perform the consistent check + Which guarantees that the key is valid. + @param cp Curve parameters + @param masking_rng For internal countermeasures + @param k scalar of size ccec_cp_n(cp), in range [1..q-1] and with no statistical bias. + @param key Resulting public key + @param generator Generator point / NULL if default + @returns 0 if no error, an error code otherwise. + */ +int +ccec_make_pub_from_priv(ccec_const_cp_t cp, + struct ccrng_state *masking_rng, + cc_unit *k, + ccec_const_affine_point_t generator, + ccec_pub_ctx_t key); + +/*! + @function ccec_generate_key_internal_legacy + @abstract Generate key pair for compatiblity purposes or deterministic keys + NOT RECOMMENDED. This internal function does not perform the consistent check + Which guarantees that the key is valid. + @param cp Curve parameters + @param rng For internal countermeasures + @param key Resulting key pair + @returns 0 if no error, an error code otherwise. + */ +int +ccec_generate_key_internal_legacy(ccec_const_cp_t cp, struct ccrng_state *rng, + ccec_full_ctx_t key); + +/* FIPS compliant and more secure */ +/*! + @function ccec_generate_key_internal_fips + @abstract Follows FIPS guideline and more secure. + This internal function does not perform the consistent check + which guarantees that the key is valid (required by FIPS). + @param cp Curve parameters + @param rng key generation and internal countermeasures + @param key Resulting key pair + @returns 0 if no error, an error code otherwise. + */ +int +ccec_generate_key_internal_fips(ccec_const_cp_t cp, struct ccrng_state *rng, + ccec_full_ctx_t key); + +/*! + @function ccec_compact_transform_key + @abstract Follow instructions from https://datatracker.ietf.org/doc/draft-jivsov-ecc-compact/ + to make a key compatible with the compact export format. + @param cp Curve parameters + @param key Input/Output full key + @returns 0 if no error, an error code otherwise. + */ +int ccec_compact_transform_key(ccec_full_ctx_t key); + +/*! + @function ccecdh_generate_key + @abstract Key generation used for ephemeral key pairs used in ECDH + This function may not perform all steps such as the FIPS consistency check. + @param cp Curve parameters + @param rng For key generation and internal countermeasures + @param key Resulting key pair + @returns 0 if no error, an error code otherwise. + */ +int ccecdh_generate_key(ccec_const_cp_t cp, struct ccrng_state *rng, ccec_full_ctx_t key); + + +/*! + @function ccecdh_pairwise_consistency_check + @abstract Does a DH with a constant key to confirm the newly generated key is + correct. + @param key Resulting key pair + @param generator Generator point / NULL if default + @param rng For key generation and internal countermeasures + @returns true if no error, false otherwise. + */ +bool ccecdh_pairwise_consistency_check(ccec_full_ctx_t full_key, + ccec_const_affine_point_t generator, + struct ccrng_state *rng); + +/* + * EC Digital Signature - ECDSA + */ + +/*! + @function ccec_verify_internal + @abstract ECDSA signature verification. + @param key Public key + @param digest_len Byte length of the digest + @param digest Pointer to the digest + @param r Pointer to input buffer for r + @param s Pointer to input buffer for s + @param valid Pointer to output boolean. + *valid=true if the input {r,s} is valid. + @returns 0 if no error, an error code otherwise. + */ + +int ccec_verify_internal(ccec_pub_ctx_t key, size_t digest_len, const uint8_t *digest, + const cc_unit *r, const cc_unit *s, bool *valid); + +/*! + @function ccec_sign_internal + @abstract ECDSA signature creation. + @param key Public key + @param digest_len Byte length of the digest + @param digest Pointer to the digest + @param r Pointer to output buffer for r + @param s Pointer to output buffer for s + @returns 0 if no error, an error code otherwise. + */ +int ccec_sign_internal(ccec_full_ctx_t key, size_t digest_len, const uint8_t *digest, + cc_unit *r, cc_unit *s, struct ccrng_state *rng); + + +/* + * RFC6637 wrap/unwrap + */ + +#define ccec_rfc6637_ecdh_public_key_id 18 +#define ccec_rfc6637_ecdsa_public_key_id 19 + +#define ccpgp_digest_sha256 8 +#define ccpgp_digest_sha384 9 +#define ccpgp_digest_sha512 10 + +#define ccpgp_cipher_aes128 7 +#define ccpgp_cipher_aes192 8 +#define ccpgp_cipher_aes256 9 + +struct ccec_rfc6637 { + const char *name; + const uint8_t kdfhash_id; + const struct ccdigest_info * (*difun)(void); + const uint8_t kek_id; + const size_t keysize; +}; + +struct ccec_rfc6637_curve { + const uint8_t *curve_oid; + uint8_t public_key_alg; +}; + +extern struct ccec_rfc6637 ccec_rfc6637_sha256_kek_aes128; +extern struct ccec_rfc6637 ccec_rfc6637_sha512_kek_aes256; + +void +ccec_rfc6637_kdf(const struct ccdigest_info *di, + const struct ccec_rfc6637_curve *curve, + const struct ccec_rfc6637 *wrap, + size_t epkey_size, const void *epkey, + size_t fingerprint_size, const void *fingerprint, + void *hash); + +size_t +ccec_rfc6637_wrap_pub_size(ccec_pub_ctx_t public_key, + unsigned long flags); + +int +ccec_rfc6637_wrap_core(ccec_pub_ctx_t public_key, + ccec_full_ctx_t ephemeral_key, + void *wrapped_key, + unsigned long flags, + uint8_t symm_alg_id, + size_t key_len, + const void *key, + const struct ccec_rfc6637_curve *curve, + const struct ccec_rfc6637_wrap *wrap, + const uint8_t *fingerprint, /* 20 bytes */ + struct ccrng_state *rng); + +uint16_t +pgp_key_checksum(size_t key_len, const uint8_t *key); + + +//imports the x and y from the in array in big-endian, sets z to 1 +CC_NONNULL_TU((1,4)) CC_NONNULL((3)) +int ccec_raw_import_pub(ccec_const_cp_t cp, size_t in_len, const uint8_t *in, ccec_pub_ctx_t key); +//imports the ecc private key k, and sets x an y to all ones. +CC_NONNULL_TU((1,4)) CC_NONNULL((3)) +int ccec_raw_import_priv_only(ccec_const_cp_t cp, size_t in_len, const uint8_t *in, ccec_full_ctx_t key); + +#endif /* _CORECRYPTO_CCEC_PRIV_H_ */ diff --git a/corecrypto/ccecies.h b/corecrypto/ccecies.h new file mode 100644 index 0000000..47abff9 --- /dev/null +++ b/corecrypto/ccecies.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +/* Elliptic Curve Integrated Encryption Scheme implementation using AES-GCM for + encryption/authentication. + Terminology borrowed from http://www.secg.org/index.php?action=secg,docs_secg + sharedinfo_1 is diversifier for the KDF: + In original design of DHIES, it needs to be set to the ephemeral public + key to address malleability concerns, which are limited for ECIES. + Even on ECIES, the mission of the public key appears to loosen the + security bounds of certain security proofs (cf p28 http://shoup.net/papers/iso-2_1.pdf) + Use option ECIES_EPH_PUBKEY_IN_SHAREDINFO1 to achieve this. + Still considered optional per standards SEC1 and x9.63 + sharedinfo_2 is diversifier for the MAC + Potential security threat when attacker controled. + */ + +#ifndef corecrypto_ccecies_h +#define corecrypto_ccecies_h + +// bit mask +#define ECIES_EPH_PUBKEY_IN_SHAREDINFO1 1 +#define ECIES_EXPORT_PUB_STANDARD 2 +#define ECIES_EXPORT_PUB_COMPACT 4 +//#define ECIES_EXPORT_PUB_COMPRESSES 8 // not supported +#define ECIES_LEGACY_IV 16 + +#include +#include +#include +#include + +typedef struct ccecies_gcm { + const struct ccdigest_info *di; + struct ccrng_state *rng; + const struct ccmode_gcm *gcm; + uint32_t key_length; + uint32_t mac_length; + uint32_t options; // bit mask +} *ccecies_gcm_t; + +/* set the structure from the argument passed */ +CC_NONNULL((1, 2, 3, 4)) +void +ccecies_encrypt_gcm_setup(ccecies_gcm_t ecies, + const struct ccdigest_info *di, + struct ccrng_state *rng, + const struct ccmode_gcm *aes_gcm_enc, + uint32_t cipher_key_size, + uint32_t mac_tag_nbytes, + uint32_t options + ); + +/* Return the size of the ciphertext from ccecies_encrypt_aes_gcm + It requires ecies to have been initialized with the setup function */ +CC_NONNULL_TU((1)) CC_NONNULL((2)) +size_t +ccecies_encrypt_gcm_ciphertext_size(ccec_pub_ctx_t public_key, + ccecies_gcm_t ecies, + size_t plaintext_nbytes + ); + +/* Encrypt using the provided public key and elliptic curve info + It requires ecies to have been initialized with the setup function. + ciphertext_nbytes must be at least "ccecies_encrypt_gcm_cipher_size" bytes + If ECIES_EPH_PUBKEY_IN_SHAREDINFO1 is set, sharedinfo1_nbytes is ignored */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 4, 9, 10)) +int +ccecies_encrypt_gcm( ccec_pub_ctx_t public_key, + const ccecies_gcm_t ecies, + size_t plaintext_nbytes, const uint8_t *plaintext, + size_t sharedinfo1_nbytes, const void *sharedinfo_1, + size_t sharedinfo2_nbytes, const void *sharedinfo_2, + size_t *encrypted_blob_nbytes, uint8_t *encrypted_blob + ); + +/* set the structure from the argument passed */ +CC_NONNULL((1, 2, 3)) +void +ccecies_decrypt_gcm_setup(ccecies_gcm_t ecies, + const struct ccdigest_info *di, + const struct ccmode_gcm *aes_gcm_dec, + uint32_t cipher_key_nbytes, + uint32_t mac_tag_nbytes, + uint32_t options + ); + +/* Return the size of the plaintext output of ccecies_decrypt_aes_gcm + It requires ecies to have been initialized with the setup function */ +CC_NONNULL_TU((1)) CC_NONNULL((2)) +size_t +ccecies_decrypt_gcm_plaintext_size(ccec_full_ctx_t full_key, + ccecies_gcm_t ecies, + size_t ciphertext_nbytes + ); + + +/* Decrypt using the provided private key and elliptic curve info + It requires ecies to have been initialized with the setup function. + ciphertext_nbytes must be at least "ccecies_encrypt_gcm_cipher_size" bytes + If ECIES_EPH_PUBKEY_IN_SHAREDINFO1 is set, sharedinfo1_nbytes is ignored */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 4, 9, 10)) +int +ccecies_decrypt_gcm(ccec_full_ctx_t full_key, + const ccecies_gcm_t ecies, + size_t encrypted_blob_nbytes, const uint8_t *encrypted_blob, + size_t sharedinfo1_nbytes, const void *sharedinfo_1, + size_t sharedinfo2_nbytes, const void *sharedinfo_2, + size_t *plaintext_nbytes, uint8_t *plaintext + ); + + + + +/* Return the size of the returned/expected exported public key */ +CC_NONNULL_TU((1)) CC_NONNULL((2)) +size_t +ccecies_pub_key_size(ccec_pub_ctx_t public_key, + ccecies_gcm_t ecies); + +/* Encrypt using the provided public key and elliptic curve info + It requires ecies to have been initialized with the setup function. + ciphertext_nbytes must be at least "ccecies_encrypt_gcm_cipher_size" bytes + If ECIES_EPH_PUBKEY_IN_SHAREDINFO1 is set, sharedinfo1_nbytes is ignored + Composite because ciphertext, mac and publickey are separate output */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4, 5, 7)) +int +ccecies_encrypt_gcm_composite(ccec_pub_ctx_t public_key, + const ccecies_gcm_t ecies, + uint8_t *exported_public_key, /* output - length from ccecies_pub_key_size */ + uint8_t *ciphertext, /* output - length same as plaintext_nbytes */ + uint8_t *mac_tag, /* output - length ecies->mac_length */ + size_t plaintext_nbytes, const uint8_t *plaintext, + size_t sharedinfo1_nbytes, const void *sharedinfo_1, + size_t sharedinfo2_nbytes, const void *sharedinfo_2 + ); + +/* Decrypt using the provided private key and elliptic curve info + It requires ecies to have been initialized with the setup function. + ciphertext_nbytes must be at least "ccecies_encrypt_gcm_cipher_size" bytes + If ECIES_EPH_PUBKEY_IN_SHAREDINFO1 is set, sharedinfo1_nbytes is ignored + Composite because ciphertext, mac and publickey are separate input */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 10, 11)) +int +ccecies_decrypt_gcm_composite(ccec_full_ctx_t full_key, + const ccecies_gcm_t ecies, + uint8_t *plaintext, /* output - length same as ciphertext_nbytes */ + size_t sharedinfo1_nbytes, const void *sharedinfo_1, + size_t sharedinfo2_nbytes, const void *sharedinfo_2, + size_t ciphertext_nbytes, const uint8_t *ciphertext, + const uint8_t *imported_public_key, /* expect length from ccecies_pub_key_size */ + const uint8_t *mac_tag /* expect length ecies->mac_nbytesgth */ + ); + + +#endif diff --git a/corecrypto/ccecies_priv.h b/corecrypto/ccecies_priv.h new file mode 100644 index 0000000..379d05f --- /dev/null +++ b/corecrypto/ccecies_priv.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_ccecies_priv_h +#define corecrypto_ccecies_priv_h + +#define ECIES_CIPHERIV_SIZE 16 + +#endif diff --git a/corecrypto/cchkdf.h b/corecrypto/cchkdf.h new file mode 100644 index 0000000..ef18b91 --- /dev/null +++ b/corecrypto/cchkdf.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCHKDF_H_ +#define _CORECRYPTO_CCHKDF_H_ + +#include + +/*! + @function cchkdf + @abstract Perform a NIST SP800-56C HKDF. + http://csrc.nist.gov/publications/nistpubs/800-56C/SP-800-56C.pdf + @discussion Derives output key data from input key data, optional salt, and info. + + @param di Hash function to use. + @param kdkLen Input key material length in bytes + @param kdk Input key material used to derive the new key + @param saltLen Salt length length + @param salt Salt data + @param infoLen Info string length + @param info Info string + @param dkLen Derived Key Length in bytes. + @param dk Derived key buffer to receive results of KDF + */ + +int cchkdf(const struct ccdigest_info *di, + size_t ikmLen, const void *ikm, + size_t saltLen, const void *salt, + size_t infoLen, const void *info, + size_t dkLen, void *dk); + +#endif /* _CORECRYPTO_CCHKDF_H_ */ diff --git a/corecrypto/cchmac.h b/corecrypto/cchmac.h new file mode 100644 index 0000000..0a48245 --- /dev/null +++ b/corecrypto/cchmac.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCHMAC_H_ +#define _CORECRYPTO_CCHMAC_H_ + +#include +#include + +/* An hmac_ctx_t is normally allocated as an array of these. */ +struct cchmac_ctx { + uint8_t b[8]; +} CC_ALIGNED(8); + +#if CORECRYPTO_USE_TRANSPARENT_UNION +typedef union { + struct cchmac_ctx *hdr; + ccdigest_ctx_t digest; +} cchmac_ctx_t __attribute__((transparent_union)); +#else +typedef struct cchmac_ctx* cchmac_ctx_t; +#endif + +#define cchmac_ctx_size(STATE_SIZE, BLOCK_SIZE) (ccdigest_ctx_size(STATE_SIZE, BLOCK_SIZE) + (STATE_SIZE)) +#define cchmac_di_size(_di_) (cchmac_ctx_size((_di_)->state_size, (_di_)->block_size)) + +#define cchmac_ctx_n(STATE_SIZE, BLOCK_SIZE) ccn_nof_size(cchmac_ctx_size((STATE_SIZE), (BLOCK_SIZE))) + +#define cchmac_ctx_decl(STATE_SIZE, BLOCK_SIZE, _name_) cc_ctx_decl(struct cchmac_ctx, cchmac_ctx_size(STATE_SIZE, BLOCK_SIZE), _name_) +#define cchmac_ctx_clear(STATE_SIZE, BLOCK_SIZE, _name_) cc_clear(cchmac_ctx_size(STATE_SIZE, BLOCK_SIZE), _name_) +#define cchmac_di_decl(_di_, _name_) cchmac_ctx_decl((_di_)->state_size, (_di_)->block_size, _name_) +#define cchmac_di_clear(_di_, _name_) cchmac_ctx_clear((_di_)->state_size, (_di_)->block_size, _name_) + +/* Return a ccdigest_ctx_t which can be accesed with the macros in ccdigest.h */ +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define cchmac_digest_ctx(_di_, HC) (((cchmac_ctx_t)(HC)).digest) +#else +#define cchmac_digest_ctx(_di_, HC) ((ccdigest_ctx_t)(HC)) +#endif + +/* Accesors for ostate fields, this is all cchmac_ctx_t adds to the ccdigest_ctx_t. */ +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define cchmac_ostate(_di_, HC) ((struct ccdigest_state *)(((cchmac_ctx_t)(HC)).hdr->b + ccdigest_di_size(_di_))) +#else +#define cchmac_ostate(_di_, HC) ((struct ccdigest_state *)(((cchmac_ctx_t)(HC))->b + ccdigest_di_size(_di_))) +#endif +#define cchmac_ostate8(_di_, HC) (ccdigest_u8(cchmac_ostate(_di_, HC))) +#define cchmac_ostate32(_di_, HC) (ccdigest_u32(cchmac_ostate(_di_, HC))) +#define cchmac_ostate64(_di_, HC) (ccdigest_u64(cchmac_ostate(_di_, HC))) +#define cchmac_ostateccn(_di_, HC) (ccdigest_ccn(cchmac_ostate(_di_, HC))) + +/* Convenience accessors for ccdigest_ctx_t fields. */ +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define cchmac_istate(_di_, HC) ccdigest_state(_di_, ((cchmac_ctx_t)(HC)).digest) +#else +#define cchmac_istate(_di_, HC) ccdigest_state(_di_, ((ccdigest_ctx_t)(HC))) +#endif +#define cchmac_istate8(_di_, HC) ccdigest_u8(cchmac_istate(_di_, HC)) +#define cchmac_istate32(_di_, HC) ccdigest_u32(cchmac_istate(_di_, HC)) +#define cchmac_istate64(_di_, HC) ccdigest_u64(cchmac_istate(_di_, HC)) +#define cchmac_istateccn(_di_, HC) ccdigest_ccn(cchmac_istate(_di_, HC)) + +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define cchmac_data(_di_, HC) ccdigest_data(_di_, ((cchmac_ctx_t)(HC)).digest) +#define cchmac_num(_di_, HC) ccdigest_num(_di_, ((cchmac_ctx_t)(HC)).digest) +#define cchmac_nbits(_di_, HC) ccdigest_nbits(_di_, ((cchmac_ctx_t)(HC)).digest) +#else +#define cchmac_data(_di_, HC) ccdigest_data(_di_, ((ccdigest_ctx_t)(HC))) +#define cchmac_num(_di_, HC) ccdigest_num(_di_, ((ccdigest_ctx_t)(HC))) +#define cchmac_nbits(_di_, HC) ccdigest_nbits(_di_, ((ccdigest_ctx_t)(HC))) +#endif + +void cchmac_init(const struct ccdigest_info *di, cchmac_ctx_t ctx, + size_t key_len, const void *key); +void cchmac_update(const struct ccdigest_info *di, cchmac_ctx_t ctx, + size_t data_len, const void *data); +void cchmac_final(const struct ccdigest_info *di, cchmac_ctx_t ctx, + unsigned char *mac); + +void cchmac(const struct ccdigest_info *di, size_t key_len, + const void *key, size_t data_len, const void *data, + unsigned char *mac); + +/* Test functions */ + +struct cchmac_test_input { + const struct ccdigest_info *di; + size_t key_len; + const void *key; + size_t data_len; + const void *data; + size_t mac_len; + const void *expected_mac; +}; + +int cchmac_test(const struct cchmac_test_input *input); +int cchmac_test_chunks(const struct cchmac_test_input *input, size_t chunk_size); + + +#endif /* _CORECRYPTO_CCHMAC_H_ */ diff --git a/corecrypto/ccmd2.h b/corecrypto/ccmd2.h new file mode 100644 index 0000000..d21149b --- /dev/null +++ b/corecrypto/ccmd2.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010,2011,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMD2_H_ +#define _CORECRYPTO_CCMD2_H_ + +#include + +#define CCMD2_BLOCK_SIZE 16 +#define CCMD2_OUTPUT_SIZE 16 +#define CCMD2_STATE_SIZE 64 + +extern const uint32_t ccmd2_initial_state[16]; + +extern const struct ccdigest_info ccmd2_ltc_di; + +/* default is libtomcrypt */ +#define ccmd2_di ccmd2_ltc_di + +void ccmd2_final(const struct ccdigest_info *di, ccdigest_ctx_t, + unsigned char *digest); + +#endif /* _CORECRYPTO_CCMD2_H_ */ diff --git a/corecrypto/ccmd4.h b/corecrypto/ccmd4.h new file mode 100644 index 0000000..f8bb54a --- /dev/null +++ b/corecrypto/ccmd4.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMD4_H_ +#define _CORECRYPTO_CCMD4_H_ + +#include + +#define CCMD4_BLOCK_SIZE 64 +#define CCMD4_OUTPUT_SIZE 16 +#define CCMD4_STATE_SIZE 16 + +/* Works for MD5 as well */ +extern const uint32_t ccmd4_initial_state[4]; + +extern const struct ccdigest_info ccmd4_ltc_di; + +/* default is libtomcrypt */ +#define ccmd4_di ccmd4_ltc_di + +#endif /* _CORECRYPTO_CCMD4_H_ */ diff --git a/corecrypto/ccmd5.h b/corecrypto/ccmd5.h new file mode 100644 index 0000000..ae4be4a --- /dev/null +++ b/corecrypto/ccmd5.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010,2012,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMD5_H_ +#define _CORECRYPTO_CCMD5_H_ + +#include + +#define CCMD5_BLOCK_SIZE 64 +#define CCMD5_OUTPUT_SIZE 16 +#define CCMD5_STATE_SIZE 16 + +extern const uint32_t ccmd5_initial_state[4]; + +/* Selector */ +const struct ccdigest_info *ccmd5_di(void); + +/* Implementations */ +extern const struct ccdigest_info ccmd5_ltc_di; + +#endif /* _CORECRYPTO_CCMD5_H_ */ diff --git a/corecrypto/ccmode.h b/corecrypto/ccmode.h new file mode 100644 index 0000000..7148577 --- /dev/null +++ b/corecrypto/ccmode.h @@ -0,0 +1,926 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMODE_H_ +#define _CORECRYPTO_CCMODE_H_ + +#include +#include +#include + +/* ECB mode. */ + +/* Declare a ecb key named _name_. Pass the size field of a struct ccmode_ecb + for _size_. */ +#define ccecb_ctx_decl(_size_, _name_) cc_ctx_decl(ccecb_ctx, _size_, _name_) +#define ccecb_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +CC_INLINE size_t ccecb_context_size(const struct ccmode_ecb *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccecb_block_size(const struct ccmode_ecb *mode) +{ + return mode->block_size; +} + +CC_INLINE int ccecb_init(const struct ccmode_ecb *mode, ccecb_ctx *ctx, + size_t key_len, const void *key) +{ + return mode->init(mode, ctx, key_len, key); +} + +CC_INLINE int ccecb_update(const struct ccmode_ecb *mode, const ccecb_ctx *ctx, + size_t nblocks, const void *in, void *out) +{ + return mode->ecb(ctx, nblocks, in, out); +} + +CC_INLINE int ccecb_one_shot(const struct ccmode_ecb *mode, + size_t key_len, const void *key, + size_t nblocks, const void *in, void *out) +{ + int rc; + ccecb_ctx_decl(mode->size, ctx); + rc = mode->init(mode, ctx, key_len, key); + mode->ecb(ctx, nblocks, in, out); + ccecb_ctx_clear(mode->size, ctx); + return rc; +} + +/* CBC mode. */ + +/* Declare a cbc key named _name_. Pass the size field of a struct ccmode_cbc + for _size_. */ +#define cccbc_ctx_decl(_size_, _name_) cc_ctx_decl(cccbc_ctx, _size_, _name_) +#define cccbc_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +/* Declare a cbc iv tweak named _name_. Pass the blocksize field of a + struct ccmode_cbc for _size_. */ +#define cccbc_iv_decl(_size_, _name_) cc_ctx_decl(cccbc_iv, _size_, _name_) +#define cccbc_iv_clear(_size_, _name_) cc_clear(_size_, _name_) + +/* Actual symmetric algorithm implementation can provide you one of these. + + Alternatively you can create a ccmode_cbc instance from any ccmode_ecb + cipher. To do so, statically initialize a struct ccmode_cbc using the + CCMODE_FACTORY_CBC_DECRYPT or CCMODE_FACTORY_CBC_ENCRYPT macros. + Alternatively you can dynamically initialize a struct ccmode_cbc + ccmode_factory_cbc_decrypt() or ccmode_factory_cbc_encrypt(). */ + +CC_INLINE size_t cccbc_context_size(const struct ccmode_cbc *mode) +{ + return mode->size; +} + +CC_INLINE size_t cccbc_block_size(const struct ccmode_cbc *mode) +{ + return mode->block_size; +} + +CC_INLINE int cccbc_init(const struct ccmode_cbc *mode, cccbc_ctx *ctx, + size_t key_len, const void *key) +{ + return mode->init(mode, ctx, key_len, key); +} + +CC_INLINE int cccbc_set_iv(const struct ccmode_cbc *mode, cccbc_iv *iv_ctx, + const void *iv) +{ + if (iv) + cc_copy(mode->block_size, iv_ctx, iv); + else + cc_zero(mode->block_size, iv_ctx); + return 0; +} + +CC_INLINE int cccbc_update(const struct ccmode_cbc *mode, cccbc_ctx *ctx, + cccbc_iv *iv, size_t nblocks, + const void *in, void *out) +{ + return mode->cbc(ctx, iv, nblocks, in, out); +} + +int cccbc_one_shot(const struct ccmode_cbc *mode, + size_t key_len, const void *key, + const void *iv, size_t nblocks, + const void *in, void *out); + +/* CFB mode. */ + +/* Declare a cfb key named _name_. Pass the size field of a struct ccmode_cfb + for _size_. */ +#define cccfb_ctx_decl(_size_, _name_) cc_ctx_decl(cccfb_ctx, _size_, _name_) +#define cccfb_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +CC_INLINE size_t cccfb_context_size(const struct ccmode_cfb *mode) +{ + return mode->size; +} + +CC_INLINE size_t cccfb_block_size(const struct ccmode_cfb *mode) +{ + return mode->block_size; +} + +CC_INLINE int cccfb_init(const struct ccmode_cfb *mode, cccfb_ctx *ctx, + size_t key_len, const void *key, + const void *iv) +{ + return mode->init(mode, ctx, key_len, key, iv); +} + +CC_INLINE int cccfb_update(const struct ccmode_cfb *mode, cccfb_ctx *ctx, + size_t nbytes, const void *in, void *out) +{ + return mode->cfb(ctx, nbytes, in, out); +} + +CC_INLINE int cccfb_one_shot(const struct ccmode_cfb *mode, + size_t key_len, const void *key, const void *iv, + size_t nbytes, const void *in, void *out) +{ + int rc; + cccfb_ctx_decl(mode->size, ctx); + rc = mode->init(mode, ctx, key_len, key, iv); + mode->cfb(ctx, nbytes, in, out); + cccfb_ctx_clear(mode->size, ctx); + return rc; +} + +/* CFB8 mode. */ + +/* Declare a cfb8 key named _name_. Pass the size field of a struct ccmode_cfb8 + for _size_. */ +#define cccfb8_ctx_decl(_size_, _name_) cc_ctx_decl(cccfb8_ctx, _size_, _name_) +#define cccfb8_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +CC_INLINE size_t cccfb8_context_size(const struct ccmode_cfb8 *mode) +{ + return mode->size; +} + +CC_INLINE size_t cccfb8_block_size(const struct ccmode_cfb8 *mode) +{ + return mode->block_size; +} + +CC_INLINE int cccfb8_init(const struct ccmode_cfb8 *mode, cccfb8_ctx *ctx, + size_t key_len, const void *key, const void *iv) +{ + return mode->init(mode, ctx, key_len, key, iv); +} + +CC_INLINE int cccfb8_update(const struct ccmode_cfb8 *mode, cccfb8_ctx *ctx, + size_t nbytes, const void *in, void *out) +{ + return mode->cfb8(ctx, nbytes, in, out); +} + +CC_INLINE int cccfb8_one_shot(const struct ccmode_cfb8 *mode, + size_t key_len, const void *key, const void *iv, + size_t nbytes, const void *in, void *out) +{ + int rc; + cccfb8_ctx_decl(mode->size, ctx); + rc = mode->init(mode, ctx, key_len, key, iv); + mode->cfb8(ctx, nbytes, in, out); + cccfb8_ctx_clear(mode->size, ctx); + return rc; +} + +/* CTR mode. */ + +/* Declare a ctr key named _name_. Pass the size field of a struct ccmode_ctr + for _size_. */ +#define ccctr_ctx_decl(_size_, _name_) cc_ctx_decl(ccctr_ctx, _size_, _name_) +#define ccctr_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +/* This is Integer Counter Mode: The IV is the initial value of the counter + that is incremented by 1 for each new block. Use the mode flags to select + if the IV/Counter is stored in big or little endian. */ + +CC_INLINE size_t ccctr_context_size(const struct ccmode_ctr *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccctr_block_size(const struct ccmode_ctr *mode) +{ + return mode->block_size; +} + +CC_INLINE int ccctr_init(const struct ccmode_ctr *mode, ccctr_ctx *ctx, + size_t key_len, const void *key, const void *iv) +{ + return mode->init(mode, ctx, key_len, key, iv); +} + +CC_INLINE int ccctr_update(const struct ccmode_ctr *mode, ccctr_ctx *ctx, + size_t nbytes, const void *in, void *out) +{ + return mode->ctr(ctx, nbytes, in, out); +} + +CC_INLINE int ccctr_one_shot(const struct ccmode_ctr *mode, + size_t key_len, const void *key, const void *iv, + size_t nbytes, const void *in, void *out) +{ + int rc; + ccctr_ctx_decl(mode->size, ctx); + rc = mode->init(mode, ctx, key_len, key, iv); + if (rc) return rc; + rc = mode->ctr(ctx, nbytes, in, out); + ccctr_ctx_clear(mode->size, ctx); + return rc; +} + + +/* OFB mode. */ + +/* Declare a ofb key named _name_. Pass the size field of a struct ccmode_ofb + for _size_. */ +#define ccofb_ctx_decl(_size_, _name_) cc_ctx_decl(ccofb_ctx, _size_, _name_) +#define ccofb_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +CC_INLINE size_t ccofb_context_size(const struct ccmode_ofb *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccofb_block_size(const struct ccmode_ofb *mode) +{ + return mode->block_size; +} + +CC_INLINE int ccofb_init(const struct ccmode_ofb *mode, ccofb_ctx *ctx, + size_t key_len, const void *key, const void *iv) +{ + return mode->init(mode, ctx, key_len, key, iv); +} + +CC_INLINE int ccofb_update(const struct ccmode_ofb *mode, ccofb_ctx *ctx, + size_t nbytes, const void *in, void *out) +{ + return mode->ofb(ctx, nbytes, in, out); +} + +CC_INLINE int ccofb_one_shot(const struct ccmode_ofb *mode, + size_t key_len, const void *key, const void *iv, + size_t nbytes, const void *in, void *out) +{ + int rc; + ccofb_ctx_decl(mode->size, ctx); + rc = mode->init(mode, ctx, key_len, key, iv); + mode->ofb(ctx, nbytes, in, out); + ccofb_ctx_clear(mode->size, ctx); + return rc; +} + +/* XTS mode. */ + +/* Declare a xts key named _name_. Pass the size field of a struct ccmode_xts + for _size_. */ +#define ccxts_ctx_decl(_size_, _name_) cc_ctx_decl(ccxts_ctx, _size_, _name_) +#define ccxts_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +/* Declare a xts tweak named _name_. Pass the tweak_size field of a + struct ccmode_xts for _size_. */ +#define ccxts_tweak_decl(_size_, _name_) cc_ctx_decl(ccxts_tweak, _size_, _name_) +#define ccxts_tweak_clear(_size_, _name_) cc_clear(_size_, _name_) + +/* Actual symmetric algorithm implementation can provide you one of these. + + Alternatively you can create a ccmode_xts instance from any ccmode_ecb + cipher. To do so, statically initialize a struct ccmode_xts using the + CCMODE_FACTORY_XTS_DECRYPT or CCMODE_FACTORY_XTS_ENCRYPT macros. Alternatively + you can dynamically initialize a struct ccmode_xts + ccmode_factory_xts_decrypt() or ccmode_factory_xts_encrypt(). */ + +/* NOTE that xts mode does not do cts padding. It's really an xex mode. + If you need cts padding use the ccpad_xts_encrypt and ccpad_xts_decrypt + functions. Also note that xts only works for ecb modes with a block_size + of 16. */ + +CC_INLINE size_t ccxts_context_size(const struct ccmode_xts *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccxts_block_size(const struct ccmode_xts *mode) +{ + return mode->block_size; +} + +/*! + @function ccxts_init + @abstract Initialize an XTS context. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param key_nbytes Length of the key arguments in bytes + @param data_key Key for data encryption + @param tweak_key Key for tweak generation + + @result 0 iff successful. + + @discussion For security reasons, the two keys must be different. + */ +CC_INLINE int ccxts_init(const struct ccmode_xts *mode, ccxts_ctx *ctx, + size_t key_nbytes, const void *data_key, + const void *tweak_key) +{ + return mode->init(mode, ctx, key_nbytes, data_key, tweak_key); +} + +/*! + @function ccxts_set_tweak + @abstract Initialize the tweak for a sector. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param tweak Context for the tweak for this sector + @param iv Data used to generate the tweak + + @discussion The IV must be exactly one block in length. + */ +CC_INLINE int ccxts_set_tweak(const struct ccmode_xts *mode, ccxts_ctx *ctx, + ccxts_tweak *tweak, const void *iv) +{ + return mode->set_tweak(ctx, tweak, iv); +} + +/*! + @function ccxts_update + @abstract Encrypt or decrypt data. + + @param mode Descriptor for the mode + @param ctx Context for an instance + @param tweak Context for the tweak for this sector + @param nblocks Length of the data in blocks + @param in Input data + @param out Output buffer + + @result The updated internal buffer of the tweak context. May be ignored. + */ +CC_INLINE void *ccxts_update(const struct ccmode_xts *mode, ccxts_ctx *ctx, + ccxts_tweak *tweak, size_t nblocks, const void *in, void *out) +{ + return mode->xts(ctx, tweak, nblocks, in, out); +} + +/*! + @function ccxts_one_shot + @abstract Encrypt or decrypt data in XTS mode. + + @param mode Descriptor for the mode + @param key_nbytes Length of the key arguments in bytes + @param data_key Key for data encryption + @param tweak_key Key for tweak generation + @param iv Data used to generate the tweak + @param nblocks Length of the data in blocks + @param in Input data + @param out Output buffer + + @result 0 iff successful. + + @discussion For security reasons, the two keys must be different. + */ +int ccxts_one_shot(const struct ccmode_xts *mode, + size_t key_nbytes, const void *data_key, + const void *tweak_key, const void *iv, + size_t nblocks, const void *in, void *out); + +/* Authenticated cipher modes. */ + +/* GCM mode. */ + +/* Declare a gcm key named _name_. Pass the size field of a struct ccmode_gcm + for _size_. */ +#define ccgcm_ctx_decl(_size_, _name_) cc_ctx_decl(ccgcm_ctx, _size_, _name_) +#define ccgcm_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +#define CCGCM_IV_NBYTES 12 +#define CCGCM_BLOCK_NBYTES 16 + +/* (2^32 - 2) blocks */ +/* (2^36 - 32) bytes */ +/* (2^39 - 256) bits */ +/* Exceeding this figure breaks confidentiality and authenticity. */ +#define CCGCM_TEXT_MAX_NBYTES ((1ULL << 36) - 32ULL) + +CC_INLINE size_t ccgcm_context_size(const struct ccmode_gcm *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccgcm_block_size(const struct ccmode_gcm *mode) +{ + return mode->block_size; +} + +/*! + @function ccgcm_init + @abstract Initialize a GCM context. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param key_nbytes Length of the key in bytes + @param key Key for the underlying blockcipher (AES) + + @result 0 iff successful. + + @discussion The correct sequence of calls is: + + @code ccgcm_init(...) + ccgcm_set_iv(...) + ccgcm_aad(...) (may be called zero or more times) + ccgcm_update(...) (may be called zero or more times) + ccgcm_finalize(...) + + To reuse the context for additional encryptions, follow this sequence: + + @code ccgcm_reset(...) + ccgcm_set_iv(...) + ccgcm_aad(...) (may be called zero or more times) + ccgcm_update(...) (may be called zero or more times) + ccgcm_finalize(...) + + @warning The key-IV pair must be unique per encryption. The IV must be nonzero in length. + + @warning It is not permitted to call @p ccgcm_inc_iv after initializing the cipher via the @p ccgcm_init interface. Nonzero is returned in the event of an improper call sequence. + + @warning This function is not FIPS-compliant. Use @p ccgcm_init_with_iv instead. + */ +CC_INLINE int ccgcm_init(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t key_nbytes, const void *key) +{ + return mode->init(mode, ctx, key_nbytes, key); +} + +/*! + @function ccgcm_init_with_iv + @abstract Initialize a GCM context to manage IVs internally. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param key_nbytes Length of the key in bytes + @param key Key for the underlying blockcipher (AES) + @param iv IV for the first encryption + + @result 0 iff successful. + + @discussion The correct sequence of calls is: + + @code ccgcm_init_with_iv(...) + ccgcm_aad(...) (may be called zero or more times) + ccgcm_update(...) (may be called zero or more times) + ccgcm_finalize(...) + + To reuse the context for additional encryptions, follow this sequence: + + @code ccgcm_reset(...) + ccgcm_inc_iv(...) + ccgcm_aad(...) (may be called zero or more times) + ccgcm_update(...) (may be called zero or more times) + ccgcm_finalize(...) + + The IV must be exactly 12 bytes in length. + + Internally, the IV is treated as a four-byte salt followed by an eight-byte counter. This is to match the behavior of certain protocols (e.g. TLS). In the call to @p ccgcm_inc_iv, the counter component will be interpreted as a big-endian, unsigned value and incremented in place. + + @warning It is not permitted to call @p ccgcm_set_iv after initializing the cipher via the @p ccgcm_init_with_iv interface. Nonzero is returned in the event of an improper call sequence. + + @warning The security of GCM depends on the uniqueness of key-IV pairs. To avoid key-IV repetition, callers should not initialize multiple contexts with the same key material via the @p ccgcm_init_with_iv interface. + */ +int ccgcm_init_with_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t key_nbytes, const void *key, + const void *iv); + +/*! + @function ccgcm_set_iv + @abstract Set the IV for encryption. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param iv_nbytes Length of the IV in bytes + @param iv Initialization vector + + @result 0 iff successful. + + @discussion Set the initialization vector for encryption. + + @warning The key-IV pair must be unique per encryption. The IV must be nonzero in length. + + In stateful protocols, if each packet exposes a guaranteed-unique value, it is recommended to format this as a 12-byte value for use as the IV. + + In stateless protocols, it is recommended to choose a 16-byte value using a cryptographically-secure pseudorandom number generator (e.g. @p ccrng). + + @warning This function may not be used after initializing the cipher via @p ccgcm_init_with_iv. Nonzero is returned in the event of an improper call sequence. + + @warning This function is not FIPS-compliant. Use @p ccgcm_init_with_iv instead. + */ +CC_INLINE int ccgcm_set_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t iv_nbytes, const void *iv) +{ + return mode->set_iv(ctx, iv_nbytes, iv); +} + +/*! + @function ccgcm_set_iv_legacy + @abstract Set the IV for encryption. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param iv_nbytes Length of the IV in bytes + @param iv Initialization vector + + @result 0 iff successful. + + @discussion Identical to @p ccgcm_set_iv except that it allows zero-length IVs. + + @warning Zero-length IVs nullify the authenticity guarantees of GCM. + + @warning Do not use this function in new applications. + */ +int ccgcm_set_iv_legacy(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t iv_nbytes, const void *iv); + +/*! + @function ccgcm_inc_iv + @abstract Increment the IV for another encryption. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param iv Updated initialization vector + + @result 0 iff successful. + + @discussion Updates the IV internally for another encryption. + + Internally, the IV is treated as a four-byte salt followed by an eight-byte counter. This is to match the behavior of certain protocols (e.g. TLS). The counter component is interpreted as a big-endian, unsigned value and incremented in place. + + The updated IV is copied to @p iv. This is to support protocols that require part of the IV to be specified explicitly in each packet (e.g. TLS). + + @warning This function may be used only after initializing the cipher via @p ccgcm_init_with_iv. + */ +int ccgcm_inc_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, void *iv); + + +/*! + @function ccgcm_aad + @abstract Authenticate additional data. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param nbytes Length of the additional data in bytes + @param additional_data Additional data to authenticate + + @result 0 iff successful. + + @discussion This is typically used to authenticate data that cannot be encrypted (e.g. packet headers). + + This function may be called zero or more times. + */ +CC_INLINE int ccgcm_aad(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t nbytes, const void *additional_data) +{ + return mode->gmac(ctx, nbytes, additional_data); +} + +/*! + @function ccgcm_gmac + + @discussion See @p ccgcm_aad. + */ +CC_INLINE int ccgcm_gmac(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t nbytes, const void *in) +{ + return mode->gmac(ctx, nbytes, in); +} + +/*! + @function ccgcm_update + @abstract Encrypt or decrypt data. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param nbytes Length of the data in bytes + @param in Input plaintext or ciphertext + @param out Output ciphertext or plaintext + + @result 0 iff successful. + + @discussion In-place processing is supported. + + This function may be called zero or more times. + */ +CC_INLINE int ccgcm_update(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t nbytes, const void *in, void *out) +{ + return mode->gcm(ctx, nbytes, in, out); +} + +/*! + @function ccgcm_finalize + @abstract Finish processing and authenticate. + + @param mode Descriptor for the mode + @param ctx Context for this instance + @param tag_nbytes Length of the tag in bytes + @param tag Authentication tag + + @result 0 iff successful. + + @discussion Finish processing a packet and generate the authentication tag. + + On encryption, @p tag is purely an output parameter. The generated tag is written to @p tag. + + On decryption, @p tag is both an input and an output parameter. Well-behaved callers should provide the authentication tag generated during encryption. The function will return nonzero if the input tag does not match the generated tag. The generated tag will be written into the @p tag buffer whether authentication succeeds or fails. + + @warning The generated tag is written to @p tag to support legacy applications that perform authentication manually. Do not follow this usage pattern in new applications. Rely on the function's error code to verify authenticity. + */ +CC_INLINE int ccgcm_finalize(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, + size_t tag_nbytes, void *tag) +{ + return mode->finalize(ctx, tag_nbytes, tag); +} + +/*! + @function ccgcm_reset + @abstract Reset the context for another encryption. + + @param mode Descriptor for the mode + @param ctx Context for this instance + + @result 0 iff successful. + + @discussion Refer to @p ccgcm_init for correct usage. + */ +CC_INLINE int ccgcm_reset(const struct ccmode_gcm *mode, ccgcm_ctx *ctx) +{ + return mode->reset(ctx); +} + + +/*! + @function ccgcm_one_shot + @abstract Encrypt or decrypt with GCM. + + @param mode Descriptor for the mode + @param key_nbytes Length of the key in bytes + @param key Key for the underlying blockcipher (AES) + @param iv_nbytes Length of the IV in bytes + @param iv Initialization vector + @param adata_nbytes Length of the additional data in bytes + @param adata Additional data to authenticate + @param nbytes Length of the data in bytes + @param in Input plaintext or ciphertext + @param out Output ciphertext or plaintext + @param tag_nbytes Length of the tag in bytes + @param tag Authentication tag + + @result 0 iff successful. + + @discussion Perform GCM encryption or decryption. + + @warning The key-IV pair must be unique per encryption. The IV must be nonzero in length. + + In stateful protocols, if each packet exposes a guaranteed-unique value, it is recommended to format this as a 12-byte value for use as the IV. + + In stateless protocols, it is recommended to choose a 16-byte value using a cryptographically-secure pseudorandom number generator (e.g. @p ccrng). + + In-place processing is supported. + + On encryption, @p tag is purely an output parameter. The generated tag is written to @p tag. + + On decryption, @p tag is primarily an input parameter. The caller should provide the authentication tag generated during encryption. The function will return nonzero if the input tag does not match the generated tag. + + @warning To support legacy applications, @p tag is also an output parameter during decryption. The generated tag is written to @p tag. Legacy callers may choose to compare this to the tag generated during encryption. Do not follow this usage pattern in new applications. + */ +int ccgcm_one_shot(const struct ccmode_gcm *mode, + size_t key_nbytes, const void *key, + size_t iv_nbytes, const void *iv, + size_t adata_nbytes, const void *adata, + size_t nbytes, const void *in, void *out, + size_t tag_nbytes, void *tag); + + +/*! + @function ccgcm_one_shot_legacy + @abstract Encrypt or decrypt with GCM. + + @param mode Descriptor for the mode + @param key_nbytes Length of the key in bytes + @param key Key for the underlying blockcipher (AES) + @param iv_nbytes Length of the IV in bytes + @param iv Initialization vector + @param adata_nbytes Length of the additional data in bytes + @param adata Additional data to authenticate + @param nbytes Length of the data in bytes + @param in Input plaintext or ciphertext + @param out Output ciphertext or plaintext + @param tag_nbytes Length of the tag in bytes + @param tag Authentication tag + + @result 0 iff successful. + + @discussion Identical to @p ccgcm_one_shot except that it allows zero-length IVs. + + @warning Zero-length IVs nullify the authenticity guarantees of GCM. + + @warning Do not use this function in new applications. + */ +int ccgcm_one_shot_legacy(const struct ccmode_gcm *mode, + size_t key_nbytes, const void *key, + size_t iv_nbytes, const void *iv, + size_t adata_nbytes, const void *adata, + size_t nbytes, const void *in, void *out, + size_t tag_nbytes, void *tag); + + +/* CCM */ + +#define ccccm_ctx_decl(_size_, _name_) cc_ctx_decl(ccccm_ctx, _size_, _name_) +#define ccccm_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +/* Declare a ccm nonce named _name_. Pass the mode->nonce_ctx_size for _size_. */ +#define ccccm_nonce_decl(_size_, _name_) cc_ctx_decl(ccccm_nonce, _size_, _name_) +#define ccccm_nonce_clear(_size_, _name_) cc_clear(_size_, _name_) + + +CC_INLINE size_t ccccm_context_size(const struct ccmode_ccm *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccccm_block_size(const struct ccmode_ccm *mode) +{ + return mode->block_size; +} + +CC_INLINE int ccccm_init(const struct ccmode_ccm *mode, ccccm_ctx *ctx, + size_t key_len, const void *key) +{ + return mode->init(mode, ctx, key_len, key); +} + +CC_INLINE int ccccm_set_iv(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, + size_t nonce_len, const void *nonce, + size_t mac_size, size_t auth_len, size_t data_len) +{ + return mode->set_iv(ctx, nonce_ctx, nonce_len, nonce, mac_size, auth_len, data_len); +} + +CC_INLINE int ccccm_cbcmac(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, + size_t nbytes, const void *in) +{ + return mode->cbcmac(ctx, nonce_ctx, nbytes, in); +} + +CC_INLINE int ccccm_update(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, + size_t nbytes, const void *in, void *out) +{ + return mode->ccm(ctx, nonce_ctx, nbytes, in, out); +} + +CC_INLINE int ccccm_finalize(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, + void *mac) +{ + return mode->finalize(ctx, nonce_ctx, mac); +} + +CC_INLINE int ccccm_reset(const struct ccmode_ccm *mode, ccccm_ctx *ctx, ccccm_nonce *nonce_ctx) +{ + return mode->reset(ctx, nonce_ctx); +} + + +CC_INLINE int ccccm_one_shot(const struct ccmode_ccm *mode, + size_t key_len, const void *key, + size_t nonce_len, const void *nonce, + size_t nbytes, const void *in, void *out, + size_t adata_len, const void* adata, + size_t mac_size, void *mac) +{ + int rc=0; + ccccm_ctx_decl(mode->size, ctx); + ccccm_nonce_decl(mode->nonce_size, nonce_ctx); + rc = mode->init(mode, ctx, key_len, key); + if(rc==0) rc=mode->set_iv(ctx, nonce_ctx, nonce_len, nonce, mac_size, adata_len, nbytes); + if(rc==0) rc=mode->cbcmac(ctx, nonce_ctx, adata_len, adata); + if(rc==0) rc=mode->ccm(ctx, nonce_ctx, nbytes, in, out); + if(rc==0) rc=mode->finalize(ctx, nonce_ctx, mac); + ccccm_ctx_clear(mode->size, ctx); + ccccm_nonce_clear(mode->nonce_size, nonce_ctx); + + return rc; +} + + +/* OMAC mode. */ + + +/* Declare a omac key named _name_. Pass the size field of a struct ccmode_omac + for _size_. */ +#define ccomac_ctx_decl(_size_, _name_) cc_ctx_decl(ccomac_ctx, _size_, _name_) +#define ccomac_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +CC_INLINE size_t ccomac_context_size(const struct ccmode_omac *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccomac_block_size(const struct ccmode_omac *mode) +{ + return mode->block_size; +} + +CC_INLINE int ccomac_init(const struct ccmode_omac *mode, ccomac_ctx *ctx, + size_t tweak_len, size_t key_len, const void *key) +{ + return mode->init(mode, ctx, tweak_len, key_len, key); +} + +CC_INLINE int ccomac_update(const struct ccmode_omac *mode, ccomac_ctx *ctx, + size_t nblocks, const void *tweak, const void *in, void *out) +{ + return mode->omac(ctx, nblocks, tweak, in, out); +} + +CC_INLINE int ccomac_one_shot(const struct ccmode_omac *mode, + size_t tweak_len, size_t key_len, const void *key, + const void *tweak, size_t nblocks, const void *in, void *out) +{ + int rc; + ccomac_ctx_decl(mode->size, ctx); + rc = mode->init(mode, ctx, tweak_len, key_len, key); + if (rc == 0) rc = mode->omac(ctx, nblocks, tweak, in, out); + ccomac_ctx_clear(mode->size, ctx); + return rc; +} + + +#endif /* _CORECRYPTO_CCMODE_H_ */ diff --git a/corecrypto/ccmode_factory.h b/corecrypto/ccmode_factory.h new file mode 100644 index 0000000..a868cee --- /dev/null +++ b/corecrypto/ccmode_factory.h @@ -0,0 +1,646 @@ +/* + * Copyright (c) 2011,2012,2013,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMODE_FACTORY_H_ +#define _CORECRYPTO_CCMODE_FACTORY_H_ + +#include /* TODO: Remove dependency on this header. */ +#include + +/* Function and macros defined in this file are only to be used + within corecrypto files. + */ + +/* For CBC, direction of underlying ecb is the same as the cbc direction */ +#define CCMODE_CBC_FACTORY(_cipher_, _dir_) \ +static struct ccmode_cbc cbc_##_cipher_##_##_dir_; \ + \ +const struct ccmode_cbc *cc##_cipher_##_cbc_##_dir_##_mode(void) \ +{ \ + const struct ccmode_ecb *ecb=cc##_cipher_##_ecb_##_dir_##_mode(); \ + ccmode_factory_cbc_##_dir_(&cbc_##_cipher_##_##_dir_, ecb); \ + return &cbc_##_cipher_##_##_dir_; \ +} + +/* For CTR, only one direction, underlying ecb is always encrypt */ +#define CCMODE_CTR_FACTORY(_cipher_) \ +static struct ccmode_ctr ctr_##_cipher_; \ + \ +const struct ccmode_ctr *cc##_cipher_##_ctr_crypt_mode(void) \ +{ \ + const struct ccmode_ecb *ecb=cc##_cipher_##_ecb_encrypt_mode(); \ + ccmode_factory_ctr_crypt(&ctr_##_cipher_, ecb); \ + return &ctr_##_cipher_; \ +} + +/* OFB, same as CTR */ +#define CCMODE_OFB_FACTORY(_cipher_) \ +static struct ccmode_ofb ofb_##_cipher_; \ + \ +const struct ccmode_ofb *cc##_cipher_##_ofb_crypt_mode(void) \ +{ \ + const struct ccmode_ecb *ecb=cc##_cipher_##_ecb_encrypt_mode(); \ + ccmode_factory_ofb_crypt(&ofb_##_cipher_, ecb); \ + return &ofb_##_cipher_; \ +} + + +/* For CFB, the underlying ecb operation is encrypt for both directions */ +#define CCMODE_CFB_FACTORY(_cipher_, _mode_, _dir_) \ +static struct ccmode_##_mode_ _mode_##_##_cipher_##_##_dir_; \ + \ +const struct ccmode_##_mode_ *cc##_cipher_##_##_mode_##_##_dir_##_mode(void) \ +{ \ + const struct ccmode_ecb *ecb=cc##_cipher_##_ecb_encrypt_mode(); \ + ccmode_factory_##_mode_##_##_dir_(&_mode_##_##_cipher_##_##_dir_, ecb); \ + return &_mode_##_##_cipher_##_##_dir_; \ +} + +/* For GCM, same as CFB */ +#define CCMODE_GCM_FACTORY(_cipher_, _dir_) CCMODE_CFB_FACTORY(_cipher_, gcm, _dir_) + +/* For CCM, same as CFB */ +#define CCMODE_CCM_FACTORY(_cipher_, _dir_) CCMODE_CFB_FACTORY(_cipher_, ccm, _dir_) + + +/* Fot XTS, you always need an ecb encrypt */ +#define CCMODE_XTS_FACTORY(_cipher_ , _dir_) \ +static struct ccmode_xts xts##_cipher_##_##_dir_; \ + \ +const struct ccmode_xts *cc##_cipher_##_xts_##_dir_##_mode(void) \ +{ \ + const struct ccmode_ecb *ecb=cc##_cipher_##_ecb_##_dir_##_mode(); \ + const struct ccmode_ecb *ecb_enc=cc##_cipher_##_ecb_encrypt_mode(); \ + \ + ccmode_factory_xts_##_dir_(&xts##_cipher_##_##_dir_, ecb, ecb_enc); \ + return &xts##_cipher_##_##_dir_; \ +} + +#if 0 + +/* example of how to make the selection function thread safe */ + +struct ccmode_cbc cc3des_cbc_mode_encrypt; +dispatch_once_t cc3des_mode_encrypt_init_once; + +void cc3des_mode_encrypt_init(void *ctx) { + struct ccmode_ecb *ecb = cc3des_ecb_encrypt_mode(); + ccmode_factory_cbc_encrypt(&cc3des_mode_encrypt, ecb); +} + +const struct ccmode_cbc *cc3des_cbc_encrypt_mode(void) { + dispatch_once_f(&cc3des_mode_encrypt_init_once, NULL, cc3des_mode_encrypt_init); + return &cc3des_mode_encrypt; +} + +struct ccmode_cbc cc3des_cbc_mode_encrypt = { + .n = CC3DES_LTC_ECB_ENCRYPT_N, + .init = ccmode_cbc_init, + .cbc = ccmode_cbc_encrypt, + .custom = &cc3des_ltc_ecb_encrypt +}; + +const struct ccmode_cbc *cc3des_cbc_encrypt_mode(void) { + return &cc3des_mode_encrypt; +} + +#endif + + + +int ccmode_cbc_init(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, + size_t rawkey_len, const void *rawkey); +int ccmode_cbc_decrypt(const cccbc_ctx *ctx, cccbc_iv *iv, size_t nblocks, + const void *in, void *out); +int ccmode_cbc_encrypt(const cccbc_ctx *ctx, cccbc_iv *iv, size_t nblocks, + const void *in, void *out); + +struct _ccmode_cbc_key { + const struct ccmode_ecb *ecb; + cc_unit u[]; +}; + +/* Use this to statically initialize a ccmode_cbc object for decryption. */ +#define CCMODE_FACTORY_CBC_DECRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_cbc_key)) + ccn_sizeof_size((ECB)->block_size) + ccn_sizeof_size((ECB)->size), \ +.block_size = (ECB)->block_size, \ +.init = ccmode_cbc_init, \ +.cbc = ccmode_cbc_decrypt, \ +.custom = (ECB) \ +} + +/* Use this to statically initialize a ccmode_cbc object for encryption. */ +#define CCMODE_FACTORY_CBC_ENCRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_cbc_key)) + ccn_sizeof_size((ECB)->block_size) + ccn_sizeof_size((ECB)->size), \ +.block_size = (ECB)->block_size, \ +.init = ccmode_cbc_init, \ +.cbc = ccmode_cbc_encrypt, \ +.custom = (ECB) \ +} + +/* Use these function to runtime initialize a ccmode_cbc decrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb decrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_cbc_decrypt(struct ccmode_cbc *cbc, + const struct ccmode_ecb *ecb); + +/* Use these function to runtime initialize a ccmode_cbc encrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_cbc_encrypt(struct ccmode_cbc *cbc, + const struct ccmode_ecb *ecb); + + +int ccmode_cfb_init(const struct ccmode_cfb *cfb, cccfb_ctx *ctx, + size_t rawkey_len, const void *rawkey, + const void *iv); +int ccmode_cfb_decrypt(cccfb_ctx *ctx, size_t nbytes, + const void *in, void *out); +int ccmode_cfb_encrypt(cccfb_ctx *ctx, size_t nbytes, + const void *in, void *out); +struct _ccmode_cfb_key { + const struct ccmode_ecb *ecb; + size_t pad_len; + cc_unit u[]; +}; + +/* Use this to statically initialize a ccmode_cfb object for decryption. */ +#define CCMODE_FACTORY_CFB_DECRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_cfb_key)) + 2 * ccn_sizeof_size((ECB)->block_size) + ccn_sizeof_size((ECB)->size), \ +.block_size = 1, \ +.init = ccmode_cfb_init, \ +.cfb = ccmode_cfb_decrypt, \ +.custom = (ECB) \ +} + +/* Use this to statically initialize a ccmode_cfb object for encryption. */ +#define CCMODE_FACTORY_CFB_ENCRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_cfb_key)) + 2 * ccn_sizeof_size((ECB)->block_size) + ccn_sizeof_size((ECB)->size), \ +.block_size = 1, \ +.init = ccmode_cfb_init, \ +.cfb = ccmode_cfb_encrypt, \ +.custom = (ECB) \ +} + +/* Use these function to runtime initialize a ccmode_cfb decrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_cfb_decrypt(struct ccmode_cfb *cfb, + const struct ccmode_ecb *ecb); + +/* Use these function to runtime initialize a ccmode_cfb encrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_cfb_encrypt(struct ccmode_cfb *cfb, + const struct ccmode_ecb *ecb); + +int ccmode_cfb8_init(const struct ccmode_cfb8 *cfb8, cccfb8_ctx *ctx, + size_t rawkey_len, const void *rawkey, const void *iv); +int ccmode_cfb8_decrypt(cccfb8_ctx *ctx, size_t nbytes, + const void *in, void *out); +int ccmode_cfb8_encrypt(cccfb8_ctx *ctx, size_t nbytes, + const void *in, void *out); + +struct _ccmode_cfb8_key { + const struct ccmode_ecb *ecb; + cc_unit u[]; +}; + +/* Use this to statically initialize a ccmode_cfb8 object for decryption. */ +#define CCMODE_FACTORY_CFB8_DECRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_cfb8_key)) + 2 * ccn_sizeof_size((ECB)->block_size) + ccn_sizeof_size((ECB)->size), \ +.block_size = 1, \ +.init = ccmode_cfb8_init, \ +.cfb8 = ccmode_cfb8_decrypt, \ +.custom = (ECB) \ +} + +/* Use this to statically initialize a ccmode_cfb8 object for encryption. */ +#define CCMODE_FACTORY_CFB8_ENCRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_cfb8_key)) + 2 * ccn_sizeof_size((ECB)->block_size) + ccn_sizeof_size((ECB)->size), \ +.block_size = 1, \ +.init = ccmode_cfb8_init, \ +.cfb8 = ccmode_cfb8_encrypt, \ +.custom = (ECB) \ +} + +/* Use these function to runtime initialize a ccmode_cfb8 decrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb decrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_cfb8_decrypt(struct ccmode_cfb8 *cfb8, + const struct ccmode_ecb *ecb); + +/* Use these function to runtime initialize a ccmode_cfb8 encrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_cfb8_encrypt(struct ccmode_cfb8 *cfb8, + const struct ccmode_ecb *ecb); + +int ccmode_ctr_init(const struct ccmode_ctr *ctr, ccctr_ctx *ctx, + size_t rawkey_len, const void *rawkey, const void *iv); +int ccmode_ctr_setctr(const struct ccmode_ctr *mode, ccctr_ctx *ctx, const void *ctr); +int ccmode_ctr_crypt(ccctr_ctx *ctx, size_t nbytes, + const void *in, void *out); + +struct _ccmode_ctr_key { + const struct ccmode_ecb *ecb; + size_t pad_offset; + cc_unit u[]; +}; + +/* Use this to statically initialize a ccmode_ctr object for decryption. */ +#define CCMODE_FACTORY_CTR_CRYPT(ECB_ENCRYPT) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_ctr_key)) + 2 * ccn_sizeof_size((ECB_ENCRYPT)->block_size) + ccn_sizeof_size((ECB_ENCRYPT)->size), \ +.block_size = 1, \ +.ecb_block_size = (ECB_ENCRYPT)->block_size, \ +.init = ccmode_ctr_init, \ +.setctr = ccmode_ctr_setctr, \ +.ctr = ccmode_ctr_crypt, \ +.custom = (ECB_ENCRYPT) \ +} + +/* Use these function to runtime initialize a ccmode_ctr decrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_ctr_crypt(struct ccmode_ctr *ctr, + const struct ccmode_ecb *ecb); + + +/* Create a gcm key from a gcm mode object. + key must point to at least sizeof(CCMODE_GCM_KEY(ecb)) bytes of free + storage. */ +int ccmode_gcm_init(const struct ccmode_gcm *gcm, ccgcm_ctx *ctx, + size_t rawkey_len, const void *rawkey); +int ccmode_gcm_set_iv(ccgcm_ctx *ctx, size_t iv_nbytes, const void *iv); +int ccmode_gcm_aad(ccgcm_ctx *ctx, size_t nbytes, const void *in); +int ccmode_gcm_decrypt(ccgcm_ctx *ctx, size_t nbytes, const void *in, + void *out); +int ccmode_gcm_encrypt(ccgcm_ctx *ctx, size_t nbytes, const void *in, + void *out); + +/*! + @function ccmode_gcm_finalize() finalizes AES-GCM call sequence + @param key encryption or decryption key + @param tag_nbytes length of tag in bytes + @param tag authentication tag + @result 0=success or non zero= error + @discussion For decryption, the tag parameter must be the expected-tag. A secure compare is performed between the provided expected-tag and the computed-tag. If they are the same, 0 is returned. Otherwise, non zero is returned. For encryption, tag is output and provides the authentication tag. + + */ +int ccmode_gcm_finalize(ccgcm_ctx *key, size_t tag_nbytes, void *tag); +int ccmode_gcm_reset(ccgcm_ctx *key); + +#define CCGCM_FLAGS_INIT_WITH_IV 1 + +// Here is what the structure looks like in memory +// [ temp space | length | *ecb | *ecb_key | table | ecb_key ] +// size of table depends on the implementation (VNG vs factory) +// currently, VNG and factory share the same "header" described here +// VNG may add additional data after the header +struct _ccmode_gcm_key { + // 5 blocks of temp space. + unsigned char H[16]; /* multiplier */ + unsigned char X[16]; /* accumulator */ + unsigned char Y[16]; /* counter */ + unsigned char Y_0[16]; /* initial counter */ + unsigned char buf[16]; /* buffer for stuff */ + + // State and length + uint16_t state; /* state the GCM code is in */ + uint16_t flags; /* flags (persistent across reset) */ + uint32_t buf_nbytes; /* length of data in buf */ + + uint64_t aad_nbytes; /* 64-bit counter used for IV and AAD */ + uint64_t text_nbytes; /* 64-bit counter for the plaintext PT */ + + // ECB + const struct ccmode_ecb *ecb; // ecb mode + // Pointer to the ECB key in the buffer + void *ecb_key; // address of the ecb_key in u, set in init function + int encdec; //is it an encrypt or decrypt object + + // Buffer with ECB key and H table if applicable + CC_ALIGNED(16) unsigned char u[]; // ecb key + tables +}; + +#define GCM_ECB_KEY_SIZE(ECB_ENCRYPT) \ + ((5 * ccn_sizeof_size((ECB_ENCRYPT)->block_size)) \ + + ccn_sizeof_size((ECB_ENCRYPT)->size)) + +/* Use these function to runtime initialize a ccmode_gcm decrypt object (for + example if it's part of a larger structure). For GCM you always pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_gcm_decrypt(struct ccmode_gcm *gcm, + const struct ccmode_ecb *ecb_encrypt); + +/* Use these function to runtime initialize a ccmode_gcm encrypt object (for + example if it's part of a larger structure). For GCM you always pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_gcm_encrypt(struct ccmode_gcm *gcm, + const struct ccmode_ecb *ecb_encrypt); + + +/* CCM (only NIST approved with AES) */ +int ccmode_ccm_init(const struct ccmode_ccm *ccm, ccccm_ctx *ctx, + size_t rawkey_len, const void *rawkey); +int ccmode_ccm_set_iv(ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nonce_len, const void *nonce, + size_t mac_size, size_t auth_len, size_t data_len); +/* internal function */ +void ccmode_ccm_macdata(ccccm_ctx *key, ccccm_nonce *nonce_ctx, unsigned new_block, size_t nbytes, const void *in); +/* api function - disallows only mac'd data after data to encrypt was sent */ +int ccmode_ccm_cbcmac(ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in); +/* internal function */ +void ccmode_ccm_crypt(ccccm_ctx *key, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in, void *out); +int ccmode_ccm_decrypt(ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in, + void *out); +int ccmode_ccm_encrypt(ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in, + void *out); +int ccmode_ccm_finalize(ccccm_ctx *key, ccccm_nonce *nonce_ctx, void *mac); +int ccmode_ccm_reset(ccccm_ctx *key, ccccm_nonce *nonce_ctx); + +struct _ccmode_ccm_key { + const struct ccmode_ecb *ecb; + cc_unit u[]; +}; + +struct _ccmode_ccm_nonce { + unsigned char A_i[16]; /* crypto block iv */ + unsigned char B_i[16]; /* mac block iv */ + unsigned char MAC[16]; /* crypted mac */ + unsigned char buf[16]; /* crypt buffer */ + + uint32_t mode; /* mode: IV -> AD -> DATA */ + uint32_t buflen; /* length of data in buf */ + uint32_t b_i_len; /* length of cbcmac data in B_i */ + + size_t nonce_size; + size_t mac_size; +}; + +/* Use this to statically initialize a ccmode_ccm object for decryption. */ +#define CCMODE_FACTORY_CCM_DECRYPT(ECB_ENCRYPT) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_ccm_key)) + ccn_sizeof_size((ECB_ENCRYPT)->block_size) + ccn_sizeof_size((ECB_ENCRYPT)->size), \ +.nonce_size = ccn_sizeof_size(sizeof(struct _ccmode_ccm_nonce)), \ +.block_size = 1, \ +.init = ccmode_ccm_init, \ +.set_iv = ccmode_ccm_set_iv, \ +.cbcmac = ccmode_ccm_cbcmac, \ +.ccm = ccmode_ccm_decrypt, \ +.finalize = ccmode_ccm_finalize, \ +.reset = ccmode_ccm_reset, \ +.custom = (ECB_ENCRYPT) \ +} + +/* Use this to statically initialize a ccmode_ccm object for encryption. */ +#define CCMODE_FACTORY_CCM_ENCRYPT(ECB_ENCRYPT) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_ccm_key)) + ccn_sizeof_size((ECB_ENCRYPT)->block_size) + ccn_sizeof_size((ECB_ENCRYPT)->size), \ +.nonce_size = ccn_sizeof_size(sizeof(struct _ccmode_ccm_nonce)), \ +.block_size = 1, \ +.init = ccmode_ccm_init, \ +.set_iv = ccmode_ccm_set_iv, \ +.cbcmac = ccmode_ccm_cbcmac, \ +.ccm = ccmode_ccm_encrypt, \ +.finalize = ccmode_ccm_finalize, \ +.reset = ccmode_ccm_reset, \ +.custom = (ECB_ENCRYPT) \ +} + +/* Use these function to runtime initialize a ccmode_ccm decrypt object (for + example if it's part of a larger structure). For CCM you always pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ + +void ccmode_factory_ccm_decrypt(struct ccmode_ccm *ccm, + const struct ccmode_ecb *ecb_encrypt); + +/* Use these function to runtime initialize a ccmode_ccm encrypt object (for + example if it's part of a larger structure). For CCM you always pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_ccm_encrypt(struct ccmode_ccm *ccm, + const struct ccmode_ecb *ecb_encrypt); + + +int ccmode_ofb_init(const struct ccmode_ofb *ofb, ccofb_ctx *ctx, + size_t rawkey_len, const void *rawkey, + const void *iv); +int ccmode_ofb_crypt(ccofb_ctx *ctx, size_t nbytes, + const void *in, void *out); + +struct _ccmode_ofb_key { + const struct ccmode_ecb *ecb; + size_t pad_len; + cc_unit u[]; +}; + +/* Use this to statically initialize a ccmode_ofb object. */ +#define CCMODE_FACTORY_OFB_CRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_ofb_key)) + ccn_sizeof_size((ECB)->block_size) + ccn_sizeof_size((ECB)->size), \ +.block_size = 1, \ +.init = ccmode_ofb_init, \ +.ofb = ccmode_ofb_crypt, \ +.custom = (ECB) \ +} + +/* Use these function to runtime initialize a ccmode_ofb encrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_ofb_crypt(struct ccmode_ofb *ofb, + const struct ccmode_ecb *ecb); + +int ccmode_omac_decrypt(ccomac_ctx *ctx, size_t nblocks, + const void *tweak, const void *in, void *out); +int ccmode_omac_encrypt(ccomac_ctx *ctx, size_t nblocks, + const void *tweak, const void *in, void *out); + +/* Create a omac key from a omac mode object. The tweak_len here + determines how long the tweak is in bytes, for each subsequent call to + ccmode_omac->omac(). + key must point to at least sizeof(CCMODE_OMAC_KEY(ecb)) bytes of free + storage. */ +int ccmode_omac_init(const struct ccmode_omac *omac, ccomac_ctx *ctx, + size_t tweak_len, size_t rawkey_len, + const void *rawkey); + +struct _ccmode_omac_key { + const struct ccmode_ecb *ecb; + size_t tweak_len; + cc_unit u[]; +}; + +/* Use this to statically initialize a ccmode_omac object for decryption. */ +#define CCMODE_FACTORY_OMAC_DECRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_omac_key)) + 2 * ccn_sizeof_size((ECB)->size), \ +.block_size = (ECB)->block_size, \ +.init = ccmode_omac_init, \ +.omac = ccmode_omac_decrypt, \ +.custom = (ECB) \ +} + +/* Use this to statically initialize a ccmode_omac object for encryption. */ +#define CCMODE_FACTORY_OMAC_ENCRYPT(ECB) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_omac_key)) + 2 * ccn_sizeof_size((ECB)->size), \ +.block_size = (ECB)->block_size, \ +.init = ccmode_omac_init, \ +.omac = ccmode_omac_encrypt, \ +.custom = (ECB) \ +} + +/* Use these function to runtime initialize a ccmode_omac decrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb decrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_omac_decrypt(struct ccmode_omac *omac, + const struct ccmode_ecb *ecb); + +/* Use these function to runtime initialize a ccmode_omac encrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_omac_encrypt(struct ccmode_omac *omac, + const struct ccmode_ecb *ecb); + + +/* Function prototypes used by the macros below, do not call directly. */ +int ccmode_xts_init(const struct ccmode_xts *xts, ccxts_ctx *ctx, + size_t key_nbytes, const void *data_key, + const void *tweak_key); +void ccmode_xts_key_sched(const struct ccmode_xts *xts, ccxts_ctx *ctx, + size_t key_nbytes, const void *data_key, + const void *tweak_key); +void *ccmode_xts_crypt(const ccxts_ctx *ctx, ccxts_tweak *tweak, + size_t nblocks, const void *in, void *out); +int ccmode_xts_set_tweak(const ccxts_ctx *ctx, ccxts_tweak *tweak, + const void *iv); + + +struct _ccmode_xts_key { + const struct ccmode_ecb *ecb; + const struct ccmode_ecb *ecb_encrypt; + cc_unit u[]; +}; + +struct _ccmode_xts_tweak { + // FIPS requires that for XTS that no more that 2^20 AES blocks may be processed for any given + // Key, Tweak Key, and tweak combination + // the bytes_processed field in the context will accumuate the number of blocks processed and + // will fail the encrypt/decrypt if the size is violated. This counter will be reset to 0 + // when set_tweak is called. + size_t blocks_processed; + cc_unit u[]; +}; + +/* Use this to statically initialize a ccmode_xts object for decryption. */ +#define CCMODE_FACTORY_XTS_DECRYPT(ECB, ECB_ENCRYPT) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_xts_key)) + 2 * ccn_sizeof_size((ECB)->size), \ +.tweak_size = ccn_sizeof_size(sizeof(struct _ccmode_xts_tweak)) + ccn_sizeof_size(ecb->block_size), \ +.block_size = ecb->block_size, \ +.init = ccmode_xts_init, \ +.key_sched = ccmode_xts_key_sched, \ +.set_tweak = ccmode_xts_set_tweak, \ +.xts = ccmode_xts_crypt, \ +.custom = (ECB), \ +.custom1 = (ECB_ENCRYPT) \ +} + +/* Use this to statically initialize a ccmode_xts object for encryption. */ +#define CCMODE_FACTORY_XTS_ENCRYPT(ECB, ECB_ENCRYPT) { \ +.size = ccn_sizeof_size(sizeof(struct _ccmode_xts_key)) + 2 * ccn_sizeof_size((ECB)->size), \ +.tweak_size = ccn_sizeof_size(sizeof(struct _ccmode_xts_tweak)) + ccn_sizeof_size(ecb->block_size), \ +.block_size = ecb->block_size, \ +.init = ccmode_xts_init, \ +.key_sched = ccmode_xts_key_sched, \ +.set_tweak = ccmode_xts_set_tweak, \ +.xts = ccmode_xts_crypt, \ +.custom = (ECB), \ +.custom1 = (ECB_ENCRYPT) \ +} + +/* Use these function to runtime initialize a ccmode_xts decrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb decrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_xts_decrypt(struct ccmode_xts *xts, + const struct ccmode_ecb *ecb, + const struct ccmode_ecb *ecb_encrypt); + +/* Use these function to runtime initialize a ccmode_xts encrypt object (for + example if it's part of a larger structure). Normally you would pass a + ecb encrypt mode implementation of some underlying algorithm as the ecb + parameter. */ +void ccmode_factory_xts_encrypt(struct ccmode_xts *xts, + const struct ccmode_ecb *ecb, + const struct ccmode_ecb *ecb_encrypt); + +#endif /* _CORECRYPTO_CCMODE_FACTORY_H_ */ diff --git a/corecrypto/ccmode_impl.h b/corecrypto/ccmode_impl.h new file mode 100644 index 0000000..b1aebf7 --- /dev/null +++ b/corecrypto/ccmode_impl.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2012,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMODE_IMPL_H_ +#define _CORECRYPTO_CCMODE_IMPL_H_ + +#include + +/* ECB mode. */ +cc_aligned_struct(16) ccecb_ctx; + + +/* Actual symmetric algorithm implementation should provide you one of these. */ +struct ccmode_ecb { + size_t size; /* first argument to ccecb_ctx_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_ecb *ecb, ccecb_ctx *ctx, + size_t key_nbytes, const void *key); + int (*ecb)(const ccecb_ctx *ctx, size_t nblocks, const void *in, + void *out); +}; + +/*! + * @brief corecrypto symmetrical encryption and decryption modes + * + * corecrypto supports 6 stateless en(de)cryption modes and 2 stateful authenticated en(de)cryption modes + * stateless modes CBC, CFB, CFB8, CTR, OFB, XTS: They provide 3 interface functions that do not return errors codes + * 1- ccmod_xxx_init() + * 2- ccmod_xxx_decrypt() + * 3- ccmod_xxx_encrypt() + * + * stateful modes CCM and GCM: They provide 7 interface functions that return error codes if a function is called out of state + * 1- ccmod_xxx_init() + * 2- ccmod_xxx_setiv() + * 3- ccmod_xxx_aad() + * 4- ccmod_xxx_decrypt() + * 5- ccmod_xxx_encrypt() + * 6- ccmod_xxx_finalize() + * 7- ccmod_xxx_reset() + * + * the correct call sequences are: + * + * calls to 1, 2 and 6 arerequired + * 2 and 3 can be called as mant times as needed + * calls to 3, 4, 5 can be skipped + * + * 1, 2*n, 3*n, 4|5, 6 + * 1, 2*n, , 4|5, 6 + * 1, 2*n, , , 6 + * 1, 2*n, 3*n, , 6 + */ + +// 1- CBC mode, stateless +cc_aligned_struct(16) cccbc_ctx; +cc_aligned_struct(16) cccbc_iv; + +struct ccmode_cbc { + size_t size; /* first argument to cccbc_ctx_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, + size_t key_len, const void *key); + /* cbc encrypt or decrypt nblocks from in to out, iv will be used and updated. */ + int (*cbc)(const cccbc_ctx *ctx, cccbc_iv *iv, + size_t nblocks, const void *in, void *out); + const void *custom; +}; + +// 2- CFB mode, stateless +cc_aligned_struct(16) cccfb_ctx; + +struct ccmode_cfb { + size_t size; /* first argument to cccfb_ctx_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_cfb *cfb, cccfb_ctx *ctx, + size_t key_len, const void *key, const void *iv); + int (*cfb)(cccfb_ctx *ctx, size_t nbytes, const void *in, void *out); + const void *custom; +}; + +// 3- CFB8 mode, stateless +cc_aligned_struct(16) cccfb8_ctx; + +struct ccmode_cfb8 { + size_t size; /* first argument to cccfb8_ctx_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_cfb8 *cfb8, cccfb8_ctx *ctx, + size_t key_len, const void *key, const void *iv); + int (*cfb8)(cccfb8_ctx *ctx, size_t nbytes, const void *in, void *out); + const void *custom; +}; + +// 4- CTR mode, stateless +cc_aligned_struct(16) ccctr_ctx; + +struct ccmode_ctr { + size_t size; /* first argument to ccctr_ctx_decl(). */ + size_t block_size; /* for historical reasons, this is set to 1 */ + size_t ecb_block_size; /* the actual block size of the underlying cipher */ + int (*init)(const struct ccmode_ctr *mode, ccctr_ctx *ctx, + size_t key_len, const void *key, const void *iv); + int (*setctr)(const struct ccmode_ctr *mode, ccctr_ctx *ctx, const void *ctr); + int (*ctr)(ccctr_ctx *ctx, size_t nbytes, const void *in, void *out); + const void *custom; +}; + +// 5- OFB mode, stateless +cc_aligned_struct(16) ccofb_ctx; + +struct ccmode_ofb { + size_t size; /* first argument to ccofb_ctx_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_ofb *ofb, ccofb_ctx *ctx, + size_t key_len, const void *key, const void *iv); + int (*ofb)(ccofb_ctx *ctx, size_t nbytes, const void *in, void *out); + const void *custom; +}; + +// 6- XTS mode, stateless +cc_aligned_struct(16) ccxts_ctx; +cc_aligned_struct(16) ccxts_tweak; + +struct ccmode_xts { + size_t size; /* first argument to ccxts_ctx_decl(). Size of the ctx data structure */ + size_t tweak_size; /* first argument to ccxts_tweak_decl(). Size of the tweak structure, not the expected tweak size */ + size_t block_size; + + /* Create a xts key from a xts mode object. + key must point to at least 'size' bytes of free storage. + tweak_key must point to at least 'tweak_size' bytes of free storage. + key and tweak_key must differ. + Returns nonzero on failure. + */ + int (*init)(const struct ccmode_xts *xts, ccxts_ctx *ctx, + size_t key_nbytes, const void *data_key, const void *tweak_key); + + void (*key_sched)(const struct ccmode_xts *xts, ccxts_ctx *ctx, + size_t key_nbytes, const void *data_key, const void *tweak_key); + + /* Set the tweak (sector number), the block within the sector zero. */ + int (*set_tweak)(const ccxts_ctx *ctx, ccxts_tweak *tweak, const void *iv); + + /* Encrypt blocks for a sector, clients must call set_tweak before calling + this function. Return a pointer to the tweak buffer */ + void *(*xts)(const ccxts_ctx *ctx, ccxts_tweak *tweak, + size_t nblocks, const void *in, void *out); + + const void *custom; + const void *custom1; +}; + +//7- GCM mode, statful +cc_aligned_struct(16) ccgcm_ctx; +#define CCMODE_GCM_DECRYPTOR 78647 +#define CCMODE_GCM_ENCRYPTOR 4073947 + +struct ccmode_gcm { + size_t size; /* first argument to ccgcm_ctx_decl(). */ + int encdec; //is it encrypt or decrypt object + size_t block_size; + int (*init)(const struct ccmode_gcm *gcm, ccgcm_ctx *ctx, + size_t key_nbytes, const void *key); + int (*set_iv)(ccgcm_ctx *ctx, size_t iv_nbytes, const void *iv); + int (*gmac)(ccgcm_ctx *ctx, size_t nbytes, const void *in); // could just be gcm with NULL out + int (*gcm)(ccgcm_ctx *ctx, size_t nbytes, const void *in, void *out); + int (*finalize)(ccgcm_ctx *key, size_t tag_nbytes, void *tag); + int (*reset)(ccgcm_ctx *ctx); + const void *custom; +}; + +//8- GCM mode, statful +cc_aligned_struct(16) ccccm_ctx; +cc_aligned_struct(16) ccccm_nonce; + +struct ccmode_ccm { + size_t size; /* first argument to ccccm_ctx_decl(). */ + size_t nonce_size; /* first argument to ccccm_nonce_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_ccm *ccm, ccccm_ctx *ctx, + size_t key_len, const void *key); + int (*set_iv)(ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nonce_len, const void *nonce, + size_t mac_size, size_t auth_len, size_t data_len); + int (*cbcmac)(ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in); // could just be ccm with NULL out + int (*ccm)(ccccm_ctx *ctx, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in, void *out); + int (*finalize)(ccccm_ctx *key, ccccm_nonce *nonce_ctx, void *mac); + int (*reset)(ccccm_ctx *key, ccccm_nonce *nonce_ctx); + const void *custom; +}; + + +/* OMAC mode. */ +cc_aligned_struct(16) ccomac_ctx; + +struct ccmode_omac { + size_t size; /* first argument to ccomac_ctx_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_omac *omac, ccomac_ctx *ctx, + size_t tweak_len, size_t key_len, const void *key); + int (*omac)(ccomac_ctx *ctx, size_t nblocks, + const void *tweak, const void *in, void *out); + const void *custom; +}; + +#endif /* _CORECRYPTO_CCMODE_IMPL_H_ */ diff --git a/corecrypto/ccmode_siv.h b/corecrypto/ccmode_siv.h new file mode 100644 index 0000000..1834c23 --- /dev/null +++ b/corecrypto/ccmode_siv.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMODE_SIV_H_ +#define _CORECRYPTO_CCMODE_SIV_H_ + +#include +#include +#include + +#include + +/* This provide an implementation of SIV + as specified in https://tools.ietf.org/html/rfc5297 + also in http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/siv/siv.pdf + Counter Mode where IV is based on CMAC + */ + +cc_aligned_struct(16) ccsiv_ctx; + +struct ccmode_siv { + size_t size; /* first argument to ccsiv_ctx_decl(). */ + size_t block_size; + int (*init)(const struct ccmode_siv *siv, ccsiv_ctx *ctx, + size_t key_len, const uint8_t *key); + int (*set_nonce)(ccsiv_ctx *ctx, size_t nbytes, const uint8_t *in); // could just be ccm with NULL out + int (*auth)(ccsiv_ctx *ctx, size_t nbytes, const uint8_t *in); // could just be ccm with NULL out + int (*crypt)(ccsiv_ctx *ctx, size_t nbytes, const uint8_t *in, uint8_t *out); + int (*reset)(ccsiv_ctx *ctx); + const struct ccmode_cbc *cbc; + const struct ccmode_ctr *ctr; +}; + +#define ccsiv_ctx_decl(_size_, _name_) cc_ctx_decl(ccsiv_ctx, _size_, _name_) +#define ccsiv_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +// Functions + +CC_INLINE size_t ccsiv_context_size(const struct ccmode_siv *mode) +{ + return mode->size; +} + +CC_INLINE size_t ccsiv_block_size(const struct ccmode_siv *mode) +{ + return mode->block_size; +} + +CC_INLINE size_t ccsiv_ciphertext_size(const struct ccmode_siv *mode, + size_t plaintext_size) +{ + return plaintext_size+mode->cbc->block_size; +} + +CC_INLINE size_t ccsiv_plaintext_size(const struct ccmode_siv *mode, + size_t ciphertext_size) +{ + if (ciphertext_sizecbc->block_size) { + return 0; // error + } + return ciphertext_size-mode->cbc->block_size; +} + +// Supported key sizes are 32, 48, 64 bytes +CC_INLINE int ccsiv_init(const struct ccmode_siv *mode, ccsiv_ctx *ctx, + size_t key_byte_len, const uint8_t *key) +{ + return mode->init(mode, ctx, key_byte_len, key); +} + +// Process nonce. it is actually just an authenticated data +CC_INLINE int ccsiv_set_nonce(const struct ccmode_siv *mode, ccsiv_ctx *ctx, + size_t nbytes, const uint8_t *in) +{ + return mode->set_nonce(ctx, nbytes, in); +} + +// Process authenticated data. Taken into account for authentication but not +// encrypted +CC_INLINE int ccsiv_aad(const struct ccmode_siv *mode, ccsiv_ctx *ctx, + size_t nbytes, const uint8_t *in) +{ + return mode->auth(ctx, nbytes, in); +} + +// Encryption data. Authenticated and encrypted. +// Encrypt/Decrypt can only be called once +CC_INLINE int ccsiv_crypt(const struct ccmode_siv *mode, ccsiv_ctx *ctx, + size_t nbytes, const uint8_t *in, uint8_t *out) +{ + return mode->crypt(ctx, nbytes, in, out); +} + +// Clear all context for reuse. +// Key is clear to avoid leaking it +CC_INLINE int ccsiv_reset(const struct ccmode_siv *mode, ccsiv_ctx *ctx) +{ + return mode->reset(ctx); +} + +// One shot with only one vector of adata +CC_INLINE int ccsiv_one_shot(const struct ccmode_siv *mode, + size_t key_len, const uint8_t *key, + unsigned nonce_nbytes, const uint8_t* nonce, + unsigned adata_nbytes, const uint8_t* adata, + size_t in_nbytes, const uint8_t *in, uint8_t *out) +{ + int rc; + ccsiv_ctx_decl(mode->size, ctx); + rc=mode->init(mode, ctx, key_len, key); + if (rc) {return rc;} + rc=mode->set_nonce(ctx, nonce_nbytes, nonce); + if (rc) {return rc;} + rc=mode->auth(ctx, adata_nbytes, adata); + if (rc) {return rc;} + rc=mode->crypt(ctx, in_nbytes, in, out); + if (rc) {return rc;} + ccsiv_ctx_clear(mode->size, ctx); + return rc; +} + +void ccmode_factory_siv_encrypt(struct ccmode_siv *siv, + const struct ccmode_cbc *cbc, + const struct ccmode_ctr *ctr); + +void ccmode_factory_siv_decrypt(struct ccmode_siv *siv, + const struct ccmode_cbc *cbc, + const struct ccmode_ctr *ctr); + + +#endif /* _CORECRYPTO_CCMODE_H_ */ diff --git a/corecrypto/ccmode_siv_priv.h b/corecrypto/ccmode_siv_priv.h new file mode 100644 index 0000000..7608e6a --- /dev/null +++ b/corecrypto/ccmode_siv_priv.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCMODE_SIV_PRIV_H_ +#define _CORECRYPTO_CCMODE_SIV_PRIV_H_ + +#include +#include +#include + +#include + +// Maximum size for the key is 512 +#define CCSIV_MAX_BLOCK_BYTESIZE 128/8 + +// Maximum size for the key is 512 +#define CCSIV_MAX_KEY_BYTESIZE 512/8 + +struct _ccmode_siv_ctx { + const struct ccmode_siv *siv; + size_t key_bytesize; + cc_unit state; + cc_unit k1[ccn_nof_size(CCSIV_MAX_KEY_BYTESIZE/2)]; // cmac key + cc_unit k2[ccn_nof_size(CCSIV_MAX_KEY_BYTESIZE/2)]; // ctr key + cc_unit block[ccn_nof_size(CCSIV_MAX_BLOCK_BYTESIZE)]; +}; + +int ccmode_siv_init(const struct ccmode_siv *siv, ccsiv_ctx *ctx, + size_t rawkey_byte_len, const uint8_t *rawkey); + +// Authentication of the adata +int ccmode_siv_auth(ccsiv_ctx *ctx, + size_t nbytes, const uint8_t *in); + +// Authentication of the last vector (the encrypted part) +int ccmode_siv_auth_last(ccsiv_ctx *ctx, + size_t nbytes, const uint8_t *in, uint8_t* V); + +int ccmode_siv_encrypt(ccsiv_ctx *ctx, + size_t nbytes, const uint8_t *in, uint8_t *out); + +int ccmode_siv_decrypt(ccsiv_ctx *ctx, + size_t nbytes, const uint8_t *in, uint8_t *out); + +int ccmode_siv_reset(ccsiv_ctx *ctx); + +/* Macros for accessing a CCMODE_SIV. + { + const struct ccmode_siv *siv; + uint8_t key[512/8]; + uint8_t d[512/8]; + cc_unit cmac_ctx[cbc->n]; + cc_unit ctr_ctx[ctr->n]; + } */ +#define _CCMODE_SIV_CTX(K) ((struct _ccmode_siv_ctx *)(K)) +#define _CCMODE_SIV_CBC_MODE(K) (_CCMODE_SIV_CTX(K)->siv->cbc) +#define _CCMODE_SIV_CTR_MODE(K) (_CCMODE_SIV_CTX(K)->siv->ctr) +#define _CCMODE_SIV_STATE(K) (_CCMODE_SIV_CTX(K)->state) +#define _CCMODE_SIV_KEYSIZE(K) (_CCMODE_SIV_CTX(K)->key_bytesize) +#define _CCMODE_SIV_K1(K) ((uint8_t *)_CCMODE_SIV_CTX(K)->k1) +#define _CCMODE_SIV_K2(K) ((uint8_t *)_CCMODE_SIV_CTX(K)->k2) +#define _CCMODE_SIV_D(K) ((uint8_t *)_CCMODE_SIV_CTX(K)->block) + + + + + +#endif /* _CORECRYPTO_CCMODE_SIV_PRIV_H_ */ diff --git a/corecrypto/ccn.h b/corecrypto/ccn.h new file mode 100644 index 0000000..9cc442b --- /dev/null +++ b/corecrypto/ccn.h @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCN_H_ +#define _CORECRYPTO_CCN_H_ + +#include +#include +#include + +typedef uint8_t cc_byte; +typedef size_t cc_size; + +#if CCN_UNIT_SIZE == 8 +typedef uint64_t cc_unit; // 64 bit unit +typedef int64_t cc_int; +#define CCN_LOG2_BITS_PER_UNIT 6 // 2^6 = 64 bits +#define CC_UNIT_C(x) UINT64_C(x) + #if CCN_UINT128_SUPPORT_FOR_64BIT_ARCH + typedef unsigned cc_dunit __attribute__((mode(TI))); // 128 bit double width unit + typedef signed cc_dint __attribute__((mode(TI))); + #else + typedef struct cc_dunit { + uint64_t l; //do not change the order of the variables. cc_dunit must be little endian + uint64_t h; + } cc_dunit; + + typedef struct cc_dint { + uint64_t l; + uint64_t h; + } cc_dint; + #endif + +#elif CCN_UNIT_SIZE == 4 +typedef uint32_t cc_unit; // 32 bit unit +typedef uint64_t cc_dunit; // 64 bit double width unit +typedef int64_t cc_dint; +typedef int32_t cc_int; +#define CCN_LOG2_BITS_PER_UNIT 5 // 2^5 = 32 bits +#define CC_UNIT_C(x) UINT32_C(x) + +#elif CCN_UNIT_SIZE == 2 +typedef uint16_t cc_unit; // 16 bit unit +typedef uint32_t cc_dunit; // 32 bit double width unit +#define CCN_LOG2_BITS_PER_UNIT 4 // 2^4 = 16 bits +#define CC_UNIT_C(x) UINT16_C(x) + +#elif CCN_UNIT_SIZE == 1 +typedef uint8_t cc_unit; // 8 bit unit +typedef uint16_t cc_dunit; // 16 bit double width unit +#define CCN_LOG2_BITS_PER_UNIT 3 // 2^3 = 8 bits +#define CC_UNIT_C(x) UINT8_C(x) + +#else +#error invalid CCN_UNIT_SIZE +#endif + +// All mp types have units in little endian unit order. +typedef cc_unit *ccn_t; // n unit long mp +typedef cc_unit *ccnp1_t; // n + 1 unit long mp +typedef cc_unit *cc2n_t; // 2 * n unit long mp +typedef cc_unit *cc2np2_t; // 2 * n + 2 unit long mp +typedef const cc_unit *ccn_in_t; // n unit long mp +typedef const cc_unit *ccnp1_in_t; // n + 1 unit long mp +typedef const cc_unit *cc2n_in_t; // 2 * n unit long mp +typedef const cc_unit *cc2np2_in_t; // 2 * n + 2 unit long mp + +#define CCN_UNIT_BITS (sizeof(cc_unit) * 8) +#define CCN_UNIT_MASK ((cc_unit)~0) + +typedef struct { + cc_unit *start; // First cc_unit of the workspace + cc_unit *end; // address and beyond NOT TO BE TOUCHED +} cc_ws,*cc_ws_t; + +/* Conversions between n sizeof and bits */ + +/* Returns the sizeof a ccn vector of length _n_ units. */ +#define ccn_sizeof_n(_n_) (sizeof(cc_unit) * (_n_)) + +/* Returns the count (n) of a ccn vector that can represent _bits_. */ +#define ccn_nof(_bits_) (((_bits_) + CCN_UNIT_BITS - 1) >> CCN_LOG2_BITS_PER_UNIT) + +/* Returns the sizeof a ccn vector that can represent _bits_. */ +#define ccn_sizeof(_bits_) (ccn_sizeof_n(ccn_nof(_bits_))) + +/* Returns the count (n) of a ccn vector that can represent _size_ bytes. */ +#define ccn_nof_size(_size_) (((_size_) + CCN_UNIT_SIZE - 1) / CCN_UNIT_SIZE) + +/* Return the max number of bits a ccn vector of _n_ units can hold. */ +#define ccn_bitsof_n(_n_) ((_n_) * CCN_UNIT_BITS) + +/* Return the max number of bits a ccn vector of _size_ bytes can hold. */ +#define ccn_bitsof_size(_size_) ((_size_) * 8) + +/* Return the size of a ccn of size bytes in bytes. */ +#define ccn_sizeof_size(_size_) ccn_sizeof_n(ccn_nof_size(_size_)) + +/* Returns the value of bit _k_ of _ccn_, both are only evaluated once. */ +#define ccn_bit(_ccn_, _k_) ({__typeof__ (_k_) __k = (_k_); \ + 1 & ((_ccn_)[ __k >> CCN_LOG2_BITS_PER_UNIT] >> (__k & (CCN_UNIT_BITS - 1)));}) + +/* Set the value of bit _k_ of _ccn_ to the value _v_ */ +#define ccn_set_bit(_ccn_, _k_, _v_) ({__typeof__ (_k_) __k = (_k_); \ + if (_v_) \ + (_ccn_)[ __k >> CCN_LOG2_BITS_PER_UNIT] |= CC_UNIT_C(1) << (__k & (CCN_UNIT_BITS - 1)); \ + else \ + (_ccn_)[ __k >> CCN_LOG2_BITS_PER_UNIT] &= ~(CC_UNIT_C(1) << (__k & (CCN_UNIT_BITS - 1))); \ + }) + +/* Macros for making ccn constants. You must use list of CCN64_C() instances + separated by commas, with an optional smaller sized CCN32_C, CCN16_C, or + CCN8_C() instance at the end of the list, when making macros to declare + larger sized constants. */ +#define CCN8_C(a0) CC_UNIT_C(0x##a0) + +#if CCN_UNIT_SIZE >= 2 +#define CCN16_C(a1,a0) CC_UNIT_C(0x##a1##a0) +#define ccn16_v(a0) (a0) +#elif CCN_UNIT_SIZE == 1 +#define CCN16_C(a1,a0) CCN8_C(a0),CCN8_C(a1) +#define ccn16_v(a0) (a0 & UINT8_C(0xff)),(a0 >> 8) +#endif + +#if CCN_UNIT_SIZE >= 4 +#define CCN32_C(a3,a2,a1,a0) CC_UNIT_C(0x##a3##a2##a1##a0) +#define ccn32_v(a0) (a0) +#else +#define CCN32_C(a3,a2,a1,a0) CCN16_C(a1,a0),CCN16_C(a3,a2) +#define ccn32_v(a0) ccn16_v(a0 & UINT16_C(0xffff)),ccn16_v(a0 >> 16) +#endif + +#if CCN_UNIT_SIZE == 8 +#define CCN64_C(a7,a6,a5,a4,a3,a2,a1,a0) CC_UNIT_C(0x##a7##a6##a5##a4##a3##a2##a1##a0) +#define CCN40_C(a4,a3,a2,a1,a0) CC_UNIT_C(0x##a4##a3##a2##a1##a0) +#define ccn64_v(a0) (a0) +//#define ccn64_32(a1,a0) ((a1 << 32) | a0) +//#define ccn_uint64(a,i) (a[i]) +#else +#define CCN64_C(a7,a6,a5,a4,a3,a2,a1,a0) CCN32_C(a3,a2,a1,a0),CCN32_C(a7,a6,a5,a4) +#define CCN40_C(a4,a3,a2,a1,a0) CCN32_C(a3,a2,a1,a0),CCN8_C(a4) +#define ccn64_v(a0) ccn32_v((uint64_t)a0 & UINT32_C(0xffffffff)),ccn32_v((uint64_t)a0 >> 32) +//#define ccn64_32(a1,a0) ccn32_v(a0),ccn32_v(a1) +//#define ccn_uint64(a,i) ((uint64_t)ccn_uint32(a, i << 1 + 1) << 32 | (uint64_t)ccn_uint32(a, i << 1)) +#endif + +/* Macro's for reading uint32_t and uint64_t from ccns, the index is in 32 or + 64 bit units respectively. */ +#if CCN_UNIT_SIZE == 8 +/* #define ccn_uint16(a,i) ((i & 3) == 3 ? ((uint16_t)(a[i >> 2] >> 48)) : \ + (i & 3) == 2 ? ((uint16_t)(a[i >> 2] >> 32) & UINT16_C(0xffff)) : \ + (i & 3) == 1 ? ((uint16_t)(a[i >> 2] >> 16) & UINT16_C(0xffff)) : \ + ((uint16_t)(a[i >> 1] & UINT16_C(0xffff)))) +*/ +//#define ccn_uint32(a,i) (i & 1 ? ((uint32_t)(a[i >> 1] >> 32)) : ((uint32_t)(a[i >> 1] & UINT32_C(0xffffffff)))) +#elif CCN_UNIT_SIZE == 4 +//#define ccn16_v(a0) (a0) +//#define ccn32_v(a0) (a0) +//#define ccn_uint16(a,i) (i & 1 ? ((uint16_t)(a[i >> 1] >> 16)) : ((uint16_t)(a[i >> 1] & UINT16_C(0xffff)))) +//#define ccn_uint32(a,i) (a[i]) +#elif CCN_UNIT_SIZE == 2 +//#define ccn16_v(a0) (a0) +//#define ccn32_v(a0,a1) (a1,a0) +//#define ccn_uint16(a,i) (a[i]) +//#define ccn_uint32(a,i) (((uint32_t)a[i << 1 + 1]) << 16 | (uint32_t)a[i << 1])) +#elif CCN_UNIT_SIZE == 1 +//#define ccn16_v(a0) (a0 & UINT8_C(0xff)),(a0 >> 8) +//#define ccn_uint16(a,i) ((uint16_t)((a[i << 1 + 1] << 8) | a[i << 1])) +//#define ccn_uint32(a,i) ((uint32_t)ccn_uint16(a, i << 1 + 1) << 16 | (uint32_t)ccn_uint16(a, i << 1)) +#endif + +/* Macro's for reading uint32_t and uint64_t from ccns, the index is in 32 or + 64 bit units respectively. */ +#if CCN_UNIT_SIZE == 8 + +#define ccn64_32(a1,a0) (((const cc_unit)a1) << 32 | ((const cc_unit)a0)) +#define ccn32_32(a0) a0 +#if __LITTLE_ENDIAN__ +#define ccn32_32_parse(p,i) (((const uint32_t *)p)[i]) +#else +#define ccn32_32_parse(p,i) (((const uint32_t *)p)[i^1]) +#endif +#define ccn32_32_null 0 + +#define ccn64_64(a0) a0 +#define ccn64_64_parse(p,i) p[i] +#define ccn64_64_null 0 + +#elif CCN_UNIT_SIZE == 4 + +#define ccn32_32(a0) a0 +#define ccn32_32_parse(p,i) p[i] +#define ccn32_32_null 0 +#define ccn64_32(a1,a0) ccn32_32(a0),ccn32_32(a1) + +#define ccn64_64(a1,a0) a0,a1 +#define ccn64_64_parse(p,i) p[1+(i<<1)],p[i<<1] +#define ccn64_64_null 0,0 + +#elif CCN_UNIT_SIZE == 2 + +#define ccn32_32(a1,a0) a0,a1 +#define ccn32_32_parse(p,i) p[1+(i<<1)],p[i<<1] +#define ccn32_32_null 0,0 +#define ccn64_32(a3,a2,a1,a0) ccn32_32(a1,a0),ccn32_32(a3,a2) + +#define ccn64_64(a3,a2,a1,a0) a0,a1,a2,a3 +#define ccn64_64_parse(p,i) p[3+(i<<2)],p[2+(i<<2)],p[1+(i<<2)],p[i<<2] +#define ccn64_64_null 0,0,0,0 + +#elif CCN_UNIT_SIZE == 1 + +#define ccn32_32(a3,a2,a1,a0) a0,a1,a2,a3 +#define ccn32_32_parse(p,i) p[3+(i<<2)],p[2+(i<<2)],p[1+(i<<2)],p[i<<2] +#define ccn32_32_null 0,0,0,0 +#define ccn64_32(a7,a6,a5,a4,a3,a2,a1,a0) ccn32_32(a3,a2,a1,a0),ccn32_32(a7,a6,a5,a4) + +#define ccn64_64(a7,a6,a5,a4,a3,a2,a1,a0) a0,a1,a2,a3,a4,a5,a6,a7 +#define ccn64_64_parse(p,i) p[7+(i<<3)],p[6+(i<<3)],p[5+(i<<3)],p[4+(i<<3)],p[3+(i<<3)],p[2+(i<<3)],p[1+(i<<3)],p[i<<3] +#define ccn64_64_null 0,0,0,0,0,0,0,0 + +#endif + + +/* Macros to construct fixed size ccn arrays from 64 or 32 bit quantities. */ +#define ccn192_64(a2,a1,a0) ccn64_64(a0),ccn64_64(a1),ccn64_64(a2) +#define ccn224_32(a6,a5,a4,a3,a2,a1,a0) ccn64_32(a1,a0),ccn64_32(a3,a2),ccn64_32(a5,a4),ccn32_32(a6) +#define ccn256_32(a7,a6,a5,a4,a3,a2,a1,a0) ccn64_32(a1,a0),ccn64_32(a3,a2),ccn64_32(a5,a4),ccn64_32(a7,a6) +#define ccn384_32(a11,a10,a9,a8,a7,a6,a5,a4,a3,a2,a1,a0) ccn64_32(a1,a0),ccn64_32(a3,a2),ccn64_32(a5,a4),ccn64_32(a7,a6),ccn64_32(a9,a8),ccn64_32(a11,a10) + + +#define CCN192_C(c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN64_C(a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN64_C(b7,b6,b5,b4,b3,b2,b1,b0),\ + CCN64_C(c7,c6,c5,c4,c3,c2,c1,c0) + +#define CCN200_C(d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN192_C(c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN8_C(d0) + +#define CCN224_C(d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN192_C(c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN32_C(d3,d2,d1,d0) + +#define CCN232_C(d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN192_C(c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN40_C(d4,d3,d2,d1,d0) + +#define CCN256_C(d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN192_C(c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN64_C(d7,d6,d5,d4,d3,d2,d1,d0) + +#define CCN264_C(e0,d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN256_C(d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN8_C(e0) + +#define CCN384_C(f7,f6,f5,f4,f3,f2,f1,f0,e7,e6,e5,e4,e3,e2,e1,e0,d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN256_C(d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN64_C(e7,e6,e5,e4,e3,e2,e1,e0),\ + CCN64_C(f7,f6,f5,f4,f3,f2,f1,f0) + +#define CCN392_C(g0,f7,f6,f5,f4,f3,f2,f1,f0,e7,e6,e5,e4,e3,e2,e1,e0,d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN384_C(f7,f6,f5,f4,f3,f2,f1,f0,e7,e6,e5,e4,e3,e2,e1,e0,d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN8_C(g0) + +#define CCN528_C(i1,i0,h7,h6,h5,h4,h3,h2,h1,h0,g7,g6,g5,g4,g3,g2,g1,g0,f7,f6,f5,f4,f3,f2,f1,f0,e7,e6,e5,e4,e3,e2,e1,e0,d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0) \ + CCN256_C(d7,d6,d5,d4,d3,d2,d1,d0,c7,c6,c5,c4,c3,c2,c1,c0,b7,b6,b5,b4,b3,b2,b1,b0,a7,a6,a5,a4,a3,a2,a1,a0),\ + CCN256_C(h7,h6,h5,h4,h3,h2,h1,h0,g7,g6,g5,g4,g3,g2,g1,g0,f7,f6,f5,f4,f3,f2,f1,f0,e7,e6,e5,e4,e3,e2,e1,e0),\ + CCN16_C(i1,i0) + +#define CCN192_N ccn_nof(192) +#define CCN224_N ccn_nof(224) +#define CCN256_N ccn_nof(256) +#define CCN384_N ccn_nof(384) +#define CCN512_N ccn_nof(512) +#define CCN521_N ccn_nof(521) + +/* Return the number of used units after stripping leading 0 units. */ +CC_PURE CC_NONNULL2 +cc_size ccn_n(cc_size n, const cc_unit *s); + +/* s >> k -> r return bits shifted out of least significant word in bits [0, n> + { N bit, scalar -> N bit } N = n * sizeof(cc_unit) * 8 + the _multi version doesn't return the shifted bits, but does support multiple + word shifts. */ +CC_NONNULL((2, 3)) +cc_unit ccn_shift_right(cc_size n, cc_unit *r, const cc_unit *s, size_t k); +CC_NONNULL((2, 3)) +void ccn_shift_right_multi(cc_size n, cc_unit *r,const cc_unit *s, size_t k); + +/* s << k -> r return bits shifted out of most significant word in bits [0, n> + { N bit, scalar -> N bit } N = n * sizeof(cc_unit) * 8 + the _multi version doesn't return the shifted bits, but does support multiple + word shifts */ +CC_NONNULL((2, 3)) +cc_unit ccn_shift_left(cc_size n, cc_unit *r, const cc_unit *s, size_t k); +CC_NONNULL((2, 3)) +void ccn_shift_left_multi(cc_size n, cc_unit *r, const cc_unit *s, size_t k); + +/* s == 0 -> return 0 | s > 0 -> return index (starting at 1) of most + significant bit that is 1. + { N bit } N = n * sizeof(cc_unit) * 8 */ +CC_NONNULL2 +size_t ccn_bitlen(cc_size n, const cc_unit *s); + +/* Returns the number of bits which are zero before the first one bit + counting from least to most significant bit. */ +CC_NONNULL2 +size_t ccn_trailing_zeros(cc_size n, const cc_unit *s); + +/* s == 0 -> return true | s != 0 -> return false + { N bit } N = n * sizeof(cc_unit) * 8 */ +#define ccn_is_zero(_n_, _s_) (!ccn_n(_n_, _s_)) + +/* s == 1 -> return true | s != 1 -> return false + { N bit } N = n * sizeof(cc_unit) * 8 */ +#define ccn_is_one(_n_, _s_) (ccn_n(_n_, _s_) == 1 && _s_[0] == 1) + +#define ccn_is_zero_or_one(_n_, _s_) (((_n_)==0) || ((ccn_n(_n_, _s_) <= 1) && (_s_[0] <= 1))) + +/* s < t -> return - 1 | s == t -> return 0 | s > t -> return 1 + { N bit, N bit -> int } N = n * sizeof(cc_unit) * 8 */ +CC_PURE CC_NONNULL((2, 3)) +int ccn_cmp(cc_size n, const cc_unit *s, const cc_unit *t); + +/* s < t -> return - 1 | s == t -> return 0 | s > t -> return 1 + { N bit, M bit -> int } N = ns * sizeof(cc_unit) * 8 M = nt * sizeof(cc_unit) * 8 */ +CC_INLINE CC_NONNULL((2, 4)) +int ccn_cmpn(cc_size ns, const cc_unit *s, + cc_size nt, const cc_unit *t) { + if (ns > nt) { + return 1; + } else if (ns < nt) { + return -1; + } + return ccn_cmp(ns, s, t); +} + +/* s - t -> r return 1 iff t > s + { N bit, N bit -> N bit } N = n * sizeof(cc_unit) * 8 */ +CC_NONNULL((2, 3, 4)) +cc_unit ccn_sub(cc_size n, cc_unit *r, const cc_unit *s, const cc_unit *t); + +/* |s - t| -> r return 1 iff t > s, 0 otherwise */ +cc_unit ccn_abs(cc_size n, cc_unit *r, const cc_unit *s, const cc_unit *t); + +/* s - v -> r return 1 iff v > s return 0 otherwise. + { N bit, sizeof(cc_unit) * 8 bit -> N bit } N = n * sizeof(cc_unit) * 8 */ +CC_NONNULL((2, 3)) +cc_unit ccn_sub1(cc_size n, cc_unit *r, const cc_unit *s, cc_unit v); + +/* s - t -> r return 1 iff t > s + { N bit, NT bit -> N bit NT <= N} N = n * sizeof(cc_unit) * 8 */ +CC_INLINE +CC_NONNULL((2, 3, 5)) +cc_unit ccn_subn(cc_size n, cc_unit *r, const cc_unit *s, + cc_size nt, const cc_unit *t) { + assert(n >= nt); + return ccn_sub1(n - nt, r + nt, s + nt, ccn_sub(nt, r, s, t)); +} + + +/* s + t -> r return carry if result doesn't fit in n bits. + { N bit, N bit -> N bit } N = n * sizeof(cc_unit) * 8 */ +CC_NONNULL((2, 3, 4)) +cc_unit ccn_add(cc_size n, cc_unit *r, const cc_unit *s, const cc_unit *t); + +/* s + v -> r return carry if result doesn't fit in n bits. + { N bit, sizeof(cc_unit) * 8 bit -> N bit } N = n * sizeof(cc_unit) * 8 */ +CC_NONNULL((2, 3)) +cc_unit ccn_add1(cc_size n, cc_unit *r, const cc_unit *s, cc_unit v); + +/* s + t -> r return carry if result doesn't fit in n bits + { N bit, NT bit -> N bit NT <= N} N = n * sizeof(cc_unit) * 8 */ +CC_INLINE +CC_NONNULL((2, 3, 5)) +cc_unit ccn_addn(cc_size n, cc_unit *r, const cc_unit *s, + cc_size nt, const cc_unit *t) { + assert(n >= nt); + return ccn_add1(n - nt, r + nt, s + nt, ccn_add(nt, r, s, t)); +} + + +CC_NONNULL((2, 3, 4)) +void ccn_lcm(cc_size n, cc_unit *r2n, const cc_unit *s, const cc_unit *t); + + +/* s * t -> r_2n r_2n must not overlap with s nor t + { n bit, n bit -> 2 * n bit } n = count * sizeof(cc_unit) * 8 + { N bit, N bit -> 2N bit } N = ccn_bitsof(n) */ +CC_NONNULL((2, 3, 4)) +void ccn_mul(cc_size n, cc_unit *r_2n, const cc_unit *s, const cc_unit *t); + +/* s * t -> r_2n r_2n must not overlap with s nor t + { n bit, n bit -> 2 * n bit } n = count * sizeof(cc_unit) * 8 + { N bit, N bit -> 2N bit } N = ccn_bitsof(n) + Provide a workspace for potential speedup */ +CC_NONNULL((1, 3, 4, 5)) +void ccn_mul_ws(cc_ws_t ws, cc_size count, cc_unit *r, const cc_unit *s, const cc_unit *t); + +/* s[0..n) * v -> r[0..n)+return value + { N bit, sizeof(cc_unit) * 8 bit -> N + sizeof(cc_unit) * 8 bit } N = n * sizeof(cc_unit) * 8 */ +CC_NONNULL((2, 3)) +cc_unit ccn_mul1(cc_size n, cc_unit *r, const cc_unit *s, const cc_unit v); + +/* s[0..n) * v + r[0..n) -> r[0..n)+return value + { N bit, sizeof(cc_unit) * 8 bit -> N + sizeof(cc_unit) * 8 bit } N = n * sizeof(cc_unit) * 8 */ +CC_NONNULL((2, 3)) +cc_unit ccn_addmul1(cc_size n, cc_unit *r, const cc_unit *s, const cc_unit v); + +#if 0 +/* a % d -> n + {2 * n bit, n bit -> n bit } n = count * sizeof(cc_unit) * 8 */ +CC_NONNULL((2, 3, 4)) +void ccn_mod(cc_size n, cc_unit *r, const cc_unit *a_2n, const cc_unit *d); +#endif + +/* r = gcd(s, t). + N bit, N bit -> N bit */ +CC_NONNULL((2, 3, 4)) +void ccn_gcd(cc_size n, cc_unit *r, const cc_unit *s, const cc_unit *t); + +/* r = gcd(s, t). + N bit, N bit -> O bit */ +CC_NONNULL((2, 4, 6)) +void ccn_gcdn(cc_size rn, cc_unit *r, cc_size sn, const cc_unit *s, cc_size tn, const cc_unit *t); + +/* r = (data, len) treated as a big endian byte array, return -1 if data + doesn't fit in r, return 0 otherwise. */ +CC_NONNULL((2, 4)) +int ccn_read_uint(cc_size n, cc_unit *r, size_t data_size, const uint8_t *data); + +/* r = (data, len) treated as a big endian byte array, return -1 if data + doesn't fit in r, return 0 otherwise. + ccn_read_uint strips leading zeroes and doesn't care about sign. */ +#define ccn_read_int(n, r, data_size, data) ccn_read_uint(n, r, data_size, data) + +/* Return actual size in bytes needed to serialize s. */ +CC_PURE CC_NONNULL2 +size_t ccn_write_uint_size(cc_size n, const cc_unit *s); + +/* Serialize s, to out. + First byte of byte stream is the m.s. byte of s, + regardless of the size of cc_unit. + + No assumption is made about the alignment of out. + + The out_size argument should be the value returned from ccn_write_uint_size, + and is also the exact number of bytes this function will write to out. + If out_size if less than the value returned by ccn_write_uint_size, only the + first out_size non-zero most significant octets of s will be written. */ +CC_NONNULL((2, 4)) +void ccn_write_uint(cc_size n, const cc_unit *s, size_t out_size, void *out); + + +CC_INLINE CC_NONNULL((2, 4)) +cc_size ccn_write_uint_padded(cc_size n, const cc_unit* s, size_t out_size, uint8_t* to) +{ + size_t bytesInKey = ccn_write_uint_size(n, s); + cc_size offset = (out_size > bytesInKey) ? out_size - bytesInKey : 0; + + cc_zero(offset, to); + ccn_write_uint(n, s, out_size - offset, to + offset); + + return offset; +} + + +/* Return actual size in bytes needed to serialize s as int + (adding leading zero if high bit is set). */ +CC_PURE CC_NONNULL2 +size_t ccn_write_int_size(cc_size n, const cc_unit *s); + +/* Serialize s, to out. + First byte of byte stream is the m.s. byte of s, + regardless of the size of cc_unit. + + No assumption is made about the alignment of out. + + The out_size argument should be the value returned from ccn_write_int_size, + and is also the exact number of bytes this function will write to out. + If out_size if less than the value returned by ccn_write_int_size, only the + first out_size non-zero most significant octets of s will be written. */ +CC_NONNULL((2, 4)) +void ccn_write_int(cc_size n, const cc_unit *s, size_t out_size, void *out); + +#if CCN_DEDICATED_SQR + +/* s^2 -> r + { n bit -> 2 * n bit } */ +CC_NONNULL((2, 3)) +void ccn_sqr(cc_size n, cc_unit *r, const cc_unit *s); + +/* s^2 -> r + { n bit -> 2 * n bit } */ +CC_NONNULL((1, 3, 4)) +void ccn_sqr_ws(cc_ws_t ws, cc_size n, cc_unit *r, const cc_unit *s); + +#else + +/* s^2 -> r + { n bit -> 2 * n bit } */ +CC_INLINE CC_NONNULL((2, 3)) +void ccn_sqr(cc_size n, cc_unit *r, const cc_unit *s) { + ccn_mul(n, r, s, s); +} + +/* s^2 -> r + { n bit -> 2 * n bit } */ +CC_INLINE CC_NONNULL((2, 3, 4)) +void ccn_sqr_ws(cc_ws_t ws, cc_size n, cc_unit *r, const cc_unit *s) { + ccn_mul_ws(ws, n, r, s, s); +} + +#endif + +/* s -> r + { n bit -> n bit } */ +CC_NONNULL((2, 3)) +void ccn_set(cc_size n, cc_unit *r, const cc_unit *s); + +CC_INLINE CC_NONNULL2 +void ccn_zero(cc_size n, cc_unit *r) { + cc_zero(ccn_sizeof_n(n),r); +} + +CC_INLINE CC_NONNULL2 +void ccn_clear(cc_size n, cc_unit *r) { + cc_clear(ccn_sizeof_n(n),r); +} + +CC_NONNULL2 +void ccn_zero_multi(cc_size n, cc_unit *r, ...); + +CC_INLINE CC_NONNULL2 +void ccn_seti(cc_size n, cc_unit *r, cc_unit v) { + /* assert(n > 0); */ + r[0] = v; + ccn_zero(n - 1, r + 1); +} + +CC_INLINE CC_NONNULL((2, 4)) +void ccn_setn(cc_size n, cc_unit *r, const cc_size s_size, const cc_unit *s) { + /* FIXME: assert not available in kernel. + assert(n > 0); + assert(s_size > 0); + assert(s_size <= n); + */ + ccn_set(s_size, r, s); + ccn_zero(n - s_size, r + s_size); +} + +#define CC_SWAP_HOST_BIG_64(x) \ + ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \ + (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ + (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ + (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) +#define CC_SWAP_HOST_BIG_32(x) \ + ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#define CC_SWAP_HOST_BIG_16(x) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8)) + +/* This should probably move if we move ccn_swap out of line. */ +#if CCN_UNIT_SIZE == 8 +#define CC_UNIT_TO_BIG(x) CC_SWAP_HOST_BIG_64(x) +#elif CCN_UNIT_SIZE == 4 +#define CC_UNIT_TO_BIG(x) CC_SWAP_HOST_BIG_32(x) +#elif CCN_UNIT_SIZE == 2 +#define CC_UNIT_TO_BIG(x) CC_SWAP_HOST_BIG_16(x) +#elif CCN_UNIT_SIZE == 1 +#define CC_UNIT_TO_BIG(x) (x) +#else +#error unsupported CCN_UNIT_SIZE +#endif + +/* Swap units in r in place from cc_unit vector byte order to big endian byte order (or back). */ +CC_INLINE CC_NONNULL2 +void ccn_swap(cc_size n, cc_unit *r) { + cc_unit *e; + for (e = r + n - 1; r < e; ++r, --e) { + cc_unit t = CC_UNIT_TO_BIG(*r); + *r = CC_UNIT_TO_BIG(*e); + *e = t; + } + if (n & 1) + *r = CC_UNIT_TO_BIG(*r); +} + +CC_INLINE CC_NONNULL((2, 3, 4)) +void ccn_xor(cc_size n, cc_unit *r, const cc_unit *s, const cc_unit *t) { + while (n--) { + r[n] = s[n] ^ t[n]; + } +} + +/* Debugging */ +CC_NONNULL2 +void ccn_print(cc_size n, const cc_unit *s); +CC_NONNULL3 +void ccn_lprint(cc_size n, const char *label, const cc_unit *s); + +/* Forward declaration so we don't depend on ccrng.h. */ +struct ccrng_state; + +#if 0 +CC_INLINE CC_NONNULL((2, 3)) +int ccn_random(cc_size n, cc_unit *r, struct ccrng_state *rng) { + return (RNG)->generate((RNG), ccn_sizeof_n(n), (unsigned char *)r); +} +#else +#define ccn_random(_n_,_r_,_ccrng_ctx_) \ + ccrng_generate(_ccrng_ctx_, ccn_sizeof_n(_n_), (unsigned char *)_r_) +#endif + +/* Make a ccn of size ccn_nof(nbits) units with up to nbits sized random value. */ +CC_NONNULL((2, 3)) +int ccn_random_bits(cc_size nbits, cc_unit *r, struct ccrng_state *rng); + +/*! + @brief ccn_make_recip(cc_size nd, cc_unit *recip, const cc_unit *d) computes the reciprocal of d: recip = 2^2b/d where b=bitlen(d) + + @param nd length of array d + @param recip returned reciprocal of size nd+1 + @param d input number d +*/ +CC_NONNULL((2, 3)) +int ccn_make_recip(cc_size nd, cc_unit *recip, const cc_unit *d); + +CC_NONNULL((6, 8)) +int ccn_div_euclid(cc_size nq, cc_unit *q, cc_size nr, cc_unit *r, cc_size na, const cc_unit *a, cc_size nd, const cc_unit *d); + +#define ccn_div(nq, q, na, a, nd, d) ccn_div_euclid(nq, q, 0, NULL, na, a, nd, d) +#define ccn_mod(nr, r, na, a, nd, d) ccn_div_euclid(0 , NULL, nr, r, na, a, nd, d) + +#endif /* _CORECRYPTO_CCN_H_ */ diff --git a/corecrypto/ccn_priv.h b/corecrypto/ccn_priv.h new file mode 100644 index 0000000..6f1b0bc --- /dev/null +++ b/corecrypto/ccn_priv.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_ccn_priv_h +#define corecrypto_ccn_priv_h + +#include +#include +#include + +#define CCN_MUL_WS_WORKSPACE_N(n) (4*((n)+1)) + +#if CCN_DEDICATED_SQR +#define CCN_SQR_WS_WORKSPACE_N(n) (2*(n)) +#else +#define CCN_SQR_WS_WORKSPACE_N(n) CCN_MUL_WS_WORKSPACE_N((n)) +#endif + +// Same ccn_make_recip, takes a ws +//#define CCN_MAKE_RECIP_WORKSPACE_SIZE(n) (3*(n)) /* shift sub */ +#define CCN_MAKE_RECIP_WORKSPACE_SIZE(n) (7*n+CCN_MUL_WS_WORKSPACE_N(n+1)) /* newtonraphson */ +void ccn_make_recip_ws(cc_ws_t ws, cc_size nd, cc_unit *recip, const cc_unit *d); + +// Same ccn_div_euclid, takes a ws +//#define CCN_DIV_EUCLID_WORKSPACE_SIZE(na,nd) (nd+1 + CC_MAX(CCN_MAKE_RECIP_WORKSPACE_SIZE(nd),CCN_DIV_USE_RECIP_WORKSPACE_SIZE(na,nd))) +#define CCN_DIV_EUCLID_WORKSPACE_SIZE(na,nd) (nd+1 + 4+CCN_DIV_USE_RECIP_WORKSPACE_SIZE(na,nd)) +int ccn_div_euclid_ws(cc_ws_t ws, cc_size nq, cc_unit *q, cc_size nr, cc_unit *r, cc_size na, const cc_unit *a, cc_size nd, const cc_unit *d); + +/*! + @brief ccn_div_use_recip(nq, q, nr, r, na, a, nd, d) computes q=a/d and r=a%d + @discussion q and rcan be NULL. Reads na from a and nd from d. Writes nq in q and nr in r. nq and nr must be large enough to accomodate results, otherwise error is retuned. Execution time depends on the size of a. Computation is perfomed on of fixedsize and the leadig zeros of a of q are are also used in the computation. + @param nq length of array q that hold the quotients. The maximum length of quotient is the actual length of dividend a + @param q returned quotient. If nq is larger than needed, it is filled with leading zeros. If it is smaller, error is returned. q can be set to NULL, if not needed. + @param nr length of array r that hold the remainder. The maximum length of remainder is the actual length of divisor d + @param r returned remainder. If nr is larger than needed, it is filled with leading zeros. Ifi is smaller error is returned. r can be set to NULL if not required. + @param na length of dividend. Dividend may have leading zeros. + @param a input Dividend + @param nd length of input divisor. Divisor may have leading zeros. + @param d input Divisor + @param recip_d The reciprocal of d, of length nd+1. + + @return returns 0 if successful, negative of error. + */ +CC_NONNULL((7, 9, 10)) +#define CCN_DIV_USE_RECIP_WORKSPACE_SIZE(na,nd) (6*(CC_MAX(2*nd,na)) + 4 + na) +int ccn_div_use_recip_ws(cc_ws_t ws, cc_size nq, cc_unit *q, cc_size nr, cc_unit *r, cc_size na, const cc_unit *a, cc_size nd, const cc_unit *d, const cc_unit *recip_d); + + +/*! + @brief ccn_make_recip_newtonraphson(cc_size nd, cc_unit *recip, const cc_unit *d) computes the reciprocal of d: recip = 2^2b/d where b=bitlen(d) + @discussion This use the NewtonRaphson method. + @param nd length of array d + @param recip returned reciprocal of size nd+1 + @param d input integer + */ + +CC_NONNULL((3, 4)) +void ccn_make_recip_newtonraphson(cc_ws_t ws, cc_size nd, cc_unit *recip, const cc_unit *d); + + +/*! + @brief ccn_make_recip_shift_sub(cc_size nd, cc_unit *recip, const cc_unit *d) computes the reciprocal of d: recip = 2^2b/d where b=bitlen(d) + @discussion This use the Shift/Sub (binary division) method. + @param nd length of array d + @param recip returned reciprocal of size nd+1 + @param d input integer + */ +CC_NONNULL((3, 4)) +void ccn_make_recip_shift_sub(cc_ws_t ws, cc_size nd, cc_unit *recip, const cc_unit *d); + + +#if defined(_WIN32) + #include + #include + #if (CCN_UNIT_SIZE==8) + CC_INLINE cc_size clz64_win( uint64_t value ) + { + DWORD leading_zero; + _BitScanReverse64( &leading_zero, value ); + return 63 - leading_zero; + } + #define clz_win(x) clz64_win(x) + #elif (CCN_UNIT_SIZE<=4) + CC_INLINE cc_size clz32_win( uint32_t value ) + { + DWORD leading_zero; + _BitScanReverse( &leading_zero, value ); + return 31 - leading_zero; + } + #define clz_win(x) clz32_win(x) + #endif +#else //for clang * GNU + #if (CCN_UNIT_SIZE==8) + #define CC_BUILTIN_CLZ __builtin_clzll + #elif (CCN_UNIT_SIZE<=4) + #define CC_BUILTIN_CLZ __builtin_clzl + #endif +#endif + +/* Counts leading zeros in data, under the assumption that data is non-zero. */ +CC_INLINE CC_CONST cc_size cc_clz_nonzero(cc_unit data) { + cc_assert(data != 0); +#if defined(_WIN32) + return clz_win(data); +#elif defined __x86_64__ || defined __i386__ + /* On i386 and x86_64, we know clang and GCC will generate BSR for + * __builtin_clzl. This instruction IS NOT constant time on all micro- + * architectures, but it *is* constant time on all micro-architectures that + * have been used by Apple, and we expect that to continue to be the case. + * + * When building for x86_64h with clang, this produces LZCNT, which is exactly + * what we want. */ + return CC_BUILTIN_CLZ(data); +#elif defined __arm64__ || defined __arm__ + /* On arm and arm64, we know that clang and GCC generate the constant-time CLZ + * instruction from __builtin_clzl( ). */ + return CC_BUILTIN_CLZ(data); +#elif defined __GNUC__ +# warning Using __builtin_clzl( ) on an unknown architecture; it may not be constant-time. + /* If you find yourself seeing this warning, file a radar for someone to + * check whether or not __builtin_clzl( ) generates a constant-time + * implementation on the architecture you are targeting. If it does, append + * the name of that architecture to the list of "safe" architectures above. */ + return CC_BUILTIN_CLZ(data); +#else + #warning Using a non-constant time implementation of cc_clz_nonzero( ). + /* If you find yourself seeing this warning, the function ccn_bitlen will not + * be constant time in the resulting build of corecrypto. Please file a radar + * for someone to implement a constant-time cc_clz_nonzero for your targeted + * architecture and compiler pair. */ + cc_unit mask = CC_UNIT_C(1) << (CCN_UNIT_BITS - 1); + size_t b = 0; + while ((data & mask >> b) == 0) b++; + return b; +#endif +} + +// perform division the division a/d, whne size n of a are d are the same. Returns remainder r and +// a cc_unit quotient. To be used only in xgcd. Exported here for test purpose only. +CC_NONNULL((2, 3, 4)) +cc_unit ccn_div_equal_size(cc_size n, cc_unit *r, const cc_unit *a, const cc_unit *d); + +// Conditionally swap the content of r0 and r1 buffers in constant time +// r0:r1 <- r1*k1 + s0*(k1-1) +void ccn_cond_swap(cc_size n, + int ki, + cc_unit *r0, + cc_unit *r1); + + +#endif diff --git a/corecrypto/ccnistkdf.h b/corecrypto/ccnistkdf.h new file mode 100644 index 0000000..ba8f55a --- /dev/null +++ b/corecrypto/ccnistkdf.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2013,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCNISTKDF_H_ +#define _CORECRYPTO_CCNISTKDF_H_ + +#include + +/*! @function ccnistkdf_ctr_hmac + + @abstract Perform a NIST SP800-108 KDF in Counter Mode with an HMAC PRF. + http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf + @discussion This performs the transformation of password and salt through + an HMAC PRF of the callers slection (any Digest, typically SHA-256) + returning dkLen bytes containing the entropy. + + + @param prf Pseudo-random function to be used + @param kdkLen Key Derivation Key Length + @param kdk Key derivation key, a key that is used as an input to a key derivation function + (along with other input data) to derive keying material. + @param labelLen label length + @param label A string that identifies the purpose for the derived keying material, + which is encoded as a binary string. The encoding method for the Label + is defined in a larger context, for example, in the protocol that uses a KDF. + @param contextLen context length + @param context A binary string containing the information related to the derived keying material. + It may include identities of parties who are deriving and/or using the derived + keying material and, optionally, a nonce known by the parties who derive the keys. + @param dkLen Derived Key Length + @param dk buffer for the results of the KDF transformation, must be dkLen big + + */ + +int ccnistkdf_ctr_hmac(const struct ccdigest_info *di, + size_t kdkLen, const void *kdk, + size_t labelLen, const void *label, + size_t contextLen, const void *context, + size_t dkLen, void *dk); + +int ccnistkdf_ctr_hmac_fixed(const struct ccdigest_info *di, + size_t kdkLen, const void *kdk, + size_t fixedDataLen, const void *fixedData, + size_t dkLen, void *dk); + +/*! @function ccnistkdf_fb_hmac + + @abstract Perform a NIST SP800-108 KDF in Feedback Mode with an HMAC PRF. + http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf + + @param di digest info defining the digest type to use in the PRF. + @param use_counter determines whether a counter will be used for each round through the PRF (0 = off). + @param kdkLen Key Derivation Key Length + @param kdk Key derivation key, a key that is used as an input to a key derivation function + (along with other input data) to derive keying material. + @param labelLen label length + @param label A string that identifies the purpose for the derived keying material, + which is encoded as a binary string. The encoding method for the Label + is defined in a larger context, for example, in the protocol that uses a KDF. + @param contextLen context length + @param context A binary string containing the information related to the derived keying material. + It may include identities of parties who are deriving and/or using the derived + keying material and, optionally, a nonce known by the parties who derive the keys. + @param ivLen iv length + @param iv A binary string that is used as an initial value in computing the first iteration in + the feedback mode. It can be either public or secret. It may be an empty string. + @param dkLen Derived Key Length + @param dk buffer for the results of the KDF transformation, must be dkLen big + + */ + +int ccnistkdf_fb_hmac(const struct ccdigest_info *di, int use_counter, + size_t kdkLen, const void *kdk, + size_t labelLen, const void *label, + size_t contextLen, const void *context, + size_t ivLen, const void *iv, + size_t dkLen, void *dk); + +int ccnistkdf_fb_hmac_fixed(CC_UNUSED const struct ccdigest_info *di, int use_counter, + CC_UNUSED size_t kdkLen, CC_UNUSED const void *kdk, + CC_UNUSED size_t fixedDataLen, CC_UNUSED const void *fixedData, + CC_UNUSED size_t ivLen, CC_UNUSED const void *iv, + CC_UNUSED size_t dkLen, CC_UNUSED void *dk); + +/*! @function ccnistkdf_dpi_hmac + + @abstract Perform a NIST SP800-108 KDF in Double Pipeline Iteration Mode with an HMAC PRF. + http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf + + @param di digest info defining the digest type to use in the PRF. + @param kdkLen Key Derivation Key Length + @param kdk Key derivation key, a key that is used as an input to a key derivation function + (along with other input data) to derive keying material. + @param labelLen label length + @param label A string that identifies the purpose for the derived keying material, + which is encoded as a binary string. The encoding method for the Label + is defined in a larger context, for example, in the protocol that uses a KDF. + @param contextLen context length + @param context A binary string containing the information related to the derived keying material. + It may include identities of parties who are deriving and/or using the derived + keying material and, optionally, a nonce known by the parties who derive the keys. + @param dkLen Derived Key Length + @param dk buffer for the results of the KDF transformation, must be dkLen big + + */ + +int ccnistkdf_dpi_hmac(const struct ccdigest_info *di, + size_t kdkLen, const void *kdk, + size_t labelLen, const void *label, + size_t contextLen, const void *context, + size_t dkLen, void *dk); + + +#endif /* _CORECRYPTO_CCNISTKDF_H_ */ diff --git a/corecrypto/ccpad.h b/corecrypto/ccpad.h new file mode 100644 index 0000000..07fa19e --- /dev/null +++ b/corecrypto/ccpad.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCPAD_H_ +#define _CORECRYPTO_CCPAD_H_ + +#include + +// CTS1,2,3 are defined in Addendum to 800-38A, +// "Cipher Modes of Operation: Three Variants of Ciphertext Stealing for CBC Mode" +// CTS3 is also known as "CTS" in RFC3962 + +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +size_t ccpad_cts1_decrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); + +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +size_t ccpad_cts1_encrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +size_t ccpad_cts2_decrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); + +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +size_t ccpad_cts2_encrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +size_t ccpad_cts3_decrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); + +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +size_t ccpad_cts3_encrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); + +/* Contract is nbytes is non zero and a multiple of block_size. Furthermore in is nbytes long and out is nbytes long. Returns number of bytes written to out (technically we always write nbytes to out but the returned value is the number of bytes decrypted after removal of padding. + + To be safe we remove the entire offending block if the pkcs7 padding checks failed. However we purposely don't report the failure to decode the padding since any use of this error leads to potential security exploits. So currently there is no way to distinguish between a full block of padding and bad padding. + */ +size_t ccpad_pkcs7_decrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); + +/* Contract is in is nbytes long. Writes (nbytes / block_size) + 1 times block_size to out. In other words, out must be nbytes rounded down to the closest multiple of block_size plus block_size bytes. */ +size_t ccpad_pkcs7_encrypt(const struct ccmode_cbc *cbc, cccbc_ctx *ctx, cccbc_iv *iv, + size_t nbytes, const void *in, void *out); + +/* Contract is 'don't break CommonCrypto functionality that allows PKCS7 padding with ECB mode'. This is basically the same routines above, without an IV, because calling + crypt with an IV makes ecb cry (and crash) */ + +size_t ccpad_pkcs7_ecb_decrypt(const struct ccmode_ecb *ecb, ccecb_ctx *ecb_key, + size_t nbytes, const void *in, void *out); + +size_t ccpad_pkcs7_ecb_encrypt(const struct ccmode_ecb *ecb, ccecb_ctx *ctx, + size_t nbytes, const void *in, void *out); + +/* Function common to ccpad_pkcs7_ecb_decrypt and ccpad_pkcs7_decrypt */ +size_t ccpad_pkcs7_decode(const size_t block_size, const uint8_t* last_block); + +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +size_t ccpad_xts_decrypt(const struct ccmode_xts *xts, ccxts_ctx *ctx, ccxts_tweak *tweak, + size_t nbytes, const void *in, void *out); + +/* Contract is nbytes is at least 1 block + 1 byte. Also in is nbytes long out is nbytes long. */ +void ccpad_xts_encrypt(const struct ccmode_xts *xts, ccxts_ctx *ctx, ccxts_tweak *tweak, + size_t nbytes, const void *in, void *out); + +#endif /* _CORECRYPTO_CCPAD_H_ */ diff --git a/corecrypto/ccpbkdf2.h b/corecrypto/ccpbkdf2.h new file mode 100644 index 0000000..f8f09fa --- /dev/null +++ b/corecrypto/ccpbkdf2.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010,2011,2012,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCPBKDF2_H_ +#define _CORECRYPTO_CCPBKDF2_H_ + +#include + +/*! @function ccpbkdf2_hmac + @abstract perform a pbkdf2 using HMAC(di) for the PRF (see PKCS#5 for specification) + @discussion This performs a standard PBKDF2 transformation of password and salt through +an HMAC PRF of the callers slection (any Digest, typically SHA-1) returning dkLen bytes +containing the entropy. + +Considerations: +The salt used should be at least 8 bytes long. Each session should use it's own salt. +We use the password as the key for the HMAC and the running data as the text for the HMAC to make a PRF. +SHA-1 is a good hash to use for the core of the HMAC PRF. + @param di digest info defining the digest type to use in the PRF. + @param passwordLen amount of data to be fed in + @param password data to be fed into the PBKDF + @param saltLen length of the salt + @param salt salt to be used in pbkdf + @param iterations itrations to go + @param dkLen length of the results + @param dk buffer for the results of the PBKDF tranformation, must be dkLen big + + */ +int ccpbkdf2_hmac(const struct ccdigest_info *di, + size_t passwordLen, const void *password, + size_t saltLen, const void *salt, + size_t iterations, + size_t dkLen, void *dk); + +#endif /* _CORECRYPTO_CCPBKDF2_H_ */ diff --git a/corecrypto/ccperf.h b/corecrypto/ccperf.h new file mode 100644 index 0000000..78038f2 --- /dev/null +++ b/corecrypto/ccperf.h @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2010,2011,2013,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCPERF_H_ +#define _CORECRYPTO_CCPERF_H_ + +#include +#include +#include "cctime.h" +#include "ccstats.h" +#include + +/** RNG instance used for perf tests */ +extern struct ccrng_state *rng; + + +struct ccperf_test { + const char *name; +}; + +/** perf family **/ + +enum ccperf_size_kind { + ccperf_size_bytes = 0, + ccperf_size_bits, + ccperf_size_iterations, + ccperf_size_units, +}; + +struct ccperf_family { + const char *name; + double(*func)(size_t loops, size_t size, const void *test); + struct ccperf_test **tests; + size_t ntests; + size_t *sizes; + size_t nsizes; + size_t loops; + enum ccperf_size_kind size_kind; + size_t nruns; + double run_time; +}; + +// Stop iterating after reaching timeout +#define RUN_TIMEOUT 10.0 + +#define numof(_x_) (sizeof(_x_)/sizeof(_x_[0])) + +/* Some macros used by family factories */ + +#define F_ARGS(_f) _f##_perf_tests +#define F_FUNC(_f) perf_##_f +#define F_SZ(_f) sizeof(F_ARGS(_f)[0]) +#define F_N(_f) numof(F_ARGS(_f)) + +#define F_GET_ALL(_family, _f) \ +do { \ + _family.name = #_f; \ + _family.func=F_FUNC(_f); \ + ccperf_family_select(&_family, F_N(_f), F_ARGS(_f), F_SZ(_f), argc, argv); \ + _family.loops=1; \ +} while(0) + +#define F_GET_ALL2(_family, _f, _func) \ +do { \ + _family.name = #_func; \ + _family.func=F_FUNC(_func); \ + ccperf_family_select(&_family, F_N(_f), F_ARGS(_f), F_SZ(_f), argc, argv); \ + _family.loops=1; \ +} while(0) + +#define F_SIZES(_family, _n, _first) ccperf_family_set_pot_sizes(&_family, (_n), (_first)) + +#define F_SIZES_FROM_ARRAY(_family, _const_array) {\ + _family.nsizes=sizeof(_const_array)/sizeof(_const_array[0]); \ + _family.sizes=malloc(sizeof(_const_array)); \ + memcpy(_family.sizes,_const_array,sizeof(_const_array));\ + } + +#define F_DEFINE(_fam, _oper, _kind, _n, _first) \ +static struct ccperf_family _fam##_##_oper##_family; \ +struct ccperf_family *ccperf_family_##_fam##_##_oper(int argc, char *argv[]) \ +{ \ + ccperf_family_##_fam##_once(argc, argv); \ + F_GET_ALL2(_fam##_##_oper##_family, _fam, _fam##_##_oper); \ + F_SIZES(_fam##_##_oper##_family, _n, _first); \ + _fam##_##_oper##_family.size_kind=_kind; \ + return &_fam##_##_oper##_family; \ +} + + +/* family factories */ +struct ccperf_family *ccperf_family_ccecb_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccecb_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccecb_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccbc_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccbc_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccbc_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccfb8_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccfb8_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccfb8_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccfb_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccfb_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccfb_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccctr_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccctr_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccctr_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccgcm_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccgcm_gmac(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccgcm_set_iv(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccgcm_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccgcm_finalize(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccgcm_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccccm_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccccm_cbcmac(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccccm_set_iv(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccccm_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccccm_finalize(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccccm_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccofb_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccofb_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccofb_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccomac_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccomac_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccomac_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccxts_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccxts_set_tweak(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccxts_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccxts_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccchacha_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccchacha_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccchacha_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccpoly_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccpoly_update(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccpoly_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccchachapoly_encrypt_and_sign(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccchachapoly_decrypt_and_verify(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccsiv_init(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccsiv_aad_or_nonce(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccsiv_one_shot(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccdigest(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cchmac(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccn(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cczp(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccec(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccec25519(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccrsa(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccpbkdf2(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccsrp(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccansikdf(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cccmac(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccrng(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccdrbg(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccdh_generate_key(int argc, char *argv[]); +struct ccperf_family *ccperf_family_ccdh_compute_shared_secret(int argc, char *argv[]); +struct ccperf_family *ccperf_family_cczp_inv(int argc, char *argv[]); + +/* utility functions */ + +double histogram_sieve(struct ccperf_family *f, size_t size, const void *arg); + +void ccperf_family_select(struct ccperf_family *f, size_t ntests, void *tests, size_t testsz, int argc, char **argv); +void ccperf_family_set_pot_sizes(struct ccperf_family *f, size_t nsizes, size_t first); +int ccperf_main(int argc, char **argv); + +#endif /* _CORECRYPTO_CCPERF_H_ */ diff --git a/corecrypto/ccprime.h b/corecrypto/ccprime.h new file mode 100644 index 0000000..b4c862a --- /dev/null +++ b/corecrypto/ccprime.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef _CORECRYPTO_CCPRIME_H_ +#define _CORECRYPTO_CCPRIME_H_ + +#include + +/* Perform rabin miller primality testing on zp, return 1 if p is prime + return 0 otherwise. */ +CC_NONNULL_TU((1)) +int ccprime_rabin_miller(cczp_t zp, size_t mr_depth); + +/* Generate a random nbits sized prime in zp. zp will be guaranteed + relatively prime to e. */ +CC_NONNULL_TU((2)) CC_NONNULL((3, 4)) +int ccprime_generate(cc_size nbits, cczp_t zp, const cc_unit *e, + struct ccrng_state *rng); + + +#endif //_CORECRYPTO_CCPRIME_H_ diff --git a/corecrypto/ccrc2.h b/corecrypto/ccrc2.h new file mode 100644 index 0000000..8a45016 --- /dev/null +++ b/corecrypto/ccrc2.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2010,2012,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRC2_H_ +#define _CORECRYPTO_CCRC2_H_ + +#include + +#define CCRC2_BLOCK_SIZE 8 + +extern const struct ccmode_ecb ccrc2_ltc_ecb_decrypt_mode; +extern const struct ccmode_ecb ccrc2_ltc_ecb_encrypt_mode; + +const struct ccmode_ecb *ccrc2_ecb_decrypt_mode(void); +const struct ccmode_ecb *ccrc2_ecb_encrypt_mode(void); + +const struct ccmode_cbc *ccrc2_cbc_decrypt_mode(void); +const struct ccmode_cbc *ccrc2_cbc_encrypt_mode(void); + +const struct ccmode_cfb *ccrc2_cfb_decrypt_mode(void); +const struct ccmode_cfb *ccrc2_cfb_encrypt_mode(void); + +const struct ccmode_cfb8 *ccrc2_cfb8_decrypt_mode(void); +const struct ccmode_cfb8 *ccrc2_cfb8_encrypt_mode(void); + +const struct ccmode_ctr *ccrc2_ctr_crypt_mode(void); + +const struct ccmode_ofb *ccrc2_ofb_crypt_mode(void); + + +#endif /* _CORECRYPTO_CCRC2_H_ */ diff --git a/corecrypto/ccrc4.h b/corecrypto/ccrc4.h new file mode 100644 index 0000000..1970ab8 --- /dev/null +++ b/corecrypto/ccrc4.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRC4_H_ +#define _CORECRYPTO_CCRC4_H_ + +#include + +cc_aligned_struct(16) ccrc4_ctx; + +/* Declare a rc4 key named _name_. Pass the size field of a struct ccmode_ecb + for _size_. */ +#define ccrc4_ctx_decl(_size_, _name_) cc_ctx_decl(ccrc4_ctx, _size_, _name_) +#define ccrc4_ctx_clear(_size_, _name_) cc_clear(_size_, _name_) + +struct ccrc4_info { + size_t size; /* first argument to ccrc4_ctx_decl(). */ + void (*init)(ccrc4_ctx *ctx, size_t key_len, const void *key); + void (*crypt)(ccrc4_ctx *ctx, size_t nbytes, const void *in, void *out); +}; + + +const struct ccrc4_info *ccrc4(void); + +extern const struct ccrc4_info ccrc4_eay; + +struct ccrc4_vector { + size_t keylen; + const void *key; + size_t datalen; + const void *pt; + const void *ct; +}; + +int ccrc4_test(const struct ccrc4_info *rc4, const struct ccrc4_vector *v); + +#endif /* _CORECRYPTO_CCRC4_H_ */ diff --git a/corecrypto/ccripemd.h b/corecrypto/ccripemd.h new file mode 100644 index 0000000..109d3d8 --- /dev/null +++ b/corecrypto/ccripemd.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRIPEMD_H_ +#define _CORECRYPTO_CCRIPEMD_H_ + +#include + +#define CCRMD_BLOCK_SIZE 64 + +#define CCRMD128_OUTPUT_SIZE 16 +#define CCRMD160_OUTPUT_SIZE 20 +#define CCRMD256_OUTPUT_SIZE 32 +#define CCRMD320_OUTPUT_SIZE 40 + +#define CCRMD128_STATE_SIZE 16 +#define CCRMD160_STATE_SIZE 20 +#define CCRMD256_STATE_SIZE 32 +#define CCRMD320_STATE_SIZE 40 + +extern const uint32_t ccrmd_initial_state[4]; + +extern const struct ccdigest_info ccrmd128_ltc_di; +extern const struct ccdigest_info ccrmd160_ltc_di; +extern const struct ccdigest_info ccrmd256_ltc_di; +extern const struct ccdigest_info ccrmd320_ltc_di; + +/* default is libtomcrypt */ +#define ccrmd128_di ccrmd128_ltc_di +#define ccrmd160_di ccrmd160_ltc_di +#define ccrmd256_di ccrmd256_ltc_di +#define ccrmd320_di ccrmd320_ltc_di + +#endif /* _CORECRYPTO_CCRIPEMD_H_ */ diff --git a/corecrypto/ccrng.h b/corecrypto/ccrng.h new file mode 100644 index 0000000..f4d0232 --- /dev/null +++ b/corecrypto/ccrng.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2010,2013,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRNG_H_ +#define _CORECRYPTO_CCRNG_H_ + +#include + +#define CCERR_DEVICE -100 +#define CCERR_INTERUPTS -101 +#define CCERR_CRYPTO_CONFIG -102 +#define CCERR_PERMS -103 +#define CCERR_PARAMETER -104 +#define CCERR_MEMORY -105 +#define CCERR_FILEDESC -106 +#define CCERR_OUT_OF_ENTROPY -107 +#define CCERR_INTERNAL -108 +#define CCERR_ATFORK -109 +#define CCERR_OVERFLOW -110 + +#define CCRNG_STATE_COMMON \ + int (*generate)(struct ccrng_state *rng, size_t outlen, void *out); + +/* default state structure. Do not instantiate, ccrng() returns a reference to this structure */ +struct ccrng_state { + CCRNG_STATE_COMMON +}; + +/*! + @function ccrng + @abstract initializes a AES-CTR mode cryptographic random number generator and returns the statically alocated rng object. + Getting a pointer to a ccrng has never been simpler! + Call this function, get an rng object and then pass the object to ccrng_generate() to generate randoms. + ccrng() may be called more than once. It returns pointer to the same object on all calls. + + @result a cryptographically secure random number generator or NULL if fails + + @discussion + - It is significantly faster than using the system /dev/random + - FIPS Compliant: NIST SP800-80A + FIPS 140-2 + - Seeded from the system entropy. + - Provides at least 128bit security if the system provide 2bit of entropy / byte. + - Entropy accumulation + - Backtracing resistance + - Prediction break with frequent (asynchronous) reseed + */ + +struct ccrng_state *ccrng(int *error); + +//call this macro with the rng argument set to output of the call to the ccrng() function +#define ccrng_generate(rng, outlen, out) ((rng)->generate((struct ccrng_state *)(rng), (outlen), (out))) + +#endif /* _CORECRYPTO_CCRNG_H_ */ diff --git a/corecrypto/ccrng_drbg.h b/corecrypto/ccrng_drbg.h new file mode 100644 index 0000000..2123480 --- /dev/null +++ b/corecrypto/ccrng_drbg.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_ccrng_drbg_h +#define corecrypto_ccrng_drbg_h + +#include +#include + +struct ccrng_drbg_state { + CCRNG_STATE_COMMON + const struct ccdrbg_info *drbg_info; + struct ccdrbg_state *drbg_state; +}; + +// Setup a RNG based on a DRBG. +// Init calls the init from the DRBG +int ccrng_drbg_init(struct ccrng_drbg_state *rng, + const struct ccdrbg_info *drbg_info, + struct ccdrbg_state *drbg_state, + size_t length, const void *seed); + +// Reseed underlying DRBG +int ccrng_drbg_reseed(struct ccrng_drbg_state *rng, + size_t entropylen, const void *entropy, + size_t inlen, const void *in); + +// Clear the DRBG +void ccrng_drbg_done(struct ccrng_drbg_state *rng); + +#endif diff --git a/corecrypto/ccrng_ecfips_test.h b/corecrypto/ccrng_ecfips_test.h new file mode 100644 index 0000000..66dd465 --- /dev/null +++ b/corecrypto/ccrng_ecfips_test.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +// To be used to set the scalar to a known fix value +// May fail if value is not as expect. + +#ifndef _CORECRYPTO_CCRNG_ECFIPS_TEST_H_ +#define _CORECRYPTO_CCRNG_ECFIPS_TEST_H_ + +#include +#include + +struct ccrng_ecfips_test_state { + CCRNG_STATE_COMMON + uint8_t *state; + size_t len; +}; + +int ccrng_ecfips_test_init(struct ccrng_ecfips_test_state *rng, + size_t len, uint8_t *sequence); + +#endif /* _CORECRYPTO_CCRNG_ECFIPS_TEST_H_ */ diff --git a/corecrypto/ccrng_pbkdf2_prng.h b/corecrypto/ccrng_pbkdf2_prng.h new file mode 100644 index 0000000..742f1d6 --- /dev/null +++ b/corecrypto/ccrng_pbkdf2_prng.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_ccrng_pbkdf2_prng_h +#define corecrypto_ccrng_pbkdf2_prng_h + +#include +#include +#include + + +#define CCRNG_PBKDF2_BUFFER 4096 + +// This RNG is limited to provide min("CCRNG_PBKDF2_BUFFER",maxbytes) of cumulated pseudo random bytes. +// Pseudo random bytes can be obtained with one or several "generate" +// When out of random, the generate function will persistently fail until a new initialization of the context is performed. + +struct ccrng_pbkdf2_prng_state { + CCRNG_STATE_COMMON + size_t random_buffer_size; + uint8_t random_buffer[CCRNG_PBKDF2_BUFFER]; +}; + + +int ccrng_pbkdf2_prng_init(struct ccrng_pbkdf2_prng_state *rng, size_t maxbytes, + size_t passwordLen, const void *password, + size_t saltLen, const void *salt, + size_t iterations); + +#endif diff --git a/corecrypto/ccrng_priv.h b/corecrypto/ccrng_priv.h new file mode 100644 index 0000000..201347d --- /dev/null +++ b/corecrypto/ccrng_priv.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRNG_PRIV_H_ +#define _CORECRYPTO_CCRNG_PRIV_H_ + +#include +#if CC_KERNEL + #include +#else + #include +#endif + +int cc_get_entropy(size_t entropy_size, void *entropy); + + +#endif /* _CORECRYPTO_CCRNG_PRIV_H_ */ diff --git a/corecrypto/ccrng_rsafips_test.h b/corecrypto/ccrng_rsafips_test.h new file mode 100644 index 0000000..ac7a4c8 --- /dev/null +++ b/corecrypto/ccrng_rsafips_test.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRNG_RSAFIPS_TEST_H_ +#define _CORECRYPTO_CCRNG_RSAFIPS_TEST_H_ + +#include +#include + +struct ccrng_rsafips_test_state { + CCRNG_STATE_COMMON + uint8_t *state; + cc_size index; + cc_size r1Len; + const cc_unit *r1; + cc_size r2Len; + const cc_unit *r2; + cc_size XLen; + const cc_unit *X; +}; + +int +ccrng_rsafips_test_init(struct ccrng_rsafips_test_state *rng, + const cc_size r1Len, const cc_unit *r1, + const cc_size r2Len, const cc_unit *r2, + const cc_size XLen, const cc_unit *X); + +#endif /* _CORECRYPTO_CCRNG_RSAFIPS_TEST_H_ */ diff --git a/corecrypto/ccrng_sequence.h b/corecrypto/ccrng_sequence.h new file mode 100644 index 0000000..acf2023 --- /dev/null +++ b/corecrypto/ccrng_sequence.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRNG_SEQUENCE_H_ +#define _CORECRYPTO_CCRNG_SEQUENCE_H_ + +#include +#include + +struct ccrng_sequence_state { + CCRNG_STATE_COMMON + const uint8_t *state; + size_t len; +}; + +int ccrng_sequence_init(struct ccrng_sequence_state *rng, size_t len, const uint8_t *sequence); + +int ccrng_sequence_non_repeat_init(struct ccrng_sequence_state *rng, size_t len, const uint8_t *sequence); + +#endif /* _CORECRYPTO_CCRNG_SEQUENCE_H_ */ diff --git a/corecrypto/ccrng_system.h b/corecrypto/ccrng_system.h new file mode 100644 index 0000000..1b88222 --- /dev/null +++ b/corecrypto/ccrng_system.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010,2013,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRNG_SYSTEM_H_ +#define _CORECRYPTO_CCRNG_SYSTEM_H_ + +#include + +struct ccrng_system_state { + CCRNG_STATE_COMMON + int fd; +}; + +/*! + @function ccrng_system_init - DEPRECATED + @abstract Default ccrng. + Please transition to ccrng() which is easier to use and with provide the fastest, most secure option + + @param rng Structure containing the state of the RNG, must remain allocated as + long as the rng is used. + @result 0 iff successful + + @discussion + This RNG require call to "init" AND "done", otherwise it may leak a file descriptor. + */ + +// Initialize ccrng +// Deprecated, if you need a rng, just call the function ccrng() +int ccrng_system_init(struct ccrng_system_state *rng); + +// Close the system RNG +// Mandatory step to avoid leaking file descriptor +void ccrng_system_done(struct ccrng_system_state *rng); + +#endif /* _CORECRYPTO_CCRNG_SYSTEM_H_ */ diff --git a/corecrypto/ccrng_test.h b/corecrypto/ccrng_test.h new file mode 100644 index 0000000..8f04c18 --- /dev/null +++ b/corecrypto/ccrng_test.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011,2014,2015,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRNG_TEST_H_ +#define _CORECRYPTO_CCRNG_TEST_H_ + +#include +#include + +struct ccrng_test_state { + CCRNG_STATE_COMMON + + struct ccdrbg_info drbg_info; + struct ccdrbg_state *drbg_state; +}; + +int ccrng_test_init(struct ccrng_test_state *rng, size_t length, const void *seed, + const char *personalization_string); + +void ccrng_test_done(struct ccrng_test_state *rng); + +#endif /* _CORECRYPTO_CCRNG_TEST_H_ */ diff --git a/corecrypto/ccrsa.h b/corecrypto/ccrsa.h new file mode 100644 index 0000000..7d84b52 --- /dev/null +++ b/corecrypto/ccrsa.h @@ -0,0 +1,663 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRSA_H_ +#define _CORECRYPTO_CCRSA_H_ + +#include +#include +#include +#include +#include + +// Apple does not generate keys of greater than 4096 bits +// This limit is relaxed to accommodate potential third-party consumers +#define CCRSA_KEYGEN_MAX_NBITS 8192 + +// Program error: buffer too small or encrypted message is too small +#define CCRSA_INVALID_INPUT -1 +// Invalid crypto configuration: Hash length versus RSA key size +#define CCRSA_INVALID_CONFIG -2 +// The data is invalid (we won't say more for security +#define CCRSA_DECRYPTION_ERROR -3 + +#define CCRSA_ENCODING_ERROR -4 +#define CCRSA_DECODING_ERROR -5 +#define CCRSA_SIGNATURE_GEN_ERROR -6 + +struct ccrsa_full_ctx { + __CCZP_ELEMENTS_DEFINITIONS(pb_) +} CC_ALIGNED(CCN_UNIT_SIZE); + +struct ccrsa_pub_ctx { + __CCZP_ELEMENTS_DEFINITIONS(pb_) +} CC_ALIGNED(CCN_UNIT_SIZE); + +struct ccrsa_priv_ctx { + __CCZP_ELEMENTS_DEFINITIONS(pv_) +} CC_ALIGNED(CCN_UNIT_SIZE); + + +#if CORECRYPTO_USE_TRANSPARENT_UNION + typedef union { + cczp_t zp; + struct ccrsa_pub_ctx* pub; + struct ccrsa_full_ctx *full; + } ccrsa_full_ctx_t __attribute__((transparent_union)); + typedef struct ccrsa_full_ctx ccrsa_full_ctx; + typedef struct ccrsa_priv_ctx ccrsa_priv_ctx; + + typedef union { + cczp_t zp; + ccrsa_priv_ctx *priv; + } ccrsa_priv_ctx_t __attribute__((transparent_union)); + + +typedef ccrsa_full_ctx_t ccrsa_pub_ctx_t; +typedef struct ccrsa_pub_ctx ccrsa_pub_ctx; + +#else + typedef struct ccrsa_full_ctx* ccrsa_full_ctx_t; + typedef struct ccrsa_pub_ctx* ccrsa_pub_ctx_t; + typedef struct ccrsa_priv_ctx* ccrsa_priv_ctx_t; +#endif + + + +/* + public key cczp d=e^-1 mod phi(m) priv key cczp priv key cczq dp, dq, qinv + | | | | | + | | | | | + +-------+------+-------+------++------++-------+------+---------++-------+------+---------++-------+-------+---------+ + | zm_hd | m[n] |mr[n+1]| e[n] || d[n] || zp_hd |p[n/2]|pr[n/2+1]|| zq_hd |q[n/2]|qr[n/2+1]||dp[n/2]|dq[n/2]|qinv[n/2]| + +-------+------+-------+------++------++-------+------+---------++-------+------+---------++-------+-------+---------+ + */ + + /* Return the size of an ccec_full_ctx where each ccn is _size_ bytes. Get _size_ through ccn_sizeof(nbits) */ + +/* Return the size of an ccec_full_ctx where each ccn is _size_ bytes. */ + +#define ccrsa_pub_ctx_size(_size_) (sizeof(struct cczp) + CCN_UNIT_SIZE + 3 * (_size_)) +#define ccrsa_priv_ctx_size(_size_) ((sizeof(struct cczp) + CCN_UNIT_SIZE) * 2 + 7 * ccn_sizeof(ccn_bitsof_size(_size_)/2 + 1)) +#define ccrsa_full_ctx_size(_size_) (ccrsa_pub_ctx_size(_size_) + _size_ + ccrsa_priv_ctx_size(_size_)) + +/* Declare a fully scheduled rsa key. Size is the size in bytes each ccn in + the key. For example to declare (on the stack or in a struct) a 1021 bit + rsa public key named foo use ccrsa_pub_ctx_decl(ccn_sizeof(1021), foo). + */ +#define ccrsa_full_ctx_decl(_size_, _name_) cc_ctx_decl(struct ccrsa_full_ctx, ccrsa_full_ctx_size(_size_), _name_) +#define ccrsa_full_ctx_clear(_size_, _name_) cc_clear(ccrsa_full_ctx_size(_size_), _name_) +#define ccrsa_pub_ctx_decl(_size_, _name_) cc_ctx_decl(struct ccrsa_pub_ctx, ccrsa_pub_ctx_size(_size_), _name_) +#define ccrsa_pub_ctx_clear(_size_, _name_) cc_clear(ccrsa_pub_ctx_size(_size_), _name_) + +// accessors to ccrsa full and public key fields. */ +// The offsets are computed using pb_ccn. If any object other than ccrsa_full_ctx_t +// or ccrsa_pub_ctx_t is passed to the macros, compiler error is generated. + + + +#if CORECRYPTO_USE_TRANSPARENT_UNION +//#define ccrsa_ctx_zm(_ctx_) (((ccrsa_pub_ctx_t)(_ctx_)).zp) + + CC_CONST CC_INLINE cczp_t ccrsa_ctx_zm(ccrsa_full_ctx_t _ctx_) { return ((cczp_t)(struct cczp *)((_ctx_).full)); } + CC_CONST CC_INLINE cc_unit *ccrsa_ctx_m(ccrsa_full_ctx_t _ctx_){ return ((_ctx_).full->pb_ccn);} + #define ccrsa_ctx_n(_ctx_) (ccrsa_ctx_zm(_ctx_).zp->n) +#else + #define ccrsa_ctx_zm(_ctx_) ((cczp_t)(_ctx_)) + #define ccrsa_ctx_n(_ctx_) (ccrsa_ctx_zm(_ctx_)->n) + #define ccrsa_ctx_m(_ctx_) ((_ctx_)->pb_ccn) +#endif + +#define ccrsa_ctx_e(_ctx_) (ccrsa_ctx_m(_ctx_) + 2 * ccrsa_ctx_n(_ctx_) + 1) +#define ccrsa_ctx_d(_ctx_) (ccrsa_ctx_m(_ctx_) + 3 * ccrsa_ctx_n(_ctx_) + 1) + +// accessors to ccrsa private key fields +// The offsets are computed using pv_ccn. If any object other than ccrsa_priv_ctx_t +// is passed to the macros, compiler error is generated. +#if CORECRYPTO_USE_TRANSPARENT_UNION + +/* rvalue accessors to ccec_key fields. */ +CC_CONST CC_INLINE +ccrsa_priv_ctx_t ccrsa_get_private_ctx_ptr(ccrsa_full_ctx_t fk) { + cc_unit *p = (cc_unit *)fk.full; + cc_size p_size = ccrsa_ctx_n(fk); + p += ccn_nof_size(ccrsa_pub_ctx_size(ccn_sizeof_n(p_size))) + p_size; + ccrsa_priv_ctx *priv = (ccrsa_priv_ctx *)p; + return (ccrsa_priv_ctx_t)priv; +} + +CC_CONST CC_INLINE +ccrsa_pub_ctx_t ccrsa_ctx_public(ccrsa_full_ctx_t fk) { + return (ccrsa_pub_ctx_t) fk.full; +} + +#define ccrsa_ctx_private_zp(FK) ((ccrsa_get_private_ctx_ptr(FK)).zp) +#define ccrsa_ctx_private_zq(FK) ((cczp_t)((ccrsa_get_private_ctx_ptr(FK)).zp.zp->ccn + 2 * ccrsa_ctx_private_zp(FK).zp->n + 1)) +#define ccrsa_ctx_private_dp(FK) ((ccrsa_get_private_ctx_ptr(FK)).zp.zp->ccn + 4 * ccrsa_ctx_private_zp(FK).zp->n + 2 + ccn_nof_size(sizeof(struct cczp))) +#define ccrsa_ctx_private_dq(FK) ((ccrsa_get_private_ctx_ptr(FK)).zp.zp->ccn + 5 * ccrsa_ctx_private_zp(FK).zp->n + 2 + ccn_nof_size(sizeof(struct cczp))) +#define ccrsa_ctx_private_qinv(FK) ((ccrsa_get_private_ctx_ptr(FK)).zp.zp->ccn + 6 * ccrsa_ctx_private_zp(FK).zp->n + 2 + ccn_nof_size(sizeof(struct cczp))) + +#else +#define ccrsa_ctx_private_zp(FK) ((cczp_t)ccrsa_get_private_ctx_ptr(FK)) +#define ccrsa_ctx_private_zq(FK) ((cczp_t)((ccrsa_get_private_ctx_ptr(FK))->pv_ccn + 2 * ccrsa_ctx_private_zp(FK)->n + 1)) +#define ccrsa_ctx_private_dp(FK) ((ccrsa_get_private_ctx_ptr(FK))->pv_ccn + 4 * ccrsa_ctx_private_zp(FK)->n + 2 + ccn_nof_size(sizeof(struct cczp))) +#define ccrsa_ctx_private_dq(FK) ((ccrsa_get_private_ctx_ptr(FK))->pv_ccn + 5 * ccrsa_ctx_private_zp(FK)->n + 2 + ccn_nof_size(sizeof(struct cczp))) +#define ccrsa_ctx_private_qinv(FK) ((ccrsa_get_private_ctx_ptr(FK))->pv_ccn + 6 * ccrsa_ctx_private_zp(FK)->n + 2 + ccn_nof_size(sizeof(struct cczp))) + +CC_CONST CC_INLINE +ccrsa_priv_ctx_t ccrsa_get_private_ctx_ptr(ccrsa_full_ctx_t fk) { + ccrsa_priv_ctx_t priv = (ccrsa_priv_ctx_t)(ccrsa_ctx_d(fk)+ccrsa_ctx_n(fk)); + return priv; +} + +/*! + @function ccrsa_ctx_public + @abstract gets the public key from full key + @param fk RSA full key + @result Returns RSA public ker + */ +CC_CONST CC_INLINE +ccrsa_pub_ctx_t ccrsa_ctx_public(ccrsa_full_ctx_t fk) { + return (ccrsa_pub_ctx_t) fk; +} + +#endif + +/* Return exact key bit size */ +static inline size_t +ccrsa_pubkeylength(ccrsa_pub_ctx_t pubk) { + return cczp_bitlen(ccrsa_ctx_zm(pubk)); +} + +/* PKCS1 pad_markers */ +#define CCRSA_PKCS1_PAD_SIGN 1 +#define CCRSA_PKCS1_PAD_ENCRYPT 2 + +/* Initialize key based on modulus and e as cc_unit. key->zp.n must already be set. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +int ccrsa_init_pub(ccrsa_pub_ctx_t key, const cc_unit *modulus, + const cc_unit *e); + +/* Initialize key based on modulus and e as big endian byte array + key->zp.n must already be set. */ +CC_NONNULL_TU((1)) CC_NONNULL((3 ,5)) +int ccrsa_make_pub(ccrsa_pub_ctx_t pubk, + size_t exp_nbytes, const uint8_t *exp, + size_t mod_nbytes, const uint8_t *mod); + +/* Do a public key crypto operation (typically verify or encrypt) on in and put + the result in out. Both in and out should be cc_unit aligned and + ccrsa_key_n(key) units long. Clients should use ccn_read_uint() to + convert bytes to a cc_unit to use for this API.*/ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +int ccrsa_pub_crypt(ccrsa_pub_ctx_t key, cc_unit *out, const cc_unit *in); + +/* Generate an nbit rsa key pair in key, which should be allocated using + ccrsa_full_ctx_decl(ccn_sizeof(1024), rsa_ctx). The unsigned big endian + byte array exponent e of length e_size is used as the exponent. It's an + error to call this function with an exponent larger than nbits. rng + must be a pointer to an initialized struct ccrng_state. */ +CC_NONNULL_TU((2)) CC_NONNULL((4, 5)) +int ccrsa_generate_key(size_t nbits, ccrsa_full_ctx_t rsa_ctx, + size_t e_size, const void *e, struct ccrng_state *rng) CC_WARN_RESULT; + +/* Generate RSA key in conformance with FIPS186-4 standard */ +CC_NONNULL_TU((2)) CC_NONNULL((4, 5, 6)) +int +ccrsa_generate_fips186_key(size_t nbits, ccrsa_full_ctx_t fk, + size_t e_size, const void *eBytes, + struct ccrng_state *rng1, struct ccrng_state *rng2) CC_WARN_RESULT; + +/* Construct RSA key from fix input in conformance with FIPS186-4 standard */ +CC_NONNULL_TU((16)) CC_NONNULL((3, 5, 7, 9, 11, 13, 15)) +int +ccrsa_make_fips186_key(size_t nbits, + const cc_size e_n, const cc_unit *e, + const cc_size xp1Len, const cc_unit *xp1, const cc_size xp2Len, const cc_unit *xp2, + const cc_size xpLen, const cc_unit *xp, + const cc_size xq1Len, const cc_unit *xq1, const cc_size xq2Len, const cc_unit *xq2, + const cc_size xqLen, const cc_unit *xq, + ccrsa_full_ctx_t fk, + cc_size *np, cc_unit *r_p, + cc_size *nq, cc_unit *r_q, + cc_size *nm, cc_unit *r_m, + cc_size *nd, cc_unit *r_d); + +/*! + * @brief ccrsa_sign_pss() generates RSASSA-PSS signature in PKCS1-V2 format + * + * note that in RSASSA-PSS, salt length is part of the signature as specified in ASN1 + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] TrailerField DEFAULT trailerFieldBC + * + * + * FIPS 186-4 for RSASSA-PSS: + * .... Both signature schemes are approved for use, but additional constraints are imposed beyond those specified in PKCS #1 v2.1..... + * + * • If nlen = 1024 bits (i.e., 128 bytes), and the output length of the approved hash function output block is 512 bits (i.e., 64 bytes), then the length (in bytes) of the salt (sLen) shall satisfy 0 ≤ sLen ≤ hLen – 2, + * • Otherwise, the length (in bytes) of the salt (sLen) shall satisfy 0 ≤ sLen ≤ hLen, where hLen is the length of the hash function output block (in bytes). + * + * + * • CAVS test vectors are not very useful in the case of RSA-PSS, because they only validate the exponentiation part of the signature. See: http://csrc.nist.gov/groups/STM/cavp/documents/components/RSA2SP1VS.pdf + * + * @param key The RSA key + * @param hashAlgorithm The hash algorithm used to generate mHash from the original message. It is also used inside the PSS encoding function. This is also the hash function to be used in the mask generation function (MGF) + * @param MgfHashAlgorithm The hash algorithm for thr mask generation function + * @param rng Random number geberator to generate salt in PSS encoding + * @param saltSize Intended length of the salt + * @param hSize Length of message hash . Must be equal to hashAlgorithm->output_size + * @param mHash The input that needs to be signed. This is the hash of message M with length of hLen + * + * @param sig The signature output + * @param sigSize The length of generated signature in bytes, which equals the size of the RSA modulus. + * @return 0:ok, non-zero:error + */ +CC_NONNULL((2,3,5,7,8,9)) +int ccrsa_sign_pss(ccrsa_full_ctx_t key, + const struct ccdigest_info* hashAlgorithm, const struct ccdigest_info* MgfHashAlgorithm, + size_t saltSize, struct ccrng_state *rng, + size_t hSize, const uint8_t *mHash, + size_t *sigSize, uint8_t *sig); + +CC_NONNULL((2,3,5,7,9)) +int ccrsa_verify_pss(ccrsa_pub_ctx_t key, + const struct ccdigest_info* di, const struct ccdigest_info* MgfDi, + size_t digestSize, const uint8_t *digest, + size_t sigSize, const uint8_t *sig, + size_t saltSize, bool *valid); + +/*! + @function ccrsa_sign_pkcs1v15 + @abstract RSA signature with PKCS#1 v1.5 format per PKCS#1 v2.2 + + @param key Full key + @param oid OID describing the type of digest passed in + @param digest_len Byte length of the digest + @param digest Byte array of digest_len bytes containing the digest + @param sig_len Pointer to the number of byte allocate for sig. + Output the exact size of the signature. + @param sig Pointer to the allocated buffer of size *sig_len + for the output signature + + @result 0 iff successful. + + @discussion Null OID is a special case, required to support RFC 4346 where the padding + is based on SHA1+MD5. In general it is not recommended to use a NULL OID, + except when strictly required for interoperability + + */ +CC_NONNULL_TU((1)) CC_NONNULL((4, 5, 6)) +int ccrsa_sign_pkcs1v15(ccrsa_full_ctx_t key, const uint8_t *oid, + size_t digest_len, const uint8_t *digest, + size_t *sig_len, uint8_t *sig); + + +/*! + @function ccrsa_sign_pkcs1v15 + @abstract RSA signature with PKCS#1 v1.5 format per PKCS#1 v2.2 + + @param key Public key + @param oid OID describing the type of digest passed in + @param digest_len Byte length of the digest + @param digest Byte array of digest_len bytes containing the digest + @param sig_len Number of byte of the signature sig. + @param sig Pointer to the signature buffer of sig_len + @param valid Output boolean, true if the signature is valid. + + @result 0 iff successful. + + @discussion Null OID is a special case, required to support RFC 4346 where the padding + is based on SHA1+MD5. In general it is not recommended to use a NULL OID, + except when strictly required for interoperability + */ +CC_NONNULL_TU((1)) CC_NONNULL((4, 6, 7)) +int ccrsa_verify_pkcs1v15(ccrsa_pub_ctx_t key, const uint8_t *oid, + size_t digest_len, const uint8_t *digest, + size_t sig_len, const uint8_t *sig, + bool *valid); + +/*! + @function ccder_encode_rsa_pub_size + @abstract Calculate size of public key export format data package. + + @param key Public key + + @result Returns size required for encoding. + */ + +CC_NONNULL_TU((1)) +size_t ccder_encode_rsa_pub_size(const ccrsa_pub_ctx_t key); + +/*! + @function ccrsa_export_priv_pkcs1 + @abstract Export a public key. + + @param key Public key + @param der Beginning of output DER buffer + @param der_end End of output DER buffer + */ + +CC_NONNULL_TU((1)) CC_NONNULL((2)) CC_NONNULL((3)) +uint8_t *ccder_encode_rsa_pub(const ccrsa_pub_ctx_t key, uint8_t *der, uint8_t *der_end); + + +/*! + @function ccder_encode_rsa_priv_size + @abstract Calculate size of full key exported in PKCS#1 format. + + @param key Full key + + @result Returns size required for encoding. + */ + +CC_NONNULL_TU((1)) +size_t ccder_encode_rsa_priv_size(const ccrsa_full_ctx_t key); + +/*! + @function ccder_encode_rsa_priv + @abstract Export a full key in PKCS#1 format. + + @param key Full key + @param der Beginning of output DER buffer + @param der_end End of output DER buffer + */ + +CC_NONNULL_TU((1)) CC_NONNULL((2)) CC_NONNULL((3)) +uint8_t *ccder_encode_rsa_priv(const ccrsa_full_ctx_t key, const uint8_t *der, uint8_t *der_end); + +/*! + @function ccder_decode_rsa_pub_n + @abstract Calculate "n" for a public key imported from a data package. + PKCS #1 format + + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + + @result the "n" of the RSA key that would result from the import. This can be used + to declare the key itself. + */ + +CC_NONNULL((1)) CC_NONNULL((2)) +cc_size ccder_decode_rsa_pub_n(const uint8_t *der, const uint8_t *der_end); + +/*! + @function ccder_decode_rsa_pub + @abstract Import a public RSA key from a package in public key format. + PKCS #1 format + + @param key Public key (n must be set) + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + + @result Key is initialized using the data in the public key message. + */ + +CC_NONNULL_TU((1)) CC_NONNULL((2)) CC_NONNULL((3)) +const uint8_t *ccder_decode_rsa_pub(const ccrsa_pub_ctx_t key, const uint8_t *der, const uint8_t *der_end); + +/*! + @function ccder_decode_rsa_pub_x509_n + @abstract Calculate "n" for a public key imported from a data package in x509 format + + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + + @result the "n" of the RSA key that would result from the import. This can be used + to declare the key itself. + */ + +CC_NONNULL((1)) CC_NONNULL((2)) +cc_size ccder_decode_rsa_pub_x509_n(const uint8_t *der, const uint8_t *der_end); + +/*! + @function ccder_decode_rsa_pub_x509 + @abstract Import a public RSA key from a package in x509 format. + + @param key Public key (n must be set) + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + + @result Key is initialized using the data in the public key message. + */ + +CC_NONNULL_TU((1)) CC_NONNULL((2)) CC_NONNULL((3)) +const uint8_t *ccder_decode_rsa_pub_x509(const ccrsa_pub_ctx_t key, const uint8_t *der, const uint8_t *der_end); + + +/*! + @function ccder_decode_rsa_priv_n + @abstract Calculate "n" for a private key imported from a data package. + + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + + @result the "n" of the RSA key that would result from the import. This can be used + to declare the key itself. + */ + +CC_NONNULL((1)) CC_NONNULL((2)) +cc_size ccder_decode_rsa_priv_n(const uint8_t *der, const uint8_t *der_end); + +/*! + @function ccder_decode_rsa_priv + @abstract Import a private RSA key from a package in PKCS#1 format. + + @param key Full key (n must be set) + @param der Beginning of input DER buffer + @param der_end End of input DER buffer + + @result Key is initialized using the data in the public key message. + */ + +CC_NONNULL_TU((1)) CC_NONNULL((2)) CC_NONNULL((3)) +const uint8_t *ccder_decode_rsa_priv(const ccrsa_full_ctx_t key, const uint8_t *der, const uint8_t *der_end); + +/*! + @function ccrsa_export_pub_size + @abstract Calculate size of public key exported data package. + + @param key Public key + + @result Returns size required for encoding. + */ + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +size_t ccrsa_export_pub_size(const ccrsa_pub_ctx_t key) { + return ccder_encode_rsa_pub_size(key); +} + +/*! + @function ccrsa_export_pub + @abstract Export a public key in public key format. + + @param key Public key + @param out_len Allocated size + @param out Output buffer + */ + +CC_NONNULL_TU((1)) CC_NONNULL((3)) +int ccrsa_export_pub(const ccrsa_pub_ctx_t key, size_t out_len, uint8_t *out); +/*! + @function ccrsa_import_pub_n + @abstract Calculate "n" for a public key imported from a data package. + + @param inlen Length of public key package data + @param der pointer to public key package data + + @result the "n" of the RSA key that would result from the import. This can be used + to declare the key itself. + */ + +CC_CONST CC_INLINE CC_NONNULL((2)) +cc_size ccrsa_import_pub_n(size_t inlen, const uint8_t *der) { + cc_size size = ccder_decode_rsa_pub_x509_n(der, der + inlen); + if(size == 0) { + size = ccder_decode_rsa_pub_n(der, der + inlen); + } + return size; +} + +/*! + @function ccrsa_import_pub + @abstract Import a public RSA key from a package in public key format. + + @param key Public key (n must be set) + @param inlen Length of public key package data + @param der pointer to public key package data + + @result Key is initialized using the data in the public key message. + */ + +CC_NONNULL_TU((1)) CC_NONNULL((3)) +int ccrsa_import_pub(ccrsa_pub_ctx_t key, size_t inlen, const uint8_t *der); + +/*! + @function ccrsa_export_priv_size + @abstract Calculate size of full key exported in PKCS#1 format. + + @param key Full key + + @result Returns size required for encoding. + */ + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) +size_t ccrsa_export_priv_size(const ccrsa_full_ctx_t key) { + return ccder_encode_rsa_priv_size(key); +} + +/*! + @function ccrsa_export_priv + @abstract Export a full key in PKCS#1 format. + + @param key Full key + @param out_len Allocated size + @param out Output buffer + */ + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) CC_NONNULL((3)) +int ccrsa_export_priv(const ccrsa_full_ctx_t key, size_t out_len, uint8_t *out) { + return (ccder_encode_rsa_priv(key, out, out+out_len) != out); +} + +/*! + @function ccrsa_import_priv_n + @abstract Calculate size of full key exported in PKCS#1 format. + + @param inlen Length of PKCS#1 package data + @param der pointer to PKCS#1 package data + + @result the "n" of the RSA key that would result from the import. This can be used + to declare the key itself. + */ + +CC_CONST CC_INLINE CC_NONNULL((2)) +cc_size ccrsa_import_priv_n(size_t inlen, const uint8_t *der) { + return ccder_decode_rsa_priv_n(der, der + inlen); +} + +/*! + @function ccrsa_import_priv + @abstract Import a full RSA key from a package in PKCS#1 format. + + @param key Full key (n must be set) + @param inlen Length of PKCS#1 package data + @param der pointer to PKCS#1 package data + + @result Key is initialized using the data in the PKCS#1 message. + */ + +CC_CONST CC_INLINE CC_NONNULL_TU((1)) CC_NONNULL((3)) +int ccrsa_import_priv(ccrsa_full_ctx_t key, size_t inlen, const uint8_t *der) { + return (ccder_decode_rsa_priv(key, der, der+inlen) == NULL); +} + + +CC_NONNULL_TU((1)) CC_NONNULL2 +int ccrsa_get_pubkey_components(const ccrsa_pub_ctx_t pubkey, uint8_t *modulus, size_t *modulusLength, uint8_t *exponent, size_t *exponentLength); + +CC_NONNULL_TU((1)) CC_NONNULL2 +int ccrsa_get_fullkey_components(const ccrsa_full_ctx_t key, uint8_t *modulus, size_t *modulusLength, uint8_t *exponent, size_t *exponentLength, + uint8_t *p, size_t *pLength, uint8_t *q, size_t *qLength); + + +/*! + @function ccrsa_dump_public_key + @abstract Print a rsa public key in the console (printf) + + @param key Public key + */ +void ccrsa_dump_public_key(ccrsa_pub_ctx_t key); + +/*! + @function ccrsa_dump_full_key + @abstract Print a rsa private key in the console (printf) + + @param key Public key + */ +void ccrsa_dump_full_key(ccrsa_full_ctx_t key); + +#endif /* _CORECRYPTO_CCRSA_H_ */ diff --git a/corecrypto/ccrsa_priv.h b/corecrypto/ccrsa_priv.h new file mode 100644 index 0000000..f4a9cb2 --- /dev/null +++ b/corecrypto/ccrsa_priv.h @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2011,2012,2013,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCRSA_PRIV_H_ +#define _CORECRYPTO_CCRSA_PRIV_H_ + +#include +#include + +// For reference, subject to change for unification accross corecrypto. + +// Program error: buffer too small or encrypted message is too small +#define CCRSA_INVALID_INPUT -1 +// Invalid crypto configuration: Hash length versus RSA key size +#define CCRSA_INVALID_CONFIG -2 +// The data is invalid (we won't say more for security +#define CCRSA_PRIVATE_OP_ERROR -3 +#define CCRSA_ENCODING_ERROR -4 +#define CCRSA_DECODING_ERROR -5 +#define CCRSA_SIGNATURE_GEN_ERROR -6 +#define CCRSA_KEY_ERROR -7 + +// Key generation specific +#define CCRSA_KEYGEN_PRIME_NOT_FOUND -9 +#define CCRSA_KEYGEN_PRIME_NEED_NEW_SEED -10 +#define CCRSA_KEYGEN_PRIME_TOO_MANY_ITERATIONS -11 +#define CCRSA_KEYGEN_PRIME_SEED_GENERATION_ERROR -12 +#define CCRSA_KEYGEN_MODULUS_CRT_INV_ERROR -13 +#define CCRSA_KEYGEN_NEXT_PRIME_ERROR -14 +#define CCRSA_KEYGEN_SEED_X_ERROR -15 +#define CCRSA_KEYGEN_SEED_r_ERROR -16 +#define CCRSA_KEYGEN_KEYGEN_CONSISTENCY_FAIL -17 +#define CCRSA_KEYGEN_R1R2_SIZE_ERROR -18 +#define CCRSA_KEYGEN_PQ_DELTA_ERROR -19 + +#define CCRSA_FIPS_KEYGEN_DISABLED -20 +// Number of entries to trace during FIPS186 key generation +// Currently, '3072' is specified by the largest 'mod' +// value in the RSA2/KeyGen_186-3 vector test file, but +// 4K keys are expected. +#define CCRSA_FIPS186_TRACE_MAX_KEY_UNITS (ccn_nof(4096)) + +// Number of ccrsa_fips186_trace objects to supply +#define CCRSA_FIPS186_TRACE_NUM 2 + +/* + Supply an array of CCRSA_FIPS186_TRACE_NUM of these objects + to the supporting functions to receive FIPS186 key generation + intermediary values. + */ +struct ccrsa_fips186_trace { + size_t bitlen1; + size_t bitlen2; + size_t curr; + cc_unit xp1[CCRSA_FIPS186_TRACE_MAX_KEY_UNITS]; + cc_unit xp2[CCRSA_FIPS186_TRACE_MAX_KEY_UNITS]; + cc_unit p1[CCRSA_FIPS186_TRACE_MAX_KEY_UNITS]; + cc_unit p2[CCRSA_FIPS186_TRACE_MAX_KEY_UNITS]; + cc_unit xp[CCRSA_FIPS186_TRACE_MAX_KEY_UNITS]; + cc_unit p[CCRSA_FIPS186_TRACE_MAX_KEY_UNITS]; +}; + + +/*! + @brief emsa_pss_encode () encodes message M acording to EMSA-PSS in PKCS 1 V2 + + + @return 0:ok non-zero:error + + + + @param di hash function (hLen denotes the length in octets of the hash function output) + @param sLen intended length in octets of the salt + @param salt salt for encoding + @param hLen length of hash function. must be equal to di->output_size + @param mHash the input that needs to be encoded. This is the hash of message M with length of hLen + @param emBits maximal bit length of the integer OS2IP (EM) (see Section 4.2), at least 8hLen + 8sLen + 9. It is one bit smalller than modulus. + @param EM encoded message output, an octet string of length emLen = ⎡emBits/8⎤ + +
+ @textblock
+                                        +-------------+
+                                        |  M[2^61-1]  |
+                                        +-------------+
+                                               |
+                                               V
+                                            Hash[hLen]
+                                               |
+                                               V
+                               +--------+-------------+------------+
+             M'[8+hLen+sLen] = |  0[8]  | mHash[hLen] | salt[sLen] |
+                               +--------+-------------+------------+
+                  t=emLen-sLen-hLen-2          |
+                  +------+---+------------+    V
+ DB[emLen-hLen-1]=| 0[t] | 1 | salt[sLen] |  Hash[hLen]
+                  +------+---+------------+    |
+                             |                 |
+                             V dbMask[]        |
+          [emLen- hLen-1]  xor <------- MGF <--|
+                             |                 |
+                             |                 |
+                 bit 0       V                 V
+                 +------------------------+----------+--+
+      EM[emLen]= | maskedDB[emLen-hLen-1] | H[hLen]  |bc|
+                 +------------------------+----------+--+
+ @/textblock
+ 
+ */ + +CC_NONNULL((1,2,4,6,8)) +int ccrsa_emsa_pss_encode(const struct ccdigest_info* di, const struct ccdigest_info* MgfDi, + size_t sSize, const uint8_t *salt, + size_t hSize, const uint8_t *mHash, + size_t emBits, uint8_t *EM); +CC_NONNULL((1,2,5,7)) +int ccrsa_emsa_pss_decode(const struct ccdigest_info* di, const struct ccdigest_info* MgfDi, + size_t sSize, + size_t mSize, const uint8_t *mHash, + size_t emBits, const uint8_t *EM); + + +/* EMSA + + Null OID in emsa encode/verify is a special case, only for use by SecKey for legacy purposes + When oid==NULL, the padding is reduced to "0001FF..FF00", oid and following seperators are skipped. + it is critical that the caller has set the oid and + other padding characters in the input "dgst". + Failing to do so results in weak signatures that may be forgeable */ +CC_NONNULL2 CC_NONNULL4 +int ccrsa_emsa_pkcs1v15_encode(size_t emlen, uint8_t *em, + size_t dgstlen, const uint8_t *dgst, + const uint8_t *oid); + +CC_NONNULL2 CC_NONNULL4 +int ccrsa_emsa_pkcs1v15_verify(size_t emlen, uint8_t *em, + size_t dgstlen, const uint8_t *dgst, + const uint8_t *oid); + + +// MGF for OAEP + +// Seed is di->output_size bytes, r_size must be >= di>output_size +CC_NONNULL1 CC_NONNULL3 CC_NONNULL5 +int ccmgf(const struct ccdigest_info* di, + size_t r_size, void* r, + size_t seed_size, const void* seed); + + +// OAEP + +/* + r_size is the blocksize of the key for which the encoding is being done. + */ +CC_NONNULL((1, 2, 4, 6)) +int ccrsa_oaep_encode_parameter(const struct ccdigest_info* di, + struct ccrng_state *rng, + size_t r_size, cc_unit *r, + size_t message_len, const uint8_t *message, + size_t parameter_data_len, const uint8_t *parameter_data); + +/* + r_size is the blocksize of the key for which the encoding is being done. + */ + +CC_INLINE CC_NONNULL((1, 2, 4, 6)) +int ccrsa_oaep_encode(const struct ccdigest_info* di, + struct ccrng_state *rng, + size_t r_size, cc_unit *r, + size_t message_len, const uint8_t *message) +{ + return ccrsa_oaep_encode_parameter(di, rng, r_size, r, message_len, message, 0, NULL); +} + +/* + r_len is the blocksize of the key for which the decoding is being done. + */ +CC_NONNULL((1, 2, 3, 5)) +int ccrsa_oaep_decode_parameter(const struct ccdigest_info* di, + size_t *r_len, uint8_t *r, + size_t s_size, cc_unit *s, + size_t parameter_data_len, const uint8_t *parameter_data); + + +CC_INLINE CC_NONNULL((1, 2, 3, 5)) +int ccrsa_oaep_decode(const struct ccdigest_info* di, + size_t *r_len, uint8_t *r, + size_t s_size, cc_unit* s) +{ + return ccrsa_oaep_decode_parameter(di, r_len, r, s_size, s, 0, NULL); +} + +CC_NONNULL_TU((1,4,7)) CC_NONNULL((2, 3, 5, 6, 8)) +int ccrsa_crt_makekey(cczp_t zm, const cc_unit *e, cc_unit *d, cczp_t zp, cc_unit *dp, cc_unit *qinv, cczp_t zq, cc_unit *dq); + +/*! + @function ccrsa_sign_pkcs1v15_blinded + @abstract Same as ccrsa_sign_pkcs1v15, with explicit argument + for RNG used for blinding + + @param blinding_rng Random number generator blinding + @param key Full key + @param oid OID describing the type of digest passed in + @param digest_len Byte length of the digest + @param digest Byte array of digest_len bytes containing the digest + @param sig_len Pointer to the number of byte allocate for sig. + Output the exact size of the signature. + @param sig Pointer to the allocated buffer of size *sig_len + for the output signature + + @result 0 iff successful. + + @discussion Null OID is a special case, required to support RFC 4346 where the padding + is based on SHA1+MD5. In general it is not recommended to use a NULL OID, + except when strictly required for interoperability + + */ +CC_NONNULL_TU((2)) CC_NONNULL((5, 6, 7)) +int ccrsa_sign_pkcs1v15_blinded(struct ccrng_state *blinding_rng, + ccrsa_full_ctx_t key, const uint8_t *oid, + size_t digest_len, const uint8_t *digest, + size_t *sig_len, uint8_t *sig); + +/*! + @function ccrsa_sign_pss_blinded + @abstract Same as ccrsa_sign_pss, with explicit argument + for RNG used for blinding + + * @param blinding_rng Random number generator blinding + * @param key The RSA key + * @param hashAlgorithm The hash algorithm used to generate mHash from the original message. It is also used inside the PSS encoding function. This is also the hash function to be used in the mask generation function (MGF) + * @param MgfHashAlgorithm The hash algorithm for thr mask generation function + * @param rng Random number geberator to generate salt in PSS encoding + * @param saltLen Intended length of the salt + * @param hLen Length of message hash . Must be equal to hashAlgorithm->output_size + * @param mHash The input that needs to be signed. This is the hash of message M with length of hLen + * + * @param sig The signature output + * @param sigLen The length of generated signature in bytes, which equals the size of the RSA modulus. + * @return 0:ok, non-zero:error + */ +CC_NONNULL((3,4,6,8,9,10)) +int ccrsa_sign_pss_blinded( + struct ccrng_state *blinding_rng, + ccrsa_full_ctx_t key, + const struct ccdigest_info* hashAlgorithm, const struct ccdigest_info* MgfHashAlgorithm, + size_t saltSize, struct ccrng_state *rng, + size_t hSize, const uint8_t *mHash, + size_t *sigSize, uint8_t *sig); + + +/*! + @function ccrsa_eme_pkcs1v15_encode + @abstract Encode a key in PKCS1 V1.5 EME format prior to encrypting. + + @param rng A handle to an initialized rng state structure. + @param r_size (In/Out) Result buffer size. + @param r Result cc_unit buffer. + @param s_size Source (payload) length. + @param s Source buffer to be encoded. + + @result Returns 0 on success, -1 otherwise. + */ + +CC_NONNULL((1, 3, 5)) +int ccrsa_eme_pkcs1v15_encode(struct ccrng_state *rng, + size_t r_size, cc_unit *r, + size_t s_size, const uint8_t *s); + +/*! + @function ccrsa_eme_pkcs1v15_decode + @abstract Decode a payload in PKCS1 V1.5 EME format to a key after decrypting. + + @param r_size (In/Out) Result buffer size. + @param r Result buffer. + @param s_size Source (PKCS1 EME Payload) length. + @param s Source cc_unit buffer to be decoded. + + @result Returns 0 on success, -1 otherwise. + */ + +CC_NONNULL((1, 2, 4)) +int ccrsa_eme_pkcs1v15_decode(size_t *r_size, uint8_t *r, + size_t s_size, cc_unit *s); + +/*! + @function ccrsa_encrypt_eme_pkcs1v15 + @abstract Encode a key in PKCS1 V1.5 EME format and encrypt. + DO NOT USE: THIS ALGORITHM IS NOT SECURE + This algorithm is vulnerable to practical attacks leading to plaintext recovery (Bleichenbach 98, Coron Joye Naccache Pailler 2000) + + @param key A public key to use to encrypt the package. + @param rng A handle to an initialized rng state structure. + @param r_size (In/Out) Result buffer size. + @param r Result cc_unit buffer. + @param s_size Source (payload) length. + @param s Source buffer to be encoded. + + @result Returns 0 on success, -1 otherwise. + */ + +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4, 6)) +int ccrsa_encrypt_eme_pkcs1v15(ccrsa_pub_ctx_t key, + struct ccrng_state *rng, + size_t *r_size, uint8_t *r, + size_t s_size, const uint8_t *s); + +/*! + @function ccrsa_decrypt_eme_pkcs1v15 + DO NOT USE: THIS ALGORITHM IS NOT SECURE + This algorithm is vulnerable to practical attacks leading to plaintext recovery (Bleichenbach 98, Coron Joye Naccache Pailler 2000) + + @abstract Decrypt and decode a payload in PKCS1 V1.5 EME format to a key. + + @param key A private key to use to decrypt the package. + @param r_size (In/Out) Result buffer size. + @param r Result buffer. + @param s_size Source (PKCS1 EME Payload) length. + @param s Source buffer to be decoded. + + @result Returns 0 on success, -1 otherwise. + */ + + +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 5)) +int ccrsa_decrypt_eme_pkcs1v15(ccrsa_full_ctx_t key, + size_t *r_size, uint8_t *r, + size_t s_size, const uint8_t *s); + +/*! + @function ccrsa_decrypt_eme_pkcs1v15_blinded + DO NOT USE: THIS ALGORITHM IS NOT SECURE + This algorithm is vulnerable to practical attacks leading to plaintext recovery (Bleichenbach 98, Coron Joye Naccache Pailler 2000) + + @abstract Same as ccrsa_decrypt_eme_pkcs1v15, with an explicit RNG for blinding + + @param blinding_rng A handle to an initialized rng state structure. + @param key A private key to use to decrypt the package. + @param r_size (In/Out) Result buffer size. + @param r Result buffer. + @param s_size Source (PKCS1 EME Payload) length. + @param s Source buffer to be decoded. + + @result Returns 0 on success, -1 otherwise. + */ + +CC_NONNULL_TU((2)) CC_NONNULL((3, 4, 6)) +int ccrsa_decrypt_eme_pkcs1v15_blinded(struct ccrng_state *blinding_rng, + ccrsa_full_ctx_t key, + size_t *r_size, uint8_t *r, + size_t s_size, const uint8_t *s); + +/*! + @function ccrsa_encrypt_eme_pkcs1v15 + @abstract Encode a key in PKCS1 V2.1 OAEP format and encrypt. + + @param key A public key to use to encrypt the package. + @param di A descriptor for the digest used to encode the package. + @param rng A handle to an initialized rng state structure. + @param r_size (In/Out) Result buffer size. + @param r Result cc_unit buffer. + @param s_size Source (payload) length. + @param s Source buffer to be encoded. + @param parameter_data_len Length of tag data (optional) + @param parameter_data Pointer to tag data (optional) + + @result Returns 0 on success, -1 otherwise. + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4, 5, 7)) +int ccrsa_encrypt_oaep(ccrsa_pub_ctx_t key, + const struct ccdigest_info* di, + struct ccrng_state *rng, + size_t *r_size, uint8_t *r, + size_t s_size, const uint8_t *s, + size_t parameter_data_len, + const uint8_t *parameter_data); + +/*! + @function ccrsa_decrypt_oaep + @abstract Decrypt and decode a payload in PKCS1 V2.1 OAEP format to a key. + + @param key A private key to use to decrypt the package. + @param di A descriptor for the digest used to encode the package. + @param r_size (In/Out) Result buffer size. + @param r Result buffer. + @param c_size Source (PKCS1 EME Payload) length. + @param c Source buffer to be decoded. + @param parameter_data_len Length of tag data (optional) + @param parameter_data Pointer to tag data (optional) + + @result Returns 0 on success, -1 otherwise. + */ + +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4, 6)) +int ccrsa_decrypt_oaep(ccrsa_full_ctx_t key, + const struct ccdigest_info* di, + size_t *r_size, uint8_t *r, + size_t c_size, const uint8_t *c, + size_t parameter_data_len, + const uint8_t *parameter_data); + +/*! + @function ccrsa_decrypt_oaep_blinded + + @abstract Same as ccrsa_decrypt_oaep, with an explicit RNG for blinding + + @param blinding_rng A handle to an initialized rng state structure. + + @param key A private key to use to decrypt the package. + @param di A descriptor for the digest used to encode the package. + @param r_size (In/Out) Result buffer size. + @param r Result buffer. + @param c_size Source (PKCS1 EME Payload) length. + @param c Source buffer to be decoded. + @param parameter_data_len Length of tag data (optional) + @param parameter_data Pointer to tag data (optional) + + @result Returns 0 on success, -1 otherwise. + */ + +CC_NONNULL_TU((2)) CC_NONNULL((3, 4, 5, 7)) +int ccrsa_decrypt_oaep_blinded( + struct ccrng_state *blinding_rng, + ccrsa_full_ctx_t key, + const struct ccdigest_info* di, + size_t *r_size, uint8_t *r, + size_t c_size, const uint8_t *c, + size_t parameter_data_len, + const uint8_t *parameter_data); + + +/*! + @function ccrsa_private_crypt + @abstract Perform RSA operation with a private key (CRT) + Clients should use ccn_read_uint() to + convert bytes to a cc_unit to use for this function. + + @param rng A handle to an initialized rng state structure. + @param key A handle an RSA private key. + @param out Output buffer, of size ccrsa_ctx_n(key). + @param in Input buffer, of size ccrsa_ctx_n(key). + + @result Returns 0 on success, !=0 otherwise. + */ +CC_NONNULL_TU((2)) CC_NONNULL((3, 4)) +int ccrsa_priv_crypt_blinded(struct ccrng_state *blinding_rng, ccrsa_full_ctx_t key, cc_unit *out, const cc_unit *in); + +/*! + @function ccrsa_priv_crypt + @abstract Perform RSA operation with a private key + + @param key A handle an RSA private key. + @param out Output buffer, of size ccrsa_ctx_n(key). + @param in Input buffer, of size ccrsa_ctx_n(key). + + @result Returns 0 on success, !=0 otherwise. + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +int ccrsa_priv_crypt(ccrsa_full_ctx_t key, cc_unit *out, const cc_unit *in); + +/* + Generate a FIPS186-4 standard RSA key, saving the intermediary values. + + This function must only be used for internal testing, and should never be + called directly outside of those circumstances. + */ +CC_NONNULL_TU((2)) CC_NONNULL((4, 5, 6)) +int ccrsa_generate_fips186_key_trace(size_t nbits, ccrsa_full_ctx_t fk, + size_t e_size, const void *eBytes, struct ccrng_state *rng1, + struct ccrng_state *rng2, struct ccrsa_fips186_trace *trace); + +/* + Construct RSA key from fix input in conformance with FIPS186-4 standard + + This function must only be used for internal testing, and should never be + called directly outside of those circumstances. + */ +CC_NONNULL_TU((16)) CC_NONNULL((3, 5, 7, 9, 11, 13, 15)) +int ccrsa_make_fips186_key_trace(size_t nbits, const cc_size e_n, + const cc_unit *e, const cc_size xp1Len, const cc_unit *xp1, + const cc_size xp2Len, const cc_unit *xp2, const cc_size xpLen, + const cc_unit *xp, const cc_size xq1Len, const cc_unit *xq1, + const cc_size xq2Len, const cc_unit *xq2, const cc_size xqLen, + const cc_unit *xq, ccrsa_full_ctx_t fk, cc_size *np, cc_unit *r_p, + cc_size *nq, cc_unit *r_q, cc_size *nm, cc_unit *r_m, cc_size *nd, + cc_unit *r_d, struct ccrsa_fips186_trace *trace); + +CC_INLINE cc_size ccrsa_n_from_size(size_t size) { + return ccn_nof_size(size); +} + +CC_INLINE size_t ccrsa_sizeof_n_from_size(size_t size) { + return ccn_sizeof_n(ccn_nof_size(size)); +} + +CC_INLINE uint8_t *ccrsa_block_start(size_t size, cc_unit *p, int clear_to_start) { + size_t fullsize = ccrsa_sizeof_n_from_size(size); + size_t offset = fullsize - size; + if(clear_to_start) cc_zero(offset,p); + return ((uint8_t *) p) + offset; +} + +CC_INLINE size_t ccrsa_block_size(ccrsa_pub_ctx_t key) { + return ccn_write_uint_size(ccrsa_ctx_n(key), ccrsa_ctx_m(key)); +} + +CC_NONNULL_TU((1)) +bool ccrsa_pairwise_consistency_check(const ccrsa_full_ctx_t full_key, + struct ccrng_state *rng); + +#endif diff --git a/corecrypto/ccsha1.h b/corecrypto/ccsha1.h new file mode 100644 index 0000000..aeebbfa --- /dev/null +++ b/corecrypto/ccsha1.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCSHA1_H_ +#define _CORECRYPTO_CCSHA1_H_ + +#include +#include + +#define CCSHA1_BLOCK_SIZE 64 +#define CCSHA1_OUTPUT_SIZE 20 +#define CCSHA1_STATE_SIZE 20 + +/* sha1 selector */ +const struct ccdigest_info *ccsha1_di(void); + +extern const uint32_t ccsha1_initial_state[5]; + +/* shared between several implementations */ +void ccsha1_final(const struct ccdigest_info *di, ccdigest_ctx_t, + unsigned char *digest); + + +/* Implementations */ +extern const struct ccdigest_info ccsha1_ltc_di; +extern const struct ccdigest_info ccsha1_eay_di; + +#if CCSHA1_VNG_INTEL +//extern const struct ccdigest_info ccsha1_vng_intel_di; +#if defined(__x86_64__) +extern const struct ccdigest_info ccsha1_vng_intel_AVX2_di; +extern const struct ccdigest_info ccsha1_vng_intel_AVX1_di; +#endif +extern const struct ccdigest_info ccsha1_vng_intel_SupplementalSSE3_di; +#endif + +#if CCSHA1_VNG_ARMV7NEON +extern const struct ccdigest_info ccsha1_vng_armv7neon_di; +#endif + +/* TODO: Placeholders */ +#define ccoid_sha1 ((unsigned char *)"\x06\x05\x2b\x0e\x03\x02\x1a") +#define ccoid_sha1_len 7 + +#endif /* _CORECRYPTO_CCSHA1_H_ */ diff --git a/corecrypto/ccsha2.h b/corecrypto/ccsha2.h new file mode 100644 index 0000000..9a3d18e --- /dev/null +++ b/corecrypto/ccsha2.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCSHA2_H_ +#define _CORECRYPTO_CCSHA2_H_ + +#include + +/* sha2 selectors */ +const struct ccdigest_info *ccsha224_di(void); +const struct ccdigest_info *ccsha256_di(void); +const struct ccdigest_info *ccsha384_di(void); +const struct ccdigest_info *ccsha512_di(void); + +/* TODO: Placeholders */ +#define ccoid_sha224 ((unsigned char *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04") +#define ccoid_sha224_len 11 + +#define ccoid_sha256 ((unsigned char *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01") +#define ccoid_sha256_len 11 + +#define ccoid_sha384 ((unsigned char *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02") +#define ccoid_sha384_len 11 + +#define ccoid_sha512 ((unsigned char *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03") +#define ccoid_sha512_len 11 + + +/* SHA256 */ +#define CCSHA256_BLOCK_SIZE 64 +#define CCSHA256_OUTPUT_SIZE 32 +#define CCSHA256_STATE_SIZE 32 +extern const struct ccdigest_info ccsha256_ltc_di; +extern const struct ccdigest_info ccsha256_v6m_di; +#if CCSHA2_VNG_INTEL +#if defined __x86_64__ +extern const struct ccdigest_info ccsha224_vng_intel_AVX2_di; +extern const struct ccdigest_info ccsha224_vng_intel_AVX1_di; +extern const struct ccdigest_info ccsha256_vng_intel_AVX2_di; +extern const struct ccdigest_info ccsha256_vng_intel_AVX1_di; +extern const struct ccdigest_info ccsha384_vng_intel_AVX2_di; +extern const struct ccdigest_info ccsha384_vng_intel_AVX1_di; +extern const struct ccdigest_info ccsha384_vng_intel_SupplementalSSE3_di; +extern const struct ccdigest_info ccsha512_vng_intel_AVX2_di; +extern const struct ccdigest_info ccsha512_vng_intel_AVX1_di; +extern const struct ccdigest_info ccsha512_vng_intel_SupplementalSSE3_di; +#endif +extern const struct ccdigest_info ccsha224_vng_intel_SupplementalSSE3_di; +extern const struct ccdigest_info ccsha256_vng_intel_SupplementalSSE3_di; +#endif +#if CCSHA2_VNG_ARMV7NEON +extern const struct ccdigest_info ccsha224_vng_armv7neon_di; +extern const struct ccdigest_info ccsha256_vng_armv7neon_di; +extern const struct ccdigest_info ccsha384_vng_arm64_di; +extern const struct ccdigest_info ccsha384_vng_armv7neon_di; +extern const struct ccdigest_info ccsha512_vng_arm64_di; +extern const struct ccdigest_info ccsha512_vng_armv7neon_di; +#endif +extern const uint32_t ccsha256_K[64]; +extern const uint64_t ccsha512_K[80]; + +/* SHA224 */ +#define CCSHA224_OUTPUT_SIZE 28 +extern const struct ccdigest_info ccsha224_ltc_di; + +/* SHA512 */ +#define CCSHA512_BLOCK_SIZE 128 +#define CCSHA512_OUTPUT_SIZE 64 +#define CCSHA512_STATE_SIZE 64 +extern const struct ccdigest_info ccsha512_ltc_di; + +/* SHA384 */ +#define CCSHA384_OUTPUT_SIZE 48 +extern const struct ccdigest_info ccsha384_ltc_di; + +#endif /* _CORECRYPTO_CCSHA2_H_ */ diff --git a/corecrypto/ccsrp.h b/corecrypto/ccsrp.h new file mode 100644 index 0000000..44294e7 --- /dev/null +++ b/corecrypto/ccsrp.h @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2012,2013,2014,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef SRP_H +#define SRP_H + +#include +#include +#include +#include +#include + +/* Aliases for DH-style group params for SRP */ +#if CORECRYPTO_USE_TRANSPARENT_UNION +typedef ccdh_gp ccsrp_gp; +#else +typedef struct ccdh_gp ccsrp_gp; +#endif +#define CCSRP_HDR_PAD 32 + +#if CORECRYPTO_USE_TRANSPARENT_UNION +typedef ccdh_gp_t ccsrp_gp_t; +typedef ccdh_const_gp_t ccsrp_const_gp_t; + +struct ccsrp_ctx_header { + const struct ccdigest_info *di; + ccsrp_const_gp_t gp; + struct ccrng_state *blinding_rng; + struct { + unsigned int authenticated:1; + unsigned int noUsernameInX:1; + unsigned int sessionkey:1; + unsigned int variant:16; + } flags; + uint8_t pad[CCSRP_HDR_PAD - (sizeof(struct ccdigest_info *)+ + sizeof(ccsrp_const_gp_t)+ + sizeof(struct ccrng_state *)+ + sizeof(bool))]; + cc_unit ccn[1]; +} CC_ALIGNED(16); + +typedef struct ccsrp_ctx { + struct ccsrp_ctx_header hdr; +} CC_ALIGNED(16) ccsrp_ctx; + +struct ccsrp_ctx_body { + struct ccsrp_ctx_header hdr; + cc_unit ccn[]; +} CC_ALIGNED(16); + +typedef union { + ccsrp_ctx *_full; // Constructor + struct ccsrp_ctx_header *hdr; + struct ccsrp_ctx_body *body; +} __attribute__((transparent_union)) ccsrp_ctx_t; +#else +typedef ccdh_gp_t ccsrp_gp_t; +typedef ccdh_const_gp_t ccsrp_const_gp_t; + +struct ccsrp_ctx { + const struct ccdigest_info *di; + ccsrp_const_gp_t gp; + struct ccrng_state *blinding_rng; + struct { + unsigned int authenticated:1; + unsigned int noUsernameInX:1; + unsigned int sessionkey:1; + unsigned int variant:16; + } flags; + uint8_t pad[CCSRP_HDR_PAD - (sizeof(struct ccdigest_info *)+ + sizeof(ccsrp_const_gp_t)+ + sizeof(struct ccrng_state *)+ + sizeof(bool))]; + cc_unit ccn[1]; +} CC_ALIGNED(16); +typedef struct ccsrp_ctx *ccsrp_ctx_t; + +#endif + +#define ccsrp_gpbuf_size(_gp_) (ccdh_ccn_size(_gp_)*4) +#define ccsrp_dibuf_size(_di_) ((_di_)->output_size*4) + +/* Size of the context structure for the di and gp combo */ +#define ccsrp_sizeof_srp(_di_,_gp_) sizeof(struct ccsrp_ctx)+\ + ccsrp_gpbuf_size(_gp_)+ccsrp_dibuf_size(_di_) + +/* Use this to declare a context on the stack + Use ccsrp_ctx_clear when done to prevent exposing key material */ +#define ccsrp_ctx_decl(_di_, _gp_, _name_) \ + cc_ctx_decl(struct ccsrp_ctx, ccsrp_sizeof_srp(_di_,_gp_), _name_) + +#define ccsrp_ctx_clear(_di_, _gp_, _name_) \ + cc_clear(ccsrp_sizeof_srp(_di_,_gp_), _name_) + +/* + Accessors to the context structure. + */ +#if CORECRYPTO_USE_TRANSPARENT_UNION +#define HDR(srp) ((srp).hdr) +#else +#define HDR(srp) (srp) +#endif + +#define SRP_DI(srp) (HDR(srp)->di) +#define SRP_GP(srp) (HDR(srp)->gp) +#define SRP_FLG(srp) (HDR(srp)->flags) +#define SRP_CCN(srp) (HDR(srp)->ccn) +#define SRP_RNG(srp) (HDR(srp)->blinding_rng) + +#define ccsrp_ctx_gp(KEY) SRP_GP((ccsrp_ctx_t)(KEY)) +#define ccsrp_ctx_di(KEY) SRP_DI((ccsrp_ctx_t)(KEY)) +#define ccsrp_ctx_zp(KEY) ccdh_gp_zp((ccsrp_ctx_gp(KEY))) +#define ccsrp_ctx_gp_g(KEY) (ccdh_gp_g(ccsrp_ctx_gp(KEY))) +#define ccsrp_ctx_gp_l(KEY) (ccdh_gp_l(ccsrp_ctx_gp(KEY))) +#define ccsrp_ctx_n(KEY) (ccdh_gp_n(ccsrp_ctx_gp(KEY))) +#define ccsrp_ctx_prime(KEY) (ccdh_gp_prime(ccsrp_ctx_gp(KEY))) +#define ccsrp_ctx_ccn(KEY) SRP_CCN((ccsrp_ctx_t)(KEY)) +#define ccsrp_ctx_pki_key(KEY,_N_) (ccsrp_ctx_ccn(KEY) + ccsrp_ctx_n(KEY) * _N_) +#define ccsrp_ctx_public(KEY) (ccsrp_ctx_pki_key(KEY,0)) +#define ccsrp_ctx_private(KEY) (ccsrp_ctx_pki_key(KEY,1)) +#define ccsrp_ctx_v(KEY) (ccsrp_ctx_pki_key(KEY,2)) +#define ccsrp_ctx_S(KEY) (ccsrp_ctx_pki_key(KEY,3)) +#define ccsrp_ctx_K(KEY) ((uint8_t *)(ccsrp_ctx_pki_key(KEY,4))) +#define ccsrp_ctx_M(KEY) (uint8_t *)(ccsrp_ctx_K(KEY)+\ +2*ccsrp_ctx_di(KEY)->output_size) +#define ccsrp_ctx_HAMK(KEY) (uint8_t *)(ccsrp_ctx_K(KEY)+\ +3*ccsrp_ctx_di(KEY)->output_size) + +/* Session Keys and M and HAMK are returned in this many bytes */ +#define ccsrp_ctx_keysize(KEY) ccsrp_get_session_key_length(KEY) + +#define ccsrp_ctx_M_HAMK_size(KEY) (ccsrp_ctx_di(KEY)->output_size) + +/* The public keys and the verifier are returned in this many bytes */ +#define ccsrp_ctx_sizeof_n(KEY) (ccn_sizeof_n(ccsrp_ctx_n(KEY))) + +/****************************************************************************** + * Error codes + *****************************************************************************/ + +#define CCSRP_ERROR_DEFAULT CCDH_ERROR_DEFAULT +#define CCSRP_GENERATE_KEY_TOO_MANY_TRIES CCDH_GENERATE_KEY_TOO_MANY_TRIES +#define CCSRP_NOT_SUPPORTED_CONFIGURATION CCDH_NOT_SUPPORTED_CONFIGURATION +#define CCSRP_SAFETY_CHECK CCDH_SAFETY_CHECK +#define CCSRP_PUBLIC_KEY_MISSING CCDH_PUBLIC_KEY_MISSING +#define CCSRP_INVALID_DOMAIN_PARAMETER CCDH_INVALID_DOMAIN_PARAMETER + +/****************************************************************************** + * Variant (main difference is key derivation after DH di + *****************************************************************************/ +/* OPTION + [0..2]: KDF to compute K from S + [3..5]: Variant (value of k in the computation of B) + [6..7]: Padding in Hash (leading zeroes hashed or skipped in hashes) */ + +// Do Not use these flags directly. Please use one of the "combo" flags. +// and request a new combo flag is needed. + +// Selection of KDF for the session key +#define CCSRP_OPTION_KDF_MASK (7<<0) +// K = H(S), size of K is the size of the digest output +#define CCSRP_OPTION_KDF_HASH (0<<0) +// K = MGF1(S), size of K is TWICE the size of the digest output +#define CCSRP_OPTION_KDF_MGF1 (1<<0) +// K = H_Interleave(S), size of K is TWICE the size of the digest output +#define CCSRP_OPTION_KDF_INTERLEAVED (2<<0) + +// Selection of the variant for internal computation +#define CCSRP_OPTION_VARIANT_MASK (7<<3) +// k = HASH(N | PAD(g)) and u = HASH(PAD(A) | PAD(B)) +#define CCSRP_OPTION_VARIANT_SRP6a (0<<3) +// K = 1 and u=MSB32bit(HASH(PAD(B)) +#define CCSRP_OPTION_VARIANT_RFC2945 (1<<3) + +// Selection of leading zeroes in integer hashes +#define CCSRP_OPTION_PAD_MASK (3<<6) +// Skip zeroes of A and B during hashes for the computation of k, U and X +#define CCSRP_OPTION_PAD_SKIP_ZEROES_k_U_X (1<<6) +// Skip leading zeroes when hashing A,B in M and HAMK only +// This is a hack to be compatible with AppleSRP implementation +#define CCSRP_OPTION_PAD_SKIP_ZEROES_TOKEN (2<<6) + + +// Higher level combos: +// Corecrypto default +#define CCSRP_OPTION_SRP6a_HASH (CCSRP_OPTION_VARIANT_SRP6a \ + | CCSRP_OPTION_KDF_HASH) + +// Improved SRP6a (with MGF1) compatible with SRP +// The domain parameter (g) is hashed on the exact number of bytes instead hashing +// modlen bytes. +#define CCSRP_OPTION_SRP6a_MGF1 (CCSRP_OPTION_VARIANT_SRP6a \ + | CCSRP_OPTION_KDF_MGF1 \ + | CCSRP_OPTION_PAD_SKIP_ZEROES_TOKEN) + +// TLS-SRP. Not recommended except when interoperability is required +#define CCSRP_OPTION_RFC2945_INTERLEAVED (CCSRP_OPTION_VARIANT_RFC2945 \ + | CCSRP_OPTION_KDF_INTERLEAVED \ + | CCSRP_OPTION_PAD_SKIP_ZEROES_k_U_X \ + | CCSRP_OPTION_PAD_SKIP_ZEROES_TOKEN) + + + + +/*! + @function ccsrp_ctx_init_option + @abstract Initialize the SRP context + + @param srp SRP + @param di handle on the digest to be used (ex. ccsha1_di()) + @param gp handle on DH group parameters (requires group with no small subgroups) + @param option Define variant, key derivation and padding of integers being hashed. + @param blinding_rng For randomization of internal computations, rng may be used for as long as the "srp" context is used. + + @result 0 if no error + */ +/* Init context structures with this function */ +CC_NONNULL_TU((1,3)) CC_NONNULL((2)) +CC_INLINE int +ccsrp_ctx_init_option(ccsrp_ctx_t srp, + const struct ccdigest_info *di, + ccsrp_const_gp_t gp, + uint32_t option, + struct ccrng_state *blinding_rng) { + cc_zero(ccsrp_sizeof_srp(di, gp),HDR(srp)); + SRP_DI(srp) = di; + SRP_GP(srp) = gp; + SRP_FLG(srp).authenticated = false; + SRP_FLG(srp).sessionkey = false; + SRP_RNG(srp)=blinding_rng; + // Option is a bit mask. If not a power of two, it's an error. + SRP_FLG(srp).variant = 0xFFFF & option; + return 0; // Success +} + +// Legacy function, initialize for the RFC5054 variant. +CC_NONNULL_TU((1,3)) CC_NONNULL((2)) +CC_INLINE void +ccsrp_ctx_init(ccsrp_ctx_t srp, const struct ccdigest_info *di, ccsrp_const_gp_t gp) { + ccsrp_ctx_init_option(srp,di,gp,CCSRP_OPTION_SRP6a_HASH,ccrng(NULL)); +} + +/****************************************************************************** + * Salt and Verification Generation - used to setup an account. + *****************************************************************************/ + +/*! + @function ccsrp_generate_salt_and_verification + @abstract Generate the salt and the verification token to be used for future + authentications + + @param srp SRP + @param rng handle on rng for ephemeral key generation + @param username identity + @param password_len length in byte of the password + @param password password of length password_len + @param salt_len length in byte of the salt + @param salt salt of length salt_len (output) + @param verifier password verifier known to the server (output) + + @result 0 if no error + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,3,5,7,8)) +int +ccsrp_generate_salt_and_verification(ccsrp_ctx_t srp, struct ccrng_state *rng, + const char *username, + size_t password_len, const void *password, + size_t salt_len, void *salt, + void *verifier); + +/*! + @function ccsrp_generate_verifier + @abstract Generate the verification token to be used for future + authentications + + @param srp SRP + @param username identity + @param password_len length in byte of the password + @param password password of length password_len + @param salt_len length in byte of the salt + @param salt salt of length salt_len (input) + @param verifier password verifier known to the server (output) + + @result 0 if no error + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,4,6,7)) +int +ccsrp_generate_verifier(ccsrp_ctx_t srp, + const char *username, + size_t password_len, const void *password, + size_t salt_len, const void *salt, + void *verifier); + +/****************************************************************************** + * Server Side Routines + *****************************************************************************/ + +/*! + @function ccsrp_server_generate_public_key + @abstract Generate the server value B. + If A is known, call directly ccsrp_server_start_authentication + + @param srp SRP + @param rng handle on rng for ephemeral key generation + @param username identity + @param verifier password verifier known to the server + @param B_bytes Value B which is the challenge to send to the client (output) + + @result 0 if no error + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,3,4)) +int +ccsrp_server_generate_public_key(ccsrp_ctx_t srp, struct ccrng_state *rng, + const void *verifier, void *B_bytes); + +/*! + @function ccsrp_server_compute_session + @abstract Generate the session key material and tokens for authentication + + @param srp SRP + @param username identity + @param salt_len length in byte of the salt + @param salt salt of length salt_len + @param A_bytes Ephemeral public key received from the client + + @result 0 if no error + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,4,5)) +int +ccsrp_server_compute_session(ccsrp_ctx_t srp, + const char *username, + size_t salt_len, const void *salt, + const void *A_bytes); + +/*! + @function ccsrp_server_start_authentication + @abstract Performs in one shot the server public key and the session key material + + @param srp SRP + @param rng handle on rng for ephemeral key generation + @param username identity + @param salt_len length in byte of the salt + @param salt salt of length salt_len + @param verifier password verifier known to the server + @param A_bytes Ephemeral public key received from the client + @param B_bytes Value B which is the challenge to send to the client (output) + + @result 0 if no error + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,3,5,6,7,8)) +int +ccsrp_server_start_authentication(ccsrp_ctx_t srp, struct ccrng_state *rng, + const char *username, + size_t salt_len, const void *salt, + const void *verifier, const void *A_bytes, + void *B_bytes); + +/*! + @function ccsrp_server_verify_session + @abstract Verify that the token received from the client is correct and that + therefore authentication succeeded. + + @param srp SRP + @param user_M Authentication token received from the client + @param HAMK_bytes Authentication token generated to be sent to the client (output) + + @result true if client is authenticated, false otherwise (fail or incomplete protocol) + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,3)) +bool +ccsrp_server_verify_session(ccsrp_ctx_t srp, const void *user_M, + void *HAMK_bytes); + +/****************************************************************************** + * Client Side Routines + *****************************************************************************/ + +/*! + @function ccsrp_client_start_authentication + @abstract Initiate protocol with an ephemeral public key + + @param srp SRP + @param rng handle on random for key generation + @param A_bytes Output public key to send to the server + + @result 0 if no error + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,3)) +int +ccsrp_client_start_authentication(ccsrp_ctx_t srp, struct ccrng_state *rng, + void *A_bytes); + +/*! + @function ccsrp_client_process_challenge + @abstract Process the challenge receive from the server + + @param srp SRP + @param username identity + @param password_len length in byte of the password + @param password password of length password_len + @param salt_len length in byte of the salt + @param salt salt of length salt_len + @param B_bytes Value B received from the server + @param M_bytes Response to the challenge (output) + + @result 0 if no error + */ +CC_NONNULL_TU((1)) CC_NONNULL((2,4,6,7,8)) +int +ccsrp_client_process_challenge(ccsrp_ctx_t srp, + const char *username, + size_t password_len, const void *password, + size_t salt_len, const void *salt, + const void *B_bytes, + void *M_bytes); + +/*! + @function ccsrp_client_verify_session + @abstract Verify that the token received from the server is correct and that + therefore authentication succeeded. + + @param srp SRP + @param HAMK_bytes Authentication token received from the server + + @result true if authenticated, false otherwise (fail or incomplete protocol) + */ +CC_NONNULL_TU((1)) CC_NONNULL((2)) +bool +ccsrp_client_verify_session(ccsrp_ctx_t srp, const uint8_t *HAMK_bytes); + +CC_NONNULL_TU((1)) +CC_INLINE bool +ccsrp_client_set_noUsernameInX(ccsrp_ctx_t srp, bool flag) +{ + return HDR(srp)->flags.noUsernameInX = !!flag; +} + + +/****************************************************************************** + * Functions for both sides + *****************************************************************************/ + +/*! + @function ccsrp_is_authenticated + @abstract Returns whether authentication was successful + + @param srp SRP + + @result true if authenticated, false otherwise (fail or incomplete protocol) + */ +CC_NONNULL_TU((1)) +CC_INLINE bool +ccsrp_is_authenticated(ccsrp_ctx_t srp) { + return HDR(srp)->flags.authenticated; +} + +/*! + @function ccsrp_exchange_size + @abstract Returns the size of the public keys exchanged + + @param srp SRP + + @result The length of the public key in bytes + */ +CC_NONNULL_TU((1)) +CC_INLINE size_t +ccsrp_exchange_size(ccsrp_ctx_t srp) { + return ccsrp_ctx_sizeof_n(srp); +} + +/*! + @function ccsrp_session_size + @abstract Returns the size of the session authentication tokens M and HAMK + + @param srp SRP + + @result The length of M and HAMK in bytes + */ +CC_NONNULL_TU((1)) +CC_INLINE size_t +ccsrp_session_size(ccsrp_ctx_t srp) { + /* Session Keys and M and HAMK are returned in this many bytes */ + return (ccsrp_ctx_di(srp)->output_size); +} + +/*! + @function ccsrp_get_session_key_length + @abstract Returns the size of the session key K, which depends on the variant + + @param srp SRP + + @result The length of K + */ +CC_NONNULL_TU((1)) +CC_INLINE size_t +ccsrp_get_session_key_length(ccsrp_ctx_t srp) { + if ((HDR(srp)->flags.variant & CCSRP_OPTION_KDF_MASK) == CCSRP_OPTION_KDF_HASH) { + return (ccsrp_ctx_di(srp)->output_size); + } + else if (( (HDR(srp)->flags.variant & CCSRP_OPTION_KDF_MASK) == CCSRP_OPTION_KDF_INTERLEAVED) + || ((HDR(srp)->flags.variant & CCSRP_OPTION_KDF_MASK) == CCSRP_OPTION_KDF_MGF1)) { + return 2*(ccsrp_ctx_di(srp)->output_size); + } + return 0; // Error +} + +/*! + @function ccsrp_get_session_key + @abstract Returns a pointer to the session key and its size + + @param srp SRP context + @param key_length pointer to output the size of the session key + + @result pointer to the session key in SRP context. NULL if the key has not been + computed yet + */ +CC_NONNULL_TU((1)) CC_NONNULL((2)) +CC_INLINE const void * +ccsrp_get_session_key(ccsrp_ctx_t srp, size_t *key_length) { + *key_length = ccsrp_get_session_key_length(srp); + if (HDR(srp)->flags.sessionkey) { + return ccsrp_ctx_K(srp); + } else { + return NULL; + } +} + +/*! + @function ccsrp_get_premaster_secret + @abstract Returns a pointer to the premaster secret key + use for TLS-SRP + This value is not a cryptographic key. A KDF is needed before + use. + + @param srp SRP context + + @result pointer to the premaster secret in SRP context. + The secret is an array of ccsrp_ctx_n(srp) cc_units */ +CC_NONNULL_TU((1)) +CC_INLINE cc_unit * +ccsrp_get_premaster_secret(ccsrp_ctx_t srp) { + if (HDR(srp)->flags.sessionkey) { + return ccsrp_ctx_S(srp); + } else { + return NULL; + } +} + +/****************************************************************************** + * Component Test Interface + *****************************************************************************/ + +int +ccsrp_test_calculations(const struct ccdigest_info *di, ccsrp_const_gp_t gp, + struct ccrng_state *blinding_rng, + const char *username, uint32_t options, + size_t password_len, const void *password, + size_t salt_len, const void *salt, + size_t k_len, const void *k, + size_t x_len, const void *x, + size_t v_len, const void *v, + size_t a_len, const void *a, + size_t b_len, const void *b, + size_t A_len, const void *A, + size_t B_len, const void *B, + size_t u_len, const void *u, + size_t S_len, const void *S, + size_t K_len, const void *K, + size_t M_len, const void *M, + size_t HAMK_len, const void *HAMK + ); + +#endif /* Include Guard */ + diff --git a/corecrypto/ccsrp_gp.h b/corecrypto/ccsrp_gp.h new file mode 100644 index 0000000..b1e2794 --- /dev/null +++ b/corecrypto/ccsrp_gp.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012,2014,2015,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_ccsrp_gp_h +#define corecrypto_ccsrp_gp_h + +#include + +ccdh_const_gp_t ccsrp_gp_rfc5054_1024(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_2048(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_3072(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_4096(void); +ccdh_const_gp_t ccsrp_gp_rfc5054_8192(void); + +#endif diff --git a/corecrypto/cctest.h b/corecrypto/cctest.h new file mode 100644 index 0000000..729e5b9 --- /dev/null +++ b/corecrypto/cctest.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010,2011,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCTEST_H_ +#define _CORECRYPTO_CCTEST_H_ + +#include + +/* bin is n byte buffer into which a 2n byte long hex string is converted. */ +void cc_hex2bin(size_t n, unsigned char *bin, const char *hex); + +/* bin is n byte buffer which is converted into 2n + 1 byte long 0 terminated + string in hex. */ +void cc_bin2hex(size_t n, char *hex, const unsigned char *bin); + + +#define CCTEST_MAX_MSG_SIZE 8192 + +struct cctest_result { + double duration; + const char *msg; /* points to msg_buffer in cctest_input */ +}; + +struct cctest_input { + double start; + char msg_buffer[CCTEST_MAX_MSG_SIZE]; + struct cctest_result(*cctest_function)(const struct cctest_input *input); +}; + +#endif /* _CORECRYPTO_CCTEST_H_ */ diff --git a/corecrypto/ccwrap.h b/corecrypto/ccwrap.h new file mode 100644 index 0000000..82e5d5f --- /dev/null +++ b/corecrypto/ccwrap.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2012,2015,2016,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCWRAP_H_ +#define _CORECRYPTO_CCWRAP_H_ + +#include + +#include + +#define CCWRAP_IV 0xA6A6A6A6A6A6A6A6 +#define CCWRAP_SEMIBLOCK 8 + +// chosen somewhat arbitrarily +// corresponds to 65536 bytes of key material and one eight-byte IV +#define CCWRAP_MAXSEMIBLOCKS 8193 + +/*! + + @function ccwrap_wrapped_size + + @param data_size The size of the unwrapped key + + @result The size of the key after wrapping + + */ +CC_INLINE size_t ccwrap_wrapped_size(const size_t data_size) +{ + return (data_size + CCWRAP_SEMIBLOCK); +} + +/*! + + @function ccwrap_unwrapped_size + + @param data_size The size of the wrapped key + + @result The size of the key after unwrapping + + @discussion If the input is illegal (i.e. it is smaller than the overhead imposed by wrapping), the result will be zero. + + */ +CC_INLINE size_t ccwrap_unwrapped_size(const size_t data_size) +{ + if (data_size < CCWRAP_SEMIBLOCK) { + // data is malformed and possibly malicious + // just avoid underflow for now + // actually detect and handle error in ccwrap_auth_decrypt + return 0; + } + + return (data_size - CCWRAP_SEMIBLOCK); +} + + +/*! + @function ccwrap_auth_decrypt + @abstract Recover the wrapped key. + + @param ecb_mode Definition of an ECB implementation + @param ctx An instance of the implementation + @param nbytes Length in bytes of the wrapped key + @param in Pointer to the wrapped key + @param obytes Return parameter describing the size of the unwrapped key + @param out Return parameter pointing to the unwrapped key + + @result 0 iff successful; -1 otherwise. + + @discussion The out buffer should be allocated by the caller based + on the result of ccwrap_unwrapped_size(nbytes). On a successful + invocation, *obytes == ccwrap_unwrapped_size(nbytes); the caller needn't + verify this invariant. + */ +int ccwrap_auth_decrypt(const struct ccmode_ecb *ecb_mode, ccecb_ctx *ctx, + size_t nbytes, const void *in, + size_t *obytes, void *out); + +/*! + @function ccwrap_auth_encrypt + @abstract Wrap a key. + + @param ecb_mode Definition of an ECB implementation + @param ctx An instance of the implementation + @param nbytes Length in bytes of the key + @param in Pointer to the key + @param obytes Return parameter describing the size of the wrapped key + @param out Return parameter pointing to the wrapped key + + @result 0 iff successful; -1 otherwise. + + @discussion The out buffer should be allocated by the caller based + on the result of ccwrap_wrapped_size(nbytes). On a successful + invocation, *obytes == ccwrap_wrapped_size(nbytes); the caller needn't + verify this invariant. + */ +int ccwrap_auth_encrypt(const struct ccmode_ecb *ecb_mode, ccecb_ctx *ctx, + size_t nbytes, const void *in, + size_t *obytes, void *out); + +/* + This was originally implemented according to the “AES Key Wrap Specification” + formalized in RFC 3394. + + The following publications track changes made over time: + + [AES-KW1] National Institute of Standards and Technology, AES Key + Wrap Specification, 17 November 2001. + http://csrc.nist.gov/groups/ST/toolkit/documents/kms/ + AES_key_wrap.pdf + + [AES-KW2] Schaad, J. and R. Housley, "Advanced Encryption Standard + (AES) Key Wrap Algorithm", RFC 3394, September 2002. + + Note: block size is required to be 128 bits. + + This implementation wraps plaintexts between two and (CCWRAP_MAXSEMIBLOCKS-1) + semiblocks in length to produce ciphertexts between three and + CCWRAP_MAXSEMIBLOCKS semiblocks in length. All other inputs are rejected. + + While only the original unpadded algorithm is implemented at this time, the + following documents include specifications for padded versions allowing + plaintexts of arbitrary length: + + http://tools.ietf.org/html/rfc5649 + + NIST SP800-38F + +*/ + +#endif /* _CORECRYPTO_CCWRAP_H_ */ diff --git a/corecrypto/ccz.h b/corecrypto/ccz.h new file mode 100644 index 0000000..e9d561b --- /dev/null +++ b/corecrypto/ccz.h @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2011,2012,2015,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCZ_H_ +#define _CORECRYPTO_CCZ_H_ + +#include +#include +#include +#include + +#define CCZ_INVALID_INPUT_ERROR -1 +#define CCZ_INVALID_RADIX_ERROR -2 + +struct ccz { + size_t n; + struct ccz_class *isa; + int sac; + cc_unit *u; +}; +typedef struct ccz ccz; + +struct ccz_class { + void *ctx; + void *(*ccz_alloc)(void *, size_t); + void *(*ccz_realloc)(void *, size_t, void *, size_t); + void (*ccz_free)(void *, size_t, void *); +}; + +/* Return the size needed for a ccz big enough to hold cls type ccz's. */ +CC_NONNULL_ALL +size_t ccz_size(struct ccz_class *cls); + +/* Initialize a new ccz instance. */ +CC_NONNULL_ALL +void ccz_init(struct ccz_class *cls, ccz *r); + +/* Release the memory a ccz is holding on to. */ +CC_NONNULL_ALL +void ccz_free(ccz *r); + +/* r = 0, and clear memory accessed by r. */ +CC_NONNULL_ALL +void ccz_zero(ccz *r); + +/* r = s */ +CC_NONNULL_ALL +void ccz_set(ccz *r, const ccz *s); + +CC_NONNULL1 +void ccz_seti(ccz *r, uint64_t v); + +/* s == 0 -> return 0 | s > 0 -> return index (starting at 1) of most + significant bit that is 1. */ +CC_PURE CC_NONNULL_ALL +size_t ccz_bitlen(const ccz *s); + +/* s == 0 -> return 0 | s > 0 -> return the number of bits which are zero + before the first one bit from least to most significant bit. */ +CC_PURE CC_NONNULL_ALL +size_t ccz_trailing_zeros(const ccz *s); + +/* Return actual size in bytes needed to serialize s. */ +CC_PURE CC_NONNULL1 +size_t ccz_write_uint_size(const ccz *s); + +/* Serialize s, to out. + First byte of byte stream is the m.s. byte of s, + regardless of the size of cc_unit. + + No assumption is made about the alignment of out. + + The out_size argument should be the value returned from ccz_write_uint_size, + and is also the exact number of bytes this function will write to out. + If out_size if less than the value returned by ccz_write_uint_size, only the + first out_size non-zero most significant octets of s will be written. */ +CC_NONNULL((1,3)) +void ccz_write_uint(const ccz *s, size_t out_size, void *out); + +/* Return actual size in bytes needed to serialize s as int + (adding leading zero if high bit is set). */ +CC_PURE CC_NONNULL1 +size_t ccz_write_int_size(const ccz *s); + +/* Serialize s, to out. + First byte of byte stream is the m.s. byte of s, + regardless of the size of cc_unit. + + No assumption is made about the alignment of out. + + The out_size argument should be the value returned from ccz_write_int_size, + and is also the exact number of bytes this function will write to out. + If out_size if less than the value returned by ccz_write_int_size, only the + first out_size non-zero most significant octets of s will be written. */ +CC_NONNULL((1,3)) +void ccz_write_int(const ccz *s, size_t out_size, void *out); + +/* Return actual size in bytes needed to serialize s in base radix. Radix can be any value between 2 and 64. */ +CC_PURE CC_NONNULL1 +size_t ccz_write_radix_size(const ccz *s, unsigned radix); + +/* r = (data, len) treated as a big endian byte array, written in base radix. Radix can be any value between 2 and 64. */ +/* Not constant time. Do not use for sensitive information. */ +CC_NONNULL((1,3)) +void ccz_write_radix(const ccz *s, size_t out_size, void *out, unsigned radix); + +/* r = (data, len) treated as a big endian byte array. */ +CC_NONNULL((1,3)) +void ccz_read_uint(ccz *r, size_t data_size, const uint8_t *data); + +/* r = (data, len) treated as a two's complement signed big endian byte + array. Negative only iff high bit of first byte is set. */ +CC_NONNULL((1,3)) +void ccz_read_int(ccz *r, size_t data_size, const uint8_t *data); + +/* r = (data, len) treated as a big endian byte array. Return nonzero iff the passed in buffer isn't a valid base radix input string. Radix can be any value between 2 and 64. + Returns: 0 if no error + CCZ_INVALID_INPUT_ERROR if the input is not valid for the select radar + CCZ_INVALID_RADIX_ERROR if the radix is not supported (>64) */ +/* Not constant time. Do not use for sensitive information. */ +CC_NONNULL((1,3)) +int ccz_read_radix(ccz *r, size_t data_size, const char *data, unsigned radix); + +CC_PURE CC_NONNULL_ALL +int ccz_cmp(const ccz *s, const ccz *t); + +CC_PURE CC_NONNULL_ALL +int ccz_cmpi(const ccz *s, uint32_t v); + +/* r = -r. */ +CC_NONNULL_ALL +void ccz_neg(ccz *r); + +/* r = s + t. */ +CC_NONNULL_ALL +void ccz_add(ccz *r, const ccz *s, const ccz *t); + +/* r = s + v. */ +CC_NONNULL_ALL +void ccz_addi(ccz *r, const ccz *s, uint32_t v); + +/* r = s - t. */ +CC_NONNULL_ALL +void ccz_sub(ccz *r, const ccz *s, const ccz *t); + +/* r = s - v. */ +CC_NONNULL_ALL +void ccz_subi(ccz *r, const ccz *s, uint32_t v); + +/* r = s * t */ +CC_NONNULL_ALL +void ccz_mul(ccz *r, const ccz *s, const ccz *t); + +/* r = s * t */ +CC_NONNULL_ALL +void ccz_muli(ccz *r, const ccz *s, uint32_t v); + +/* q = s / t, r = s % t */ +CC_NONNULL((3,4)) +void ccz_divmod(ccz *q, ccz *r, const ccz *s, const ccz *t); + +/* r = s >> k */ +CC_NONNULL((1,2)) +void ccz_lsr(ccz *r, const ccz *s, size_t k); + +/* r = s << k */ +CC_NONNULL((1,2)) +void ccz_lsl(ccz *r, const ccz *s, size_t k); + +/* r = s / 2 */ +CC_INLINE CC_NONNULL_ALL +void ccz_div2(ccz *r, const ccz *s) { + ccz_lsr(r, s, 1); +} + +/* r = s % t */ +CC_NONNULL_ALL +void ccz_mod(ccz *r, const ccz *s, const ccz *t); + +/* r = s^2. */ +CC_NONNULL_ALL +void ccz_sqr(ccz *r, const ccz *s); + +/* r = gcd(s, t). */ +CC_NONNULL_ALL +void ccz_gcd(ccz *r, const ccz *s, const ccz *t); + +/* r = lcm(s, t). */ +CC_NONNULL_ALL +void ccz_lcm(ccz *r, const ccz *s, const ccz *t); + +/* r = (s * t) mod u. */ +CC_NONNULL_ALL +void ccz_mulmod(ccz *r, const ccz *s, const ccz *t, const ccz *u); + +/* r = (s^2) mod t. */ +CC_NONNULL_ALL +int ccz_sqrmod(ccz *r, const ccz *s, const ccz *t); + +/* r = (s^-1) mod t. */ +CC_NONNULL_ALL +int ccz_invmod(ccz *r, const ccz *s, const ccz *t); + +/* r = (s^t) mod u. */ +CC_NONNULL_ALL +int ccz_expmod(ccz *r, const ccz *s, const ccz *t, const ccz *u); + +/* Return the value of bit k in s. */ +CC_PURE CC_NONNULL1 +bool ccz_bit(const ccz *s, size_t k); + +/* Set the value of bit k in r to value. */ +CC_NONNULL1 +void ccz_set_bit(ccz *r, size_t k, bool value); + +/* Return true iff s a is likely prime. Using rabin miller for depth. */ +CC_NONNULL_ALL +bool ccz_is_prime(const ccz *s, unsigned depth); + +/* s == odd -> return true | s == even -> return false */ +CC_INLINE CC_PURE CC_NONNULL_ALL +bool ccz_is_odd(const ccz *s) { + return ccz_bit(s, 0); +} + +/* s == 0 -> return true | s != 0 -> return false */ +CC_PURE CC_NONNULL_ALL +bool ccz_is_zero(const ccz *s); + +/* s == 1 -> return true | s != 1 -> return false */ +CC_PURE CC_NONNULL_ALL +bool ccz_is_one(const ccz *s); + +/* s < 0 -> return true | s >= 0 -> return false */ +CC_PURE CC_NONNULL_ALL +bool ccz_is_negative(const ccz *s); + + + +/* Debugging */ +CC_NONNULL1 +void ccz_print(const ccz *s); +CC_NONNULL2 +void ccz_lprint(const char *label, const ccz *s); + +/* Forward declaration so we don't depend on ccrng.h. */ +struct ccrng_state; + +/* Make a ccz with up to nbits sized random value. */ +CC_NONNULL((1,3)) +int ccz_random_bits(ccz *r, size_t nbits, struct ccrng_state *rng); + +#endif /* _CORECRYPTO_CCZ_H_ */ diff --git a/corecrypto/ccz_priv.h b/corecrypto/ccz_priv.h new file mode 100644 index 0000000..907f7f2 --- /dev/null +++ b/corecrypto/ccz_priv.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011,2012,2015,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCZ_PRIV_H_ +#define _CORECRYPTO_CCZ_PRIV_H_ + +#include +#include +#include +#include /* For abs() */ + +#ifndef CCZ_PREC +#define CCZ_PREC 32 /* default units of precision */ +#endif + +/* Error codes. */ +enum { + CCZ_OK = 0, + CCZ_MEM, +}; + +#define ccz_zp_decl(_ccz_, _name_) \ + cczp_decl_n(ccz_n(_ccz_), _name_); \ + CCZP_N(_name_) = ccz_n(_ccz_); \ + ccn_set(ccz_n(_ccz_), CCZP_PRIME(_name_), _ccz_->u); + + +CC_INLINE CC_CONST CC_NONNULL_ALL +int ccz_sign(const ccz *s) { + return s->sac < 0 ? -1 : 1; +} + +CC_INLINE CC_NONNULL1 +void ccz_set_sign(ccz *r, int sign) +{ + if (ccz_sign(r) != sign) + r->sac = -r->sac; +} + +CC_INLINE CC_CONST CC_NONNULL_ALL +cc_size ccz_n(const ccz *s) { + return s->n; +} + +CC_INLINE CC_NONNULL1 +void ccz_set_n(ccz *r, cc_size n) { + r->n = n; +} + +CC_INLINE CC_CONST CC_NONNULL_ALL +cc_size ccz_capacity(const ccz *s) { + return (cc_size)abs(s->sac); +} + +CC_INLINE CC_NONNULL1 +void ccz_set_capacity(ccz *r, cc_size capacity) +{ + if (ccz_capacity(r) < capacity) { + size_t ncapacity = capacity + (CCZ_PREC * 2) - (capacity % CCZ_PREC); + cc_unit *t; + if (ccz_capacity(r)) + t = r->isa->ccz_realloc(r->isa->ctx, ccn_sizeof_n(ccz_capacity(r)), r->u, ccn_sizeof_n(ncapacity)); + else + t = r->isa->ccz_alloc(r->isa->ctx, ccn_sizeof_n(ncapacity)); + + r->sac = r->sac < 0 ? -(int)ncapacity : (int)ncapacity; + r->u = t; + } +} + +/* From ccn_write_radix. */ +extern const char *ccn_radix_digit_map; + +#endif /* _CORECRYPTO_CCZ_PRIV_H_ */ diff --git a/corecrypto/cczp.h b/corecrypto/cczp.h new file mode 100644 index 0000000..fb8de7d --- /dev/null +++ b/corecrypto/cczp.h @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2010,2011,2012,2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef _CORECRYPTO_CCZP_H_ +#define _CORECRYPTO_CCZP_H_ + +#include +#include + +/* + Don't use cczp_hd struct directly, except in static tables such as eliptic curve parameter definitions. + + Declare cczp objects using cczp_decl_n(). It allocates cc_unit arrays of the length returned by either cczp_nof_n() or cczp_short_nof_n(). +*/ + +struct cczp; +#if CORECRYPTO_USE_TRANSPARENT_UNION + +typedef union { + cc_unit *u; + struct cczp *zp; + //cczp_const_t czp; //for automatic type cast + //struct cczp_prime *prime; +} cczp_t __attribute__((transparent_union)); + +typedef union { + const cc_unit *u; + const struct cczp *zp; + //const struct cczp_prime *prime; + cczp_t _nczp; +} cczp_const_t __attribute__((transparent_union)); + +#else + typedef struct cczp* cczp_t; + typedef const struct cczp* cczp_const_t; +#endif +typedef void (*ccmod_func_t)(cc_ws_t ws, cczp_const_t zp, cc_unit *r, const cc_unit *s); + +// keep cczp_hd and cczp structures consistent +// cczp_hd is typecasted to cczp to read EC curve params +// options field is to specify Montgomery arithmetic, bit field, etc +// make sure n is the first element see ccrsa_ctx_n macro +#define __CCZP_HEADER_ELEMENTS_DEFINITIONS(pre) \ +cc_size pre ## n;\ +cc_unit pre ## options;\ +ccmod_func_t pre ## mod_prime; + +#define __CCZP_ELEMENTS_DEFINITIONS(pre) \ +__CCZP_HEADER_ELEMENTS_DEFINITIONS(pre) \ +cc_unit pre ## ccn[]; + +//cczp_hd must be defined separetly without variable length array ccn[], because it is used in sructures such as ccdh_gp_decl_n +struct cczp_hd{ + __CCZP_HEADER_ELEMENTS_DEFINITIONS() +} CC_ALIGNED(CCN_UNIT_SIZE); + +struct cczp { + __CCZP_ELEMENTS_DEFINITIONS() +} CC_ALIGNED(CCN_UNIT_SIZE); + + +/* Return the size of an cczp where each ccn is _size_ bytes. */ +#define cczp_size(_size_) (sizeof(struct cczp) + ccn_sizeof_n(1) + 2 * (_size_)) + +/* Return number of units that a struct cczp needs to be in units for a prime + size of N units. This is large enough for all operations. */ +#define cczp_nof_n(_n_) (ccn_nof_size(sizeof(struct cczp)) + 1 + 2 * (_n_)) + +/* Return number of units that a struct cczp needs to be in units for a prime + size of _n_ units. The _short variant does not have room for CCZP_RECIP, + so it can not be used with cczp_mod, cczp_mul, cczp_sqr. It can be used + with cczp_add, cczp_sub, cczp_div2, cczp_mod_inv. */ +#define cczp_short_nof_n(_n_) (ccn_nof_size(sizeof(struct cczp)) + (_n_)) + +#define cczp_decl_n(_n_, _name_) cc_ctx_decl(struct cczp, ccn_sizeof_n(cczp_nof_n(_n_)), _name_) +#define cczp_short_decl_n(_n_, _name_) cc_ctx_decl(struct cczp_short, ccn_sizeof_n(cczp_short_nof_n(_n_)), _name_) + +#define cczp_clear_n(_n_, _name_) cc_clear(ccn_sizeof_n(cczp_nof_n(_n_)), _name_) +#define cczp_short_clear_n(_n_, _name_) cc_clear(ccn_sizeof_n(cczp_short_nof_n(_n_)), _name_) + +#if CORECRYPTO_USE_TRANSPARENT_UNION + #define CCZP_N(ZP) (((cczp_t)(ZP)).zp->n) + #define CCZP_MOD(ZP) (((cczp_t)(ZP)).zp->mod_prime) + #define CCZP_PRIME(ZP) (((cczp_t)(ZP)).zp->ccn) + #define CCZP_RECIP(ZP) (((cczp_t)(ZP)).zp->ccn + cczp_n(ZP)) + #define CCZP_OPS(ZP) ((ZP).zp->options) + #define CCZP_MOD_PRIME(ZP) CCZP_MOD(ZP) + +CC_CONST CC_NONNULL_TU((1)) +static inline cc_size cczp_n(cczp_const_t zp) { + return zp.zp->n; +} + +CC_CONST CC_NONNULL_TU((1)) +static inline cc_unit cczp_options(cczp_const_t zp) { + return zp.zp->options; +} + +CC_CONST CC_NONNULL_TU((1)) +static inline ccmod_func_t cczp_mod_prime(cczp_const_t zp) { + return zp.zp->mod_prime; +} + +CC_CONST CC_NONNULL_TU((1)) +static inline const cc_unit *cczp_prime(cczp_const_t zp) { + return zp.zp->ccn; +} + +/* Return a pointer to the Reciprocal or Montgomery constant of zp, which is + allocated cczp_n(zp) + 1 units long. */ +CC_CONST CC_NONNULL_TU((1)) + +static inline const cc_unit *cczp_recip(cczp_const_t zp) { + return zp.zp->ccn + zp.zp->n; +} + +#else + #define CCZP_N(ZP) ((ZP)->n) + #define CCZP_MOD(ZP) ((ZP)->mod_prime) + #define CCZP_MOD_PRIME(ZP) CCZP_MOD(ZP) + #define CCZP_PRIME(ZP) ((ZP)->ccn) + #define CCZP_RECIP(ZP) ((ZP)->ccn + CCZP_N(ZP)) + #define CCZP_OPS(ZP) ((ZP)->options) +CC_CONST CC_NONNULL_TU((1)) +static inline cc_size cczp_n(cczp_const_t zp) { + return zp->n; +} + +CC_CONST CC_NONNULL_TU((1)) +static inline cc_unit cczp_options(cczp_const_t zp) { + return zp->options; +} + +CC_CONST CC_NONNULL_TU((1)) +static inline ccmod_func_t cczp_mod_prime(cczp_const_t zp) { + return zp->mod_prime; +} + +CC_CONST CC_NONNULL_TU((1)) +static inline const cc_unit *cczp_prime(cczp_const_t zp) { + return zp->ccn; +} + +/* Return a pointer to the Reciprocal or Montgomery constant of zp, which is + allocated cczp_n(zp) + 1 units long. */ +CC_CONST CC_NONNULL_TU((1)) + +static inline const cc_unit *cczp_recip(cczp_const_t zp) { + return zp->ccn + zp->n; +} + +#endif + + +CC_CONST CC_NONNULL_TU((1)) +CC_INLINE size_t cczp_bitlen(cczp_const_t zp) { + return ccn_bitlen(cczp_n(zp), cczp_prime(zp)); +} + + +/* Ensure both cczp_mod_prime(zp) and cczp_recip(zp) are valid. cczp_n and + cczp_prime must have been previously initialized. */ +CC_NONNULL_TU((1)) +int cczp_init(cczp_t zp); + +/* Compute r = s2n mod cczp_prime(zp). Will write cczp_n(zp) + units to r and reads 2 * cczp_n(zp) units units from s2n. If r and s2n are not + identical they must not overlap. Before calling this function either + cczp_init(zp) must have been called or both CCZP_MOD_PRIME((cc_unit *)zp) + and CCZP_RECIP((cc_unit *)zp) must be initialized some other way. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +void cczp_mod(cc_ws_t ws, cczp_const_t zp, cc_unit *r, const cc_unit *s2n); + +/* Compute r = sn mod cczp_prime(zp), Will write cczp_n(zp) + units to r and reads sn units units from s. If r and s are not + identical they must not overlap. Before calling this function either + cczp_init(zp) must have been called or both CCZP_MOD_PRIME((cc_unit *)zp) + and CCZP_RECIP((cc_unit *)zp) must be initialized some other way. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 4)) +int cczp_modn(cczp_const_t zp, cc_unit *r, cc_size ns, const cc_unit *s); + +/* Compute r = x * y mod cczp_prime(zp). Will write cczp_n(zp) units to r + and reads cczp_n(zp) units units from both x and y. If r and x are not + identical they must not overlap, The same holds for r and y. Before + calling this function either cczp_init(zp) must have been called or both + CCZP_MOD_PRIME((cc_unit *)zp) and CCZP_RECIP((cc_unit *)zp) must be + initialized some other way. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +void cczp_mul(cczp_const_t zp, cc_unit *t, const cc_unit *x, const cc_unit *y); + +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4, 5)) +void cczp_mul_ws(cc_ws_t ws, cczp_const_t zp, cc_unit *t, const cc_unit *x, const cc_unit *y); + +/* Compute r = x * x mod cczp_prime(zp). Will write cczp_n(zp) units to r + and reads cczp_n(zp) units from x. If r and x are not identical they must + not overlap. Before calling this function either cczp_init(zp) must have + been called or both CCZP_MOD_PRIME((cc_unit *)zp) and + CCZP_RECIP((cc_unit *)zp) must be initialized some other way. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +void cczp_sqr(cczp_const_t zp, cc_unit *r, const cc_unit *x); + +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +void cczp_sqr_ws(cc_ws_t ws, cczp_const_t zp, cc_unit *r, const cc_unit *x); + +/* Compute r = x^(1/2) mod cczp_prime(zp). Will write cczp_n(zp) units to r + and reads cczp_n(zp) units from x. If r and x are not identical they must + not overlap. Before calling this function either cczp_init(zp) must have + been called or both CCZP_MOD_PRIME((cc_unit *)zp) and + CCZP_RECIP((cc_unit *)zp) must be initialized some other way. + Only support prime = 3 mod 4 */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +int cczp_sqrt(cczp_const_t zp, cc_unit *r, const cc_unit *x); + +/* Compute r = m ^ e mod cczp_prime(zp), using Montgomery ladder. + - writes cczp_n(zp) units to r + - reads cczp_n(zp) units units from m and e + - if r and m are not identical they must not overlap. + - r and e must not overlap nor be identical. + - before calling this function either cczp_init(zp) must have been called + or both CCZP_MOD_PRIME((cc_unit *)zp) and CCZP_RECIP((cc_unit *)zp) must + be initialized some other way. + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +int cczp_power(cczp_const_t zp, cc_unit *r, const cc_unit *m, + const cc_unit *e); + +/* Compute r = m ^ e mod cczp_prime(zp), using Square Square Multiply Always. + - writes cczp_n(zp) units to r + - reads cczp_n(zp) units units from m and e + - if r and m are not identical they must not overlap. + - r and e must not overlap nor be identical. + - before calling this function either cczp_init(zp) must have been called + or both CCZP_MOD_PRIME((cc_unit *)zp) and CCZP_RECIP((cc_unit *)zp) must + be initialized some other way. + + Important: This function is intented to be constant time but is more likely + to leak information due to memory cache. Only used with randomized input + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +int cczp_power_ssma(cczp_const_t zp, cc_unit *r, const cc_unit *m, + const cc_unit *e); + +int cczp_power_ssma_ws(cc_ws_t ws, cczp_const_t zp, cc_unit *r, const cc_unit *s, const cc_unit *e); + +/* Compute r = m ^ e mod cczp_prime(zp). Will write cczp_n(zp) units to r and + reads cczp_n(zp) units units from m. Reads ebitlen bits from e. + m must be <= to cczp_prime(zp). If r and m are not identical they must not + overlap. r and e must not overlap nor be identical. + Before calling this function either cczp_init(zp) must have been called + or both CCZP_MOD_PRIME((cc_unit *)zp) and CCZP_RECIP((cc_unit *)zp) must + be initialized some other way. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 5)) +int cczp_powern(cczp_const_t zp, cc_unit *r, const cc_unit *s, + size_t ebitlen, const cc_unit *e); + +/* Compute r = x + y mod cczp_prime(zp). Will write cczp_n(zp) units to r and + reads cczp_n(zp) units units from x and y. If r and x are not identical + they must not overlap. Only cczp_n(zp) and cczp_prime(zp) need to be valid. + Can be used with cczp_short_nof_n sized cc_unit array zp. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +void cczp_add(cczp_const_t zp, cc_unit *r, const cc_unit *x, + const cc_unit *y); + +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4, 5)) +void cczp_add_ws(cc_ws_t ws, cczp_const_t zp, cc_unit *r, const cc_unit *x, + const cc_unit *y); + +/* Compute r = x - y mod cczp_prime(zp). Will write cczp_n(zp) units to r and + reads cczp_n(zp) units units from x and y. If r and x are not identical + they must not overlap. Only cczp_n(zp) and cczp_prime(zp) need to be valid. + Can be used with cczp_short_nof_n sized cc_unit array zp. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +void cczp_sub(cczp_const_t zp, cc_unit *r, const cc_unit *x, const cc_unit *y); + +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4, 5)) +void cczp_sub_ws(cc_ws_t ws, cczp_const_t zp, cc_unit *r, const cc_unit *x, + const cc_unit *y); + +/* Compute r = x / 2 mod cczp_prime(zp). Will write cczp_n(zp) units to r and + reads cczp_n(zp) units units from x. If r and x are not identical + they must not overlap. Only cczp_n(zp) and cczp_prime(zp) need to be valid. + Can be used with cczp_short_nof_n sized cc_unit array zp. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +void cczp_div2(cczp_const_t zp, cc_unit *r, const cc_unit *x); + +/* Compute q = a_2n / cczp_prime(zd) (mod cczp_prime(zd)) . Will write cczp_n(zd) + units to q and r. Will read 2 * cczp_n(zd) units units from a. If r and a + are not identical they must not overlap. Before calling this function + either cczp_init(zp) must have been called or both + CCZP_MOD_PRIME((cc_unit *)zp) and CCZP_RECIP((cc_unit *)zp) must be + initialized some other way. */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +void cczp_div(cczp_const_t zd, cc_unit *q, cc_unit *r, const cc_unit *a_2n); + + +/*! + @brief cczp_inv(zp, r, x) computes r = x^-1 (mod p) , where p=cczp_prime(zp). + @discussion It is a general function and works for any p. It validates the inputs. r and x can overlap. It writes n =cczp_n(zp) units to r, and read n units units from x and p. The output r is overwriten only if the inverse is correctly computed. This function is not constant time in absolute sense, but it does not have data dependent 'if' statements in the code. + @param zp The input zp. cczp_n(zp) and cczp_prime(zp) need to be valid. cczp_init(zp) need not to be called before invoking cczp_inv(). + @param x input big integer + @param r output big integer + @return 0 if inverse exists and correctly computed. + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) + +int cczp_inv(cczp_const_t zp, cc_unit *r, const cc_unit *x); + +/*! + @brief cczp_inv_odd(zp, r, x) computes r = x^-1 (mod p) , where p=cczp_prime(zp) is an odd number. + @discussion r and x can overlap. + @param zp The input zp. cczp_n(zp) and cczp_prime(zp) need to be valid. cczp_init(zp) need not to be called before invoking. + @param x input big integer + @param r output big integer + @return 0 if successful + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +int cczp_inv_odd(cczp_const_t zp, cc_unit *r, const cc_unit *x); + +/*! + @brief cczp_inv_field(zp, r, x) computes r = x^-1 (mod p) , where p=cczp_prime(zp) is a prime number number. + @discussion r and x must NOT overlap. The excution time of the function is independent to the value of the input x. It works only if p is a field. That is, when p is a prime. It supports Montgomery and non-Montgomery form of zp. It leaks the value of the prime and should only be used be used for public (not secret) primes (ex. Elliptic Curves) + + @param zp The input zp. cczp_n(zp) and cczp_prime(zp) need to be valid. cczp_init(zp) need not to be called before invoking cczp_inv_field(). + @param x input big unteger + @param r output big integer + @return 0 if inverse exists and correctly computed. + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +int cczp_inv_field(cczp_const_t zp, cc_unit *r, const cc_unit *x); + +#endif /* _CORECRYPTO_CCZP_H_ */ diff --git a/corecrypto/cczp_priv.h b/corecrypto/cczp_priv.h new file mode 100644 index 0000000..08e2750 --- /dev/null +++ b/corecrypto/cczp_priv.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ + +#ifndef corecrypto_cczp_priv_h +#define corecrypto_cczp_priv_h + +#include +#include + +#define CCZP_MOD_WORKSPACE_N(n) (6*((n)+1)+CCN_MUL_WS_WORKSPACE_N(n)) +#define CCZP_MUL_WORKSPACE_N(n) (2*(n) + CCZP_MOD_WORKSPACE_N(n)) +#define CCZP_POWER_SSMA_WORKSPACE_N(n) (5*(n) + CCZP_MUL_WORKSPACE_N(n)) +#define CCZP_SQR_WORKSPACE_N(n) (CCZP_MUL_WORKSPACE_N(n)) +#define CCZP_ADD_WORKSPACE_N(n) (1*n) +#define CCZP_SUB_WORKSPACE_N(n) (1*n) + +#define CCZP_MONTGOMERY 1 + +/* + * Same as cczp_init with workspace + */ +void cczp_init_ws(cc_ws_t ws, cczp_t zp); + +/* + * Same as cczp_modn with workspace + */ +int cczp_modn_ws(cc_ws_t ws, cczp_const_t zp, cc_unit *r, cc_size ns, const cc_unit *s); + + +/* Compute r = m ^ e (mod p), where p=cczp_prime(zp). Writes n=cczp_n(zp) units to r and + reads n units units from m and e. If r and m are not identical + they must not overlap. r and e must not overlap nor be identical. + Before calling this function either cczp_init(zp) must have been called + or both CCZP_MOD_PRIME((cc_unit *)zp) and CCZP_RECIP((cc_unit *)zp) must + be initialized some other way. + + Use this function with PUBLIC values only, it may leak the parameters + in timing / Simple power analysis + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3, 4)) +int +cczp_power_fast(cczp_const_t zp, cc_unit *r, const cc_unit *s, const cc_unit *e); + +/* + * Montgomery representation support + */ +CC_NONNULL_TU((1)) +CC_INLINE +bool cczp_is_montgomery(cczp_const_t zp) { + return (CCZP_OPS(zp) & CCZP_MONTGOMERY) == CCZP_MONTGOMERY ; +} + +/* + * to Montgomery representation + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +CC_INLINE +void cczp_convert_to_montgomery(cczp_const_t zp,cc_unit *r, const cc_unit *x) { + //ccn_lprint(cczp_n(zp)+1, "Montgomery cst:",cczp_recip(zp));q + cc_assert(cczp_is_montgomery(zp)); + cczp_mul(zp,r,x,cczp_recip(zp)); +} + +/* + * from Montgomery representation + */ +CC_NONNULL_TU((1)) CC_NONNULL((2, 3)) +CC_INLINE +void cczp_convert_from_montgomery(cczp_const_t zp,cc_unit *r, const cc_unit *x) { + cc_unit t2[2*cczp_n(zp)];//vla + ccn_setn(2*cczp_n(zp), t2, cczp_n(zp),x); + cczp_mod_prime(zp)(NULL, zp, r, t2); +} + +#if CORECRYPTO_USE_TRANSPARENT_UNION + #define cczp_const_decl(zp, ini) cczp_const_t (zp); (zp).zp = (ini); +#else + #define cczp_const_decl(zp, ini) cczp_const_t (zp) = (ini); +#endif + +#endif diff --git a/corecrypto/fipspost.h b/corecrypto/fipspost.h new file mode 100644 index 0000000..b4b9aec --- /dev/null +++ b/corecrypto/fipspost.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012,2015,2016,2017,2018 Apple Inc. All rights reserved. + * + * corecrypto Internal Use License Agreement + * + * IMPORTANT: This Apple corecrypto software is supplied to you by Apple Inc. ("Apple") + * in consideration of your agreement to the following terms, and your download or use + * of this Apple software constitutes acceptance of these terms. If you do not agree + * with these terms, please do not download or use this Apple software. + * + * 1. As used in this Agreement, the term "Apple Software" collectively means and + * includes all of the Apple corecrypto materials provided by Apple here, including + * but not limited to the Apple corecrypto software, frameworks, libraries, documentation + * and other Apple-created materials. In consideration of your agreement to abide by the + * following terms, conditioned upon your compliance with these terms and subject to + * these terms, Apple grants you, for a period of ninety (90) days from the date you + * download the Apple Software, a limited, non-exclusive, non-sublicensable license + * under Apple’s copyrights in the Apple Software to make a reasonable number of copies + * of, compile, and run the Apple Software internally within your organization only on + * devices and computers you own or control, for the sole purpose of verifying the + * security characteristics and correct functioning of the Apple Software; provided + * that you must retain this notice and the following text and disclaimers in all + * copies of the Apple Software that you make. You may not, directly or indirectly, + * redistribute the Apple Software or any portions thereof. The Apple Software is only + * licensed and intended for use as expressly stated above and may not be used for other + * purposes or in other contexts without Apple's prior written permission. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, are + * granted by Apple herein. + * + * 2. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES + * OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING + * THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS, + * SYSTEMS, OR SERVICES. APPLE DOES NOT WARRANT THAT THE APPLE SOFTWARE WILL MEET YOUR + * REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR + * ERROR-FREE, THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED, OR THAT THE APPLE + * SOFTWARE WILL BE COMPATIBLE WITH FUTURE APPLE PRODUCTS, SOFTWARE OR SERVICES. NO ORAL + * OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE + * WILL CREATE A WARRANTY. + * + * 3. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING + * IN ANY WAY OUT OF THE USE, REPRODUCTION, COMPILATION OR OPERATION OF THE APPLE + * SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING + * NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 4. This Agreement is effective until terminated. Your rights under this Agreement will + * terminate automatically without notice from Apple if you fail to comply with any term(s) + * of this Agreement. Upon termination, you agree to cease all use of the Apple Software + * and destroy all copies, full or partial, of the Apple Software. This Agreement will be + * governed and construed in accordance with the laws of the State of California, without + * regard to its choice of law rules. + * + * You may report security issues about Apple products to product-security@apple.com, + * as described here:  https://www.apple.com/support/security/. Non-security bugs and + * enhancement requests can be made via https://bugreport.apple.com as described + * here: https://developer.apple.com/bug-reporting/ + * + * EA1350 + * 10/5/15 + */ +#ifndef _CORECRYPTO_FIPSPOST_H_ +#define _CORECRYPTO_FIPSPOST_H_ + +#include + +// Error list +#define CCERR_GENERIC_FAILURE -1 // Configuration or unexpect issue +#define CCERR_INVALID_SLICE -2 +#define CCERR_FILE_ERROR -3 +#define CCERR_LIBRARY_ERROR -4 +#define CCERR_INTEGRITY_ERROR -5 +#define CCERR_KAT_FAILURE -6 // Output of the algo is not as expect + +// Boot-Arg fips_mode Flags +// +// FIPS_MODE_FLAG_FULL is the default value when no other value is set, which +// is the case for all production devices. +// +// When performing tests, if _FORCEFAIL is set to true, then the tests +// intentionally fail and log their failure. The kernelspace and userspace +// flags can be enabled independently. +// +// If it's not desired to panic, supply the _NOPANIC flag with the +// _FORCEFAIL flag. +// +// Additional logging can be enabled by supplying the _VERBOSE flag. +// +// _NOINTEG is used to ignore just the results of the module integrity +// check process, which is very useful when setting breakpoints in the +// kext for diagnostic or auditing purposes. +// +// Supplying _TRACE causes a trace buffer to be accumulated of the instrumented +// functions for only one execution of the POST. As the POST finishes, the +// _TRACE flag is cleared from the fips_mode and no further tracing will occur. +#define FIPS_MODE_FLAG_DEBUG (1 << 0) +#define FIPS_MODE_FLAG_FULL (1 << 1) +#define FIPS_MODE_FLAG_DISABLE (1 << 2) +#define FIPS_MODE_FLAG_VERBOSE (1 << 3) +#define FIPS_MODE_FLAG_US_FORCEFAIL (1 << 4) +#define FIPS_MODE_FLAG_KS_FORCEFAIL (1 << 5) +#define FIPS_MODE_FLAG_NOINTEG (1 << 6) +#define FIPS_MODE_FLAG_TRACE (1 << 7) +#define FIPS_MODE_FLAG_NOPANIC (1 << 8) + +#define FIPS_MODE_IS_DEBUG(MODE) ((MODE) & FIPS_MODE_FLAG_DEBUG) +#define FIPS_MODE_IS_FULL(MODE) ((MODE) & FIPS_MODE_FLAG_FULL) +#define FIPS_MODE_IS_DISABLE(MODE) ((MODE) & FIPS_MODE_FLAG_DISABLE) +#define FIPS_MODE_IS_VERBOSE(MODE) ((MODE) & FIPS_MODE_FLAG_VERBOSE) +#define FIPS_MODE_IS_US_FORCEFAIL(MODE) ((MODE) & FIPS_MODE_FLAG_US_FORCEFAIL) +#define FIPS_MODE_IS_KS_FORCEFAIL(MODE) ((MODE) & FIPS_MODE_FLAG_KS_FORCEFAIL) +#define FIPS_MODE_IS_NOINTEG(MODE) ((MODE) & FIPS_MODE_FLAG_NOINTEG) +#define FIPS_MODE_IS_TRACE(MODE) ((MODE) & FIPS_MODE_FLAG_TRACE) +#define FIPS_MODE_IS_NOPANIC(MODE) ((MODE) & FIPS_MODE_FLAG_NOPANIC) + +#if CC_KERNEL +#define FIPS_MODE_FLAG_FORCEFAIL FIPS_MODE_FLAG_KS_FORCEFAIL +#define FIPS_MODE_IS_FORCEFAIL(MODE) FIPS_MODE_IS_KS_FORCEFAIL(MODE) +#else +#define FIPS_MODE_FLAG_FORCEFAIL FIPS_MODE_FLAG_US_FORCEFAIL +#define FIPS_MODE_IS_FORCEFAIL(MODE) FIPS_MODE_IS_US_FORCEFAIL(MODE) +#endif + +struct mach_header; + +/* + * Entrypoint for all POST tests. + */ +int fipspost_post(int fips_mode, struct mach_header *pmach_header); + +#endif /* _CORECRYPTO_FIPSPOST_H_ */ diff --git a/ldid/ldid.cpp b/ldid/ldid.cpp new file mode 100644 index 0000000..6a12d43 --- /dev/null +++ b/ldid/ldid.cpp @@ -0,0 +1,2453 @@ +/* ldid - (Mach-O) Link-Loader Identity Editor + * Copyright (C) 2007-2015 Jay Freeman (saurik) +*/ + +/* GNU Affero General Public License, Version 3 {{{ */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +**/ +/* }}} */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef LDID_NOSMIME +#include +#include +#include +#include +#endif + +#ifdef __APPLE__ +#include + +#define LDID_SHA1_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH +#define LDID_SHA1 CC_SHA1 +#define LDID_SHA1_CTX CC_SHA1_CTX +#define LDID_SHA1_Init CC_SHA1_Init +#define LDID_SHA1_Update CC_SHA1_Update +#define LDID_SHA1_Final CC_SHA1_Final + +#define LDID_SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH +#define LDID_SHA256 CC_SHA256 +#define LDID_SHA256_CTX CC_SHA256_CTX +#define LDID_SHA256_Init CC_SHA256_Init +#define LDID_SHA256_Update CC_SHA256_Update +#define LDID_SHA256_Final CC_SHA256_Final +#else +#include + +#define LDID_SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH +#define LDID_SHA1 SHA1 +#define LDID_SHA1_CTX SHA_CTX +#define LDID_SHA1_Init SHA1_Init +#define LDID_SHA1_Update SHA1_Update +#define LDID_SHA1_Final SHA1_Final + +#define LDID_SHA256_DIGEST_LENGTH SHA256_DIGEST_LENGTH +#define LDID_SHA256 SHA256 +#define LDID_SHA256_CTX SHA256_CTX +#define LDID_SHA256_Init SHA256_Init +#define LDID_SHA256_Update SHA256_Update +#define LDID_SHA256_Final SHA256_Final +#endif + +#ifndef LDID_NOPLIST +#include +#endif + +#include "ldid.hpp" + +#define _assert___(line) \ + #line +#define _assert__(line) \ + _assert___(line) + +#ifdef __EXCEPTIONS +#define _assert_(expr, format, ...) \ + do if (!(expr)) { \ + fprintf(stderr, "%s(%u): _assert(): " format "\n", "ldid.cpp", __LINE__, ## __VA_ARGS__); \ + throw "ldid.cpp" "(" _assert__(__LINE__) "): _assert(" #expr ")"; \ + } while (false) +#else +// XXX: this is not acceptable +#define _assert_(expr, format, ...) \ + do if (!(expr)) { \ + fprintf(stderr, "%s(%u): _assert(): " format "\n", "ldid.cpp", __LINE__, ## __VA_ARGS__); \ + exit(-1); \ + } while (false) +#endif + +#define _assert(expr) \ + _assert_(expr, "%s", #expr) + +#define _syscall(expr, ...) [&] { for (;;) { \ + auto _value(expr); \ + if ((long) _value != -1) \ + return _value; \ + int error(errno); \ + if (error == EINTR) \ + continue; \ + /* XXX: EINTR is included in this list to fix g++ */ \ + for (auto success : (long[]) {EINTR, __VA_ARGS__}) \ + if (error == success) \ + return (decltype(expr)) -success; \ + _assert_(false, "errno=%u", error); \ +} }() + +#define _trace() \ + fprintf(stderr, "_trace(%s:%u): %s\n", "ldid.cpp", __LINE__, __FUNCTION__) + +#define _not(type) \ + ((type) ~ (type) 0) + +#define _packed \ + __attribute__((packed)) + +template +struct Iterator_ { + typedef typename Type_::const_iterator Result; +}; + +#define _foreach(item, list) \ + for (bool _stop(true); _stop; ) \ + for (const __typeof__(list) &_list = (list); _stop; _stop = false) \ + for (Iterator_<__typeof__(list)>::Result _item = _list.begin(); _item != _list.end(); ++_item) \ + for (bool _suck(true); _suck; _suck = false) \ + for (const __typeof__(*_item) &item = *_item; _suck; _suck = false) + +class _Scope { +}; + +template +class Scope : + public _Scope +{ + private: + Function_ function_; + + public: + Scope(const Function_ &function) : + function_(function) + { + } + + ~Scope() { + function_(); + } +}; + +template +Scope _scope(const Function_ &function) { + return Scope(function); +} + +#define _scope__(counter, function) \ + __attribute__((__unused__)) \ + const _Scope &_scope ## counter(_scope([&]function)) +#define _scope_(counter, function) \ + _scope__(counter, function) +#define _scope(function) \ + _scope_(__COUNTER__, function) + +#define CPU_ARCH_MASK uint32_t(0xff000000) +#define CPU_ARCH_ABI64 uint32_t(0x01000000) + +#define CPU_TYPE_ANY uint32_t(-1) +#define CPU_TYPE_VAX uint32_t( 1) +#define CPU_TYPE_MC680x0 uint32_t( 6) +#define CPU_TYPE_X86 uint32_t( 7) +#define CPU_TYPE_MC98000 uint32_t(10) +#define CPU_TYPE_HPPA uint32_t(11) +#define CPU_TYPE_ARM uint32_t(12) +#define CPU_TYPE_MC88000 uint32_t(13) +#define CPU_TYPE_SPARC uint32_t(14) +#define CPU_TYPE_I860 uint32_t(15) +#define CPU_TYPE_POWERPC uint32_t(18) + +#define CPU_TYPE_I386 CPU_TYPE_X86 + +#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM) +#define CPU_TYPE_POWERPC64 (CPU_ARCH_ABI64 | CPU_TYPE_POWERPC) +#define CPU_TYPE_X86_64 (CPU_ARCH_ABI64 | CPU_TYPE_X86) + +struct fat_header { + uint32_t magic; + uint32_t nfat_arch; +} _packed; + +#define FAT_MAGIC 0xcafebabe +#define FAT_CIGAM 0xbebafeca + +struct fat_arch { + uint32_t cputype; + uint32_t cpusubtype; + uint32_t offset; + uint32_t size; + uint32_t align; +} _packed; + +struct mach_header { + uint32_t magic; + uint32_t cputype; + uint32_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; +} _packed; + +#define MH_MAGIC 0xfeedface +#define MH_CIGAM 0xcefaedfe + +#define MH_MAGIC_64 0xfeedfacf +#define MH_CIGAM_64 0xcffaedfe + +#define MH_DYLDLINK 0x4 + +#define MH_OBJECT 0x1 +#define MH_EXECUTE 0x2 +#define MH_DYLIB 0x6 +#define MH_BUNDLE 0x8 +#define MH_DYLIB_STUB 0x9 + +struct load_command { + uint32_t cmd; + uint32_t cmdsize; +} _packed; + +#define LC_REQ_DYLD uint32_t(0x80000000) + +#define LC_SEGMENT uint32_t(0x01) +#define LC_SYMTAB uint32_t(0x02) +#define LC_DYSYMTAB uint32_t(0x0b) +#define LC_LOAD_DYLIB uint32_t(0x0c) +#define LC_ID_DYLIB uint32_t(0x0d) +#define LC_SEGMENT_64 uint32_t(0x19) +#define LC_UUID uint32_t(0x1b) +#define LC_CODE_SIGNATURE uint32_t(0x1d) +#define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e) +#define LC_REEXPORT_DYLIB uint32_t(0x1f | LC_REQ_DYLD) +#define LC_ENCRYPTION_INFO uint32_t(0x21) +#define LC_DYLD_INFO uint32_t(0x22) +#define LC_DYLD_INFO_ONLY uint32_t(0x22 | LC_REQ_DYLD) +#define LC_ENCRYPTION_INFO_64 uint32_t(0x2c) + +union Version { + struct { + uint8_t patch; + uint8_t minor; + uint16_t major; + } _packed; + + uint32_t value; +}; + +struct dylib { + uint32_t name; + uint32_t timestamp; + uint32_t current_version; + uint32_t compatibility_version; +} _packed; + +struct dylib_command { + uint32_t cmd; + uint32_t cmdsize; + struct dylib dylib; +} _packed; + +struct uuid_command { + uint32_t cmd; + uint32_t cmdsize; + uint8_t uuid[16]; +} _packed; + +struct symtab_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t symoff; + uint32_t nsyms; + uint32_t stroff; + uint32_t strsize; +} _packed; + +struct dyld_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t rebase_off; + uint32_t rebase_size; + uint32_t bind_off; + uint32_t bind_size; + uint32_t weak_bind_off; + uint32_t weak_bind_size; + uint32_t lazy_bind_off; + uint32_t lazy_bind_size; + uint32_t export_off; + uint32_t export_size; +} _packed; + +struct dysymtab_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t iundefsym; + uint32_t nundefsym; + uint32_t tocoff; + uint32_t ntoc; + uint32_t modtaboff; + uint32_t nmodtab; + uint32_t extrefsymoff; + uint32_t nextrefsyms; + uint32_t indirectsymoff; + uint32_t nindirectsyms; + uint32_t extreloff; + uint32_t nextrel; + uint32_t locreloff; + uint32_t nlocrel; +} _packed; + +struct dylib_table_of_contents { + uint32_t symbol_index; + uint32_t module_index; +} _packed; + +struct dylib_module { + uint32_t module_name; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t irefsym; + uint32_t nrefsym; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextrel; + uint32_t nextrel; + uint32_t iinit_iterm; + uint32_t ninit_nterm; + uint32_t objc_module_info_addr; + uint32_t objc_module_info_size; +} _packed; + +struct dylib_reference { + uint32_t isym:24; + uint32_t flags:8; +} _packed; + +struct relocation_info { + int32_t r_address; + uint32_t r_symbolnum:24; + uint32_t r_pcrel:1; + uint32_t r_length:2; + uint32_t r_extern:1; + uint32_t r_type:4; +} _packed; + +struct nlist { + union { + char *n_name; + int32_t n_strx; + } n_un; + + uint8_t n_type; + uint8_t n_sect; + uint8_t n_desc; + uint32_t n_value; +} _packed; + +struct segment_command { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint32_t vmaddr; + uint32_t vmsize; + uint32_t fileoff; + uint32_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} _packed; + +struct segment_command_64 { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} _packed; + +struct section { + char sectname[16]; + char segname[16]; + uint32_t addr; + uint32_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + uint32_t reserved1; + uint32_t reserved2; +} _packed; + +struct section_64 { + char sectname[16]; + char segname[16]; + uint64_t addr; + uint64_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; +} _packed; + +struct linkedit_data_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t dataoff; + uint32_t datasize; +} _packed; + +struct encryption_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t cryptoff; + uint32_t cryptsize; + uint32_t cryptid; +} _packed; + +#define BIND_OPCODE_MASK 0xf0 +#define BIND_IMMEDIATE_MASK 0x0f +#define BIND_OPCODE_DONE 0x00 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM 0x10 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB 0x20 +#define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 +#define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 +#define BIND_OPCODE_SET_TYPE_IMM 0x50 +#define BIND_OPCODE_SET_ADDEND_SLEB 0x60 +#define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 +#define BIND_OPCODE_ADD_ADDR_ULEB 0x80 +#define BIND_OPCODE_DO_BIND 0x90 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xa0 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xb0 +#define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xc0 + +static auto dummy([](double) {}); + +static std::streamsize read(std::streambuf &stream, void *data, size_t size) { + auto writ(stream.sgetn(static_cast(data), size)); + _assert(writ >= 0); + return writ; +} + +static inline void get(std::streambuf &stream, void *data, size_t size) { + _assert(read(stream, data, size) == size); +} + +static inline void put(std::streambuf &stream, const void *data, size_t size) { + _assert(stream.sputn(static_cast(data), size) == size); +} + +static inline void put(std::streambuf &stream, const void *data, size_t size, const ldid::Functor &percent) { + percent(0); + for (size_t total(0); total != size;) { + auto writ(std::min(size - total, size_t(4096 * 4))); + _assert(stream.sputn(static_cast(data) + total, writ) == writ); + total += writ; + percent(double(total) / size); + } +} + +static size_t most(std::streambuf &stream, void *data, size_t size) { + size_t total(size); + while (size > 0) + if (auto writ = read(stream, data, size)) + size -= writ; + else break; + return total - size; +} + +static inline void pad(std::streambuf &stream, size_t size) { + char padding[size]; + memset(padding, 0, size); + put(stream, padding, size); +} + +template +Type_ Align(Type_ value, size_t align) { + value += align - 1; + value /= align; + value *= align; + return value; +} + +static const uint8_t PageShift_(0x0c); +static const uint32_t PageSize_(1 << PageShift_); + +static inline uint16_t Swap_(uint16_t value) { + return + ((value >> 8) & 0x00ff) | + ((value << 8) & 0xff00); +} + +static inline uint32_t Swap_(uint32_t value) { + value = ((value >> 8) & 0x00ff00ff) | + ((value << 8) & 0xff00ff00); + value = ((value >> 16) & 0x0000ffff) | + ((value << 16) & 0xffff0000); + return value; +} + +static inline uint64_t Swap_(uint64_t value) { + value = (value & 0x00000000ffffffff) << 32 | (value & 0xffffffff00000000) >> 32; + value = (value & 0x0000ffff0000ffff) << 16 | (value & 0xffff0000ffff0000) >> 16; + value = (value & 0x00ff00ff00ff00ff) << 8 | (value & 0xff00ff00ff00ff00) >> 8; + return value; +} + +static inline int16_t Swap_(int16_t value) { + return Swap_(static_cast(value)); +} + +static inline int32_t Swap_(int32_t value) { + return Swap_(static_cast(value)); +} + +static inline int64_t Swap_(int64_t value) { + return Swap_(static_cast(value)); +} + +static bool little_(true); + +static inline uint16_t Swap(uint16_t value) { + return little_ ? Swap_(value) : value; +} + +static inline uint32_t Swap(uint32_t value) { + return little_ ? Swap_(value) : value; +} + +static inline uint64_t Swap(uint64_t value) { + return little_ ? Swap_(value) : value; +} + +static inline int16_t Swap(int16_t value) { + return Swap(static_cast(value)); +} + +static inline int32_t Swap(int32_t value) { + return Swap(static_cast(value)); +} + +static inline int64_t Swap(int64_t value) { + return Swap(static_cast(value)); +} + +class Swapped { + protected: + bool swapped_; + + Swapped() : + swapped_(false) + { + } + + public: + Swapped(bool swapped) : + swapped_(swapped) + { + } + + template + Type_ Swap(Type_ value) const { + return swapped_ ? Swap_(value) : value; + } +}; + +class Data : + public Swapped +{ + private: + void *base_; + size_t size_; + + public: + Data(void *base, size_t size) : + base_(base), + size_(size) + { + } + + void *GetBase() const { + return base_; + } + + size_t GetSize() const { + return size_; + } +}; + +class MachHeader : + public Data +{ + private: + bool bits64_; + + struct mach_header *mach_header_; + struct load_command *load_command_; + + public: + MachHeader(void *base, size_t size) : + Data(base, size) + { + mach_header_ = (mach_header *) base; + + switch (Swap(mach_header_->magic)) { + case MH_CIGAM: + swapped_ = !swapped_; + case MH_MAGIC: + bits64_ = false; + break; + + case MH_CIGAM_64: + swapped_ = !swapped_; + case MH_MAGIC_64: + bits64_ = true; + break; + + default: + _assert(false); + } + + void *post = mach_header_ + 1; + if (bits64_) + post = (uint32_t *) post + 1; + load_command_ = (struct load_command *) post; + + _assert( + Swap(mach_header_->filetype) == MH_EXECUTE || + Swap(mach_header_->filetype) == MH_DYLIB || + Swap(mach_header_->filetype) == MH_BUNDLE + ); + } + + bool Bits64() const { + return bits64_; + } + + struct mach_header *operator ->() const { + return mach_header_; + } + + operator struct mach_header *() const { + return mach_header_; + } + + uint32_t GetCPUType() const { + return Swap(mach_header_->cputype); + } + + uint32_t GetCPUSubtype() const { + return Swap(mach_header_->cpusubtype) & 0xff; + } + + struct load_command *GetLoadCommand() const { + return load_command_; + } + + std::vector GetLoadCommands() const { + std::vector load_commands; + + struct load_command *load_command = load_command_; + for (uint32_t cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) { + load_commands.push_back(load_command); + load_command = (struct load_command *) ((uint8_t *) load_command + Swap(load_command->cmdsize)); + } + + return load_commands; + } + + void ForSection(const ldid::Functor &code) const { + _foreach (load_command, GetLoadCommands()) + switch (Swap(load_command->cmd)) { + case LC_SEGMENT: { + auto segment(reinterpret_cast(load_command)); + code(segment->segname, NULL, GetOffset(segment->fileoff), segment->filesize); + auto section(reinterpret_cast(segment + 1)); + for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section) + code(segment->segname, section->sectname, GetOffset(segment->fileoff + section->offset), section->size); + } break; + + case LC_SEGMENT_64: { + auto segment(reinterpret_cast(load_command)); + code(segment->segname, NULL, GetOffset(segment->fileoff), segment->filesize); + auto section(reinterpret_cast(segment + 1)); + for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section) + code(segment->segname, section->sectname, GetOffset(segment->fileoff + section->offset), section->size); + } break; + } + } + + template + Target_ *GetOffset(uint32_t offset) const { + return reinterpret_cast(offset + (uint8_t *) mach_header_); + } +}; + +class FatMachHeader : + public MachHeader +{ + private: + fat_arch *fat_arch_; + + public: + FatMachHeader(void *base, size_t size, fat_arch *fat_arch) : + MachHeader(base, size), + fat_arch_(fat_arch) + { + } + + fat_arch *GetFatArch() const { + return fat_arch_; + } +}; + +class FatHeader : + public Data +{ + private: + fat_header *fat_header_; + std::vector mach_headers_; + + public: + FatHeader(void *base, size_t size) : + Data(base, size) + { + fat_header_ = reinterpret_cast(base); + + if (Swap(fat_header_->magic) == FAT_CIGAM) { + swapped_ = !swapped_; + goto fat; + } else if (Swap(fat_header_->magic) != FAT_MAGIC) { + fat_header_ = NULL; + mach_headers_.push_back(FatMachHeader(base, size, NULL)); + } else fat: { + size_t fat_narch = Swap(fat_header_->nfat_arch); + fat_arch *fat_arch = reinterpret_cast(fat_header_ + 1); + size_t arch; + for (arch = 0; arch != fat_narch; ++arch) { + uint32_t arch_offset = Swap(fat_arch->offset); + uint32_t arch_size = Swap(fat_arch->size); + mach_headers_.push_back(FatMachHeader((uint8_t *) base + arch_offset, arch_size, fat_arch)); + ++fat_arch; + } + } + } + + std::vector &GetMachHeaders() { + return mach_headers_; + } + + bool IsFat() const { + return fat_header_ != NULL; + } + + struct fat_header *operator ->() const { + return fat_header_; + } + + operator struct fat_header *() const { + return fat_header_; + } +}; + +#define CSMAGIC_REQUIREMENT uint32_t(0xfade0c00) +#define CSMAGIC_REQUIREMENTS uint32_t(0xfade0c01) +#define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02) +#define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0) +#define CSMAGIC_EMBEDDED_SIGNATURE_OLD uint32_t(0xfade0b02) +#define CSMAGIC_EMBEDDED_ENTITLEMENTS uint32_t(0xfade7171) +#define CSMAGIC_DETACHED_SIGNATURE uint32_t(0xfade0cc1) +#define CSMAGIC_BLOBWRAPPER uint32_t(0xfade0b01) + +#define CSSLOT_CODEDIRECTORY uint32_t(0x00000) +#define CSSLOT_INFOSLOT uint32_t(0x00001) +#define CSSLOT_REQUIREMENTS uint32_t(0x00002) +#define CSSLOT_RESOURCEDIR uint32_t(0x00003) +#define CSSLOT_APPLICATION uint32_t(0x00004) +#define CSSLOT_ENTITLEMENTS uint32_t(0x00005) +#define CSSLOT_ALTERNATE uint32_t(0x01000) + +#define CSSLOT_SIGNATURESLOT uint32_t(0x10000) + +#define CS_HASHTYPE_SHA160_160 1 +#define CS_HASHTYPE_SHA256_256 2 +#define CS_HASHTYPE_SHA256_160 3 +#define CS_HASHTYPE_SHA386_386 4 + +struct BlobIndex { + uint32_t type; + uint32_t offset; +} _packed; + +struct Blob { + uint32_t magic; + uint32_t length; +} _packed; + +struct SuperBlob { + struct Blob blob; + uint32_t count; + struct BlobIndex index[]; +} _packed; + +struct CodeDirectory { + uint32_t version; + uint32_t flags; + uint32_t hashOffset; + uint32_t identOffset; + uint32_t nSpecialSlots; + uint32_t nCodeSlots; + uint32_t codeLimit; + uint8_t hashSize; + uint8_t hashType; + uint8_t spare1; + uint8_t pageSize; + uint32_t spare2; + uint32_t scatterOffset; + uint32_t teamIDOffset; + uint32_t spare3; + uint64_t codeLimit64; +} _packed; + +#ifndef LDID_NOFLAGT +extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval); +#endif + +struct Algorithm { + size_t size_; + uint8_t type_; + + Algorithm(size_t size, uint8_t type) : + size_(size), + type_(type) + { + } + + virtual const uint8_t *operator [](const ldid::Hash &hash) const = 0; + + virtual void operator ()(uint8_t *hash, const void *data, size_t size) const = 0; + virtual void operator ()(ldid::Hash &hash, const void *data, size_t size) const = 0; + virtual void operator ()(std::vector &hash, const void *data, size_t size) const = 0; +}; + +struct AlgorithmSHA1 : + Algorithm +{ + AlgorithmSHA1() : + Algorithm(LDID_SHA1_DIGEST_LENGTH, CS_HASHTYPE_SHA160_160) + { + } + + virtual const uint8_t *operator [](const ldid::Hash &hash) const { + return hash.sha1_; + } + + void operator ()(uint8_t *hash, const void *data, size_t size) const { + LDID_SHA1(static_cast(data), size, hash); + } + + void operator ()(ldid::Hash &hash, const void *data, size_t size) const { + return operator()(hash.sha1_, data, size); + } + + void operator ()(std::vector &hash, const void *data, size_t size) const { + hash.resize(LDID_SHA1_DIGEST_LENGTH); + return operator ()(reinterpret_cast(hash.data()), data, size); + } +}; + +struct AlgorithmSHA256 : + Algorithm +{ + AlgorithmSHA256() : + Algorithm(LDID_SHA256_DIGEST_LENGTH, CS_HASHTYPE_SHA256_256) + { + } + + virtual const uint8_t *operator [](const ldid::Hash &hash) const { + return hash.sha256_; + } + + void operator ()(uint8_t *hash, const void *data, size_t size) const { + LDID_SHA256(static_cast(data), size, hash); + } + + void operator ()(ldid::Hash &hash, const void *data, size_t size) const { + return operator()(hash.sha256_, data, size); + } + + void operator ()(std::vector &hash, const void *data, size_t size) const { + hash.resize(LDID_SHA256_DIGEST_LENGTH); + return operator ()(reinterpret_cast(hash.data()), data, size); + } +}; + +static const std::vector &GetAlgorithms() { + static AlgorithmSHA1 sha1; + static AlgorithmSHA256 sha256; + + static Algorithm *array[] = { + &sha1, + &sha256, + }; + + static std::vector algorithms(array, array + sizeof(array) / sizeof(array[0])); + return algorithms; +} + +struct CodesignAllocation { + FatMachHeader mach_header_; + uint32_t offset_; + uint32_t size_; + uint32_t limit_; + uint32_t alloc_; + uint32_t align_; + + CodesignAllocation(FatMachHeader mach_header, size_t offset, size_t size, size_t limit, size_t alloc, size_t align) : + mach_header_(mach_header), + offset_(offset), + size_(size), + limit_(limit), + alloc_(alloc), + align_(align) + { + } +}; + +#ifndef LDID_NOTOOLS +class File { + private: + int file_; + + public: + File() : + file_(-1) + { + } + + ~File() { + if (file_ != -1) + _syscall(close(file_)); + } + + void open(const char *path, int flags) { + _assert(file_ == -1); + file_ = _syscall(::open(path, flags)); + } + + int file() const { + return file_; + } +}; + +class Map { + private: + File file_; + void *data_; + size_t size_; + + void clear() { + if (data_ == NULL) + return; + _syscall(munmap(data_, size_)); + data_ = NULL; + size_ = 0; + } + + public: + Map() : + data_(NULL), + size_(0) + { + } + + Map(const std::string &path, int oflag, int pflag, int mflag) : + Map() + { + open(path, oflag, pflag, mflag); + } + + Map(const std::string &path, bool edit) : + Map() + { + open(path, edit); + } + + ~Map() { + clear(); + } + + bool empty() const { + return data_ == NULL; + } + + void open(const std::string &path, int oflag, int pflag, int mflag) { + clear(); + + file_.open(path.c_str(), oflag); + int file(file_.file()); + + struct stat stat; + _syscall(fstat(file, &stat)); + size_ = stat.st_size; + + data_ = _syscall(mmap(NULL, size_, pflag, mflag, file, 0)); + } + + void open(const std::string &path, bool edit) { + if (edit) + open(path, O_RDWR, PROT_READ | PROT_WRITE, MAP_SHARED); + else + open(path, O_RDONLY, PROT_READ, MAP_PRIVATE); + } + + void *data() const { + return data_; + } + + size_t size() const { + return size_; + } + + operator std::string() const { + return std::string(static_cast(data_), size_); + } +}; +#endif + +namespace ldid { + +std::string Analyze(const void *data, size_t size) { + std::string entitlements; + + FatHeader fat_header(const_cast(data), size); + _foreach (mach_header, fat_header.GetMachHeaders()) + _foreach (load_command, mach_header.GetLoadCommands()) + if (mach_header.Swap(load_command->cmd) == LC_CODE_SIGNATURE) { + auto signature(reinterpret_cast(load_command)); + auto offset(mach_header.Swap(signature->dataoff)); + auto pointer(reinterpret_cast(mach_header.GetBase()) + offset); + auto super(reinterpret_cast(pointer)); + + for (size_t index(0); index != Swap(super->count); ++index) + if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) { + auto begin(Swap(super->index[index].offset)); + auto blob(reinterpret_cast(pointer + begin)); + auto writ(Swap(blob->length) - sizeof(*blob)); + + if (entitlements.empty()) + entitlements.assign(reinterpret_cast(blob + 1), writ); + else + _assert(entitlements.compare(0, entitlements.size(), reinterpret_cast(blob + 1), writ) == 0); + } + } + + return entitlements; +} + +static void Allocate(const void *idata, size_t isize, std::streambuf &output, const Functor &allocate, const Functor &)> &save, const Functor &percent) { + FatHeader source(const_cast(idata), isize); + + size_t offset(0); + if (source.IsFat()) + offset += sizeof(fat_header) + sizeof(fat_arch) * source.Swap(source->nfat_arch); + + std::vector allocations; + _foreach (mach_header, source.GetMachHeaders()) { + struct linkedit_data_command *signature(NULL); + struct symtab_command *symtab(NULL); + + _foreach (load_command, mach_header.GetLoadCommands()) { + uint32_t cmd(mach_header.Swap(load_command->cmd)); + if (false); + else if (cmd == LC_CODE_SIGNATURE) + signature = reinterpret_cast(load_command); + else if (cmd == LC_SYMTAB) + symtab = reinterpret_cast(load_command); + } + + size_t size; + if (signature == NULL) + size = mach_header.GetSize(); + else { + size = mach_header.Swap(signature->dataoff); + _assert(size <= mach_header.GetSize()); + } + + if (symtab != NULL) { + auto end(mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize)); + _assert(end <= size); + _assert(end >= size - 0x10); + size = end; + } + + size_t alloc(allocate(mach_header, size)); + + auto *fat_arch(mach_header.GetFatArch()); + uint32_t align; + + if (fat_arch != NULL) + align = source.Swap(fat_arch->align); + else switch (mach_header.GetCPUType()) { + case CPU_TYPE_POWERPC: + case CPU_TYPE_POWERPC64: + case CPU_TYPE_X86: + case CPU_TYPE_X86_64: + align = 0xc; + break; + case CPU_TYPE_ARM: + case CPU_TYPE_ARM64: + align = 0xe; + break; + default: + align = 0x0; + break; + } + + offset = Align(offset, 1 << align); + + uint32_t limit(size); + if (alloc != 0) + limit = Align(limit, 0x10); + + allocations.push_back(CodesignAllocation(mach_header, offset, size, limit, alloc, align)); + offset += size + alloc; + offset = Align(offset, 0x10); + } + + size_t position(0); + + if (source.IsFat()) { + fat_header fat_header; + fat_header.magic = Swap(FAT_MAGIC); + fat_header.nfat_arch = Swap(uint32_t(allocations.size())); + put(output, &fat_header, sizeof(fat_header)); + position += sizeof(fat_header); + + _foreach (allocation, allocations) { + auto &mach_header(allocation.mach_header_); + + fat_arch fat_arch; + fat_arch.cputype = Swap(mach_header->cputype); + fat_arch.cpusubtype = Swap(mach_header->cpusubtype); + fat_arch.offset = Swap(allocation.offset_); + fat_arch.size = Swap(allocation.limit_ + allocation.alloc_); + fat_arch.align = Swap(allocation.align_); + put(output, &fat_arch, sizeof(fat_arch)); + position += sizeof(fat_arch); + } + } + + _foreach (allocation, allocations) { + auto &mach_header(allocation.mach_header_); + + pad(output, allocation.offset_ - position); + position = allocation.offset_; + + std::vector commands; + + _foreach (load_command, mach_header.GetLoadCommands()) { + std::string copy(reinterpret_cast(load_command), load_command->cmdsize); + + switch (mach_header.Swap(load_command->cmd)) { + case LC_CODE_SIGNATURE: + continue; + break; + + case LC_SEGMENT: { + auto segment_command(reinterpret_cast(©[0])); + if (strncmp(segment_command->segname, "__LINKEDIT", 16) != 0) + break; + size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff))); + segment_command->filesize = size; + segment_command->vmsize = Align(size, 1 << allocation.align_); + } break; + + case LC_SEGMENT_64: { + auto segment_command(reinterpret_cast(©[0])); + if (strncmp(segment_command->segname, "__LINKEDIT", 16) != 0) + break; + size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff))); + segment_command->filesize = size; + segment_command->vmsize = Align(size, 1 << allocation.align_); + } break; + } + + commands.push_back(copy); + } + + if (allocation.alloc_ != 0) { + linkedit_data_command signature; + signature.cmd = mach_header.Swap(LC_CODE_SIGNATURE); + signature.cmdsize = mach_header.Swap(uint32_t(sizeof(signature))); + signature.dataoff = mach_header.Swap(allocation.limit_); + signature.datasize = mach_header.Swap(allocation.alloc_); + commands.push_back(std::string(reinterpret_cast(&signature), sizeof(signature))); + } + + size_t begin(position); + + uint32_t after(0); + _foreach(command, commands) + after += command.size(); + + std::stringbuf altern; + + struct mach_header header(*mach_header); + header.ncmds = mach_header.Swap(uint32_t(commands.size())); + header.sizeofcmds = mach_header.Swap(after); + put(output, &header, sizeof(header)); + put(altern, &header, sizeof(header)); + position += sizeof(header); + + if (mach_header.Bits64()) { + auto pad(mach_header.Swap(uint32_t(0))); + put(output, &pad, sizeof(pad)); + put(altern, &pad, sizeof(pad)); + position += sizeof(pad); + } + + _foreach(command, commands) { + put(output, command.data(), command.size()); + put(altern, command.data(), command.size()); + position += command.size(); + } + + uint32_t before(mach_header.Swap(mach_header->sizeofcmds)); + if (before > after) { + pad(output, before - after); + pad(altern, before - after); + position += before - after; + } + + auto top(reinterpret_cast(mach_header.GetBase())); + + std::string overlap(altern.str()); + overlap.append(top + overlap.size(), Align(overlap.size(), 0x1000) - overlap.size()); + + put(output, top + (position - begin), allocation.size_ - (position - begin), percent); + position = begin + allocation.size_; + + pad(output, allocation.limit_ - allocation.size_); + position += allocation.limit_ - allocation.size_; + + size_t saved(save(mach_header, output, allocation.limit_, overlap, top, percent)); + if (allocation.alloc_ > saved) + pad(output, allocation.alloc_ - saved); + else + _assert(allocation.alloc_ == saved); + position += allocation.alloc_; + } +} + +} + +typedef std::map Blobs; + +static void insert(Blobs &blobs, uint32_t slot, const std::stringbuf &buffer) { + auto value(buffer.str()); + std::swap(blobs[slot], value); +} + +static const std::string &insert(Blobs &blobs, uint32_t slot, uint32_t magic, const std::stringbuf &buffer) { + auto value(buffer.str()); + Blob blob; + blob.magic = Swap(magic); + blob.length = Swap(uint32_t(sizeof(blob) + value.size())); + value.insert(0, reinterpret_cast(&blob), sizeof(blob)); + auto &save(blobs[slot]); + std::swap(save, value); + return save; +} + +static size_t put(std::streambuf &output, uint32_t magic, const Blobs &blobs) { + size_t total(0); + _foreach (blob, blobs) + total += blob.second.size(); + + struct SuperBlob super; + super.blob.magic = Swap(magic); + super.blob.length = Swap(uint32_t(sizeof(SuperBlob) + blobs.size() * sizeof(BlobIndex) + total)); + super.count = Swap(uint32_t(blobs.size())); + put(output, &super, sizeof(super)); + + size_t offset(sizeof(SuperBlob) + sizeof(BlobIndex) * blobs.size()); + + _foreach (blob, blobs) { + BlobIndex index; + index.type = Swap(blob.first); + index.offset = Swap(uint32_t(offset)); + put(output, &index, sizeof(index)); + offset += blob.second.size(); + } + + _foreach (blob, blobs) + put(output, blob.second.data(), blob.second.size()); + + return offset; +} + +#ifndef LDID_NOSMIME +class Buffer { + private: + BIO *bio_; + + public: + Buffer(BIO *bio) : + bio_(bio) + { + _assert(bio_ != NULL); + } + + Buffer() : + bio_(BIO_new(BIO_s_mem())) + { + } + + Buffer(const char *data, size_t size) : + Buffer(BIO_new_mem_buf(const_cast(data), size)) + { + } + + Buffer(const std::string &data) : + Buffer(data.data(), data.size()) + { + } + + Buffer(CMS_ContentInfo *cms) : + Buffer() + { + _assert(i2d_CMS_bio(bio_, cms) != 0); + } + + ~Buffer() { + BIO_free_all(bio_); + } + + operator BIO *() const { + return bio_; + } + + explicit operator std::string() const { + char *data; + auto size(BIO_get_mem_data(bio_, &data)); + return std::string(data, size); + } +}; + +class Stuff { + private: + PKCS12 *value_; + EVP_PKEY *key_; + X509 *cert_; + STACK_OF(X509) *ca_; + + public: + Stuff(BIO *bio) : + value_(d2i_PKCS12_bio(bio, NULL)), + ca_(NULL) + { + _assert(value_ != NULL); + _assert(PKCS12_parse(value_, "", &key_, &cert_, &ca_) != 0); + _assert(key_ != NULL); + _assert(cert_ != NULL); + } + + Stuff(const std::string &data) : + Stuff(Buffer(data)) + { + } + + ~Stuff() { + sk_X509_pop_free(ca_, X509_free); + X509_free(cert_); + EVP_PKEY_free(key_); + PKCS12_free(value_); + } + + operator PKCS12 *() const { + return value_; + } + + operator EVP_PKEY *() const { + return key_; + } + + operator X509 *() const { + return cert_; + } + + operator STACK_OF(X509) *() const { + return ca_; + } +}; + +class Signature { + private: + CMS_ContentInfo *value_; + + public: + Signature(const Stuff &stuff, const Buffer &data) + { + int flags = CMS_PARTIAL | CMS_DETACHED | CMS_NOSMIMECAP | CMS_BINARY; + + CMS_ContentInfo *stream = CMS_sign(NULL, NULL, stuff, NULL, flags); + + // iOS 12 requires both SHA1 and SHA256 signing digests. + CMS_add1_signer(stream, stuff, stuff, EVP_sha256(), flags); + CMS_add1_signer(stream, stuff, stuff, EVP_sha1(), flags); + + CMS_final(stream, data, NULL, flags); + + value_ = stream; + _assert(value_ != NULL); + } + + ~Signature() { + CMS_ContentInfo_free(value_); + } + + operator CMS_ContentInfo *() const { + return value_; + } +}; +#endif + +class NullBuffer : + public std::streambuf +{ + public: + virtual std::streamsize xsputn(const char_type *data, std::streamsize size) { + return size; + } + + virtual int_type overflow(int_type next) { + return next; + } +}; + +class Digest { + public: + uint8_t sha1_[LDID_SHA1_DIGEST_LENGTH]; +}; + +class HashBuffer : + public std::streambuf +{ + private: + ldid::Hash &hash_; + + LDID_SHA1_CTX sha1_; + LDID_SHA256_CTX sha256_; + + public: + HashBuffer(ldid::Hash &hash) : + hash_(hash) + { + LDID_SHA1_Init(&sha1_); + LDID_SHA256_Init(&sha256_); + } + + ~HashBuffer() { + LDID_SHA1_Final(reinterpret_cast(hash_.sha1_), &sha1_); + LDID_SHA256_Final(reinterpret_cast(hash_.sha256_), &sha256_); + } + + virtual std::streamsize xsputn(const char_type *data, std::streamsize size) { + LDID_SHA1_Update(&sha1_, data, size); + LDID_SHA256_Update(&sha256_, data, size); + return size; + } + + virtual int_type overflow(int_type next) { + if (next == traits_type::eof()) + return sync(); + char value(next); + xsputn(&value, 1); + return next; + } +}; + +class HashProxy : + public HashBuffer +{ + private: + std::streambuf &buffer_; + + public: + HashProxy(ldid::Hash &hash, std::streambuf &buffer) : + HashBuffer(hash), + buffer_(buffer) + { + } + + virtual std::streamsize xsputn(const char_type *data, std::streamsize size) { + _assert(HashBuffer::xsputn(data, size) == size); + return buffer_.sputn(data, size); + } +}; + +#ifndef LDID_NOTOOLS +static bool Starts(const std::string &lhs, const std::string &rhs) { + return lhs.size() >= rhs.size() && lhs.compare(0, rhs.size(), rhs) == 0; +} + +class Split { + public: + std::string dir; + std::string base; + + Split(const std::string &path) { + size_t slash(path.rfind('/')); + if (slash == std::string::npos) + base = path; + else { + dir = path.substr(0, slash + 1); + base = path.substr(slash + 1); + } + } +}; + +static void mkdir_p(const std::string &path) { + if (path.empty()) + return; +#ifdef __WIN32__ + if (_syscall(mkdir(path.c_str()), EEXIST) == -EEXIST) + return; +#else + if (_syscall(mkdir(path.c_str(), 0755), EEXIST) == -EEXIST) + return; +#endif + auto slash(path.rfind('/', path.size() - 1)); + if (slash == std::string::npos) + return; + mkdir_p(path.substr(0, slash)); +} + +static std::string Temporary(std::filebuf &file, const Split &split) { + std::string temp(split.dir + ".ldid." + split.base); + mkdir_p(split.dir); + _assert_(file.open(temp.c_str(), std::ios::out | std::ios::trunc | std::ios::binary) == &file, "open(): %s", temp.c_str()); + return temp; +} + +static void Commit(const std::string &path, const std::string &temp) { + struct stat info; + if (_syscall(stat(path.c_str(), &info), ENOENT) == 0) { +#ifndef __WIN32__ + _syscall(chown(temp.c_str(), info.st_uid, info.st_gid)); +#endif + _syscall(chmod(temp.c_str(), info.st_mode)); + } + + _syscall(rename(temp.c_str(), path.c_str())); +} +#endif + +namespace ldid { + +Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::string &identifier, const std::string &entitlements, const std::string &requirement, const std::string &key, const Slots &slots, const Functor &percent) { + Hash hash; + + std::string team; + +#ifndef LDID_NOSMIME + if (!key.empty()) { + Stuff stuff(key); + auto name(X509_get_subject_name(stuff)); + _assert(name != NULL); + auto index(X509_NAME_get_index_by_NID(name, NID_organizationalUnitName, -1)); + _assert(index >= 0); + auto next(X509_NAME_get_index_by_NID(name, NID_organizationalUnitName, index)); + _assert(next == -1); + auto entry(X509_NAME_get_entry(name, index)); + _assert(entry != NULL); + auto asn(X509_NAME_ENTRY_get_data(entry)); + _assert(asn != NULL); + team.assign(reinterpret_cast(ASN1_STRING_data(asn)), ASN1_STRING_length(asn)); + } +#endif + + // XXX: this is just a "sufficiently large number" + size_t certificate(0x3000); + + Allocate(idata, isize, output, fun([&](const MachHeader &mach_header, size_t size) -> size_t { + size_t alloc(sizeof(struct SuperBlob)); + + uint32_t normal((size + PageSize_ - 1) / PageSize_); + + uint32_t special(0); + + _foreach (slot, slots) + special = std::max(special, slot.first); + + mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { + if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) + special = std::max(special, CSSLOT_INFOSLOT); + })); + + special = std::max(special, CSSLOT_REQUIREMENTS); + alloc += sizeof(struct BlobIndex); + if (requirement.empty()) + alloc += 0xc; + else + alloc += requirement.size(); + + if (!entitlements.empty()) { + special = std::max(special, CSSLOT_ENTITLEMENTS); + alloc += sizeof(struct BlobIndex); + alloc += sizeof(struct Blob); + alloc += entitlements.size(); + } + + size_t directory(0); + + directory += sizeof(struct BlobIndex); + directory += sizeof(struct Blob); + directory += sizeof(struct CodeDirectory); + directory += identifier.size() + 1; + + if (!team.empty()) + directory += team.size() + 1; + + for (Algorithm *algorithm : GetAlgorithms()) + alloc = Align(alloc + directory + (special + normal) * algorithm->size_, 16); + + if (!key.empty()) { + alloc += sizeof(struct BlobIndex); + alloc += sizeof(struct Blob); + alloc += certificate; + } + + return alloc; + }), fun([&](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top, const Functor &percent) -> size_t { + Blobs blobs; + + if (true) { + std::stringbuf data; + + if (requirement.empty()) { + Blobs requirements; + put(data, CSMAGIC_REQUIREMENTS, requirements); + } else { + put(data, requirement.data(), requirement.size()); + } + + insert(blobs, CSSLOT_REQUIREMENTS, data); + } + + if (!entitlements.empty()) { + std::stringbuf data; + put(data, entitlements.data(), entitlements.size()); + insert(blobs, CSSLOT_ENTITLEMENTS, CSMAGIC_EMBEDDED_ENTITLEMENTS, data); + } + + Slots posts(slots); + + mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { + if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) { + auto &slot(posts[CSSLOT_INFOSLOT]); + for (Algorithm *algorithm : GetAlgorithms()) + (*algorithm)(slot, data, size); + } + })); + + unsigned total(0); + for (Algorithm *pointer : GetAlgorithms()) { + Algorithm &algorithm(*pointer); + + std::stringbuf data; + + uint32_t special(0); + _foreach (blob, blobs) + special = std::max(special, blob.first); + _foreach (slot, posts) + special = std::max(special, slot.first); + uint32_t normal((limit + PageSize_ - 1) / PageSize_); + + CodeDirectory directory; + directory.version = Swap(uint32_t(0x00020200)); + directory.flags = Swap(uint32_t(0)); + directory.nSpecialSlots = Swap(special); + directory.codeLimit = Swap(uint32_t(limit)); + directory.nCodeSlots = Swap(normal); + directory.hashSize = algorithm.size_; + directory.hashType = algorithm.type_; + directory.spare1 = 0x00; + directory.pageSize = PageShift_; + directory.spare2 = Swap(uint32_t(0)); + directory.scatterOffset = Swap(uint32_t(0)); + directory.spare3 = Swap(uint32_t(0)); + directory.codeLimit64 = Swap(uint64_t(0)); + + uint32_t offset(sizeof(Blob) + sizeof(CodeDirectory)); + + directory.identOffset = Swap(uint32_t(offset)); + offset += identifier.size() + 1; + + if (team.empty()) + directory.teamIDOffset = Swap(uint32_t(0)); + else { + directory.teamIDOffset = Swap(uint32_t(offset)); + offset += team.size() + 1; + } + + offset += special * algorithm.size_; + directory.hashOffset = Swap(uint32_t(offset)); + offset += normal * algorithm.size_; + + put(data, &directory, sizeof(directory)); + + put(data, identifier.c_str(), identifier.size() + 1); + if (!team.empty()) + put(data, team.c_str(), team.size() + 1); + + std::vector storage((special + normal) * algorithm.size_); + auto *hashes(&storage[special * algorithm.size_]); + + memset(storage.data(), 0, special * algorithm.size_); + + _foreach (blob, blobs) { + auto local(reinterpret_cast(&blob.second[0])); + algorithm(hashes - blob.first * algorithm.size_, local, Swap(local->length)); + } + + _foreach (slot, posts) + memcpy(hashes - slot.first * algorithm.size_, algorithm[slot.second], algorithm.size_); + + percent(0); + if (normal != 1) + for (size_t i = 0; i != normal - 1; ++i) { + algorithm(hashes + i * algorithm.size_, (PageSize_ * i < overlap.size() ? overlap.data() : top) + PageSize_ * i, PageSize_); + percent(double(i) / normal); + } + if (normal != 0) + algorithm(hashes + (normal - 1) * algorithm.size_, top + PageSize_ * (normal - 1), ((limit - 1) % PageSize_) + 1); + percent(1); + + put(data, storage.data(), storage.size()); + + const auto &save(insert(blobs, total == 0 ? CSSLOT_CODEDIRECTORY : CSSLOT_ALTERNATE + total - 1, CSMAGIC_CODEDIRECTORY, data)); + algorithm(hash, save.data(), save.size()); + + ++total; + } + +#ifndef LDID_NOSMIME + if (!key.empty()) { + std::stringbuf data; + const std::string &sign(blobs[CSSLOT_CODEDIRECTORY]); + + Stuff stuff(key); + Buffer bio(sign); + + Signature signature(stuff, sign); + Buffer result(signature); + std::string value(result); + put(data, value.data(), value.size()); + + const auto &save(insert(blobs, CSSLOT_SIGNATURESLOT, CSMAGIC_BLOBWRAPPER, data)); + _assert(save.size() <= certificate); + } +#endif + + return put(output, CSMAGIC_EMBEDDED_SIGNATURE, blobs); + }), percent); + + return hash; +} + +#ifndef LDID_NOTOOLS +static void Unsign(void *idata, size_t isize, std::streambuf &output, const Functor &percent) { + Allocate(idata, isize, output, fun([](const MachHeader &mach_header, size_t size) -> size_t { + return 0; + }), fun([](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top, const Functor &percent) -> size_t { + return 0; + }), percent); +} + +std::string DiskFolder::Path(const std::string &path) const { + return path_ + "/" + path; +} + +DiskFolder::DiskFolder(const std::string &path) : + path_(path) +{ +} + +DiskFolder::~DiskFolder() { + if (!std::uncaught_exception()) + for (const auto &commit : commit_) + Commit(commit.first, commit.second); +} + +#ifndef __WIN32__ +std::string readlink(const std::string &path) { + for (size_t size(1024); ; size *= 2) { + std::string data; + data.resize(size); + + int writ(_syscall(::readlink(path.c_str(), &data[0], data.size()))); + if (size_t(writ) >= size) + continue; + + data.resize(writ); + return data; + } +} +#endif + +void DiskFolder::Find(const std::string &root, const std::string &base, const Functor &code, const Functor &)> &link) const { + std::string path(Path(root) + base); + + DIR *dir(opendir(path.c_str())); + _assert(dir != NULL); + _scope({ _syscall(closedir(dir)); }); + + while (auto child = readdir(dir)) { + std::string name(child->d_name); + if (name == "." || name == "..") + continue; + if (Starts(name, ".ldid.")) + continue; + + bool directory; + +#ifdef __WIN32__ + struct stat info; + _syscall(stat((path + name).c_str(), &info)); + if (false); + else if (S_ISDIR(info.st_mode)) + directory = true; + else if (S_ISREG(info.st_mode)) + directory = false; + else + _assert_(false, "st_mode=%x", info.st_mode); +#else + switch (child->d_type) { + case DT_DIR: + directory = true; + break; + case DT_REG: + directory = false; + break; + case DT_LNK: + link(base + name, fun([&]() { return readlink(path + name); })); + continue; + default: + _assert_(false, "d_type=%u", child->d_type); + } +#endif + + if (directory) + Find(root, base + name + "/", code, link); + else + code(base + name); + } +} + +void DiskFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { + if (!edit) { + // XXX: use nullbuf + std::stringbuf save; + code(save); + } else { + std::filebuf save; + auto from(Path(path)); + commit_[from] = Temporary(save, from); + code(save); + } +} + +bool DiskFolder::Look(const std::string &path) const { + return _syscall(access(Path(path).c_str(), R_OK), ENOENT) == 0; +} + +void DiskFolder::Open(const std::string &path, const Functor &code) const { + std::filebuf data; + auto result(data.open(Path(path).c_str(), std::ios::binary | std::ios::in)); + _assert_(result == &data, "DiskFolder::Open(%s)", path.c_str()); + + auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); + data.pubseekpos(0, std::ios::in); + code(data, length, NULL); +} + +void DiskFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { + Find(path, "", code, link); +} +#endif + +SubFolder::SubFolder(Folder &parent, const std::string &path) : + parent_(parent), + path_(path) +{ +} + +void SubFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { + return parent_.Save(path_ + path, edit, flag, code); +} + +bool SubFolder::Look(const std::string &path) const { + return parent_.Look(path_ + path); +} + +void SubFolder::Open(const std::string &path, const Functor &code) const { + return parent_.Open(path_ + path, code); +} + +void SubFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { + return parent_.Find(path_ + path, code, link); +} + +std::string UnionFolder::Map(const std::string &path) const { + auto remap(remaps_.find(path)); + if (remap == remaps_.end()) + return path; + return remap->second; +} + +void UnionFolder::Map(const std::string &path, const Functor &code, const std::string &file, const Functor &)> &save) const { + if (file.size() >= path.size() && file.substr(0, path.size()) == path) + code(file.substr(path.size())); +} + +UnionFolder::UnionFolder(Folder &parent) : + parent_(parent) +{ +} + +void UnionFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { + return parent_.Save(Map(path), edit, flag, code); +} + +bool UnionFolder::Look(const std::string &path) const { + auto file(resets_.find(path)); + if (file != resets_.end()) + return true; + return parent_.Look(Map(path)); +} + +void UnionFolder::Open(const std::string &path, const Functor &code) const { + auto file(resets_.find(path)); + if (file == resets_.end()) + return parent_.Open(Map(path), code); + auto &entry(file->second); + + auto &data(*entry.data_); + auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); + data.pubseekpos(0, std::ios::in); + code(data, length, entry.flag_); +} + +void UnionFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { + for (auto &reset : resets_) + Map(path, code, reset.first, fun([&](const Functor &code) { + auto &entry(reset.second); + auto &data(*entry.data_); + auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); + data.pubseekpos(0, std::ios::in); + code(data, length, entry.flag_); + })); + + for (auto &remap : remaps_) + Map(path, code, remap.first, fun([&](const Functor &code) { + parent_.Open(remap.second, fun([&](std::streambuf &data, size_t length, const void *flag) { + code(data, length, flag); + })); + })); + + parent_.Find(path, fun([&](const std::string &name) { + if (deletes_.find(path + name) == deletes_.end()) + code(name); + }), fun([&](const std::string &name, const Functor &read) { + if (deletes_.find(path + name) == deletes_.end()) + link(name, read); + })); +} + +#ifndef LDID_NOTOOLS +static void copy(std::streambuf &source, std::streambuf &target, size_t length, const ldid::Functor &percent) { + percent(0); + size_t total(0); + for (;;) { + char data[4096 * 4]; + size_t writ(source.sgetn(data, sizeof(data))); + if (writ == 0) + break; + _assert(target.sputn(data, writ) == writ); + total += writ; + percent(double(total) / length); + } +} + +#ifndef LDID_NOPLIST +static plist_t plist(const std::string &data) { + plist_t plist(NULL); + if (Starts(data, "bplist00")) + plist_from_bin(data.data(), data.size(), &plist); + else + plist_from_xml(data.data(), data.size(), &plist); + _assert(plist != NULL); + return plist; +} + +static void plist_d(std::streambuf &buffer, size_t length, const Functor &code) { + std::stringbuf data; + copy(buffer, data, length, ldid::fun(dummy)); + auto node(plist(data.str())); + _scope({ plist_free(node); }); + _assert(plist_get_node_type(node) == PLIST_DICT); + code(node); +} + +static std::string plist_s(plist_t node) { + _assert(node != NULL); + _assert(plist_get_node_type(node) == PLIST_STRING); + char *data; + plist_get_string_val(node, &data); + _scope({ free(data); }); + return data; +} +#endif + +enum Mode { + NoMode, + OptionalMode, + OmitMode, + NestedMode, + TopMode, +}; + +class Expression { + private: + regex_t regex_; + std::vector matches_; + + public: + Expression(const std::string &code) { + _assert_(regcomp(®ex_, code.c_str(), REG_EXTENDED) == 0, "regcomp()"); + matches_.resize(regex_.re_nsub + 1); + } + + ~Expression() { + regfree(®ex_); + } + + bool operator ()(const std::string &data) { + regmatch_t matches[matches_.size()]; + auto value(regexec(®ex_, data.c_str(), matches_.size(), matches, 0)); + if (value == REG_NOMATCH) + return false; + _assert_(value == 0, "regexec()"); + for (size_t i(0); i != matches_.size(); ++i) + matches_[i].assign(data.data() + matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so); + return true; + } + + const std::string &operator [](size_t index) const { + return matches_[index]; + } +}; + +struct Rule { + unsigned weight_; + Mode mode_; + std::string code_; + + mutable std::auto_ptr regex_; + + Rule(unsigned weight, Mode mode, const std::string &code) : + weight_(weight), + mode_(mode), + code_(code) + { + } + + Rule(const Rule &rhs) : + weight_(rhs.weight_), + mode_(rhs.mode_), + code_(rhs.code_) + { + } + + void Compile() const { + regex_.reset(new Expression(code_)); + } + + bool operator ()(const std::string &data) const { + _assert(regex_.get() != NULL); + return (*regex_)(data); + } + + bool operator <(const Rule &rhs) const { + if (weight_ > rhs.weight_) + return true; + if (weight_ < rhs.weight_) + return false; + return mode_ > rhs.mode_; + } +}; + +struct RuleCode { + bool operator ()(const Rule *lhs, const Rule *rhs) const { + return lhs->code_ < rhs->code_; + } +}; + +#ifndef LDID_NOPLIST +static Hash Sign(const uint8_t *prefix, size_t size, std::streambuf &buffer, Hash &hash, std::streambuf &save, const std::string &identifier, const std::string &entitlements, const std::string &requirement, const std::string &key, const Slots &slots, size_t length, const Functor &percent) { + // XXX: this is a miserable fail + std::stringbuf temp; + put(temp, prefix, size); + copy(buffer, temp, length - size, percent); + // XXX: this is a stupid hack + pad(temp, 0x10 - (length & 0xf)); + auto data(temp.str()); + + HashProxy proxy(hash, save); + return Sign(data.data(), data.size(), proxy, identifier, entitlements, requirement, key, slots, percent); +} + +Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std::map &remote, const std::string &requirement, const Functor &alter, const Functor &progress, const Functor &percent) { + std::string executable; + std::string identifier; + + bool mac(false); + + std::string info("Info.plist"); + if (!folder.Look(info) && folder.Look("Resources/" + info)) { + mac = true; + info = "Resources/" + info; + } + + folder.Open(info, fun([&](std::streambuf &buffer, size_t length, const void *flag) { + plist_d(buffer, length, fun([&](plist_t node) { + executable = plist_s(plist_dict_get_item(node, "CFBundleExecutable")); + identifier = plist_s(plist_dict_get_item(node, "CFBundleIdentifier")); + })); + })); + + if (!mac && folder.Look("MacOS/" + executable)) { + executable = "MacOS/" + executable; + mac = true; + } + + std::string entitlements; + folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) { + // XXX: this is a miserable fail + std::stringbuf temp; + copy(buffer, temp, length, percent); + // XXX: this is a stupid hack + pad(temp, 0x10 - (length & 0xf)); + auto data(temp.str()); + entitlements = alter(root, Analyze(data.data(), data.size())); + })); + + static const std::string directory("_CodeSignature/"); + static const std::string signature(directory + "CodeResources"); + + std::map> versions; + + auto &rules1(versions[""]); + auto &rules2(versions["2"]); + + const std::string resources(mac ? "Resources/" : ""); + + if (true) { + rules1.insert(Rule{1, NoMode, "^" + resources}); + if (!mac) rules1.insert(Rule{10000, OmitMode, "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/|())SC_Info/[^/]+\\.(sinf|supf|supp)$"}); + rules1.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"}); + rules1.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"}); + if (!mac) rules1.insert(Rule{10000, OmitMode, "^Watch/[^/]+\\.app/(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/)SC_Info/[^/]+\\.(sinf|supf|supp)$"}); + rules1.insert(Rule{1, NoMode, "^version.plist$"}); + } + + if (true) { + rules2.insert(Rule{11, NoMode, ".*\\.dSYM($|/)"}); + rules2.insert(Rule{20, NoMode, "^" + resources}); + rules2.insert(Rule{2000, OmitMode, "^(.*/)?\\.DS_Store$"}); + if (!mac) rules2.insert(Rule{10000, OmitMode, "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/|())SC_Info/[^/]+\\.(sinf|supf|supp)$"}); + rules2.insert(Rule{10, NestedMode, "^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/"}); + rules2.insert(Rule{1, NoMode, "^.*"}); + rules2.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"}); + rules2.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"}); + rules2.insert(Rule{20, OmitMode, "^Info\\.plist$"}); + rules2.insert(Rule{20, OmitMode, "^PkgInfo$"}); + if (!mac) rules2.insert(Rule{10000, OmitMode, "^Watch/[^/]+\\.app/(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/)SC_Info/[^/]+\\.(sinf|supf|supp)$"}); + rules2.insert(Rule{10, NestedMode, "^[^/]+$"}); + rules2.insert(Rule{20, NoMode, "^embedded\\.provisionprofile$"}); + rules2.insert(Rule{20, NoMode, "^version\\.plist$"}); + } + + std::map local; + + std::string failure(mac ? "Contents/|Versions/[^/]*/Resources/" : ""); + Expression nested("^(Frameworks/[^/]*\\.framework|PlugIns/[^/]*\\.appex(()|/[^/]*.app))/(" + failure + ")Info\\.plist$"); + std::map bundles; + + folder.Find("", fun([&](const std::string &name) { + if (!nested(name)) + return; + auto bundle(root + Split(name).dir); + bundle.resize(bundle.size() - resources.size()); + SubFolder subfolder(folder, bundle); + + bundles[nested[1]] = Sign(bundle, subfolder, key, local, "", Starts(name, "PlugIns/") ? alter : + static_cast &>(fun([&](const std::string &, const std::string &entitlements) -> std::string { return entitlements; })) + , progress, percent); + }), fun([&](const std::string &name, const Functor &read) { + })); + + std::set excludes; + + auto exclude([&](const std::string &name) { + // BundleDiskRep::adjustResources -> builder.addExclusion + if (name == executable || Starts(name, directory) || Starts(name, "_MASReceipt/") || name == "CodeResources") + return true; + + for (const auto &bundle : bundles) + if (Starts(name, bundle.first + "/")) { + excludes.insert(name); + return true; + } + + return false; + }); + + std::map links; + + folder.Find("", fun([&](const std::string &name) { + if (exclude(name)) + return; + + if (local.find(name) != local.end()) + return; + auto &hash(local[name]); + + folder.Open(name, fun([&](std::streambuf &data, size_t length, const void *flag) { + progress(root + name); + + union { + struct { + uint32_t magic; + uint32_t count; + }; + + uint8_t bytes[8]; + } header; + + auto size(most(data, &header.bytes, sizeof(header.bytes))); + + if (name != "_WatchKitStub/WK" && size == sizeof(header.bytes)) + switch (Swap(header.magic)) { + case FAT_MAGIC: + // Java class file format + if (Swap(header.count) >= 40) + break; + case FAT_CIGAM: + case MH_MAGIC: case MH_MAGIC_64: + case MH_CIGAM: case MH_CIGAM_64: + folder.Save(name, true, flag, fun([&](std::streambuf &save) { + Slots slots; + Sign(header.bytes, size, data, hash, save, identifier, "", "", key, slots, length, percent); + })); + return; + } + + folder.Save(name, false, flag, fun([&](std::streambuf &save) { + HashProxy proxy(hash, save); + put(proxy, header.bytes, size); + copy(data, proxy, length - size, percent); + })); + })); + }), fun([&](const std::string &name, const Functor &read) { + if (exclude(name)) + return; + + links[name] = read(); + })); + + auto plist(plist_new_dict()); + _scope({ plist_free(plist); }); + + for (const auto &version : versions) { + auto files(plist_new_dict()); + plist_dict_set_item(plist, ("files" + version.first).c_str(), files); + + for (const auto &rule : version.second) + rule.Compile(); + + bool old(&version.second == &rules1); + + for (const auto &hash : local) + for (const auto &rule : version.second) + if (rule(hash.first)) { + if (!old && mac && excludes.find(hash.first) != excludes.end()); + else if (old && rule.mode_ == NoMode) + plist_dict_set_item(files, hash.first.c_str(), plist_new_data(reinterpret_cast(hash.second.sha1_), sizeof(hash.second.sha1_))); + else if (rule.mode_ != OmitMode) { + auto entry(plist_new_dict()); + plist_dict_set_item(entry, "hash", plist_new_data(reinterpret_cast(hash.second.sha1_), sizeof(hash.second.sha1_))); + if (!old) + plist_dict_set_item(entry, "hash2", plist_new_data(reinterpret_cast(hash.second.sha256_), sizeof(hash.second.sha256_))); + if (rule.mode_ == OptionalMode) + plist_dict_set_item(entry, "optional", plist_new_bool(true)); + plist_dict_set_item(files, hash.first.c_str(), entry); + } + + break; + } + + for (const auto &link : links) + for (const auto &rule : version.second) + if (rule(link.first)) { + if (rule.mode_ != OmitMode) { + auto entry(plist_new_dict()); + plist_dict_set_item(entry, "symlink", plist_new_string(link.second.c_str())); + if (rule.mode_ == OptionalMode) + plist_dict_set_item(entry, "optional", plist_new_bool(true)); + plist_dict_set_item(files, link.first.c_str(), entry); + } + + break; + } + + if (!old && mac) + for (const auto &bundle : bundles) { + auto entry(plist_new_dict()); + plist_dict_set_item(entry, "cdhash", plist_new_data(reinterpret_cast(bundle.second.hash.sha256_), sizeof(bundle.second.hash.sha256_))); + plist_dict_set_item(entry, "requirement", plist_new_string("anchor apple generic")); + plist_dict_set_item(files, bundle.first.c_str(), entry); + } + } + + for (const auto &version : versions) { + auto rules(plist_new_dict()); + plist_dict_set_item(plist, ("rules" + version.first).c_str(), rules); + + std::multiset ordered; + for (const auto &rule : version.second) + ordered.insert(&rule); + + for (const auto &rule : ordered) + if (rule->weight_ == 1 && rule->mode_ == NoMode) + plist_dict_set_item(rules, rule->code_.c_str(), plist_new_bool(true)); + else { + auto entry(plist_new_dict()); + plist_dict_set_item(rules, rule->code_.c_str(), entry); + + switch (rule->mode_) { + case NoMode: + break; + case OmitMode: + plist_dict_set_item(entry, "omit", plist_new_bool(true)); + break; + case OptionalMode: + plist_dict_set_item(entry, "optional", plist_new_bool(true)); + break; + case NestedMode: + plist_dict_set_item(entry, "nested", plist_new_bool(true)); + break; + case TopMode: + plist_dict_set_item(entry, "top", plist_new_bool(true)); + break; + } + + if (rule->weight_ >= 10000) + plist_dict_set_item(entry, "weight", plist_new_uint(rule->weight_)); + else if (rule->weight_ != 1) + plist_dict_set_item(entry, "weight", plist_new_real(rule->weight_)); + } + } + + folder.Save(signature, true, NULL, fun([&](std::streambuf &save) { + HashProxy proxy(local[signature], save); + char *xml(NULL); + uint32_t size; + plist_to_xml(plist, &xml, &size); + _scope({ free(xml); }); + put(proxy, xml, size); + })); + + Bundle bundle; + bundle.path = executable; + + folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) { + progress(root + executable); + folder.Save(executable, true, flag, fun([&](std::streambuf &save) { + Slots slots; + slots[1] = local.at(info); + slots[3] = local.at(signature); + bundle.hash = Sign(NULL, 0, buffer, local[executable], save, identifier, entitlements, requirement, key, slots, length, percent); + })); + })); + + for (const auto &entry : local) + remote[root + entry.first] = entry.second; + + return bundle; +} + +Bundle Sign(const std::string &root, Folder &folder, const std::string &key, const std::string &requirement, const Functor &alter, const Functor &progress, const Functor &percent) { + std::map local; + return Sign(root, folder, key, local, requirement, alter, progress, percent); +} +#endif + +#endif +} diff --git a/ldid/ldid.hpp b/ldid/ldid.hpp new file mode 100644 index 0000000..58bbc09 --- /dev/null +++ b/ldid/ldid.hpp @@ -0,0 +1,159 @@ +#ifndef LDID_HPP +#define LDID_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace ldid { + +// I wish Apple cared about providing quality toolchains :/ + +template +class Functor; + +template +class Functor { + public: + virtual Type_ operator ()(Args_... args) const = 0; +}; + +template +class FunctorImpl; + +template +class FunctorImpl : + public Functor +{ + private: + const Value_ *value_; + + public: + FunctorImpl(const Value_ &value) : + value_(&value) + { + } + + virtual Type_ operator ()(Args_... args) const { + return (*value_)(args...); + } +}; + +template +FunctorImpl fun(const Function_ &value) { + return value; +} + +class Folder { + public: + virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code) = 0; + virtual bool Look(const std::string &path) const = 0; + virtual void Open(const std::string &path, const Functor &code) const = 0; + virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const = 0; +}; + +class DiskFolder : + public Folder +{ + private: + const std::string path_; + std::map commit_; + + protected: + std::string Path(const std::string &path) const; + + private: + void Find(const std::string &root, const std::string &base, const Functor &code, const Functor &)> &link) const; + + public: + DiskFolder(const std::string &path); + ~DiskFolder(); + + virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); + virtual bool Look(const std::string &path) const; + virtual void Open(const std::string &path, const Functor &code) const; + virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; +}; + +class SubFolder : + public Folder +{ + private: + Folder &parent_; + std::string path_; + + public: + SubFolder(Folder &parent, const std::string &path); + + virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); + virtual bool Look(const std::string &path) const; + virtual void Open(const std::string &path, const Functor &code) const; + virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; +}; + +class UnionFolder : + public Folder +{ + private: + struct Reset { + const void *flag_; + std::streambuf *data_; + }; + + Folder &parent_; + std::set deletes_; + + std::map remaps_; + mutable std::map resets_; + + std::string Map(const std::string &path) const; + void Map(const std::string &path, const Functor &code, const std::string &file, const Functor &)> &save) const; + + public: + UnionFolder(Folder &parent); + + virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); + virtual bool Look(const std::string &path) const; + virtual void Open(const std::string &path, const Functor &code) const; + virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; + + void operator ()(const std::string &from) { + deletes_.insert(from); + } + + void operator ()(const std::string &from, const std::string &to) { + operator ()(from); + remaps_[to] = from; + } + + void operator ()(const std::string &from, const void *flag, std::streambuf &data) { + operator ()(from); + auto &reset(resets_[from]); + reset.flag_ = flag; + reset.data_ = &data; + } +}; + +struct Hash { + uint8_t sha1_[0x14]; + uint8_t sha256_[0x20]; +}; + +struct Bundle { + std::string path; + Hash hash; +}; + +Bundle Sign(const std::string &root, Folder &folder, const std::string &key, const std::string &requirement, const Functor &alter, const Functor &progress, const Functor &percent); + +typedef std::map Slots; + +Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::string &identifier, const std::string &entitlements, const std::string &requirement, const std::string &key, const Slots &slots, const Functor &percent); + +} + +#endif//LDID_HPP diff --git a/ldid/lookup2.c b/ldid/lookup2.c new file mode 100644 index 0000000..cd87c4d --- /dev/null +++ b/ldid/lookup2.c @@ -0,0 +1,416 @@ +/* +-------------------------------------------------------------------- +lookup2.c, by Bob Jenkins, December 1996, Public Domain. +hash(), hash2(), hash3, and mix() are externally useful functions. +Routines to test the hash are included if SELF_TEST is defined. +You can use this free for any purpose. It has no warranty. +-------------------------------------------------------------------- +*/ +#include +#include +#include +typedef unsigned long int ub4; /* unsigned 4-byte quantities */ +typedef unsigned char ub1; + +#define hashsize(n) ((ub4)1<<(n)) +#define hashmask(n) (hashsize(n)-1) + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bit set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* same, but slower, works on systems that might have 8 byte ub4's */ +#define mix2(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<< 8); \ + c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ + a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ + b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ + a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ + b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 36+6len instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i= 12) + { + a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); + b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); + c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((ub4)k[10]<<24); + case 10: c+=((ub4)k[9]<<16); + case 9 : c+=((ub4)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((ub4)k[7]<<24); + case 7 : b+=((ub4)k[6]<<16); + case 6 : b+=((ub4)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((ub4)k[3]<<24); + case 3 : a+=((ub4)k[2]<<16); + case 2 : a+=((ub4)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + + +/* +-------------------------------------------------------------------- + This works on all machines. hash2() is identical to hash() on + little-endian machines, except that the length has to be measured + in ub4s instead of bytes. It is much faster than hash(). It + requires + -- that the key be an array of ub4's, and + -- that all your machines have the same endianness, and + -- that the length be the number of ub4's in the key +-------------------------------------------------------------------- +*/ +ub4 hash2( k, length, initval) +register ub4 *k; /* the key */ +register ub4 length; /* the length of the key, in ub4s */ +register ub4 initval; /* the previous hash, or an arbitrary value */ +{ + register ub4 a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + while (len >= 3) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + k += 3; len -= 3; + } + + /*-------------------------------------- handle the last 2 ub4's */ + c += length; + switch(len) /* all the case statements fall through */ + { + /* c is reserved for the length */ + case 2 : b+=k[1]; + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + +/* +-------------------------------------------------------------------- + This is identical to hash() on little-endian machines (like Intel + x86s or VAXen). It gives nondeterministic results on big-endian + machines. It is faster than hash(), but a little slower than + hash2(), and it requires + -- that all your machines be little-endian +-------------------------------------------------------------------- +*/ + +ub4 hash3( k, length, initval) +register ub1 *k; /* the key */ +register ub4 length; /* the length of the key */ +register ub4 initval; /* the previous hash, or an arbitrary value */ +{ + register ub4 a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + if (((ub4)k)&3) + { + while (len >= 12) /* unaligned */ + { + a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); + b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); + c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + } + else + { + while (len >= 12) /* aligned */ + { + a += *(ub4 *)(k+0); + b += *(ub4 *)(k+4); + c += *(ub4 *)(k+8); + mix(a,b,c); + k += 12; len -= 12; + } + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((ub4)k[10]<<24); + case 10: c+=((ub4)k[9]<<16); + case 9 : c+=((ub4)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((ub4)k[7]<<24); + case 7 : b+=((ub4)k[6]<<16); + case 6 : b+=((ub4)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((ub4)k[3]<<24); + case 3 : a+=((ub4)k[2]<<16); + case 2 : a+=((ub4)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + + + +#ifdef SELF_TEST + +/* used for timings */ +void driver1() +{ + ub4 buf[256]; + ub4 i; + ub4 h=0; + + for (i=0; i<256; ++i) + { + h = hash(buf,i,h); + } +} + +/* check that every input bit changes every output bit half the time */ +#define HASHSTATE 1 +#define HASHLEN 1 +#define MAXPAIR 80 +#define MAXLEN 70 +void driver2() +{ + ub1 qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; + ub4 c[HASHSTATE], d[HASHSTATE], i, j=0, k, l, m, z; + ub4 e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; + ub4 x[HASHSTATE],y[HASHSTATE]; + ub4 hlen; + + printf("No more than %d trials should ever be needed \n",MAXPAIR/2); + for (hlen=0; hlen < MAXLEN; ++hlen) + { + z=0; + for (i=0; i>(8-j)); + c[0] = hash(a, hlen, m); + b[i] ^= ((k+1)<>(8-j)); + d[0] = hash(b, hlen, m); + /* check every bit is 1, 0, set, and not set at least once */ + for (l=0; lz) z=k; + if (k==MAXPAIR) + { + printf("Some bit didn't change: "); + printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ", + e[0],f[0],g[0],h[0],x[0],y[0]); + printf("i %ld j %ld m %ld len %ld\n",i,j,m,hlen); + } + if (z==MAXPAIR) goto done; + } + } + } + done: + if (z < MAXPAIR) + { + printf("Mix success %2ld bytes %2ld initvals ",i,m); + printf("required %ld trials\n",z/2); + } + } + printf("\n"); +} + +/* Check for reading beyond the end of the buffer and alignment problems */ +void driver3() +{ + ub1 buf[MAXLEN+20], *b; + ub4 len; + ub1 q[] = "This is the time for all good men to come to the aid of their country"; + ub1 qq[] = "xThis is the time for all good men to come to the aid of their country"; + ub1 qqq[] = "xxThis is the time for all good men to come to the aid of their country"; + ub1 qqqq[] = "xxxThis is the time for all good men to come to the aid of their country"; + ub4 h,i,j,ref,x,y; + + printf("Endianness. These should all be the same:\n"); + printf("%.8lx\n", hash(q, sizeof(q)-1, (ub4)0)); + printf("%.8lx\n", hash(qq+1, sizeof(q)-1, (ub4)0)); + printf("%.8lx\n", hash(qqq+2, sizeof(q)-1, (ub4)0)); + printf("%.8lx\n", hash(qqqq+3, sizeof(q)-1, (ub4)0)); + printf("\n"); + for (h=0, b=buf+1; h<8; ++h, ++b) + { + for (i=0; i + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define SHA1HashSize 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const uint8_t *, + unsigned int); +int SHA1Result( SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +#endif diff --git a/minizip/crypt.h b/minizip/crypt.h new file mode 100644 index 0000000..622f4bc --- /dev/null +++ b/minizip/crypt.h @@ -0,0 +1,132 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) + const char *passwd; /* password string */ + unsigned char *buf; /* where to write header */ + int bufSize; + unsigned long* pkeys; + const unsigned long* pcrc_32_tab; + unsigned long crcForCrypting; +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/minizip/ioapi.c b/minizip/ioapi.c new file mode 100644 index 0000000..f1bee23 --- /dev/null +++ b/minizip/ioapi.c @@ -0,0 +1,177 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_file_func OF(( + voidpf opaque, + voidpf stream)); + + +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + + +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + fseek((FILE *)stream, offset, fseek_origin); + return ret; +} + +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/minizip/ioapi.h b/minizip/ioapi.h new file mode 100644 index 0000000..7d457ba --- /dev/null +++ b/minizip/ioapi.h @@ -0,0 +1,75 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + +#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + + + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/minizip/miniunz.c b/minizip/miniunz.c new file mode 100644 index 0000000..1a0a5e2 --- /dev/null +++ b/minizip/miniunz.c @@ -0,0 +1,446 @@ +/* + miniunz.c + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + + +#include +#include +#include +#include +#include +#include + + + +#ifdef unix +# include +# include +# include +#else +# include +# include +#endif + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef WIN32 + ret = mkdir(dirname); +#else +#ifdef unix + ret = mkdir (dirname,0775); +#endif +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info gi; + int err; + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (file_info.compressed_size*100)/file_info.uncompressed_size; + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + string_method="Unkn. "; + + printf("%7lu %6s%c%7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + file_info.uncompressed_size,string_method, + charCrypt, + file_info.compressed_size, + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen(write_filename,"wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=fopen(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "zip.h" + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATA ff32; + + hFind = FindFirstFile(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %x\n",filenameinzip,calculate_crc); + return err; +} + diff --git a/minizip/mztools.c b/minizip/mztools.c new file mode 100644 index 0000000..8a50ee4 --- /dev/null +++ b/minizip/mztools.c @@ -0,0 +1,281 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/minizip/mztools.h b/minizip/mztools.h new file mode 100644 index 0000000..eee78dc --- /dev/null +++ b/minizip/mztools.h @@ -0,0 +1,31 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/minizip/unzip.c b/minizip/unzip.c new file mode 100644 index 0000000..9ad4766 --- /dev/null +++ b/minizip/unzip.c @@ -0,0 +1,1598 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + Read unzip.h for more info +*/ + +/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of +compatibility with older software. The following is from the original crypt.c. Code +woven in by Terry Thorsen 1/2003. +*/ +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html +*/ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + */ + +/* + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + */ + + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def) + const char *path; + zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&us.z_filefunc); + else + us.z_filefunc = *pzlib_filefunc_def; + + us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + if (ZSEEK(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (ZSEEK(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info cur_file_infoSaved; + unz_file_info_internal cur_file_info_internalSaved; + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; // offset in file + uLong num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) + unzFile file; + int* method; + int* level; + int raw; + const char* password; +{ + int err=UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_DEFLATED) && + (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (file, password) + unzFile file; + const char* password; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) + unzFile file; + int* method; + int* level; + int raw; +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + int err=UNZ_OK; + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern uLong ZEXPORT unzGetOffset (file) + unzFile file; +{ + unz_s* s; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern int ZEXPORT unzSetOffset (file, pos) + unzFile file; + uLong pos; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} diff --git a/minizip/unzip.h b/minizip/unzip.h new file mode 100644 index 0000000..b247937 --- /dev/null +++ b/minizip/unzip.h @@ -0,0 +1,354 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/minizip/zip.c b/minizip/zip.c new file mode 100644 index 0000000..7fbe002 --- /dev/null +++ b/minizip/zip.c @@ -0,0 +1,1219 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.01e, February 12th, 2005 + + 27 Dec 2004 Rolf Kalbermatter + Modification to zipOpen2 to support globalComment retrieval. + + Copyright (C) 1998-2005 Gilles Vollant + + Read zip.h for more info +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] = + " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + uLong pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralheader; /* size of the central header for cur file */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile_info; + +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile_info ci; /* info on the file curretly writing */ + + uLong begin_pos; /* position of the beginning of the zipfile */ + uLong add_position_when_writting_offset; + uLong number_entry; +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif +} zip_internal; + + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(ldi) + linkedlist_datablock_internal* ldi; +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(ll) + linkedlist_data* ll; +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(ll) + linkedlist_data* ll; +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(ll,buf,len) + linkedlist_data* ll; + const void* buf; + uLong len; +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 or 4 (byte, short or long) +*/ + +local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, uLong x, int nbByte)); +local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong x; + int nbByte; +{ + unsigned char buf[4]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); +local void ziplocal_putValue_inmemory (dest, x, nbByte) + void* dest; + uLong x; + int nbByte; +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) + const tm_zip* ptm; + uLong dosDate; +{ + uLong year = (uLong)ptm->tm_year; + if (year>1980) + year-=1980; + else if (year>80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int ziplocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int ziplocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int ziplocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong ziplocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + +/************************************************************/ +extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc_def) + const char *pathname; + int append; + zipcharpc* globalcomment; + zlib_filefunc_def* pzlib_filefunc_def; +{ + zip_internal ziinit; + zip_internal* zi; + int err=ZIP_OK; + + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&ziinit.z_filefunc); + else + ziinit.z_filefunc = *pzlib_filefunc_def; + + ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) + (ziinit.z_filefunc.opaque, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + zi = (zip_internal*)ALLOC(sizeof(zip_internal)); + if (zi==NULL) + { + ZCLOSE(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory */ + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry; + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong size_comment; + + central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); + if (central_pos==0) + err=ZIP_ERRNO; + + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* zipfile global comment length */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((central_pos0) + { + ziinit.globalcomment = ALLOC(size_comment+1); + if (ziinit.globalcomment) + { + size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment); + ziinit.globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - + (offset_central_dir+size_central_dir); + ziinit.add_position_when_writting_offset = byte_before_the_zipfile; + + { + uLong size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir + byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + uLong read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&ziinit.central_dir,buf_read, + (uLong)read_this); + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + ziinit.begin_pos = byte_before_the_zipfile; + ziinit.number_entry = number_entry_CD; + + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen (pathname, append) + const char *pathname; + int append; +{ + return zipOpen2(pathname,append,NULL,NULL); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; + int windowBits; + int memLevel; + int strategy; + const char* password; + uLong crcForCrypting; +{ + zip_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); + } + + zi->ci.flag = 0; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + + size_extrafield_global + size_comment; + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); + + ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); + ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + /* write the local header */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); + + if ((err==ZIP_OK) && (size_filename>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + + if ((err==ZIP_OK) && (size_extrafield_local>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) + !=size_extrafield_local) + err = ZIP_ERRNO; + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, + Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = 1; + } +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; +{ + return zipOpenNewFileInZip3 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; +{ + return zipOpenNewFileInZip2 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0); +} + +local int zipFlushWriteBuffer(zi) + zip_internal* zi; +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, + zi->ci.buffered_data[i],t); +#endif + } + if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) + !=zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + zi->ci.pos_in_buffered_data = 0; + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (file, buf, len) + zipFile file; + const void* buf; + unsigned len; +{ + zip_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.stream.next_in = (void*)buf; + zi->ci.stream.avail_in = len; + zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + for (i=0;ici.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32) + zipFile file; + uLong uncompressed_size; + uLong crc32; +{ + zip_internal* zi; + uLong compressed_size; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + err=deflateEnd(&zi->ci.stream); + zi->ci.stream_initialised = 0; + } + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = (uLong)zi->ci.stream.total_in; + } + compressed_size = (uLong)zi->ci.stream.total_out; +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20, + compressed_size,4); /*compr size*/ + if (zi->ci.stream.data_type == Z_ASCII) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + ziplocal_putValue_inmemory(zi->ci.central_header+24, + uncompressed_size,4); /*uncompr size*/ + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, + (uLong)zi->ci.size_centralheader); + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (ZSEEK(zi->z_filefunc,zi->filestream, + zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if (err==ZIP_OK) /* compressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + + if (ZSEEK(zi->z_filefunc,zi->filestream, + cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (file) + zipFile file; +{ + return zipCloseFileInZipRaw (file,0,0); +} + +extern int ZEXPORT zipClose (file, global_comment) + zipFile file; + const char* global_comment; +{ + zip_internal* zi; + int err = 0; + uLong size_centraldir = 0; + uLong centraldir_pos_inzip; + uInt size_global_comment; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + if (global_comment==NULL) + size_global_comment = 0; + else + size_global_comment = (uInt)strlen(global_comment); + + centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + ldi->data,ldi->filled_in_this_block) + !=ldi->filled_in_this_block ) + err = ZIP_ERRNO; + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_datablock(zi->central_dir.first_block); + + if (err==ZIP_OK) /* Magic End */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* size of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the + starting disk number */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, + (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + + if (err==ZIP_OK) /* zipfile comment length */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if ((err==ZIP_OK) && (size_global_comment>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + global_comment,size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + + if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} diff --git a/minizip/zip.h b/minizip/zip.h new file mode 100644 index 0000000..acacce8 --- /dev/null +++ b/minizip/zip.h @@ -0,0 +1,235 @@ +/* zip.h -- IO for compress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This unzip package allow creates .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + For uncompress .zip file, look at unzip.h + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.html for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _zip_H +#define _zip_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCtypting)); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCtypting : crc of file to compress (needed for crypting) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); +/* + Close the current file in the zipfile, for fiel opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip_H */