├── .gitignore ├── Account.cpp ├── Account.hpp ├── AnisetteData.cpp ├── AnisetteData.h ├── AppGroup.cpp ├── AppGroup.hpp ├── AppID.cpp ├── AppID.hpp ├── AppleAPI+Authentication.cpp ├── AppleAPI.cpp ├── AppleAPI.hpp ├── AppleAPISession.cpp ├── AppleAPISession.h ├── Application.cpp ├── Application.hpp ├── Archiver.cpp ├── Archiver.hpp ├── Certificate.cpp ├── Certificate.hpp ├── CertificateRequest.cpp ├── CertificateRequest.hpp ├── Device.cpp ├── Device.hpp ├── Error.hpp ├── Makefile ├── PrefixHeader.pch ├── ProvisioningProfile.cpp ├── ProvisioningProfile.hpp ├── Signer.cpp ├── Signer.hpp ├── Team.cpp ├── Team.hpp ├── altsign_common.h ├── ldid ├── control.sh ├── ldid.cpp ├── ldid.hpp ├── lookup2.c └── sha1.h └── minizip ├── ChangeLogUnzip ├── Makefile ├── crypt.h ├── ioapi.c ├── ioapi.h ├── iowin32.c ├── iowin32.h ├── miniunz.c ├── minizip.c ├── mztools.c ├── mztools.h ├── unzip.c ├── unzip.h ├── zip.c └── zip.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | /AltServer 4 | 5 | .vscode 6 | .ccls-cache 7 | 8 | -------------------------------------------------------------------------------- /Account.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Account.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/8/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | #include "PrefixHeader.pch" 12 | 13 | Account::Account(plist_t plist) /* throws */ 14 | { 15 | auto appleIDNode = plist_dict_get_item(plist, "email"); 16 | auto identifierNode = plist_dict_get_item(plist, "personId"); 17 | 18 | auto firstNameNode = plist_dict_get_item(plist, "firstName"); 19 | if (firstNameNode == nullptr) 20 | { 21 | firstNameNode = plist_dict_get_item(plist, "dsFirstName"); 22 | } 23 | 24 | auto lastNameNode = plist_dict_get_item(plist, "lastName"); 25 | if (lastNameNode == nullptr) 26 | { 27 | lastNameNode = plist_dict_get_item(plist, "dsLastName"); 28 | } 29 | 30 | if (appleIDNode == nullptr || identifierNode == nullptr || firstNameNode == nullptr || lastNameNode == nullptr) 31 | { 32 | throw APIError(APIErrorCode::InvalidResponse); 33 | } 34 | 35 | uint64_t identifier = 0; 36 | switch (plist_get_node_type(identifierNode)) 37 | { 38 | case PLIST_UINT: 39 | plist_get_uint_val(identifierNode, &identifier); 40 | break; 41 | 42 | case PLIST_REAL: 43 | { 44 | double value = 0; 45 | plist_get_real_val(identifierNode, &value); 46 | identifier = (uint64_t)value; 47 | break; 48 | } 49 | 50 | default: 51 | break; 52 | } 53 | 54 | char* appleID = nullptr; 55 | plist_get_string_val(appleIDNode, &appleID); 56 | 57 | char *firstName = nullptr; 58 | plist_get_string_val(firstNameNode, &firstName); 59 | 60 | char *lastName = nullptr; 61 | plist_get_string_val(lastNameNode, &lastName); 62 | 63 | _appleID = appleID; 64 | _identifier = std::to_string(identifier); 65 | _firstName = firstName; 66 | _lastName = lastName; 67 | } 68 | 69 | Account::Account() 70 | { 71 | } 72 | 73 | Account::~Account() 74 | { 75 | } 76 | 77 | #pragma mark - Description - 78 | 79 | std::ostream& operator<<(std::ostream& os, const Account& account) 80 | { 81 | os << "Name: " << account.name() << " Apple ID: " << account.appleID(); 82 | return os; 83 | } 84 | 85 | #pragma mark - Getters - 86 | 87 | std::string Account::appleID() const 88 | { 89 | return _appleID; 90 | } 91 | 92 | std::string Account::identifier() const 93 | { 94 | return _identifier; 95 | } 96 | 97 | std::string Account::firstName() const 98 | { 99 | return _firstName; 100 | } 101 | 102 | std::string Account::lastName() const 103 | { 104 | return _lastName; 105 | } 106 | 107 | std::string Account::name() const 108 | { 109 | return firstName() + " " + lastName(); 110 | } 111 | 112 | std::string Account::cookie() const 113 | { 114 | return _cookie; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /Account.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Account.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/8/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Account_hpp 10 | #define Account_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | class Account 22 | { 23 | public: 24 | Account(); 25 | ~Account(); 26 | 27 | Account(plist_t plist); /* throws */ 28 | 29 | std::string appleID() const; 30 | std::string identifier() const; 31 | std::string firstName() const; 32 | std::string lastName() const; 33 | std::string name() const; 34 | std::string cookie() const; 35 | 36 | friend std::ostream& operator<<(std::ostream& os, const Account& account); 37 | 38 | private: 39 | std::string _appleID; 40 | std::string _identifier; 41 | std::string _firstName; 42 | std::string _lastName; 43 | std::string _cookie; 44 | }; 45 | 46 | #pragma GCC visibility pop 47 | 48 | #endif /* Account_hpp */ 49 | -------------------------------------------------------------------------------- /AnisetteData.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // AnisetteData.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 11/26/19. 6 | // Copyright � 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "AnisetteData.h" 10 | #include 11 | 12 | AnisetteData::AnisetteData() : _routingInfo(0), _date({ 0 }) 13 | { 14 | } 15 | 16 | AnisetteData::~AnisetteData() 17 | { 18 | } 19 | 20 | AnisetteData::AnisetteData(std::string machineID, 21 | std::string oneTimePassword, 22 | std::string localUserID, 23 | unsigned long long routingInfo, 24 | std::string deviceUniqueIdentifier, 25 | std::string deviceSerialNumber, 26 | std::string deviceDescription, 27 | struct timeval date, 28 | std::string locale, 29 | std::string timeZone) : 30 | _machineID(machineID), _oneTimePassword(oneTimePassword), _localUserID(localUserID), _routingInfo(routingInfo), 31 | _deviceUniqueIdentifier(deviceUniqueIdentifier), _deviceSerialNumber(deviceSerialNumber), _deviceDescription(deviceDescription), 32 | _date(date), _locale(locale), _timeZone(timeZone) 33 | { 34 | } 35 | 36 | //AnisetteData::AnisetteData(web::json::value json) 37 | //{ 38 | // auto machineID = StringFromWideString(json["machineID"].as_string()); 39 | // auto oneTimePassword = StringFromWideString(json["oneTimePassword"].as_string()); 40 | // auto localUserID = StringFromWideString(json["localUserID"].as_string()); 41 | // auto routingInfo = json["routingInfo"].as_integer(); 42 | // auto deviceUniqueIdentifier = StringFromWideString(json["deviceUniqueIdentifier"].as_string()); 43 | // auto deviceSerialNumber = StringFromWideString(json["deviceSerialNumber"].as_string()); 44 | // auto deviceDescription = StringFromWideString(json["deviceDescription"].as_string()); 45 | // auto date = StringFromWideString(json["date"].as_string()); 46 | // auto locale = StringFromWideString(json["locale"].as_string()); 47 | // auto timeZone = StringFromWideString(json["timeZone"].as_string()); 48 | // 49 | // _machineID = machineID; 50 | // _oneTimePassword = oneTimePassword; 51 | // _localUserID = localUserID; 52 | // _routingInfo = routingInfo; 53 | // _deviceUniqueIdentifier = deviceUniqueIdentifier; 54 | // _deviceSerialNumber = deviceSerialNumber; 55 | // _deviceDescription = deviceDescription; 56 | // _date = date; 57 | // _locale = locale; 58 | // _timeZone = timeZone; 59 | //} 60 | 61 | std::ostream& operator<<(std::ostream& os, const AnisetteData& anisetteData) 62 | { 63 | time_t time; 64 | struct tm* tm; 65 | char dateString[64]; 66 | 67 | time = anisetteData.date().tv_sec; 68 | tm = localtime(&time); 69 | 70 | strftime(dateString, sizeof dateString, "%FT%T%z", tm); 71 | 72 | os << "MachineID : " << anisetteData.machineID() << 73 | "\nOne-Time Password: " << anisetteData.oneTimePassword() << 74 | "\nLocal User ID: " << anisetteData.localUserID() << 75 | "\nDevice UDID: " << anisetteData.deviceUniqueIdentifier() << 76 | "\nDevice Description: " << anisetteData.deviceDescription() << 77 | "\nDate: " << dateString; 78 | 79 | return os; 80 | } 81 | 82 | std::string AnisetteData::machineID() const 83 | { 84 | return _machineID; 85 | } 86 | 87 | std::string AnisetteData::oneTimePassword() const 88 | { 89 | return _oneTimePassword; 90 | } 91 | 92 | std::string AnisetteData::localUserID() const 93 | { 94 | return _localUserID; 95 | } 96 | 97 | unsigned long long AnisetteData::routingInfo() const 98 | { 99 | return _routingInfo; 100 | } 101 | 102 | std::string AnisetteData::deviceUniqueIdentifier() const 103 | { 104 | return _deviceUniqueIdentifier; 105 | } 106 | 107 | std::string AnisetteData::deviceSerialNumber() const 108 | { 109 | return _deviceSerialNumber; 110 | } 111 | 112 | std::string AnisetteData::deviceDescription() const 113 | { 114 | return _deviceDescription; 115 | } 116 | 117 | TIMEVAL AnisetteData::date() const 118 | { 119 | return _date; 120 | } 121 | 122 | std::string AnisetteData::locale() const 123 | { 124 | return _locale; 125 | } 126 | 127 | std::string AnisetteData::timeZone() const 128 | { 129 | return _timeZone; 130 | } 131 | 132 | web::json::value AnisetteData::json() const 133 | { 134 | time_t time; 135 | struct tm* tm; 136 | char dateString[64]; 137 | 138 | time = this->date().tv_sec; 139 | tm = localtime(&time); 140 | 141 | strftime(dateString, sizeof dateString, "%FT%T%z", tm); 142 | 143 | auto json = web::json::value(); 144 | json["machineID"] = web::json::value::string((this->machineID())); 145 | json["oneTimePassword"] = web::json::value::string((this->oneTimePassword())); 146 | json["localUserID"] = web::json::value::string((this->localUserID())); 147 | json["routingInfo"] = web::json::value::string((std::to_string(this->routingInfo()))); 148 | json["deviceUniqueIdentifier"] = web::json::value::string((this->deviceUniqueIdentifier())); 149 | json["deviceSerialNumber"] = web::json::value::string((this->deviceSerialNumber())); 150 | json["deviceDescription"] = web::json::value::string((this->deviceDescription())); 151 | json["date"] = web::json::value::string((dateString)); 152 | json["locale"] = web::json::value::string((this->locale())); 153 | json["timeZone"] = web::json::value::string((this->timeZone())); 154 | 155 | return json; 156 | } 157 | 158 | -------------------------------------------------------------------------------- /AnisetteData.h: -------------------------------------------------------------------------------- 1 | // 2 | // AnisetteData.h 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 11/26/19. 6 | // Copyright � 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #pragma once 10 | 11 | /* The classes below are exported */ 12 | #pragma GCC visibility push(default) 13 | 14 | #include "altsign_common.h" 15 | 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | 24 | class AnisetteData 25 | { 26 | public: 27 | AnisetteData(); 28 | ~AnisetteData(); 29 | 30 | AnisetteData(std::string machineID, 31 | std::string oneTimePassword, 32 | std::string localUserID, 33 | unsigned long long routingInfo, 34 | std::string deviceUniqueIdentifier, 35 | std::string deviceSerialNumber, 36 | std::string deviceDescription, 37 | struct timeval date, 38 | std::string locale, 39 | std::string timeZone); 40 | 41 | std::string machineID() const; 42 | std::string oneTimePassword() const; 43 | std::string localUserID() const; 44 | unsigned long long routingInfo() const; 45 | std::string deviceUniqueIdentifier() const; 46 | std::string deviceSerialNumber() const; 47 | std::string deviceDescription() const; 48 | TIMEVAL date() const; 49 | std::string locale() const; 50 | std::string timeZone() const; 51 | 52 | web::json::value json() const; 53 | 54 | friend std::ostream& operator<<(std::ostream& os, const AnisetteData& anisetteData); 55 | 56 | private: 57 | std::string _machineID; 58 | std::string _oneTimePassword; 59 | std::string _localUserID; 60 | unsigned long long _routingInfo; 61 | std::string _deviceUniqueIdentifier; 62 | std::string _deviceSerialNumber; 63 | std::string _deviceDescription; 64 | TIMEVAL _date; 65 | std::string _locale; 66 | std::string _timeZone; 67 | }; 68 | 69 | #pragma GCC visibility pop 70 | 71 | -------------------------------------------------------------------------------- /AppGroup.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // AppGroup.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 5/19/20. 6 | // Copyright (c) 2020 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "AppGroup.hpp" 10 | 11 | #include "Error.hpp" 12 | 13 | AppGroup::AppGroup() 14 | { 15 | } 16 | 17 | AppGroup::~AppGroup() 18 | { 19 | } 20 | 21 | AppGroup::AppGroup(plist_t plist) 22 | { 23 | auto nameNode = plist_dict_get_item(plist, "name"); 24 | auto identifierNode = plist_dict_get_item(plist, "applicationGroup"); 25 | auto groupIdentifierNode = plist_dict_get_item(plist, "identifier"); 26 | 27 | if (nameNode == nullptr || identifierNode == nullptr || groupIdentifierNode == nullptr) 28 | { 29 | throw APIError(APIErrorCode::InvalidResponse); 30 | } 31 | 32 | char* name = nullptr; 33 | plist_get_string_val(nameNode, &name); 34 | 35 | char* identifier = nullptr; 36 | plist_get_string_val(identifierNode, &identifier); 37 | 38 | char* groupIdentifier = nullptr; 39 | plist_get_string_val(groupIdentifierNode, &groupIdentifier); 40 | 41 | _name = name; 42 | _identifier = identifier; 43 | _groupIdentifier = groupIdentifier; 44 | } 45 | 46 | #pragma mark - Description - 47 | 48 | std::ostream& operator<<(std::ostream& os, const AppGroup& appGroup) 49 | { 50 | os << "Name: " << appGroup.name() << " ID: " << appGroup.identifier() << " GroupID: " << appGroup.groupIdentifier(); 51 | return os; 52 | } 53 | 54 | #pragma mark - Getters - 55 | 56 | std::string AppGroup::name() const 57 | { 58 | return _name; 59 | } 60 | 61 | std::string AppGroup::identifier() const 62 | { 63 | return _identifier; 64 | } 65 | 66 | std::string AppGroup::groupIdentifier() const 67 | { 68 | return _groupIdentifier; 69 | } 70 | -------------------------------------------------------------------------------- /AppGroup.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // AppGroup.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 5/19/20. 6 | // Copyright (c) 2020 Riley Testut. All rights reserved. 7 | // 8 | 9 | #pragma once 10 | 11 | /* The classes below are exported */ 12 | #pragma GCC visibility push(default) 13 | 14 | #include 15 | 16 | #include 17 | 18 | class AppGroup 19 | { 20 | public: 21 | AppGroup(); 22 | ~AppGroup(); 23 | 24 | AppGroup(plist_t plist) /* throws */; 25 | 26 | std::string name() const; 27 | std::string identifier() const; 28 | std::string groupIdentifier() const; 29 | 30 | friend std::ostream& operator<<(std::ostream& os, const AppGroup& appGroup); 31 | 32 | private: 33 | std::string _name; 34 | std::string _identifier; 35 | std::string _groupIdentifier; 36 | }; 37 | 38 | #pragma GCC visibility pop -------------------------------------------------------------------------------- /AppID.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // AppID.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "AppID.hpp" 10 | 11 | #include "Error.hpp" 12 | 13 | std::string AppIDFeatureAppGroups = "APG3427HIY"; 14 | 15 | AppID::AppID() 16 | { 17 | } 18 | 19 | AppID::~AppID() 20 | { 21 | for (auto& pair : _features) 22 | { 23 | plist_free(pair.second); 24 | } 25 | } 26 | 27 | AppID::AppID(const AppID& appID) 28 | { 29 | _name = appID.name(); 30 | _identifier = appID.identifier(); 31 | _bundleIdentifier = appID.bundleIdentifier(); 32 | 33 | // Deep copy features 34 | this->setFeatures(appID.features()); 35 | } 36 | 37 | AppID& AppID::operator=(const AppID& appID) 38 | { 39 | if (this == &appID) 40 | { 41 | return *this; 42 | } 43 | 44 | _name = appID.name(); 45 | _identifier = appID.identifier(); 46 | _bundleIdentifier = appID.bundleIdentifier(); 47 | 48 | // Deep copy features 49 | this->setFeatures(appID.features()); 50 | 51 | return *this; 52 | } 53 | 54 | AppID::AppID(plist_t plist) 55 | { 56 | auto nameNode = plist_dict_get_item(plist, "name"); 57 | auto identifierNode = plist_dict_get_item(plist, "appIdId"); 58 | auto bundleIdentifierNode = plist_dict_get_item(plist, "identifier"); 59 | 60 | if (nameNode == nullptr || identifierNode == nullptr || bundleIdentifierNode == nullptr) 61 | { 62 | throw APIError(APIErrorCode::InvalidResponse); 63 | } 64 | 65 | auto allFeaturesNode = plist_dict_get_item(plist, "features"); 66 | auto enabledFeaturesNode = plist_dict_get_item(plist, "enabledFeatures"); 67 | 68 | std::map features; 69 | if (allFeaturesNode != NULL && enabledFeaturesNode != NULL) 70 | { 71 | for (int i = 0; i < plist_array_get_size(enabledFeaturesNode); i++) 72 | { 73 | auto featureNode = plist_array_get_item(enabledFeaturesNode, i); 74 | 75 | char *featureName = nullptr; 76 | plist_get_string_val(featureNode, &featureName); 77 | 78 | auto valueNode = plist_copy(plist_dict_get_item(allFeaturesNode, featureName)); 79 | features[featureName] = valueNode; 80 | } 81 | } 82 | 83 | char *name = nullptr; 84 | plist_get_string_val(nameNode, &name); 85 | 86 | char *identifier = nullptr; 87 | plist_get_string_val(identifierNode, &identifier); 88 | 89 | char *bundleIdentifier = nullptr; 90 | plist_get_string_val(bundleIdentifierNode, &bundleIdentifier); 91 | 92 | _name = name; 93 | _identifier = identifier; 94 | _bundleIdentifier = bundleIdentifier; 95 | 96 | _features = features; 97 | } 98 | 99 | #pragma mark - Description - 100 | 101 | std::ostream& operator<<(std::ostream& os, const AppID& appID) 102 | { 103 | os << "Name: " << appID.name() << " ID: " << appID.identifier() << " BundleID: " << appID.bundleIdentifier(); 104 | return os; 105 | } 106 | 107 | #pragma mark - Getters - 108 | 109 | std::string AppID::name() const 110 | { 111 | return _name; 112 | } 113 | 114 | std::string AppID::identifier() const 115 | { 116 | return _identifier; 117 | } 118 | 119 | std::string AppID::bundleIdentifier() const 120 | { 121 | return _bundleIdentifier; 122 | } 123 | 124 | std::map AppID::features() const 125 | { 126 | return _features; 127 | } 128 | 129 | void AppID::setFeatures(std::map features) 130 | { 131 | for (auto& pair : _features) 132 | { 133 | // Free previous features. 134 | plist_free(pair.second); 135 | } 136 | 137 | std::map copiedFeatures; 138 | for (auto& pair : features) 139 | { 140 | copiedFeatures[pair.first] = plist_copy(pair.second); 141 | } 142 | 143 | _features = copiedFeatures; 144 | } 145 | -------------------------------------------------------------------------------- /AppID.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // AppID.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef AppID_hpp 10 | #define AppID_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | extern std::string AppIDFeatureAppGroups; 22 | 23 | class AppID 24 | { 25 | public: 26 | AppID(); 27 | ~AppID(); 28 | 29 | AppID(const AppID& appID); 30 | AppID& operator=(const AppID& appID); 31 | 32 | AppID(plist_t plist) /* throws */; 33 | 34 | std::string name() const; 35 | std::string identifier() const; 36 | std::string bundleIdentifier() const; 37 | 38 | std::map features() const; 39 | void setFeatures(std::map features); 40 | 41 | friend std::ostream& operator<<(std::ostream& os, const AppID& appID); 42 | 43 | private: 44 | std::string _name; 45 | std::string _identifier; 46 | std::string _bundleIdentifier; 47 | 48 | std::map _features; 49 | }; 50 | 51 | #pragma GCC visibility pop 52 | 53 | #endif /* AppID_hpp */ 54 | -------------------------------------------------------------------------------- /AppleAPI.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // AltSign_Windows.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/8/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef AppleAPI_hpp 10 | #define AppleAPI_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | 18 | #include "Account.hpp" 19 | #include "AppID.hpp" 20 | #include "AppGroup.hpp" 21 | #include "Certificate.hpp" 22 | #include "Device.hpp" 23 | #include "ProvisioningProfile.hpp" 24 | #include "Team.hpp" 25 | #include "Error.hpp" 26 | 27 | #include "AppleAPISession.h" 28 | 29 | 30 | #define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED 31 | #include 32 | 33 | class AppleAPI 34 | { 35 | public: 36 | static AppleAPI *getInstance(); 37 | 38 | pplx::task, std::shared_ptr>> Authenticate( 39 | std::string appleID, 40 | std::string password, 41 | std::shared_ptr anisetteData, 42 | std::optional>(void)>> verificationHandler); 43 | 44 | // Teams 45 | pplx::task>> FetchTeams(std::shared_ptr account, std::shared_ptr session); 46 | 47 | // Devices 48 | pplx::task>> FetchDevices(std::shared_ptr team, Device::Type types, std::shared_ptr session); 49 | pplx::task> RegisterDevice(std::string name, std::string identifier, Device::Type type, std::shared_ptr team, std::shared_ptr session); 50 | 51 | // Certificates 52 | pplx::task>> FetchCertificates(std::shared_ptr team, std::shared_ptr session); 53 | pplx::task> AddCertificate(std::string machineName, std::shared_ptr team, std::shared_ptr session); 54 | pplx::task RevokeCertificate(std::shared_ptr certificate, std::shared_ptr team, std::shared_ptr session); 55 | 56 | // App IDs 57 | pplx::task>> FetchAppIDs(std::shared_ptr team, std::shared_ptr session); 58 | pplx::task> AddAppID(std::string name, std::string bundleIdentifier, std::shared_ptr team, std::shared_ptr session); 59 | pplx::task> UpdateAppID(std::shared_ptr appID, std::shared_ptr team, std::shared_ptr session); 60 | 61 | // App Groups 62 | pplx::task>> FetchAppGroups(std::shared_ptr team, std::shared_ptr session); 63 | pplx::task> AddAppGroup(std::string name, std::string groupIdentifier, std::shared_ptr team, std::shared_ptr session); 64 | pplx::task AssignAppIDToGroups(std::shared_ptr appID, std::vector> groups, std::shared_ptr team, std::shared_ptr session); 65 | 66 | // Provisioning Profiles 67 | pplx::task> FetchProvisioningProfile(std::shared_ptr appID, Device::Type deviceType, std::shared_ptr team, std::shared_ptr session); 68 | pplx::task DeleteProvisioningProfile(std::shared_ptr profile, std::shared_ptr team, std::shared_ptr session); 69 | 70 | private: 71 | AppleAPI(); 72 | 73 | static AppleAPI *instance_; 74 | 75 | web::http::client::http_client _servicesClient; 76 | web::http::client::http_client servicesClient(); 77 | 78 | web::http::client::http_client _gsaClient; 79 | web::http::client::http_client gsaClient(); 80 | 81 | web::http::client::http_client _client; 82 | web::http::client::http_client client(); 83 | 84 | pplx::task SendRequest(std::string uri, 85 | std::map additionalParameters, 86 | std::shared_ptr session, 87 | std::shared_ptr team); 88 | 89 | pplx::task SendRequest(std::string uri, 90 | std::map additionalParameters, 91 | std::shared_ptr session, 92 | std::shared_ptr team); 93 | 94 | pplx::task SendAuthenticationRequest(std::map requestParameters, 95 | std::shared_ptr anisetteData); 96 | 97 | pplx::task SendServicesRequest(std::string uri, 98 | std::string method, 99 | std::map requestParameters, 100 | std::shared_ptr session, 101 | std::shared_ptr team); 102 | 103 | pplx::task FetchAuthToken(std::map requestParameters, std::vector sk, std::shared_ptr anisetteData); 104 | pplx::task> FetchAccount(std::shared_ptr session); 105 | 106 | pplx::task RequestTwoFactorCode( 107 | std::string dsid, 108 | std::string idmsToken, 109 | std::shared_ptr anisetteData, 110 | const std::function >(void)>& verificationHandler); 111 | 112 | template 113 | T ProcessAnyResponse(plist_t plist, std::string errorCodeKey, std::vector errorMessageKeys, std::function parseHandler, std::function(int64_t)> resultCodeHandler) 114 | { 115 | try 116 | { 117 | try 118 | { 119 | auto value = parseHandler(plist); 120 | plist_free(plist); 121 | return value; 122 | } 123 | catch (std::exception& exception) 124 | { 125 | //odslog("Parse exception: " << exception.what()); 126 | 127 | int64_t resultCode = 0; 128 | 129 | auto node = plist_dict_get_item(plist, errorCodeKey.c_str()); 130 | if (node == nullptr) 131 | { 132 | throw APIError(APIErrorCode::InvalidResponse); 133 | } 134 | 135 | auto type = plist_get_node_type(node); 136 | switch (type) 137 | { 138 | case PLIST_STRING: 139 | { 140 | char* value = nullptr; 141 | plist_get_string_val(node, &value); 142 | 143 | resultCode = atoi(value); 144 | break; 145 | } 146 | 147 | case PLIST_UINT: 148 | { 149 | uint64_t value = 0; 150 | plist_get_uint_val(node, &value); 151 | 152 | resultCode = (int64_t)value; 153 | break; 154 | } 155 | 156 | case PLIST_REAL: 157 | { 158 | double value = 0; 159 | plist_get_real_val(node, &value); 160 | 161 | resultCode = (int64_t)value; 162 | break; 163 | } 164 | 165 | default: 166 | break; 167 | } 168 | 169 | auto error = resultCodeHandler(resultCode); 170 | if (error.has_value()) 171 | { 172 | throw error.value(); 173 | } 174 | 175 | plist_t descriptionNode = nullptr; 176 | for (auto& errorMessageKey : errorMessageKeys) 177 | { 178 | auto node = plist_dict_get_item(plist, errorMessageKey.c_str()); 179 | if (node == NULL) 180 | { 181 | continue; 182 | } 183 | 184 | descriptionNode = node; 185 | break; 186 | } 187 | 188 | char* errorDescription = nullptr; 189 | plist_get_string_val(descriptionNode, &errorDescription); 190 | 191 | if (errorDescription == nullptr) 192 | { 193 | throw APIError(APIErrorCode::InvalidResponse); 194 | } 195 | 196 | std::stringstream ss; 197 | ss << errorDescription << " (" << resultCode << ")"; 198 | 199 | throw LocalizedError((int)resultCode, ss.str()); 200 | } 201 | } 202 | catch (std::exception& exception) 203 | { 204 | plist_free(plist); 205 | throw; 206 | } 207 | } 208 | 209 | template 210 | T ProcessResponse(plist_t plist, std::function parseHandler, std::function(int64_t)> resultCodeHandler) 211 | { 212 | return this->ProcessAnyResponse(plist, "resultCode", { "userString", "resultString" }, parseHandler, resultCodeHandler); 213 | } 214 | 215 | template 216 | T ProcessTwoFactorResponse(plist_t plist, std::function parseHandler, std::function(int64_t)> resultCodeHandler) 217 | { 218 | return this->ProcessAnyResponse(plist, "ec", {"em"}, parseHandler, resultCodeHandler); 219 | } 220 | 221 | template 222 | T ProcessServicesResponse(web::json::value json, std::function parseHandler, std::function(int64_t)> resultCodeHandler) 223 | { 224 | try 225 | { 226 | auto value = parseHandler(json); 227 | return value; 228 | } 229 | catch (std::exception& exception) 230 | { 231 | int64_t resultCode = 0; 232 | 233 | if (json.has_field("resultCode")) 234 | { 235 | resultCode = json["resultCode"].as_integer(); 236 | } 237 | else if (json.has_field("errorCode")) 238 | { 239 | resultCode = json["errorCode"].as_integer(); 240 | } 241 | else 242 | { 243 | resultCode = -1; 244 | } 245 | 246 | auto error = resultCodeHandler(resultCode); 247 | if (error.has_value()) 248 | { 249 | throw error.value(); 250 | } 251 | 252 | std::string errorDescription; 253 | 254 | if (json.has_field("userString")) 255 | { 256 | errorDescription = (json["userString"].as_string()); 257 | } 258 | else if (json.has_field("resultString")) 259 | { 260 | errorDescription = (json["resultString"].as_string()); 261 | } 262 | else if (json.has_field("errorMessage")) 263 | { 264 | errorDescription = (json["errorMessage"].as_string()); 265 | } 266 | else if (json.has_field("errorId")) 267 | { 268 | errorDescription = (json["errorId"].as_string()); 269 | } 270 | else 271 | { 272 | errorDescription = "Unknown services response error."; 273 | } 274 | 275 | std::stringstream ss; 276 | ss << errorDescription << " (" << resultCode << ")"; 277 | //odslog(boost::stacktrace::stacktrace()); 278 | 279 | throw LocalizedError((int)resultCode, ss.str() + " [" + exception.what() + "]"); 280 | } 281 | } 282 | 283 | }; 284 | 285 | #pragma GCC visibility pop 286 | #endif 287 | -------------------------------------------------------------------------------- /AppleAPISession.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaMisty/AltSign-Linux/0daf1076fc29682884bbae793453856de454befe/AppleAPISession.cpp -------------------------------------------------------------------------------- /AppleAPISession.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaMisty/AltSign-Linux/0daf1076fc29682884bbae793453856de454befe/AppleAPISession.h -------------------------------------------------------------------------------- /Application.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Application.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "Application.hpp" 10 | 11 | #include "Error.hpp" 12 | #include "ldid/ldid.hpp" 13 | 14 | #include 15 | #include 16 | #include "altsign_common.h" 17 | 18 | extern std::vector readFile(const char* filename); 19 | 20 | namespace fs = std::filesystem; 21 | 22 | Application::Application() 23 | { 24 | } 25 | 26 | Application::~Application() 27 | { 28 | for (auto& pair : _entitlements) 29 | { 30 | plist_free(pair.second); 31 | } 32 | } 33 | 34 | Application::Application(const Application& app) 35 | { 36 | _name = app.name(); 37 | _bundleIdentifier = app.bundleIdentifier(); 38 | _version = app.version(); 39 | _path = app.path(); 40 | 41 | // Don't assign _entitlementsString or _entitlements, 42 | // since each copy will create its own entitlements lazily. 43 | // Otherwise there might be duplicate frees in deconstructor. 44 | } 45 | 46 | Application& Application::operator=(const Application& app) 47 | { 48 | if (this == &app) 49 | { 50 | return *this; 51 | } 52 | 53 | _name = app.name(); 54 | _bundleIdentifier = app.bundleIdentifier(); 55 | _version = app.version(); 56 | _path = app.path(); 57 | 58 | return *this; 59 | } 60 | 61 | Application::Application(std::string appBundlePath) 62 | { 63 | fs::path path(appBundlePath); 64 | path.append("Info.plist"); 65 | 66 | auto plistData = readFile(path.string().c_str()); 67 | 68 | plist_t plist = nullptr; 69 | plist_from_memory((const char *)plistData.data(), (int)plistData.size(), &plist); 70 | if (plist == nullptr) 71 | { 72 | throw SignError(SignErrorCode::InvalidApp); 73 | } 74 | 75 | auto nameNode = plist_dict_get_item(plist, "CFBundleName"); 76 | auto bundleIdentifierNode = plist_dict_get_item(plist, "CFBundleIdentifier"); 77 | auto versionNode = plist_dict_get_item(plist, "CFBundleShortVersionString"); 78 | 79 | if (nameNode == nullptr || bundleIdentifierNode == nullptr || versionNode == nullptr) 80 | { 81 | throw SignError(SignErrorCode::InvalidApp); 82 | } 83 | 84 | char *name = nullptr; 85 | plist_get_string_val(nameNode, &name); 86 | 87 | char *bundleIdentifier = nullptr; 88 | plist_get_string_val(bundleIdentifierNode, &bundleIdentifier); 89 | 90 | char *version = nullptr; 91 | plist_get_string_val(versionNode, &version); 92 | 93 | _name = name; 94 | _bundleIdentifier = bundleIdentifier; 95 | _version = version; 96 | _path = appBundlePath; 97 | } 98 | 99 | 100 | #pragma mark - Description - 101 | 102 | std::ostream& operator<<(std::ostream& os, const Application& app) 103 | { 104 | os << "Name: " << app.name() << " ID: " << app.bundleIdentifier(); 105 | return os; 106 | } 107 | 108 | #pragma mark - Getters - 109 | 110 | std::string Application::name() const 111 | { 112 | return _name; 113 | } 114 | 115 | std::string Application::bundleIdentifier() const 116 | { 117 | return _bundleIdentifier; 118 | } 119 | 120 | std::string Application::version() const 121 | { 122 | return _version; 123 | } 124 | 125 | std::string Application::path() const 126 | { 127 | return _path; 128 | } 129 | 130 | std::shared_ptr Application::provisioningProfile() 131 | { 132 | if (_provisioningProfile == NULL) 133 | { 134 | fs::path path(this->path()); 135 | path.append("embedded.mobileprovision"); 136 | 137 | _provisioningProfile = std::make_shared(path.string()); 138 | } 139 | 140 | return _provisioningProfile; 141 | } 142 | 143 | std::vector> Application::appExtensions() const 144 | { 145 | std::vector> appExtensions; 146 | 147 | fs::path plugInsPath(this->path()); 148 | plugInsPath.append("PlugIns"); 149 | 150 | if (!fs::exists(plugInsPath)) 151 | { 152 | return appExtensions; 153 | } 154 | 155 | for (auto& file : fs::directory_iterator(plugInsPath)) 156 | { 157 | if (file.path().extension() != ".appex") 158 | { 159 | continue; 160 | } 161 | 162 | auto appExtension = std::make_shared(file.path().string()); 163 | if (appExtension == nullptr) 164 | { 165 | continue; 166 | } 167 | 168 | appExtensions.push_back(appExtension); 169 | } 170 | 171 | return appExtensions; 172 | } 173 | 174 | std::string Application::entitlementsString() 175 | { 176 | if (_entitlementsString == "") 177 | { 178 | odslog("Querying entitlements for " << this->path() << " with ldid..."); 179 | _entitlementsString = ldid::Entitlements(this->path()); 180 | } 181 | 182 | return _entitlementsString; 183 | } 184 | 185 | std::map Application::entitlements() 186 | { 187 | if (_entitlements.size() == 0) 188 | { 189 | auto rawEntitlements = this->entitlementsString(); 190 | 191 | plist_t plist = nullptr; 192 | plist_from_memory((const char*)rawEntitlements.data(), (int)rawEntitlements.size(), &plist); 193 | 194 | if (plist != nullptr) 195 | { 196 | std::map entitlements; 197 | char* key = NULL; 198 | plist_t node = NULL; 199 | 200 | plist_dict_iter it = NULL; 201 | plist_dict_new_iter(plist, &it); 202 | plist_dict_next_item(plist, it, &key, &node); 203 | 204 | while (node != nullptr) 205 | { 206 | entitlements[key] = plist_copy(node); 207 | 208 | node = NULL; 209 | free(key); 210 | key = NULL; 211 | plist_dict_next_item(plist, it, &key, &node); 212 | } 213 | 214 | free(it); 215 | plist_free(plist); 216 | 217 | _entitlements = entitlements; 218 | } 219 | else 220 | { 221 | odslog("Error parsing entitlements:\n" << rawEntitlements); 222 | } 223 | } 224 | 225 | return _entitlements; 226 | } 227 | 228 | bool Application::isAltStoreApp() const 229 | { 230 | auto isAltStoreApp = this->bundleIdentifier().find("com.rileytestut.AltStore") != std::string::npos; 231 | return isAltStoreApp; 232 | } -------------------------------------------------------------------------------- /Application.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Application.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Application_hpp 10 | #define Application_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include "ProvisioningProfile.hpp" 23 | 24 | class Application 25 | { 26 | public: 27 | Application(); 28 | ~Application(); 29 | 30 | Application(std::string appBundlePath) /* throws */; 31 | 32 | Application(const Application& app); 33 | Application& operator=(const Application& app); 34 | 35 | std::string name() const; 36 | std::string bundleIdentifier() const; 37 | std::string version() const; 38 | std::string path() const; 39 | 40 | std::shared_ptr provisioningProfile(); 41 | std::vector> appExtensions() const; 42 | 43 | std::map entitlements(); 44 | 45 | bool isAltStoreApp() const; 46 | 47 | friend std::ostream& operator<<(std::ostream& os, const Application& app); 48 | 49 | private: 50 | std::string _name; 51 | std::string _bundleIdentifier; 52 | std::string _version; 53 | std::string _path; 54 | 55 | std::shared_ptr _provisioningProfile; 56 | 57 | std::string _entitlementsString; 58 | std::map _entitlements; 59 | 60 | std::string entitlementsString(); 61 | }; 62 | 63 | #pragma GCC visibility pop 64 | 65 | #endif /* Application_hpp */ 66 | -------------------------------------------------------------------------------- /Archiver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Archiver.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Archiver.hpp" 14 | #include "Error.hpp" 15 | 16 | extern "C" { 17 | #include "zip.h" 18 | #include "unzip.h" 19 | } 20 | 21 | #ifdef _WIN32 22 | #include 23 | #define access _access_s 24 | #else 25 | #include 26 | #include 27 | #include 28 | #endif 29 | 30 | const int ALTReadBufferSize = 8192; 31 | const int ALTMaxFilenameLength = 512; 32 | 33 | #include 34 | #include "altsign_common.h" 35 | 36 | 37 | #ifdef _WIN32 38 | char ALTDirectoryDeliminator = '\\'; 39 | #else 40 | char ALTDirectoryDeliminator = '/'; 41 | #endif 42 | 43 | #define READ_BUFFER_SIZE 8192 44 | #define MAX_FILENAME 512 45 | 46 | namespace fs = std::filesystem; 47 | 48 | static bool endsWith(const std::string& str, const std::string& suffix) 49 | { 50 | return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix); 51 | } 52 | 53 | static bool startsWith(const std::string& str, const std::string& prefix) 54 | { 55 | return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix); 56 | } 57 | 58 | extern std::string replace_all( 59 | const std::string& str, // where to work 60 | const std::string& find, // substitute 'find' 61 | const std::string& replace // by 'replace' 62 | ); 63 | 64 | std::string UnzipAppBundle(std::string filepath, std::string outputDirectory) 65 | { 66 | if (outputDirectory[outputDirectory.size() - 1] != ALTDirectoryDeliminator) 67 | { 68 | outputDirectory += ALTDirectoryDeliminator; 69 | } 70 | 71 | unzFile zipFile = unzOpen(filepath.c_str()); 72 | if (zipFile == NULL) 73 | { 74 | throw ArchiveError(ArchiveErrorCode::NoSuchFile); 75 | } 76 | 77 | FILE *outputFile = nullptr; 78 | 79 | auto finish = [&outputFile, &zipFile](void) 80 | { 81 | if (outputFile != nullptr) 82 | { 83 | fclose(outputFile); 84 | } 85 | 86 | unzCloseCurrentFile(zipFile); 87 | unzClose(zipFile); 88 | }; 89 | 90 | unz_global_info zipInfo; 91 | if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK) 92 | { 93 | finish(); 94 | throw ArchiveError(ArchiveErrorCode::CorruptFile); 95 | } 96 | 97 | fs::path payloadDirectoryPath = fs::path(outputDirectory).append("Payload"); 98 | if (!fs::exists(payloadDirectoryPath)) 99 | { 100 | fs::create_directory(payloadDirectoryPath); 101 | } 102 | 103 | char buffer[ALTReadBufferSize]; 104 | 105 | for (int i = 0; i < zipInfo.number_entry; i++) 106 | { 107 | unz_file_info info; 108 | char cFilename[ALTMaxFilenameLength]; 109 | 110 | if (unzGetCurrentFileInfo(zipFile, &info, cFilename, ALTMaxFilenameLength, NULL, 0, NULL, 0) != UNZ_OK) 111 | { 112 | finish(); 113 | throw ArchiveError(ArchiveErrorCode::Unknown); 114 | } 115 | 116 | std::string filename(cFilename); 117 | if (startsWith(filename, "__MACOSX")) 118 | { 119 | if (i + 1 < zipInfo.number_entry) 120 | { 121 | if (unzGoToNextFile(zipFile) != UNZ_OK) 122 | { 123 | finish(); 124 | throw ArchiveError(ArchiveErrorCode::Unknown); 125 | } 126 | } 127 | 128 | continue; 129 | } 130 | 131 | std::replace(filename.begin(), filename.end(), '/', ALTDirectoryDeliminator); 132 | filename = replace_all(filename, ":", "__colon__"); 133 | 134 | fs::path filepath = fs::path(outputDirectory).append(filename); 135 | fs::path parentDirectory = (filename[filename.size() - 1] == ALTDirectoryDeliminator) ? filepath.parent_path().parent_path() : filepath.parent_path(); 136 | 137 | if (!fs::exists(parentDirectory)) 138 | { 139 | fs::create_directory(parentDirectory); 140 | } 141 | 142 | if (filename[filename.size() - 1] == ALTDirectoryDeliminator) 143 | { 144 | // Directory 145 | fs::create_directory(filepath); 146 | } 147 | else 148 | { 149 | // File 150 | if (unzOpenCurrentFile(zipFile) != UNZ_OK) 151 | { 152 | finish(); 153 | throw ArchiveError(ArchiveErrorCode::Unknown); 154 | } 155 | 156 | std::string narrowFilepath = filepath.string(); 157 | 158 | outputFile = fopen(narrowFilepath.c_str(), "wb"); 159 | if (outputFile == NULL) 160 | { 161 | finish(); 162 | throw ArchiveError(ArchiveErrorCode::UnknownWrite); 163 | } 164 | 165 | int result = UNZ_OK; 166 | 167 | do 168 | { 169 | result = unzReadCurrentFile(zipFile, buffer, ALTReadBufferSize); 170 | 171 | if (result < 0) 172 | { 173 | finish(); 174 | throw ArchiveError(ArchiveErrorCode::Unknown); 175 | } 176 | 177 | size_t count = fwrite(buffer, result, 1, outputFile); 178 | if (result > 0 && count != 1) 179 | { 180 | finish(); 181 | throw ArchiveError(ArchiveErrorCode::UnknownWrite); 182 | } 183 | 184 | } while (result > 0); 185 | 186 | odslog("Extracted file:" << filepath); 187 | 188 | short permissions = (info.external_fa >> 16) & 0x01FF; 189 | chmod(narrowFilepath.c_str(), permissions); 190 | 191 | fclose(outputFile); 192 | outputFile = NULL; 193 | } 194 | 195 | unzCloseCurrentFile(zipFile); 196 | 197 | if (i + 1 < zipInfo.number_entry) 198 | { 199 | if (unzGoToNextFile(zipFile) != UNZ_OK) 200 | { 201 | finish(); 202 | throw ArchiveError(ArchiveErrorCode::Unknown); 203 | } 204 | } 205 | } 206 | 207 | for (auto & p : fs::directory_iterator(payloadDirectoryPath)) 208 | { 209 | auto filename = p.path().filename().string(); 210 | 211 | auto lowercaseFilename = filename; 212 | std::transform(lowercaseFilename.begin(), lowercaseFilename.end(), lowercaseFilename.begin(), [](unsigned char c) { 213 | return std::tolower(c); 214 | }); 215 | 216 | if (!endsWith(lowercaseFilename, ".app")) 217 | { 218 | continue; 219 | } 220 | 221 | auto appBundlePath = payloadDirectoryPath; 222 | appBundlePath.append(filename); 223 | 224 | auto outputPath = outputDirectory; 225 | outputPath.append(filename); 226 | 227 | if (fs::exists(outputPath)) 228 | { 229 | fs::remove(outputPath); 230 | } 231 | 232 | fs::rename(appBundlePath, outputPath); 233 | 234 | finish(); 235 | 236 | // Operation not permitted on iSH 237 | //fs::remove(payloadDirectoryPath); 238 | 239 | return outputPath; 240 | } 241 | 242 | throw SignError(SignError(SignErrorCode::MissingAppBundle)); 243 | } 244 | 245 | 246 | void WriteFileToZipFile(zipFile *zipFile, fs::path filepath, fs::path relativePath) 247 | { 248 | bool isDirectory = fs::is_directory(filepath); 249 | 250 | std::string filename = relativePath.string(); 251 | 252 | zip_fileinfo fileInfo = {}; 253 | 254 | char *bytes = nullptr; 255 | unsigned int fileSize = 0; 256 | 257 | if (isDirectory) 258 | { 259 | // Remove leading directory slash. 260 | if (filename[0] == ALTDirectoryDeliminator) 261 | { 262 | filename = std::string(filename.begin() + 1, filename.end()); 263 | } 264 | 265 | // Add trailing directory slash. 266 | if (filename[filename.size() - 1] != ALTDirectoryDeliminator) 267 | { 268 | filename = filename + ALTDirectoryDeliminator; 269 | } 270 | } 271 | else 272 | { 273 | fs::file_status status = fs::status(filepath); 274 | 275 | short permissions = (short)status.permissions(); 276 | long shiftedPermissions = 0100000 + permissions; 277 | 278 | uLong permissionsLong = (uLong)shiftedPermissions; 279 | 280 | fileInfo.external_fa = (unsigned int)(permissionsLong << 16L); 281 | 282 | std::ifstream ifs(filepath.string()); 283 | std::vector data((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); 284 | 285 | bytes = data.data(); 286 | fileSize = (unsigned int)data.size(); 287 | } 288 | 289 | std::replace(filename.begin(), filename.end(), ALTDirectoryDeliminator, '/'); 290 | 291 | if (zipOpenNewFileInZip(*zipFile, (const char *)filename.c_str(), &fileInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) 292 | { 293 | throw ArchiveError(ArchiveErrorCode::UnknownWrite); 294 | } 295 | 296 | if (zipWriteInFileInZip(*zipFile, bytes, fileSize) != ZIP_OK) 297 | { 298 | zipCloseFileInZip(*zipFile); 299 | throw ArchiveError(ArchiveErrorCode::UnknownWrite); 300 | } 301 | } 302 | 303 | std::string ZipAppBundle(std::string filepath) 304 | { 305 | fs::path appBundlePath = filepath; 306 | 307 | auto appBundleFilename = appBundlePath.filename(); 308 | auto appName = appBundlePath.filename().stem().string(); 309 | 310 | auto ipaName = appName + ".ipa"; 311 | auto ipaPath = appBundlePath.remove_filename().append(ipaName); 312 | 313 | if (fs::exists(ipaPath)) 314 | { 315 | fs::remove(ipaPath); 316 | } 317 | 318 | zipFile zipFile = zipOpen((const char *)ipaPath.string().c_str(), APPEND_STATUS_CREATE); 319 | if (zipFile == nullptr) 320 | { 321 | throw ArchiveError(ArchiveErrorCode::UnknownWrite); 322 | } 323 | 324 | fs::path payloadDirectory = "Payload"; 325 | fs::path appBundleDirectory = payloadDirectory.append(appBundleFilename.string()); 326 | 327 | fs::path rootPath = fs::relative("", appBundleDirectory); 328 | 329 | for (auto& entry: fs::recursive_directory_iterator(rootPath)) 330 | { 331 | auto filepath = entry.path(); 332 | auto relativePath = entry.path().relative_path(); 333 | 334 | WriteFileToZipFile(&zipFile, filepath, relativePath); 335 | } 336 | 337 | WriteFileToZipFile(&zipFile, payloadDirectory, payloadDirectory); 338 | WriteFileToZipFile(&zipFile, appBundleDirectory, appBundleDirectory); 339 | 340 | zipClose(zipFile, NULL); 341 | 342 | return ipaPath.string(); 343 | } 344 | -------------------------------------------------------------------------------- /Archiver.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Archiver.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Archiver_hpp 10 | #define Archiver_hpp 11 | 12 | #include 13 | 14 | std::string UnzipAppBundle(std::string filepath, std::string outputDirectory); 15 | std::string ZipAppBundle(std::string filepath); 16 | 17 | #endif /* Archiver_hpp */ 18 | -------------------------------------------------------------------------------- /Certificate.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Certificate.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "Certificate.hpp" 10 | #include "Error.hpp" 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | std::string kCertificatePEMPrefix = "-----BEGIN CERTIFICATE-----"; 18 | std::string kCertificatePEMSuffix = "-----END CERTIFICATE-----"; 19 | 20 | static const std::string base64_chars = 21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 22 | "abcdefghijklmnopqrstuvwxyz" 23 | "0123456789+/"; 24 | 25 | static inline bool is_base64(unsigned char c) { 26 | return (isalnum(c) || (c == '+') || (c == '/')); 27 | } 28 | 29 | std::vector base64_decode(std::string const& encoded_string) { 30 | int in_len = encoded_string.size(); 31 | int i = 0; 32 | int j = 0; 33 | int in_ = 0; 34 | unsigned char char_array_4[4], char_array_3[3]; 35 | std::vector ret; 36 | 37 | while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { 38 | char_array_4[i++] = encoded_string[in_]; in_++; 39 | if (i == 4) { 40 | for (i = 0; i < 4; i++) 41 | char_array_4[i] = base64_chars.find(char_array_4[i]); 42 | 43 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 44 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 45 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 46 | 47 | for (i = 0; (i < 3); i++) 48 | { 49 | ret.push_back(char_array_3[i]); 50 | } 51 | 52 | i = 0; 53 | } 54 | } 55 | 56 | if (i) { 57 | for (j = i; j < 4; j++) 58 | char_array_4[j] = 0; 59 | 60 | for (j = 0; j < 4; j++) 61 | char_array_4[j] = base64_chars.find(char_array_4[j]); 62 | 63 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 64 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 65 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 66 | 67 | for (j = 0; (j < i - 1); j++) 68 | { 69 | ret.push_back(char_array_3[j]); 70 | } 71 | } 72 | 73 | return ret; 74 | } 75 | 76 | Certificate::Certificate() 77 | { 78 | } 79 | 80 | Certificate::~Certificate() 81 | { 82 | } 83 | 84 | Certificate::Certificate(plist_t plist) 85 | { 86 | auto dataNode = plist_dict_get_item(plist, "certContent"); 87 | 88 | if (dataNode != nullptr) 89 | { 90 | char *bytes = nullptr; 91 | uint64_t size = 0; 92 | plist_get_data_val(dataNode, &bytes, &size); 93 | 94 | std::vector data; 95 | data.reserve(size); 96 | 97 | for (int i = 0; i < size; i++) 98 | { 99 | data.push_back(bytes[i]); 100 | } 101 | 102 | this->ParseData(data); 103 | } 104 | else 105 | { 106 | auto nameNode = plist_dict_get_item(plist, "name"); 107 | auto serialNumberNode = plist_dict_get_item(plist, "serialNumber"); 108 | if (serialNumberNode == nullptr) 109 | { 110 | serialNumberNode = plist_dict_get_item(plist, "serialNum"); 111 | } 112 | 113 | if (nameNode == nullptr || serialNumberNode == nullptr) 114 | { 115 | throw APIError(APIErrorCode::InvalidResponse); 116 | } 117 | 118 | char* name = nullptr; 119 | plist_get_string_val(nameNode, &name); 120 | 121 | char* serialNumber = nullptr; 122 | plist_get_string_val(serialNumberNode, &serialNumber); 123 | 124 | _name = name; 125 | _serialNumber = serialNumber; 126 | } 127 | 128 | auto machineNameNode = plist_dict_get_item(plist, "machineName"); 129 | auto machineIdentifierNode = plist_dict_get_item(plist, "machineId"); 130 | 131 | if (machineNameNode != nullptr) 132 | { 133 | char* machineName = nullptr; 134 | plist_get_string_val(machineNameNode, &machineName); 135 | 136 | _machineName = machineName; 137 | } 138 | 139 | if (machineIdentifierNode != nullptr) 140 | { 141 | char* machineIdentifier = nullptr; 142 | plist_get_string_val(machineIdentifierNode, &machineIdentifier); 143 | 144 | _machineIdentifier = machineIdentifier; 145 | } 146 | } 147 | 148 | Certificate::Certificate(web::json::value json) 149 | { 150 | auto identifier = json[U("id")].as_string(); 151 | auto attributes = json[U("attributes")]; 152 | 153 | std::vector data; 154 | if (attributes.has_field(U("certificateContent"))) 155 | { 156 | auto encodedData = attributes[U("certificateContent")].as_string(); 157 | data = base64_decode(encodedData); 158 | } 159 | 160 | auto machineName = attributes[U("machineName")].as_string(); 161 | auto machineIdentifier = attributes[U("machineId")].as_string(); 162 | 163 | if (data.size() != 0) 164 | { 165 | this->ParseData(data); 166 | } 167 | else 168 | { 169 | auto name = attributes[U("name")].as_string(); 170 | auto serialNumber = attributes[U("serialNumber")].as_string(); 171 | 172 | _name = name.c_str(); 173 | _serialNumber = serialNumber.c_str(); 174 | } 175 | 176 | _identifier = std::make_optional(identifier.c_str()); 177 | _machineName = std::make_optional(machineName.c_str()); 178 | _machineIdentifier = std::make_optional(machineIdentifier.c_str()); 179 | } 180 | 181 | Certificate::Certificate(std::vector& p12Data, std::string password) 182 | { 183 | BIO* inputP12Buffer = BIO_new(BIO_s_mem()); 184 | BIO_write(inputP12Buffer, p12Data.data(), (int)p12Data.size()); 185 | 186 | PKCS12* inputP12 = d2i_PKCS12_bio(inputP12Buffer, NULL); 187 | 188 | // Extract key + certificate from .p12. 189 | EVP_PKEY* key; 190 | X509* certificate; 191 | PKCS12_parse(inputP12, password.c_str(), &key, &certificate, NULL); 192 | 193 | if (key == nullptr || certificate == nullptr) 194 | { 195 | throw APIError(APIErrorCode::InvalidResponse); 196 | } 197 | 198 | BIO* pemBuffer = BIO_new(BIO_s_mem()); 199 | PEM_write_bio_X509(pemBuffer, certificate); 200 | 201 | BIO* privateKeyBuffer = BIO_new(BIO_s_mem()); 202 | PEM_write_bio_PrivateKey(privateKeyBuffer, key, NULL, NULL, 0, NULL, NULL); 203 | 204 | char* pemBytes = NULL; 205 | int pemSize = BIO_get_mem_data(pemBuffer, &pemBytes); 206 | 207 | char* privateKeyBytes = NULL; 208 | int privateKeySize = BIO_get_mem_data(privateKeyBuffer, &privateKeyBytes); 209 | 210 | std::vector pemData; 211 | pemData.reserve(pemSize); 212 | for (int i = 0; i < pemSize; i++) 213 | { 214 | pemData.push_back(pemBytes[i]); 215 | } 216 | 217 | std::vector privateKey; 218 | privateKey.reserve(privateKeySize); 219 | for (int i = 0; i < privateKeySize; i++) 220 | { 221 | privateKey.push_back(privateKeyBytes[i]); 222 | } 223 | 224 | this->ParseData(pemData); 225 | 226 | _privateKey = privateKey; 227 | 228 | BIO_free(privateKeyBuffer); 229 | BIO_free(pemBuffer); 230 | } 231 | 232 | Certificate::Certificate(std::vector& data) 233 | { 234 | this->ParseData(data); 235 | } 236 | 237 | void Certificate::ParseData(std::vector& data) 238 | { 239 | std::vector pemData; 240 | 241 | std::string prefix(data.begin(), data.begin() + std::min(data.size(), kCertificatePEMPrefix.size())); 242 | if (prefix != kCertificatePEMPrefix) 243 | { 244 | // Convert to proper PEM format before storing. 245 | utility::string_t base64Data = utility::conversions::to_base64(data); 246 | 247 | std::stringstream ss; 248 | ss << kCertificatePEMPrefix << std::endl << (base64Data) << std::endl << kCertificatePEMSuffix; 249 | 250 | auto content = ss.str(); 251 | pemData = std::vector(content.begin(), content.end()); 252 | } 253 | else 254 | { 255 | pemData = data; 256 | } 257 | 258 | BIO *certificateBuffer = BIO_new(BIO_s_mem()); 259 | BIO_write(certificateBuffer, pemData.data(), (int)pemData.size()); 260 | 261 | X509 *certificate = nullptr; 262 | PEM_read_bio_X509(certificateBuffer, &certificate, 0, 0); 263 | if (certificate == nullptr) 264 | { 265 | throw APIError(APIErrorCode::InvalidResponse); 266 | } 267 | 268 | /* Certificate Common Name */ 269 | X509_NAME *subject = X509_get_subject_name(certificate); 270 | int index = X509_NAME_get_index_by_NID(subject, NID_commonName, -1); 271 | if (index == -1) 272 | { 273 | throw APIError(APIErrorCode::InvalidResponse); 274 | } 275 | 276 | X509_NAME_ENTRY *nameEntry = X509_NAME_get_entry(subject, index); 277 | ASN1_STRING *nameData = X509_NAME_ENTRY_get_data(nameEntry); 278 | char *cName = (char *)ASN1_STRING_data(nameData); 279 | 280 | 281 | /* Serial Number */ 282 | ASN1_INTEGER *serialNumberData = X509_get_serialNumber(certificate); 283 | BIGNUM *number = ASN1_INTEGER_to_BN(serialNumberData, NULL); 284 | if (number == nullptr) 285 | { 286 | throw APIError(APIErrorCode::InvalidResponse); 287 | } 288 | 289 | char *cSerialNumber = BN_bn2hex(number); 290 | 291 | if (cName == nullptr || cSerialNumber == nullptr) 292 | { 293 | throw APIError(APIErrorCode::InvalidResponse); 294 | } 295 | 296 | std::string serialNumber(cSerialNumber); 297 | serialNumber.erase(0, std::min(serialNumber.find_first_not_of('0'), serialNumber.size() - 1)); // Remove leading zeroes. 298 | 299 | _name = cName; 300 | _serialNumber = serialNumber; 301 | _data = pemData; 302 | } 303 | 304 | #pragma mark - Description - 305 | 306 | std::ostream& operator<<(std::ostream& os, const Certificate& certificate) 307 | { 308 | os << "Name: " << certificate.name() << " SN: " << certificate.serialNumber(); 309 | return os; 310 | } 311 | 312 | #pragma mark - Getters - 313 | 314 | std::string Certificate::name() const 315 | { 316 | return _name; 317 | } 318 | 319 | std::string Certificate::serialNumber() const 320 | { 321 | return _serialNumber; 322 | } 323 | 324 | std::optional Certificate::identifier() const 325 | { 326 | return _identifier; 327 | } 328 | 329 | std::optional Certificate::machineName() const 330 | { 331 | return _machineName; 332 | } 333 | 334 | std::optional Certificate::machineIdentifier() const 335 | { 336 | return _machineIdentifier; 337 | } 338 | 339 | void Certificate::setMachineIdentifier(std::optional machineIdentifier) 340 | { 341 | _machineIdentifier = machineIdentifier; 342 | } 343 | 344 | std::optional> Certificate::data() const 345 | { 346 | return _data; 347 | } 348 | 349 | std::optional> Certificate::privateKey() const 350 | { 351 | return _privateKey; 352 | } 353 | 354 | void Certificate::setPrivateKey(std::optional> privateKey) 355 | { 356 | _privateKey = privateKey; 357 | } 358 | 359 | std::optional> Certificate::p12Data() const 360 | { 361 | return this->encryptedP12Data(""); 362 | } 363 | 364 | std::optional> Certificate::encryptedP12Data(std::string password) const 365 | { 366 | if (!this->data().has_value()) 367 | { 368 | return std::nullopt; 369 | } 370 | 371 | BIO* certificateBuffer = BIO_new(BIO_s_mem()); 372 | BIO* privateKeyBuffer = BIO_new(BIO_s_mem()); 373 | 374 | BIO_write(certificateBuffer, this->data()->data(), (int)this->data()->size()); 375 | 376 | if (this->privateKey().has_value()) 377 | { 378 | BIO_write(privateKeyBuffer, this->privateKey()->data(), (int)this->privateKey()->size()); 379 | } 380 | 381 | X509* certificate = nullptr; 382 | PEM_read_bio_X509(certificateBuffer, &certificate, 0, 0); 383 | 384 | EVP_PKEY* privateKey = nullptr; 385 | PEM_read_bio_PrivateKey(privateKeyBuffer, &privateKey, 0, 0); 386 | 387 | char emptyString[] = ""; 388 | PKCS12* outputP12 = PKCS12_create((char *)password.c_str(), emptyString, privateKey, certificate, NULL, 0, 0, 0, 0, 0); 389 | 390 | BIO* p12Buffer = BIO_new(BIO_s_mem()); 391 | i2d_PKCS12_bio(p12Buffer, outputP12); 392 | 393 | char* buffer = NULL; 394 | int size = (int)BIO_get_mem_data(p12Buffer, &buffer); 395 | 396 | std::vector p12Data; 397 | p12Data.reserve(size); 398 | for (int i = 0; i < size; i++) 399 | { 400 | p12Data.push_back(buffer[i]); 401 | } 402 | 403 | BIO_free(p12Buffer); 404 | PKCS12_free(outputP12); 405 | 406 | EVP_PKEY_free(privateKey); 407 | X509_free(certificate); 408 | 409 | BIO_free(privateKeyBuffer); 410 | BIO_free(certificateBuffer); 411 | 412 | return p12Data; 413 | } 414 | -------------------------------------------------------------------------------- /Certificate.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Certificate.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Certificate_hpp 10 | #define Certificate_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | class Certificate 23 | { 24 | public: 25 | Certificate(); 26 | ~Certificate(); 27 | 28 | Certificate(plist_t plist) /* throws */; 29 | Certificate(web::json::value plist) /* throws */; 30 | Certificate(std::vector& data); 31 | Certificate(std::vector& p12Data, std::string password); 32 | 33 | std::string name() const; 34 | std::string serialNumber() const; 35 | std::optional identifier() const; 36 | std::optional machineName() const; 37 | 38 | std::optional machineIdentifier() const; 39 | void setMachineIdentifier(std::optional machineIdentifier); 40 | 41 | std::optional> data() const; 42 | std::optional> encryptedP12Data(std::string password) const; 43 | 44 | std::optional> privateKey() const; 45 | void setPrivateKey(std::optional> privateKey); 46 | 47 | std::optional> p12Data() const; 48 | 49 | friend std::ostream& operator<<(std::ostream& os, const Certificate& certificate); 50 | 51 | private: 52 | std::string _name; 53 | std::string _serialNumber; 54 | std::optional _identifier; 55 | std::optional _machineName; 56 | std::optional _machineIdentifier; 57 | 58 | std::optional> _data; 59 | std::optional> _privateKey; 60 | 61 | void ParseData(std::vector& data); 62 | }; 63 | 64 | #pragma GCC visibility pop 65 | 66 | #endif /* Certificate_hpp */ 67 | -------------------------------------------------------------------------------- /CertificateRequest.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // CertificateRequest.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "CertificateRequest.hpp" 10 | #include "Error.hpp" 11 | 12 | #include 13 | 14 | #include 15 | 16 | // Based on https://www.codepool.biz/how-to-use-openssl-to-generate-x-509-certificate-request.html 17 | CertificateRequest::CertificateRequest() 18 | { 19 | std::optional> outputData = std::nullopt; 20 | std::optional> outputPrivateKey = std::nullopt; 21 | 22 | BIGNUM *bignum = NULL; 23 | RSA *rsa = NULL; 24 | 25 | X509_REQ *request = NULL; 26 | EVP_PKEY *publicKey = NULL; 27 | 28 | BIO *csr = NULL; 29 | BIO *privateKey = NULL; 30 | 31 | auto finish = [this, &bignum, &rsa, &request, &publicKey, &csr, &privateKey, &outputData, &outputPrivateKey](void) { 32 | if (publicKey != NULL) 33 | { 34 | // Also frees rsa, so we check if non-nil to prevent double free. 35 | EVP_PKEY_free(publicKey); 36 | } 37 | else 38 | { 39 | RSA_free(rsa); 40 | } 41 | 42 | BN_free(bignum); 43 | X509_REQ_free(request); 44 | 45 | BIO_free_all(csr); 46 | BIO_free_all(privateKey); 47 | 48 | if (!outputData.has_value() || !outputPrivateKey.has_value()) 49 | { 50 | throw APIError(APIErrorCode::InvalidCertificateRequest); 51 | } 52 | else 53 | { 54 | this->_data = *outputData; 55 | this->_privateKey = *outputPrivateKey; 56 | } 57 | }; 58 | 59 | /* Generate RSA Key */ 60 | 61 | bignum = BN_new(); 62 | if (BN_set_word(bignum, RSA_F4) != 1) 63 | { 64 | finish(); 65 | return; 66 | } 67 | 68 | rsa = RSA_new(); 69 | if (RSA_generate_key_ex(rsa, 2048, bignum, NULL) != 1) 70 | { 71 | finish(); 72 | return; 73 | } 74 | 75 | /* Generate request */ 76 | 77 | const char *country = "US"; 78 | const char *state = "CA"; 79 | const char *city = "Los Angeles"; 80 | const char *organization = "AltSign"; 81 | const char *commonName = "AltSign"; 82 | 83 | request = X509_REQ_new(); 84 | if (X509_REQ_set_version(request, 1) != 1) 85 | { 86 | finish(); 87 | return; 88 | } 89 | 90 | // Subject 91 | X509_NAME *subject = X509_REQ_get_subject_name(request); 92 | X509_NAME_add_entry_by_txt(subject, "C", MBSTRING_ASC, (const unsigned char *)country, -1, -1, 0); 93 | X509_NAME_add_entry_by_txt(subject, "ST", MBSTRING_ASC, (const unsigned char*)state, -1, -1, 0); 94 | X509_NAME_add_entry_by_txt(subject, "", MBSTRING_ASC, (const unsigned char*)city, -1, -1, 0); 95 | X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC, (const unsigned char*)organization, -1, -1, 0); 96 | X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (const unsigned char*)commonName, -1, -1, 0); 97 | 98 | // Public Key 99 | publicKey = EVP_PKEY_new(); 100 | EVP_PKEY_assign_RSA(publicKey, rsa); 101 | 102 | if (X509_REQ_set_pubkey(request, publicKey) != 1) 103 | { 104 | finish(); 105 | return; 106 | } 107 | 108 | // Sign request 109 | if (X509_REQ_sign(request, publicKey, EVP_sha1()) <= 0) 110 | { 111 | finish(); 112 | return; 113 | } 114 | 115 | // Output 116 | csr = BIO_new(BIO_s_mem()); 117 | if (PEM_write_bio_X509_REQ(csr, request) != 1) 118 | { 119 | finish(); 120 | return; 121 | } 122 | 123 | privateKey = BIO_new(BIO_s_mem()); 124 | if (PEM_write_bio_RSAPrivateKey(privateKey, rsa, NULL, NULL, 0, NULL, NULL) != 1) 125 | { 126 | finish(); 127 | return; 128 | } 129 | 130 | /* Return values */ 131 | 132 | char *csrData = NULL; 133 | long csrLength = BIO_get_mem_data(csr, &csrData); 134 | 135 | char *privateKeyBuffer = NULL; 136 | long privateKeyLength = BIO_get_mem_data(privateKey, &privateKeyBuffer); 137 | 138 | std::vector requestData; 139 | requestData.reserve(csrLength); 140 | for (int i = 0; i < csrLength; i++) 141 | { 142 | requestData.push_back(csrData[i]); 143 | } 144 | outputData = requestData; 145 | 146 | std::vector privateKeyData; 147 | privateKeyData.reserve(privateKeyLength); 148 | for (int i = 0; i < privateKeyLength; i++) 149 | { 150 | privateKeyData.push_back(privateKeyBuffer[i]); 151 | } 152 | outputPrivateKey = privateKeyData; 153 | 154 | finish(); 155 | } 156 | 157 | CertificateRequest::~CertificateRequest() 158 | { 159 | } 160 | 161 | #pragma mark - Getters - 162 | 163 | std::vector CertificateRequest::data() const 164 | { 165 | return _data; 166 | } 167 | 168 | std::vector CertificateRequest::privateKey() const 169 | { 170 | return _privateKey; 171 | } 172 | -------------------------------------------------------------------------------- /CertificateRequest.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // CertificateRequest.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef CertificateRequest_hpp 10 | #define CertificateRequest_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | 18 | class CertificateRequest 19 | { 20 | public: 21 | CertificateRequest(); 22 | ~CertificateRequest(); 23 | 24 | std::vector data() const; 25 | std::vector privateKey() const; 26 | 27 | private: 28 | std::vector _data; 29 | std::vector _privateKey; 30 | }; 31 | 32 | #pragma GCC visibility pop 33 | 34 | #endif /* CertificateRequest_hpp */ 35 | -------------------------------------------------------------------------------- /Device.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Device.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/10/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "Device.hpp" 10 | 11 | #include "Error.hpp" 12 | 13 | #include 14 | 15 | Device::Device() 16 | { 17 | } 18 | 19 | Device::~Device() 20 | { 21 | } 22 | 23 | Device::Device(std::string name, std::string identifier, Device::Type type) : _name(name), _identifier(identifier), _type(type) 24 | { 25 | } 26 | 27 | Device::Device(plist_t plist) 28 | { 29 | auto nameNode = plist_dict_get_item(plist, "name"); 30 | auto identifierNode = plist_dict_get_item(plist, "deviceNumber"); 31 | auto deviceTypeNode = plist_dict_get_item(plist, "deviceClass"); 32 | 33 | if (nameNode == nullptr || identifierNode == nullptr) 34 | { 35 | throw APIError(APIErrorCode::InvalidResponse); 36 | } 37 | 38 | char *name = nullptr; 39 | plist_get_string_val(nameNode, &name); 40 | 41 | char *identifier = nullptr; 42 | plist_get_string_val(identifierNode, &identifier); 43 | 44 | Device::Type deviceType = Device::Type::None; 45 | if (deviceTypeNode != nullptr) 46 | { 47 | char* rawDeviceClass = nullptr; 48 | plist_get_string_val(deviceTypeNode, &rawDeviceClass); 49 | 50 | std::string deviceClass = rawDeviceClass; 51 | std::transform(deviceClass.begin(), deviceClass.end(), deviceClass.begin(), ::tolower); 52 | 53 | if (deviceClass == "iphone" || deviceClass == "ipod") 54 | { 55 | deviceType = Device::Type::iPhone; 56 | } 57 | else if (deviceClass == "ipad") 58 | { 59 | deviceType = Device::Type::iPad; 60 | } 61 | else if (deviceClass == "tvos") 62 | { 63 | deviceType = Device::Type::AppleTV; 64 | } 65 | } 66 | 67 | _name = name; 68 | _identifier = identifier; 69 | _type = deviceType; 70 | } 71 | 72 | #pragma mark - Description - 73 | 74 | std::ostream& operator<<(std::ostream& os, const Device& device) 75 | { 76 | os << "Name: " << device.name() << " UDID: " << device.identifier(); 77 | return os; 78 | } 79 | 80 | #pragma mark - Getters - 81 | 82 | std::string Device::name() const 83 | { 84 | return _name; 85 | } 86 | 87 | std::string Device::identifier() const 88 | { 89 | return _identifier; 90 | } 91 | 92 | Device::Type Device::type() const 93 | { 94 | return _type; 95 | } 96 | -------------------------------------------------------------------------------- /Device.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Device.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/10/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Device_hpp 10 | #define Device_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | class Device 21 | { 22 | public: 23 | enum Type 24 | { 25 | iPhone = 1 << 1, 26 | iPad = 1 << 2, 27 | AppleTV = 1 << 3, 28 | 29 | None = 0, 30 | All = (iPhone | iPad | AppleTV) 31 | }; 32 | 33 | Device(); 34 | ~Device(); 35 | 36 | Device(std::string name, std::string identifier, Device::Type type); 37 | Device(plist_t plist) /* throws */; 38 | 39 | std::string name() const; 40 | std::string identifier() const; 41 | Device::Type type() const; 42 | 43 | friend std::ostream& operator<<(std::ostream& os, const Device& device); 44 | 45 | private: 46 | std::string _name; 47 | std::string _identifier; 48 | Device::Type _type; 49 | }; 50 | 51 | #pragma GCC visibility pop 52 | 53 | #endif /* Device_hpp */ 54 | -------------------------------------------------------------------------------- /Error.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Error.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/8/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Error_hpp 10 | #define Error_hpp 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | enum class SignErrorCode 17 | { 18 | Unknown, 19 | InvalidApp, 20 | MissingAppBundle, 21 | MissingInfoPlist, 22 | MissingProvisioningProfile, 23 | MissingAppleRootCertificate, 24 | InvalidCertificate, 25 | InvalidProvisioningProfile, 26 | }; 27 | 28 | enum class APIErrorCode 29 | { 30 | Unknown, 31 | InvalidParameters, 32 | 33 | IncorrectCredentials, 34 | AppSpecificPasswordRequired, 35 | 36 | NoTeams, 37 | InvalidDeviceID, 38 | DeviceAlreadyRegistered, 39 | 40 | InvalidCertificateRequest, 41 | CertificateDoesNotExist, 42 | 43 | InvalidAppIDName, 44 | InvalidBundleIdentifier, 45 | BundleIdentifierUnavailable, 46 | AppIDDoesNotExist, 47 | 48 | InvalidAppGroup, 49 | AppGroupDoesNotExist, 50 | 51 | InvalidProvisioningProfileIdentifier, 52 | ProvisioningProfileDoesNotExist, 53 | 54 | InvalidResponse, 55 | 56 | RequiresTwoFactorAuthentication, 57 | IncorrectVerificationCode, 58 | AuthenticationHandshakeFailed, 59 | 60 | InvalidAnisetteData, 61 | }; 62 | 63 | enum class ArchiveErrorCode 64 | { 65 | Unknown, 66 | UnknownWrite, 67 | NoSuchFile, 68 | CorruptFile, 69 | }; 70 | 71 | class Error: public std::exception 72 | { 73 | public: 74 | Error(int code) : _code(code), _userInfo(std::map()) 75 | { 76 | } 77 | 78 | Error(int code, std::map userInfo) : _code(code), _userInfo(userInfo) 79 | { 80 | } 81 | 82 | virtual std::string localizedDescription() const 83 | { 84 | return ""; 85 | } 86 | 87 | int code() const 88 | { 89 | return _code; 90 | } 91 | 92 | std::map userInfo() const 93 | { 94 | return _userInfo; 95 | } 96 | 97 | virtual std::string domain() const 98 | { 99 | return "com.rileytestut.AltServer.Error"; 100 | } 101 | 102 | friend std::ostream& operator<<(std::ostream& os, const Error& error) 103 | { 104 | os << "Error: (" << error.domain() << "): " << error.localizedDescription() << " (" << error.code() << ")"; 105 | return os; 106 | } 107 | 108 | private: 109 | int _code; 110 | std::map _userInfo; 111 | }; 112 | 113 | class LocalizedError: public Error 114 | { 115 | public: 116 | LocalizedError(int code, std::string localizedDescription) : Error(code), _localizedDescription(localizedDescription) 117 | { 118 | } 119 | 120 | virtual std::string localizedDescription() const 121 | { 122 | return _localizedDescription; 123 | } 124 | 125 | private: 126 | std::string _localizedDescription; 127 | }; 128 | 129 | class APIError : public Error 130 | { 131 | public: 132 | APIError(APIErrorCode code) : Error((int)code) 133 | { 134 | } 135 | 136 | virtual std::string domain() const 137 | { 138 | return "com.rileytestut.ALTAppleAPI"; 139 | } 140 | 141 | virtual std::string localizedDescription() const 142 | { 143 | switch ((APIErrorCode)this->code()) 144 | { 145 | case APIErrorCode::Unknown: 146 | return "An unknown error occured."; 147 | 148 | case APIErrorCode::InvalidParameters: 149 | return "The provided parameters are invalid."; 150 | 151 | case APIErrorCode::IncorrectCredentials: 152 | return "Incorrect Apple ID or password."; 153 | 154 | case APIErrorCode::NoTeams: 155 | return "You are not a member of any development teams."; 156 | 157 | case APIErrorCode::AppSpecificPasswordRequired: 158 | return "An app-specific password is required. You can create one at appleid.apple.com."; 159 | 160 | case APIErrorCode::InvalidDeviceID: 161 | return "This device's UDID is invalid."; 162 | 163 | case APIErrorCode::DeviceAlreadyRegistered: 164 | return "This device is already registered with this team."; 165 | 166 | case APIErrorCode::InvalidCertificateRequest: 167 | return "The certificate request is invalid."; 168 | 169 | case APIErrorCode::CertificateDoesNotExist: 170 | return "There is no certificate with the requested serial number for this team."; 171 | 172 | case APIErrorCode::InvalidAppIDName: 173 | return "The name for this app is invalid."; 174 | 175 | case APIErrorCode::InvalidBundleIdentifier: 176 | return "The bundle identifier for this app is invalid."; 177 | 178 | case APIErrorCode::BundleIdentifierUnavailable: 179 | return "The bundle identifier for this app has already been registered."; 180 | 181 | case APIErrorCode::AppIDDoesNotExist: 182 | return "There is no App ID with the requested identifier on this team."; 183 | 184 | case APIErrorCode::InvalidAppGroup: 185 | return "The provided app group is invalid."; 186 | 187 | case APIErrorCode::AppGroupDoesNotExist: 188 | return "App group does not exist."; 189 | 190 | case APIErrorCode::InvalidProvisioningProfileIdentifier: 191 | return "The identifier for the requested provisioning profile is invalid."; 192 | 193 | case APIErrorCode::ProvisioningProfileDoesNotExist: 194 | return "There is no provisioning profile with the requested identifier on this team."; 195 | 196 | case APIErrorCode::InvalidResponse: 197 | return "Server returned invalid response."; 198 | 199 | case APIErrorCode::RequiresTwoFactorAuthentication: 200 | return "This account requires signing in with two-factor authentication."; 201 | 202 | case APIErrorCode::IncorrectVerificationCode: 203 | return "Incorrect verification code."; 204 | 205 | case APIErrorCode::AuthenticationHandshakeFailed: 206 | return "Failed to perform authentication handshake with server."; 207 | 208 | case APIErrorCode::InvalidAnisetteData: 209 | return "Invalid anisette data. Please close both iTunes and iCloud, then try again."; 210 | } 211 | 212 | return "Unknown error."; 213 | } 214 | }; 215 | 216 | class SignError: public Error 217 | { 218 | public: 219 | SignError(SignErrorCode code) : Error((int)code) 220 | { 221 | } 222 | 223 | virtual std::string domain() const 224 | { 225 | return "com.rileytestut.AltSign"; 226 | } 227 | 228 | virtual std::string localizedDescription() const 229 | { 230 | switch ((SignErrorCode)this->code()) 231 | { 232 | case SignErrorCode::Unknown: 233 | return "An unknown error occured."; 234 | 235 | case SignErrorCode::InvalidApp: 236 | return "The app is invalid."; 237 | 238 | case SignErrorCode::MissingAppBundle: 239 | return "The provided .ipa does not contain an app bundle."; 240 | 241 | case SignErrorCode::MissingInfoPlist: 242 | return "The provided app is missing its Info.plist."; 243 | 244 | case SignErrorCode::MissingProvisioningProfile: 245 | return "Could not find matching provisioning profile."; 246 | 247 | case SignErrorCode::MissingAppleRootCertificate: 248 | return "Could not locate the root signing certificate."; 249 | 250 | case SignErrorCode::InvalidCertificate: 251 | return "The signing certificate is invalid."; 252 | 253 | case SignErrorCode::InvalidProvisioningProfile: 254 | return "The provisioning profile is invalid."; 255 | } 256 | 257 | return "Unknown error."; 258 | } 259 | }; 260 | 261 | class ArchiveError: public Error 262 | { 263 | public: 264 | ArchiveError(ArchiveErrorCode code) : Error((int)code) 265 | { 266 | } 267 | 268 | virtual std::string domain() const 269 | { 270 | return "com.rileytestut.Archive"; 271 | } 272 | 273 | virtual std::string localizedDescription() const 274 | { 275 | switch ((ArchiveErrorCode)this->code()) 276 | { 277 | case ArchiveErrorCode::Unknown: 278 | return "An unknown error occured."; 279 | 280 | case ArchiveErrorCode::UnknownWrite: 281 | return "An unknown error occured while writing to disk."; 282 | 283 | case ArchiveErrorCode::NoSuchFile: 284 | return "The app could not be found."; 285 | 286 | case ArchiveErrorCode::CorruptFile: 287 | return "The app is corrupted."; 288 | } 289 | 290 | return "Unknown error."; 291 | } 292 | }; 293 | 294 | #endif /* Error_hpp */ 295 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := clang 2 | CXX := clang++ 3 | 4 | CFLAGS += -Iminizip -I../libplist/include -I. -mno-sse 5 | CXXFLAGS := $(CFLAGS) -std=c++17 6 | 7 | src := $(wildcard *.cpp) 8 | src += minizip/ioapi.c minizip/zip.c minizip/unzip.c 9 | ldid_src += ldid/ldid.cpp ldid/lookup2.c 10 | 11 | #ldid/%.o : CC := gcc 12 | #ldid/%.o : CXX := g++ 13 | 14 | %.c.o : %.c 15 | $(CC) $(CFLAGS) $(EXTRA_FLAGS) -o $@ -c $< 16 | 17 | %.cpp.o : %.cpp 18 | $(CXX) $(CXXFLAGS) $(EXTRA_FLAGS) -o $@ -c $< 19 | 20 | objs := $(src) $(ldid_src) 21 | objs := $(addsuffix .o, $(objs)) 22 | AltSign.a : $(objs) 23 | ar rcs $@ $^ 24 | 25 | clean: 26 | rm -f $(objs) AltSign.a -------------------------------------------------------------------------------- /PrefixHeader.pch: -------------------------------------------------------------------------------- 1 | // 2 | // PrefixHeader.pch 3 | // AltServer-Windows 4 | // 5 | // Created by Riley Testut on 8/8/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef PrefixHeader_pch 10 | #define PrefixHeader_pch 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "Account.hpp" 18 | #include "Team.hpp" 19 | #include "Error.hpp" 20 | 21 | using namespace utility; // Common utilities like string conversions 22 | using namespace web; // Common features like URIs. 23 | using namespace web::http; // Common HTTP functionality 24 | using namespace web::http::client; // HTTP client features 25 | using namespace concurrency::streams; // Asynchronous streams 26 | 27 | // Include any system framework and library headers here that should be included in all compilation units. 28 | // You will also need to set the Prefix Header build setting of one or more of your targets to reference this file. 29 | 30 | #endif /* PrefixHeader_pch */ 31 | -------------------------------------------------------------------------------- /ProvisioningProfile.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ProvisioningProfile.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "ProvisioningProfile.hpp" 10 | #include "Certificate.hpp" 11 | #include "Error.hpp" 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #if SIZE_MAX == UINT_MAX 22 | typedef int ssize_t; /* common 32 bit case */ 23 | #elif SIZE_MAX == ULONG_MAX 24 | typedef long ssize_t; /* linux 64 bits */ 25 | #elif SIZE_MAX == ULLONG_MAX 26 | typedef long long ssize_t; /* windows 64 bits */ 27 | #elif SIZE_MAX == USHRT_MAX 28 | typedef short ssize_t; /* is this even possible? */ 29 | #else 30 | #error platform has exotic SIZE_MAX 31 | #endif 32 | 33 | #define ASN1_SEQUENCE 0x30 34 | #define ASN1_CONTAINER 0xA0 35 | #define ASN1_OBJECT_IDENTIFIER 0x06 36 | #define ASN1_OCTET_STRING 0x04 37 | 38 | extern std::vector readFile(const char* filename); 39 | 40 | #include "altsign_common.h" 41 | 42 | #define SECONDS_FROM_1970_TO_APPLE_REFERENCE_DATE 978307200 43 | 44 | ProvisioningProfile::ProvisioningProfile() 45 | { 46 | } 47 | 48 | ProvisioningProfile::~ProvisioningProfile() 49 | { 50 | if (this->_entitlements != nullptr) 51 | { 52 | //plist_free(this->_entitlements); 53 | } 54 | } 55 | 56 | ProvisioningProfile::ProvisioningProfile(plist_t plist) 57 | { 58 | auto identifierNode = plist_dict_get_item(plist, "provisioningProfileId"); 59 | auto dataNode = plist_dict_get_item(plist, "encodedProfile"); 60 | 61 | if (identifierNode == nullptr || dataNode == nullptr) 62 | { 63 | throw APIError(APIErrorCode::InvalidResponse); 64 | } 65 | 66 | char *bytes = nullptr; 67 | uint64_t length = 0; 68 | plist_get_data_val(dataNode, &bytes, &length); 69 | 70 | std::vector data; 71 | data.reserve(length); 72 | for (int i = 0; i < length; i++) 73 | { 74 | data.push_back(bytes[i]); 75 | } 76 | 77 | try 78 | { 79 | this->ParseData(data); 80 | } 81 | catch (std::exception& exception) 82 | { 83 | throw APIError(APIErrorCode::InvalidResponse); 84 | } 85 | 86 | char *identifier = nullptr; 87 | plist_get_string_val(identifierNode, &identifier); 88 | 89 | _identifier = identifier; 90 | _data = data; 91 | } 92 | 93 | ProvisioningProfile::ProvisioningProfile(std::string filepath) /* throws */ 94 | { 95 | auto data = readFile(filepath.c_str()); 96 | this->ParseData(data); 97 | } 98 | 99 | ProvisioningProfile::ProvisioningProfile(std::vector& data) /* throws */ 100 | { 101 | this->ParseData(data); 102 | } 103 | 104 | // Heavily inspired by libimobiledevice/ideviceprovision.c 105 | // https://github.com/libimobiledevice/libimobiledevice/blob/ddba0b5efbcab483e80be10130c5c797f9ac8d08/tools/ideviceprovision.c#L98 106 | void ProvisioningProfile::ParseData(std::vector &encodedData) 107 | { 108 | // Helper blocks 109 | auto itemSize = [](unsigned char *pointer) -> size_t 110 | { 111 | size_t size = -1; 112 | 113 | char bsize = *(pointer + 1); 114 | if (bsize & 0x80) 115 | { 116 | switch (bsize & 0xF) 117 | { 118 | case 2: 119 | { 120 | uint16_t value = *(uint16_t *)(pointer + 2); 121 | size = ntohs(value); 122 | break; 123 | } 124 | 125 | case 3: 126 | { 127 | uint32_t value = *(uint32_t *)(pointer + 2); 128 | size = ntohl(value) >> 8; 129 | break; 130 | } 131 | 132 | case 4: 133 | { 134 | uint32_t value = *(uint32_t *)(pointer + 2); 135 | size = ntohl(value); 136 | break; 137 | } 138 | 139 | default: 140 | break; 141 | } 142 | } 143 | else 144 | { 145 | size = (size_t)bsize; 146 | } 147 | 148 | return size; 149 | }; 150 | 151 | auto advanceToNextItem = [](unsigned char *pointer) -> unsigned char * 152 | { 153 | unsigned char *nextItem = pointer; 154 | 155 | char bsize = *(pointer + 1); 156 | if (bsize & 0x80) 157 | { 158 | nextItem += 2 + (bsize & 0xF); 159 | } 160 | else 161 | { 162 | nextItem += 3; 163 | } 164 | 165 | return nextItem; 166 | }; 167 | 168 | auto skipNextItem = [&itemSize](unsigned char *pointer) -> unsigned char * 169 | { 170 | size_t size = itemSize(pointer); 171 | 172 | unsigned char *nextItem = pointer + 2 + size; 173 | return nextItem; 174 | }; 175 | 176 | /* Start parsing */ 177 | unsigned char *pointer = (unsigned char *)encodedData.data(); 178 | if (!pointer || *pointer != ASN1_SEQUENCE) 179 | { 180 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 181 | } 182 | 183 | pointer = advanceToNextItem(pointer); 184 | if (!pointer || *pointer != ASN1_OBJECT_IDENTIFIER) 185 | { 186 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 187 | } 188 | 189 | pointer = skipNextItem(pointer); 190 | if (!pointer || *pointer != ASN1_CONTAINER) 191 | { 192 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 193 | } 194 | 195 | pointer = advanceToNextItem(pointer); 196 | if (!pointer || *pointer != ASN1_SEQUENCE) 197 | { 198 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 199 | } 200 | 201 | pointer = advanceToNextItem(pointer); 202 | 203 | // Skip 2 items. 204 | for (int i = 0; i < 2; i++) 205 | { 206 | pointer = skipNextItem(pointer); 207 | } 208 | 209 | if (!pointer || *pointer != ASN1_SEQUENCE) 210 | { 211 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 212 | } 213 | 214 | pointer = advanceToNextItem(pointer); 215 | if (!pointer || *pointer != ASN1_OBJECT_IDENTIFIER) 216 | { 217 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 218 | } 219 | 220 | pointer = skipNextItem(pointer); 221 | if (!pointer || *pointer != ASN1_CONTAINER) 222 | { 223 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 224 | } 225 | 226 | pointer = advanceToNextItem(pointer); 227 | if (!pointer || *pointer != ASN1_OCTET_STRING) 228 | { 229 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 230 | } 231 | 232 | size_t length = itemSize(pointer); 233 | pointer = advanceToNextItem(pointer); 234 | 235 | plist_t parsedPlist = nullptr; 236 | plist_from_memory((const char *)pointer, (unsigned int)length, &parsedPlist); 237 | 238 | if (parsedPlist == nullptr) 239 | { 240 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 241 | } 242 | 243 | auto nameNode = plist_dict_get_item(parsedPlist, "Name"); 244 | auto uuidNode = plist_dict_get_item(parsedPlist, "UUID"); 245 | auto teamIdentifiersNode = plist_dict_get_item(parsedPlist, "TeamIdentifier"); 246 | auto creationDateNode = plist_dict_get_item(parsedPlist, "CreationDate"); 247 | auto expirationDateNode = plist_dict_get_item(parsedPlist, "ExpirationDate"); 248 | auto entitlementsNode = plist_dict_get_item(parsedPlist, "Entitlements"); 249 | 250 | if (nameNode == nullptr || uuidNode == nullptr || teamIdentifiersNode == nullptr || creationDateNode == nullptr || expirationDateNode == nullptr || entitlementsNode == nullptr) 251 | { 252 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 253 | } 254 | 255 | auto teamIdentifierNode = plist_array_get_item(teamIdentifiersNode, 0); 256 | if (teamIdentifierNode == nullptr) 257 | { 258 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 259 | } 260 | 261 | auto isFreeProvisioningProfileNode = plist_dict_get_item(parsedPlist, "LocalProvision"); 262 | if (isFreeProvisioningProfileNode != nullptr) 263 | { 264 | uint8_t isFreeProvisioningProfile = 0; 265 | plist_get_bool_val(isFreeProvisioningProfileNode, &isFreeProvisioningProfile); 266 | 267 | _isFreeProvisioningProfile = (isFreeProvisioningProfile != 0); 268 | } 269 | else 270 | { 271 | _isFreeProvisioningProfile = 0; 272 | } 273 | 274 | char *name = nullptr; 275 | plist_get_string_val(nameNode, &name); 276 | 277 | char *uuid = nullptr; 278 | plist_get_string_val(uuidNode, &uuid); 279 | 280 | char *teamIdentifier = nullptr; 281 | plist_get_string_val(teamIdentifierNode, &teamIdentifier); 282 | 283 | int32_t create_sec = 0; 284 | int32_t create_usec = 0; 285 | plist_get_date_val(creationDateNode, &create_sec, &create_usec); 286 | 287 | int32_t expiration_sec = 0; 288 | int32_t expiration_usec = 0; 289 | plist_get_date_val(expirationDateNode, &expiration_sec, &expiration_usec); 290 | 291 | plist_t bundleIdentifierNode = plist_dict_get_item(entitlementsNode, "application-identifier"); 292 | if (bundleIdentifierNode == nullptr) 293 | { 294 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 295 | } 296 | 297 | char *rawApplicationIdentifier = nullptr; 298 | plist_get_string_val(bundleIdentifierNode, &rawApplicationIdentifier); 299 | 300 | std::string applicationIdentifier(rawApplicationIdentifier); 301 | 302 | size_t location = applicationIdentifier.find("."); 303 | if (location == std::string::npos) 304 | { 305 | throw SignError(SignErrorCode::InvalidProvisioningProfile); 306 | } 307 | 308 | std::string bundleIdentifier(applicationIdentifier.begin() + location + 1, applicationIdentifier.end()); 309 | 310 | _name = name; 311 | _uuid = uuid; 312 | _teamIdentifier = teamIdentifier; 313 | _bundleIdentifier = bundleIdentifier; 314 | 315 | _creationDateSeconds = create_sec + SECONDS_FROM_1970_TO_APPLE_REFERENCE_DATE; 316 | _creationDateMicroseconds = create_usec; 317 | 318 | _expirationDateSeconds = expiration_sec + SECONDS_FROM_1970_TO_APPLE_REFERENCE_DATE; 319 | _expirationDateMicroseconds = expiration_usec; 320 | 321 | _entitlements = plist_copy(entitlementsNode); 322 | 323 | _data = encodedData; 324 | } 325 | 326 | #pragma mark - Getters - 327 | 328 | std::string ProvisioningProfile::name() const 329 | { 330 | return _name; 331 | } 332 | 333 | std::optional ProvisioningProfile::identifier() const 334 | { 335 | return _identifier; 336 | } 337 | 338 | std::string ProvisioningProfile::uuid() const 339 | { 340 | return _uuid; 341 | } 342 | 343 | std::string ProvisioningProfile::bundleIdentifier() const 344 | { 345 | return _bundleIdentifier; 346 | } 347 | 348 | std::string ProvisioningProfile::teamIdentifier() const 349 | { 350 | return _teamIdentifier; 351 | } 352 | 353 | std::vector ProvisioningProfile::data() const 354 | { 355 | return _data; 356 | } 357 | 358 | timeval ProvisioningProfile::creationDate() const 359 | { 360 | timeval creationDate = { this->_creationDateSeconds, this->_creationDateMicroseconds }; 361 | return creationDate; 362 | } 363 | 364 | timeval ProvisioningProfile::expirationDate() const 365 | { 366 | timeval expirationDate = { this->_expirationDateSeconds, this->_expirationDateMicroseconds }; 367 | return expirationDate; 368 | } 369 | 370 | plist_t ProvisioningProfile::entitlements() const 371 | { 372 | return _entitlements; 373 | } 374 | 375 | bool ProvisioningProfile::isFreeProvisioningProfile() const 376 | { 377 | return _isFreeProvisioningProfile; 378 | } -------------------------------------------------------------------------------- /ProvisioningProfile.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // ProvisioningProfile.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef ProvisioningProfile_hpp 10 | #define ProvisioningProfile_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | struct timeval; 22 | 23 | class ProvisioningProfile 24 | { 25 | public: 26 | ProvisioningProfile(); 27 | ~ProvisioningProfile(); 28 | 29 | ProvisioningProfile(plist_t plist) /* throws */; 30 | ProvisioningProfile(std::vector& data) /* throws */; 31 | ProvisioningProfile(std::string filepath) /* throws */; 32 | 33 | std::string name() const; 34 | std::optional identifier() const; 35 | std::string uuid() const; 36 | 37 | std::string bundleIdentifier() const; 38 | std::string teamIdentifier() const; 39 | 40 | timeval creationDate() const; 41 | timeval expirationDate() const; 42 | 43 | plist_t entitlements() const; 44 | 45 | bool isFreeProvisioningProfile() const; 46 | 47 | std::vector data() const; 48 | 49 | friend std::ostream& operator<<(std::ostream& os, const ProvisioningProfile& profile); 50 | 51 | private: 52 | std::string _name; 53 | std::optional _identifier; 54 | std::string _uuid; 55 | 56 | std::string _bundleIdentifier; 57 | std::string _teamIdentifier; 58 | 59 | long _creationDateSeconds; 60 | long _creationDateMicroseconds; 61 | 62 | long _expirationDateSeconds; 63 | long _expirationDateMicroseconds; 64 | 65 | plist_t _entitlements; 66 | bool _isFreeProvisioningProfile; 67 | 68 | std::vector _data; 69 | 70 | void ParseData(std::vector& data); 71 | }; 72 | 73 | #pragma GCC visibility pop 74 | 75 | #endif /* ProvisioningProfile_hpp */ 76 | -------------------------------------------------------------------------------- /Signer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Signer.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "altsign_common.h" 10 | #include "Signer.hpp" 11 | #include "Error.hpp" 12 | #include "Archiver.hpp" 13 | #include "Application.hpp" 14 | 15 | #include "ldid/ldid.hpp" 16 | 17 | #include 18 | #include 19 | //#include 20 | 21 | #include 22 | 23 | #include // std::this_thread::sleep_for 24 | #include // std::chrono::seconds 25 | 26 | #include "altsign_common.h" 27 | 28 | const char* AppleRootCertificateData = "" 29 | "-----BEGIN CERTIFICATE-----\n" 30 | "MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET\n" 31 | "MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv\n" 32 | "biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0\n" 33 | "MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw\n" 34 | "bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx\n" 35 | "FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" 36 | "ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+\n" 37 | "+FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1\n" 38 | "XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w\n" 39 | "tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW\n" 40 | "q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM\n" 41 | "aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E\n" 42 | "BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3\n" 43 | "R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE\n" 44 | "ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93\n" 45 | "d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl\n" 46 | "IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0\n" 47 | "YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj\n" 48 | "b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp\n" 49 | "Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc\n" 50 | "NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP\n" 51 | "y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7\n" 52 | "R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg\n" 53 | "xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP\n" 54 | "IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX\n" 55 | "UKqK1drk/NAJBzewdXUh\n" 56 | "-----END CERTIFICATE-----\n"; 57 | 58 | const char* AppleWWDRCertificateData = "" 59 | "-----BEGIN CERTIFICATE-----\n" 60 | "MIIEUTCCAzmgAwIBAgIQfK9pCiW3Of57m0R6wXjF7jANBgkqhkiG9w0BAQsFADBi\n" 61 | "MQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBw\n" 62 | "bGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3Qg\n" 63 | "Q0EwHhcNMjAwMjE5MTgxMzQ3WhcNMzAwMjIwMDAwMDAwWjB1MUQwQgYDVQQDDDtB\n" 64 | "cHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9ucyBDZXJ0aWZpY2F0aW9u\n" 65 | "IEF1dGhvcml0eTELMAkGA1UECwwCRzMxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJ\n" 66 | "BgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2PWJ/KhZ\n" 67 | "C4fHTJEuLVaQ03gdpDDppUjvC0O/LYT7JF1FG+XrWTYSXFRknmxiLbTGl8rMPPbW\n" 68 | "BpH85QKmHGq0edVny6zpPwcR4YS8Rx1mjjmi6LRJ7TrS4RBgeo6TjMrA2gzAg9Dj\n" 69 | "+ZHWp4zIwXPirkbRYp2SqJBgN31ols2N4Pyb+ni743uvLRfdW/6AWSN1F7gSwe0b\n" 70 | "5TTO/iK1nkmw5VW/j4SiPKi6xYaVFuQAyZ8D0MyzOhZ71gVcnetHrg21LYwOaU1A\n" 71 | "0EtMOwSejSGxrC5DVDDOwYqGlJhL32oNP/77HK6XF8J4CjDgXx9UO0m3JQAaN4LS\n" 72 | "VpelUkl8YDib7wIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j\n" 73 | "BBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wRAYIKwYBBQUHAQEEODA2MDQGCCsG\n" 74 | "AQUFBzABhihodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLWFwcGxlcm9vdGNh\n" 75 | "MC4GA1UdHwQnMCUwI6AhoB+GHWh0dHA6Ly9jcmwuYXBwbGUuY29tL3Jvb3QuY3Js\n" 76 | "MB0GA1UdDgQWBBQJ/sAVkPmvZAqSErkmKGMMl+ynsjAOBgNVHQ8BAf8EBAMCAQYw\n" 77 | "EAYKKoZIhvdjZAYCAQQCBQAwDQYJKoZIhvcNAQELBQADggEBAK1lE+j24IF3RAJH\n" 78 | "Qr5fpTkg6mKp/cWQyXMT1Z6b0KoPjY3L7QHPbChAW8dVJEH4/M/BtSPp3Ozxb8qA\n" 79 | "HXfCxGFJJWevD8o5Ja3T43rMMygNDi6hV0Bz+uZcrgZRKe3jhQxPYdwyFot30ETK\n" 80 | "XXIDMUacrptAGvr04NM++i+MZp+XxFRZ79JI9AeZSWBZGcfdlNHAwWx/eCHvDOs7\n" 81 | "bJmCS1JgOLU5gm3sUjFTvg+RTElJdI+mUcuER04ddSduvfnSXPN/wmwLCTbiZOTC\n" 82 | "NwMUGdXqapSqqdv+9poIZ4vvK7iqF0mDr8/LvOnP6pVxsLRFoszlh6oKw0E6eVza\n" 83 | "UDSdlTs=\n" 84 | "-----END CERTIFICATE-----\n"; 85 | 86 | const char* LegacyAppleWWDRCertificateData = "" 87 | "-----BEGIN CERTIFICATE-----\n" 88 | "MIIEIjCCAwqgAwIBAgIIAd68xDltoBAwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UE\n" 89 | "BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp\n" 90 | "ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEz\n" 91 | "MDIwNzIxNDg0N1oXDTIzMDIwNzIxNDg0N1owgZYxCzAJBgNVBAYTAlVTMRMwEQYD\n" 92 | "VQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxv\n" 93 | "cGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3Bl\n" 94 | "ciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3\n" 95 | "DQEBAQUAA4IBDwAwggEKAoIBAQDKOFSmy1aqyCQ5SOmM7uxfuH8mkbw0U3rOfGOA\n" 96 | "YXdkXqUHI7Y5/lAtFVZYcC1+xG7BSoU+L/DehBqhV8mvexj/avoVEkkVCBmsqtsq\n" 97 | "Mu2WY2hSFT2Miuy/axiV4AOsAX2XBWfODoWVN2rtCbauZ81RZJ/GXNG8V25nNYB2\n" 98 | "NqSHgW44j9grFU57Jdhav06DwY3Sk9UacbVgnJ0zTlX5ElgMhrgWDcHld0WNUEi6\n" 99 | "Ky3klIXh6MSdxmilsKP8Z35wugJZS3dCkTm59c3hTO/AO0iMpuUhXf1qarunFjVg\n" 100 | "0uat80YpyejDi+l5wGphZxWy8P3laLxiX27Pmd3vG2P+kmWrAgMBAAGjgaYwgaMw\n" 101 | "HQYDVR0OBBYEFIgnFwmpthhgi+zruvZHWcVSVKO3MA8GA1UdEwEB/wQFMAMBAf8w\n" 102 | "HwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wLgYDVR0fBCcwJTAjoCGg\n" 103 | "H4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5jcmwwDgYDVR0PAQH/BAQDAgGG\n" 104 | "MBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQBPz+9Zviz1smwv\n" 105 | "j+4ThzLoBTWobot9yWkMudkXvHcs1Gfi/ZptOllc34MBvbKuKmFysa/Nw0Uwj6OD\n" 106 | "Dc4dR7Txk4qjdJukw5hyhzs+r0ULklS5MruQGFNrCk4QttkdUGwhgAqJTleMa1s8\n" 107 | "Pab93vcNIx0LSiaHP7qRkkykGRIZbVf1eliHe2iK5IaMSuviSRSqpd1VAKmuu0sw\n" 108 | "ruGgsbwpgOYJd+W+NKIByn/c4grmO7i77LpilfMFY0GCzQ87HUyVpNur+cmV6U/k\n" 109 | "TecmmYHpvPm0KdIBembhLoz2IYrF+Hjhga6/05Cdqa3zr/04GpZnMBxRpVzscYqC\n" 110 | "tGwPDBUf\n" 111 | "-----END CERTIFICATE-----\n"; 112 | 113 | namespace fs = std::filesystem; 114 | 115 | extern std::string make_uuid(); 116 | 117 | std::string CertificatesContent(std::shared_ptr altCertificate) 118 | { 119 | auto altCertificateP12Data = altCertificate->p12Data(); 120 | if (!altCertificateP12Data.has_value()) 121 | { 122 | throw SignError(SignErrorCode::InvalidCertificate); 123 | } 124 | 125 | BIO *inputP12Buffer = BIO_new(BIO_s_mem()); 126 | BIO_write(inputP12Buffer, altCertificateP12Data->data(), (int)altCertificateP12Data->size()); 127 | 128 | auto inputP12 = d2i_PKCS12_bio(inputP12Buffer, NULL); 129 | 130 | // Extract key + certificate from .p12. 131 | EVP_PKEY *key = nullptr; 132 | X509 *certificate = nullptr; 133 | PKCS12_parse(inputP12, "", &key, &certificate, NULL); 134 | 135 | // Prepare certificate chain of trust. 136 | auto* certificates = sk_X509_new(NULL); 137 | 138 | BIO* rootCertificateBuffer = BIO_new_mem_buf(AppleRootCertificateData, (int)strlen(AppleRootCertificateData)); 139 | BIO* wwdrCertificateBuffer = NULL; 140 | 141 | unsigned long issuerHash = X509_issuer_name_hash(certificate); 142 | if (issuerHash == 0x817d2f7a) 143 | { 144 | // Use legacy WWDR certificate. 145 | wwdrCertificateBuffer = BIO_new_mem_buf(LegacyAppleWWDRCertificateData, (int)strlen(LegacyAppleWWDRCertificateData)); 146 | } 147 | else 148 | { 149 | // Use latest WWDR certificate. 150 | wwdrCertificateBuffer = BIO_new_mem_buf(AppleWWDRCertificateData, (int)strlen(AppleWWDRCertificateData)); 151 | } 152 | 153 | auto rootCertificate = PEM_read_bio_X509(rootCertificateBuffer, NULL, NULL, NULL); 154 | if (rootCertificate != NULL) 155 | { 156 | sk_X509_push(certificates, rootCertificate); 157 | } 158 | 159 | auto wwdrCertificate = PEM_read_bio_X509(wwdrCertificateBuffer, NULL, NULL, NULL); 160 | if (wwdrCertificate != NULL) 161 | { 162 | sk_X509_push(certificates, wwdrCertificate); 163 | } 164 | 165 | // Create new .p12 in memory with private key and certificate chain. 166 | char emptyString[] = ""; 167 | auto outputP12 = PKCS12_create(emptyString, emptyString, key, certificate, certificates, 0, 0, 0, 0, 0); 168 | 169 | BIO *outputP12Buffer = BIO_new(BIO_s_mem()); 170 | i2d_PKCS12_bio(outputP12Buffer, outputP12); 171 | 172 | char *buffer = NULL; 173 | int size = (int)BIO_get_mem_data(outputP12Buffer, &buffer); 174 | 175 | // Create string before freeing memory. 176 | std::string output((const char*)buffer, size); 177 | 178 | // Free .p12 structures 179 | PKCS12_free(inputP12); 180 | PKCS12_free(outputP12); 181 | 182 | BIO_free(wwdrCertificateBuffer); 183 | BIO_free(rootCertificateBuffer); 184 | 185 | BIO_free(inputP12Buffer); 186 | BIO_free(outputP12Buffer); 187 | 188 | return output; 189 | } 190 | 191 | Signer::Signer(std::shared_ptr team, std::shared_ptr certificate) : _team(team), _certificate(certificate) 192 | { 193 | } 194 | 195 | Signer::~Signer() 196 | { 197 | int i = 0; 198 | } 199 | 200 | void Signer::SignApp(std::string path, std::vector> profiles) 201 | { 202 | fs::path appPath = fs::path(path); 203 | 204 | auto pathExtension = appPath.extension().string(); 205 | std::transform(pathExtension.begin(), pathExtension.end(), pathExtension.begin(), [](unsigned char c) { 206 | return std::tolower(c); 207 | }); 208 | 209 | std::optional ipaPath; 210 | fs::path appBundlePath; 211 | 212 | try 213 | { 214 | if (pathExtension == ".ipa") 215 | { 216 | ipaPath = appPath; 217 | 218 | auto uuid = make_uuid(); 219 | auto outputDirectoryPath = appPath.remove_filename().append(uuid); 220 | 221 | fs::create_directory(outputDirectoryPath); 222 | 223 | appBundlePath = UnzipAppBundle(appPath.string(), outputDirectoryPath.string()); 224 | } 225 | else 226 | { 227 | appBundlePath = appPath; 228 | } 229 | 230 | std::map entitlementsByFilepath; 231 | 232 | auto profileForApp = [&profiles](Application &app) -> std::shared_ptr { 233 | for (auto& profile : profiles) 234 | { 235 | if (profile->bundleIdentifier() == app.bundleIdentifier()) 236 | { 237 | return profile; 238 | } 239 | } 240 | 241 | return nullptr; 242 | }; 243 | 244 | auto prepareApp = [&profileForApp, &entitlementsByFilepath](Application &app) 245 | { 246 | auto profile = profileForApp(app); 247 | if (profile == nullptr) 248 | { 249 | throw SignError(SignErrorCode::MissingProvisioningProfile); 250 | } 251 | 252 | fs::path profilePath = fs::path(app.path()).append("embedded.mobileprovision"); 253 | 254 | std::ofstream fout(profilePath.string(), std::ios::out | std::ios::binary); 255 | fout.write((char*)& profile->data()[0], profile->data().size() * sizeof(char)); 256 | fout.close(); 257 | 258 | plist_t entitlements = profile->entitlements(); 259 | 260 | char *entitlementsString = nullptr; 261 | uint32_t entitlementsSize = 0; 262 | plist_to_xml(entitlements, &entitlementsString, &entitlementsSize); 263 | 264 | entitlementsByFilepath[app.path()] = entitlementsString; 265 | }; 266 | 267 | odslog("Signing app " << appBundlePath.string() << " using ldid..."); 268 | 269 | Application app(appBundlePath.string()); 270 | prepareApp(app); 271 | 272 | for (auto appExtension : app.appExtensions()) 273 | { 274 | prepareApp(*appExtension); 275 | } 276 | 277 | // Sign application 278 | ldid::DiskFolder appBundle(app.path()); 279 | std::string key = CertificatesContent(this->certificate()); 280 | 281 | ldid::Sign("", appBundle, key, "", 282 | ldid::fun([&](const std::string &path, const std::string &binaryEntitlements) -> std::string { 283 | std::string filepath; 284 | 285 | if (path.size() == 0) 286 | { 287 | filepath = app.path(); 288 | } 289 | else 290 | { 291 | filepath = fs::canonical(fs::path(app.path()).append(path)).string(); 292 | } 293 | 294 | auto entitlements = entitlementsByFilepath[filepath]; 295 | return entitlements; 296 | }), 297 | ldid::fun([&](const std::string &string) { 298 | odslog("Signing: " << string); 299 | // progress.completedUnitCount += 1; 300 | }), 301 | ldid::fun([&](const double signingProgress) { 302 | //odslog("Signing Progress: " << signingProgress); 303 | })); 304 | 305 | // Zip app back up. 306 | if (ipaPath.has_value()) 307 | { 308 | auto resignedPath = ZipAppBundle(appBundlePath.string()); 309 | 310 | if (fs::exists(*ipaPath)) 311 | { 312 | fs::remove(*ipaPath); 313 | } 314 | 315 | fs::rename(*ipaPath, resignedPath); 316 | } 317 | 318 | return; 319 | } 320 | catch (std::exception& e) 321 | { 322 | if (!ipaPath.has_value()) 323 | { 324 | return; 325 | } 326 | 327 | fs::remove(*ipaPath); 328 | 329 | throw; 330 | } 331 | } 332 | 333 | std::shared_ptr Signer::team() const 334 | { 335 | return _team; 336 | } 337 | 338 | std::shared_ptr Signer::certificate() const 339 | { 340 | return _certificate; 341 | } 342 | -------------------------------------------------------------------------------- /Signer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Signer.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/12/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Signer_hpp 10 | #define Signer_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | 18 | #include "Team.hpp" 19 | #include "Certificate.hpp" 20 | #include "ProvisioningProfile.hpp" 21 | 22 | class Signer 23 | { 24 | public: 25 | Signer(std::shared_ptr team, std::shared_ptr certificate); 26 | ~Signer(); 27 | 28 | std::shared_ptr team() const; 29 | std::shared_ptr certificate() const; 30 | 31 | void SignApp(std::string appPath, std::vector> profiles); 32 | 33 | private: 34 | std::shared_ptr _team; 35 | std::shared_ptr _certificate; 36 | }; 37 | 38 | #pragma GCC visibility pop 39 | 40 | #endif /* Signer_hpp */ 41 | -------------------------------------------------------------------------------- /Team.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Team.cpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/9/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #include "Team.hpp" 10 | 11 | #include "PrefixHeader.pch" 12 | 13 | Team::Team() 14 | { 15 | } 16 | 17 | Team::~Team() 18 | { 19 | } 20 | 21 | Team::Team(std::shared_ptr account, plist_t plist) /* throws */ 22 | { 23 | auto nameNode = plist_dict_get_item(plist, "name"); 24 | auto identifierNode = plist_dict_get_item(plist, "teamId"); 25 | auto typeNode = plist_dict_get_item(plist, "type"); 26 | 27 | if (nameNode == nullptr || identifierNode == nullptr || typeNode == nullptr) 28 | { 29 | throw APIError(APIErrorCode::InvalidResponse); 30 | } 31 | 32 | char *name = nullptr; 33 | plist_get_string_val(nameNode, &name); 34 | 35 | char *identifier = 0; 36 | plist_get_string_val(identifierNode, &identifier); 37 | 38 | char *teamType = nullptr; 39 | plist_get_string_val(typeNode, &teamType); 40 | 41 | Team::Type type = Type::Unknown; 42 | 43 | if (std::string(teamType) == "Company/Organization") 44 | { 45 | type = Type::Organization; 46 | } 47 | else if (std::string(teamType) == "Individual") 48 | { 49 | type = Type::Individual; 50 | 51 | plist_t memberships = plist_dict_get_item(plist, "memberships"); 52 | if (memberships != nullptr && plist_array_get_size(memberships) == 1) 53 | { 54 | plist_t membership = plist_array_get_item(memberships, 0); 55 | 56 | plist_t nameNode = plist_dict_get_item(membership, "name"); 57 | if (nameNode != nullptr) 58 | { 59 | char *rawName = nullptr; 60 | plist_get_string_val(nameNode, &rawName); 61 | 62 | // Make lowercase. 63 | std::string name = rawName; 64 | std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { 65 | return std::tolower(c); 66 | }); 67 | 68 | if (name.find("free") != std::string::npos) 69 | { 70 | type = Type::Free; 71 | } 72 | } 73 | } 74 | } 75 | else 76 | { 77 | type = Type::Unknown; 78 | } 79 | 80 | _name = name; 81 | _identifier = identifier; 82 | _type = type; 83 | _account = account; 84 | } 85 | 86 | #pragma mark - Description - 87 | 88 | std::ostream& operator<<(std::ostream& os, const Team& team) 89 | { 90 | os << "Name: " << team.name(); 91 | return os; 92 | } 93 | 94 | #pragma mark - Getters - 95 | 96 | std::string Team::name() const 97 | { 98 | return _name; 99 | } 100 | 101 | std::string Team::identifier() const 102 | { 103 | return _identifier; 104 | } 105 | 106 | Team::Type Team::type() const 107 | { 108 | return _type; 109 | } 110 | 111 | std::shared_ptr Team::account() const 112 | { 113 | return _account; 114 | } 115 | -------------------------------------------------------------------------------- /Team.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Team.hpp 3 | // AltSign-Windows 4 | // 5 | // Created by Riley Testut on 8/9/19. 6 | // Copyright © 2019 Riley Testut. All rights reserved. 7 | // 8 | 9 | #ifndef Team_hpp 10 | #define Team_hpp 11 | 12 | /* The classes below are exported */ 13 | #pragma GCC visibility push(default) 14 | 15 | #include 16 | #include 17 | 18 | #include "Account.hpp" 19 | 20 | class Account; 21 | 22 | class Team 23 | { 24 | public: 25 | enum Type 26 | { 27 | Unknown, 28 | Free, 29 | Individual, 30 | Organization 31 | }; 32 | 33 | Team(); 34 | ~Team(); 35 | 36 | Team(std::shared_ptr account, plist_t plist) /* throws */; 37 | 38 | friend std::ostream& operator<<(std::ostream& os, const Team& account); 39 | 40 | std::string name() const; 41 | std::string identifier() const; 42 | Type type() const; 43 | 44 | std::shared_ptr account() const; 45 | 46 | private: 47 | 48 | std::string _name; 49 | std::string _identifier; 50 | 51 | Type _type; 52 | std::shared_ptr _account; 53 | }; 54 | 55 | #pragma GCC visibility pop 56 | 57 | #endif /* Team_hpp */ 58 | -------------------------------------------------------------------------------- /altsign_common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct timeval TIMEVAL; 5 | #ifndef odslog 6 | #define odslog(msg) { std::cout << msg << std::endl; } 7 | #endif -------------------------------------------------------------------------------- /ldid/control.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | dir=$1 3 | dir=${dir:=_} 4 | sed -e "s@^\(Version:.*\)@\1$(./version.sh)@" control 5 | echo "Installed-Size: $(du -s "${dir}" | cut -f 1)" 6 | -------------------------------------------------------------------------------- /ldid/ldid.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LDID_HPP 2 | #define LDID_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace ldid { 13 | 14 | // I wish Apple cared about providing quality toolchains :/ 15 | 16 | template 17 | class Functor; 18 | 19 | template 20 | class Functor { 21 | public: 22 | virtual Type_ operator ()(Args_... args) const = 0; 23 | }; 24 | 25 | template 26 | class FunctorImpl; 27 | 28 | template 29 | class FunctorImpl : 30 | public Functor 31 | { 32 | private: 33 | const Value_ *value_; 34 | 35 | public: 36 | FunctorImpl(const Value_ &value) : 37 | value_(&value) 38 | { 39 | } 40 | 41 | virtual Type_ operator ()(Args_... args) const { 42 | return (*value_)(args...); 43 | } 44 | }; 45 | 46 | template 47 | FunctorImpl fun(const Function_ &value) { 48 | return value; 49 | } 50 | 51 | class Folder { 52 | public: 53 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code) = 0; 54 | virtual bool Look(const std::string &path) const = 0; 55 | virtual void Open(const std::string &path, const Functor &code) const = 0; 56 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const = 0; 57 | }; 58 | 59 | class DiskFolder : 60 | public Folder 61 | { 62 | private: 63 | const std::string path_; 64 | std::map commit_; 65 | 66 | protected: 67 | std::string Path(const std::string &path) const; 68 | 69 | private: 70 | void Find(const std::string &root, const std::string &base, const Functor &code, const Functor &)> &link) const; 71 | 72 | public: 73 | DiskFolder(const std::string &path); 74 | ~DiskFolder(); 75 | 76 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); 77 | virtual bool Look(const std::string &path) const; 78 | virtual void Open(const std::string &path, const Functor &code) const; 79 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; 80 | }; 81 | 82 | class SubFolder : 83 | public Folder 84 | { 85 | private: 86 | Folder &parent_; 87 | std::string path_; 88 | 89 | public: 90 | SubFolder(Folder &parent, const std::string &path); 91 | 92 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); 93 | virtual bool Look(const std::string &path) const; 94 | virtual void Open(const std::string &path, const Functor &code) const; 95 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; 96 | }; 97 | 98 | class UnionFolder : 99 | public Folder 100 | { 101 | private: 102 | struct Reset { 103 | const void *flag_; 104 | std::streambuf *data_; 105 | }; 106 | 107 | Folder &parent_; 108 | std::set deletes_; 109 | 110 | std::map remaps_; 111 | mutable std::map resets_; 112 | 113 | std::string Map(const std::string &path) const; 114 | void Map(const std::string &path, const Functor &code, const std::string &file, const Functor &)> &save) const; 115 | 116 | public: 117 | UnionFolder(Folder &parent); 118 | 119 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); 120 | virtual bool Look(const std::string &path) const; 121 | virtual void Open(const std::string &path, const Functor &code) const; 122 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; 123 | 124 | void operator ()(const std::string &from) { 125 | deletes_.insert(from); 126 | } 127 | 128 | void operator ()(const std::string &from, const std::string &to) { 129 | operator ()(from); 130 | remaps_[to] = from; 131 | } 132 | 133 | void operator ()(const std::string &from, const void *flag, std::streambuf &data) { 134 | operator ()(from); 135 | auto &reset(resets_[from]); 136 | reset.flag_ = flag; 137 | reset.data_ = &data; 138 | } 139 | }; 140 | 141 | struct Hash { 142 | uint8_t sha1_[0x14]; 143 | uint8_t sha256_[0x20]; 144 | }; 145 | 146 | struct Bundle { 147 | std::string path; 148 | Hash hash; 149 | }; 150 | 151 | 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); 152 | 153 | typedef std::map Slots; 154 | 155 | 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); 156 | 157 | std::string Entitlements(std::string path); 158 | } 159 | 160 | #endif//LDID_HPP 161 | -------------------------------------------------------------------------------- /ldid/lookup2.c: -------------------------------------------------------------------------------- 1 | /* 2 | -------------------------------------------------------------------- 3 | lookup2.c, by Bob Jenkins, December 1996, Public Domain. 4 | hash(), hash2(), hash3, and mix() are externally useful functions. 5 | Routines to test the hash are included if SELF_TEST is defined. 6 | You can use this free for any purpose. It has no warranty. 7 | -------------------------------------------------------------------- 8 | */ 9 | #include 10 | #include 11 | #include 12 | typedef unsigned long int ub4; /* unsigned 4-byte quantities */ 13 | typedef unsigned char ub1; 14 | 15 | #define hashsize(n) ((ub4)1<<(n)) 16 | #define hashmask(n) (hashsize(n)-1) 17 | 18 | /* 19 | -------------------------------------------------------------------- 20 | mix -- mix 3 32-bit values reversibly. 21 | For every delta with one or two bit set, and the deltas of all three 22 | high bits or all three low bits, whether the original value of a,b,c 23 | is almost all zero or is uniformly distributed, 24 | * If mix() is run forward or backward, at least 32 bits in a,b,c 25 | have at least 1/4 probability of changing. 26 | * If mix() is run forward, every bit of c will change between 1/3 and 27 | 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) 28 | mix() was built out of 36 single-cycle latency instructions in a 29 | structure that could supported 2x parallelism, like so: 30 | a -= b; 31 | a -= c; x = (c>>13); 32 | b -= c; a ^= x; 33 | b -= a; x = (a<<8); 34 | c -= a; b ^= x; 35 | c -= b; x = (b>>13); 36 | ... 37 | Unfortunately, superscalar Pentiums and Sparcs can't take advantage 38 | of that parallelism. They've also turned some of those single-cycle 39 | latency instructions into multi-cycle latency instructions. Still, 40 | this is the fastest good hash I could find. There were about 2^^68 41 | to choose from. I only looked at a billion or so. 42 | -------------------------------------------------------------------- 43 | */ 44 | #define mix(a,b,c) \ 45 | { \ 46 | a -= b; a -= c; a ^= (c>>13); \ 47 | b -= c; b -= a; b ^= (a<<8); \ 48 | c -= a; c -= b; c ^= (b>>13); \ 49 | a -= b; a -= c; a ^= (c>>12); \ 50 | b -= c; b -= a; b ^= (a<<16); \ 51 | c -= a; c -= b; c ^= (b>>5); \ 52 | a -= b; a -= c; a ^= (c>>3); \ 53 | b -= c; b -= a; b ^= (a<<10); \ 54 | c -= a; c -= b; c ^= (b>>15); \ 55 | } 56 | 57 | /* same, but slower, works on systems that might have 8 byte ub4's */ 58 | #define mix2(a,b,c) \ 59 | { \ 60 | a -= b; a -= c; a ^= (c>>13); \ 61 | b -= c; b -= a; b ^= (a<< 8); \ 62 | c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ 63 | a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ 64 | b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ 65 | c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ 66 | a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ 67 | b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ 68 | c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ 69 | } 70 | 71 | /* 72 | -------------------------------------------------------------------- 73 | hash() -- hash a variable-length key into a 32-bit value 74 | k : the key (the unaligned variable-length array of bytes) 75 | len : the length of the key, counting by bytes 76 | level : can be any 4-byte value 77 | Returns a 32-bit value. Every bit of the key affects every bit of 78 | the return value. Every 1-bit and 2-bit delta achieves avalanche. 79 | About 36+6len instructions. 80 | 81 | The best hash table sizes are powers of 2. There is no need to do 82 | mod a prime (mod is sooo slow!). If you need less than 32 bits, 83 | use a bitmask. For example, if you need only 10 bits, do 84 | h = (h & hashmask(10)); 85 | In which case, the hash table should have hashsize(10) elements. 86 | 87 | If you are hashing n strings (ub1 **)k, do it like this: 88 | for (i=0, h=0; i= 12) 113 | { 114 | a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); 115 | b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); 116 | c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); 117 | mix(a,b,c); 118 | k += 12; len -= 12; 119 | } 120 | 121 | /*------------------------------------- handle the last 11 bytes */ 122 | c += length; 123 | switch(len) /* all the case statements fall through */ 124 | { 125 | case 11: c+=((ub4)k[10]<<24); 126 | case 10: c+=((ub4)k[9]<<16); 127 | case 9 : c+=((ub4)k[8]<<8); 128 | /* the first byte of c is reserved for the length */ 129 | case 8 : b+=((ub4)k[7]<<24); 130 | case 7 : b+=((ub4)k[6]<<16); 131 | case 6 : b+=((ub4)k[5]<<8); 132 | case 5 : b+=k[4]; 133 | case 4 : a+=((ub4)k[3]<<24); 134 | case 3 : a+=((ub4)k[2]<<16); 135 | case 2 : a+=((ub4)k[1]<<8); 136 | case 1 : a+=k[0]; 137 | /* case 0: nothing left to add */ 138 | } 139 | mix(a,b,c); 140 | /*-------------------------------------------- report the result */ 141 | return c; 142 | } 143 | 144 | 145 | /* 146 | -------------------------------------------------------------------- 147 | This works on all machines. hash2() is identical to hash() on 148 | little-endian machines, except that the length has to be measured 149 | in ub4s instead of bytes. It is much faster than hash(). It 150 | requires 151 | -- that the key be an array of ub4's, and 152 | -- that all your machines have the same endianness, and 153 | -- that the length be the number of ub4's in the key 154 | -------------------------------------------------------------------- 155 | */ 156 | ub4 hash2( k, length, initval) 157 | register ub4 *k; /* the key */ 158 | register ub4 length; /* the length of the key, in ub4s */ 159 | register ub4 initval; /* the previous hash, or an arbitrary value */ 160 | { 161 | register ub4 a,b,c,len; 162 | 163 | /* Set up the internal state */ 164 | len = length; 165 | a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ 166 | c = initval; /* the previous hash value */ 167 | 168 | /*---------------------------------------- handle most of the key */ 169 | while (len >= 3) 170 | { 171 | a += k[0]; 172 | b += k[1]; 173 | c += k[2]; 174 | mix(a,b,c); 175 | k += 3; len -= 3; 176 | } 177 | 178 | /*-------------------------------------- handle the last 2 ub4's */ 179 | c += length; 180 | switch(len) /* all the case statements fall through */ 181 | { 182 | /* c is reserved for the length */ 183 | case 2 : b+=k[1]; 184 | case 1 : a+=k[0]; 185 | /* case 0: nothing left to add */ 186 | } 187 | mix(a,b,c); 188 | /*-------------------------------------------- report the result */ 189 | return c; 190 | } 191 | 192 | /* 193 | -------------------------------------------------------------------- 194 | This is identical to hash() on little-endian machines (like Intel 195 | x86s or VAXen). It gives nondeterministic results on big-endian 196 | machines. It is faster than hash(), but a little slower than 197 | hash2(), and it requires 198 | -- that all your machines be little-endian 199 | -------------------------------------------------------------------- 200 | */ 201 | 202 | ub4 hash3( k, length, initval) 203 | register ub1 *k; /* the key */ 204 | register ub4 length; /* the length of the key */ 205 | register ub4 initval; /* the previous hash, or an arbitrary value */ 206 | { 207 | register ub4 a,b,c,len; 208 | 209 | /* Set up the internal state */ 210 | len = length; 211 | a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ 212 | c = initval; /* the previous hash value */ 213 | 214 | /*---------------------------------------- handle most of the key */ 215 | if (((ub4)k)&3) 216 | { 217 | while (len >= 12) /* unaligned */ 218 | { 219 | a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); 220 | b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); 221 | c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); 222 | mix(a,b,c); 223 | k += 12; len -= 12; 224 | } 225 | } 226 | else 227 | { 228 | while (len >= 12) /* aligned */ 229 | { 230 | a += *(ub4 *)(k+0); 231 | b += *(ub4 *)(k+4); 232 | c += *(ub4 *)(k+8); 233 | mix(a,b,c); 234 | k += 12; len -= 12; 235 | } 236 | } 237 | 238 | /*------------------------------------- handle the last 11 bytes */ 239 | c += length; 240 | switch(len) /* all the case statements fall through */ 241 | { 242 | case 11: c+=((ub4)k[10]<<24); 243 | case 10: c+=((ub4)k[9]<<16); 244 | case 9 : c+=((ub4)k[8]<<8); 245 | /* the first byte of c is reserved for the length */ 246 | case 8 : b+=((ub4)k[7]<<24); 247 | case 7 : b+=((ub4)k[6]<<16); 248 | case 6 : b+=((ub4)k[5]<<8); 249 | case 5 : b+=k[4]; 250 | case 4 : a+=((ub4)k[3]<<24); 251 | case 3 : a+=((ub4)k[2]<<16); 252 | case 2 : a+=((ub4)k[1]<<8); 253 | case 1 : a+=k[0]; 254 | /* case 0: nothing left to add */ 255 | } 256 | mix(a,b,c); 257 | /*-------------------------------------------- report the result */ 258 | return c; 259 | } 260 | 261 | 262 | 263 | #ifdef SELF_TEST 264 | 265 | /* used for timings */ 266 | void driver1() 267 | { 268 | ub4 buf[256]; 269 | ub4 i; 270 | ub4 h=0; 271 | 272 | for (i=0; i<256; ++i) 273 | { 274 | h = hash(buf,i,h); 275 | } 276 | } 277 | 278 | /* check that every input bit changes every output bit half the time */ 279 | #define HASHSTATE 1 280 | #define HASHLEN 1 281 | #define MAXPAIR 80 282 | #define MAXLEN 70 283 | void driver2() 284 | { 285 | ub1 qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; 286 | ub4 c[HASHSTATE], d[HASHSTATE], i, j=0, k, l, m, z; 287 | ub4 e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; 288 | ub4 x[HASHSTATE],y[HASHSTATE]; 289 | ub4 hlen; 290 | 291 | printf("No more than %d trials should ever be needed \n",MAXPAIR/2); 292 | for (hlen=0; hlen < MAXLEN; ++hlen) 293 | { 294 | z=0; 295 | for (i=0; i>(8-j)); 312 | c[0] = hash(a, hlen, m); 313 | b[i] ^= ((k+1)<>(8-j)); 315 | d[0] = hash(b, hlen, m); 316 | /* check every bit is 1, 0, set, and not set at least once */ 317 | for (l=0; lz) z=k; 330 | if (k==MAXPAIR) 331 | { 332 | printf("Some bit didn't change: "); 333 | printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ", 334 | e[0],f[0],g[0],h[0],x[0],y[0]); 335 | printf("i %ld j %ld m %ld len %ld\n",i,j,m,hlen); 336 | } 337 | if (z==MAXPAIR) goto done; 338 | } 339 | } 340 | } 341 | done: 342 | if (z < MAXPAIR) 343 | { 344 | printf("Mix success %2ld bytes %2ld initvals ",i,m); 345 | printf("required %ld trials\n",z/2); 346 | } 347 | } 348 | printf("\n"); 349 | } 350 | 351 | /* Check for reading beyond the end of the buffer and alignment problems */ 352 | void driver3() 353 | { 354 | ub1 buf[MAXLEN+20], *b; 355 | ub4 len; 356 | ub1 q[] = "This is the time for all good men to come to the aid of their country"; 357 | ub1 qq[] = "xThis is the time for all good men to come to the aid of their country"; 358 | ub1 qqq[] = "xxThis is the time for all good men to come to the aid of their country"; 359 | ub1 qqqq[] = "xxxThis is the time for all good men to come to the aid of their country"; 360 | ub4 h,i,j,ref,x,y; 361 | 362 | printf("Endianness. These should all be the same:\n"); 363 | printf("%.8lx\n", hash(q, sizeof(q)-1, (ub4)0)); 364 | printf("%.8lx\n", hash(qq+1, sizeof(q)-1, (ub4)0)); 365 | printf("%.8lx\n", hash(qqq+2, sizeof(q)-1, (ub4)0)); 366 | printf("%.8lx\n", hash(qqqq+3, sizeof(q)-1, (ub4)0)); 367 | printf("\n"); 368 | for (h=0, b=buf+1; h<8; ++h, ++b) 369 | { 370 | for (i=0; i 21 | 22 | #ifndef _SHA_enum_ 23 | #define _SHA_enum_ 24 | enum 25 | { 26 | shaSuccess = 0, 27 | shaNull, /* Null pointer parameter */ 28 | shaInputTooLong, /* input data too long */ 29 | shaStateError /* called Input after Result */ 30 | }; 31 | #endif 32 | #define SHA1HashSize 20 33 | 34 | /* 35 | * This structure will hold context information for the SHA-1 36 | * hashing operation 37 | */ 38 | typedef struct SHA1Context 39 | { 40 | uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 41 | 42 | uint32_t Length_Low; /* Message length in bits */ 43 | uint32_t Length_High; /* Message length in bits */ 44 | 45 | /* Index into message block array */ 46 | int_least16_t Message_Block_Index; 47 | uint8_t Message_Block[64]; /* 512-bit message blocks */ 48 | 49 | int Computed; /* Is the digest computed? */ 50 | int Corrupted; /* Is the message digest corrupted? */ 51 | } SHA1Context; 52 | 53 | /* 54 | * Function Prototypes 55 | */ 56 | 57 | int SHA1Reset( SHA1Context *); 58 | int SHA1Input( SHA1Context *, 59 | const uint8_t *, 60 | unsigned int); 61 | int SHA1Result( SHA1Context *, 62 | uint8_t Message_Digest[SHA1HashSize]); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /minizip/ChangeLogUnzip: -------------------------------------------------------------------------------- 1 | Change in 1.01e (12 feb 05) 2 | - Fix in zipOpen2 for globalcomment (Rolf Kalbermatter) 3 | - Fix possible memory leak in unzip.c (Zoran Stevanovic) 4 | 5 | Change in 1.01b (20 may 04) 6 | - Integrate patch from Debian package (submited by Mark Brown) 7 | - Add tools mztools from Xavier Roche 8 | 9 | Change in 1.01 (8 may 04) 10 | - fix buffer overrun risk in unzip.c (Xavier Roche) 11 | - fix a minor buffer insecurity in minizip.c (Mike Whittaker) 12 | 13 | Change in 1.00: (10 sept 03) 14 | - rename to 1.00 15 | - cosmetic code change 16 | 17 | Change in 0.22: (19 May 03) 18 | - crypting support (unless you define NOCRYPT) 19 | - append file in existing zipfile 20 | 21 | Change in 0.21: (10 Mar 03) 22 | - bug fixes 23 | 24 | Change in 0.17: (27 Jan 02) 25 | - bug fixes 26 | 27 | Change in 0.16: (19 Jan 02) 28 | - Support of ioapi for virtualize zip file access 29 | 30 | Change in 0.15: (19 Mar 98) 31 | - fix memory leak in minizip.c 32 | 33 | Change in 0.14: (10 Mar 98) 34 | - fix bugs in minizip.c sample for zipping big file 35 | - fix problem in month in date handling 36 | - fix bug in unzlocal_GetCurrentFileInfoInternal in unzip.c for 37 | comment handling 38 | 39 | Change in 0.13: (6 Mar 98) 40 | - fix bugs in zip.c 41 | - add real minizip sample 42 | 43 | Change in 0.12: (4 Mar 98) 44 | - add zip.c and zip.h for creates .zip file 45 | - fix change_file_date in miniunz.c for Unix (Jean-loup Gailly) 46 | - fix miniunz.c for file without specific record for directory 47 | 48 | Change in 0.11: (3 Mar 98) 49 | - fix bug in unzGetCurrentFileInfo for get extra field and comment 50 | - enhance miniunz sample, remove the bad unztst.c sample 51 | 52 | Change in 0.10: (2 Mar 98) 53 | - fix bug in unzReadCurrentFile 54 | - rename unzip* to unz* function and structure 55 | - remove Windows-like hungary notation variable name 56 | - modify some structure in unzip.h 57 | - add somes comment in source 58 | - remove unzipGetcCurrentFile function 59 | - replace ZUNZEXPORT by ZEXPORT 60 | - add unzGetLocalExtrafield for get the local extrafield info 61 | - add a new sample, miniunz.c 62 | 63 | Change in 0.4: (25 Feb 98) 64 | - suppress the type unzipFileInZip. 65 | Only on file in the zipfile can be open at the same time 66 | - fix somes typo in code 67 | - added tm_unz structure in unzip_file_info (date/time in readable format) 68 | -------------------------------------------------------------------------------- /minizip/Makefile: -------------------------------------------------------------------------------- 1 | CC=cc 2 | CFLAGS=-O -I../.. 3 | 4 | UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a 5 | ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a 6 | 7 | .c.o: 8 | $(CC) -c $(CFLAGS) $*.c 9 | 10 | all: miniunz minizip 11 | 12 | miniunz: $(UNZ_OBJS) 13 | $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS) 14 | 15 | minizip: $(ZIP_OBJS) 16 | $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS) 17 | 18 | test: miniunz minizip 19 | ./minizip test readme.txt 20 | ./miniunz -l test.zip 21 | mv readme.txt readme.old 22 | ./miniunz test.zip 23 | 24 | clean: 25 | /bin/rm -f *.o *~ minizip miniunz 26 | -------------------------------------------------------------------------------- /minizip/crypt.h: -------------------------------------------------------------------------------- 1 | /* crypt.h -- base code for crypt/uncrypt ZIPfile 2 | 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | 8 | This code is a modified version of crypting code in Infozip distribution 9 | 10 | The encryption/decryption parts of this source code (as opposed to the 11 | non-echoing password parts) were originally written in Europe. The 12 | whole source package can be freely distributed, including from the USA. 13 | (Prior to January 2000, re-export from the US was a violation of US law.) 14 | 15 | This encryption code is a direct transcription of the algorithm from 16 | Roger Schlafly, described by Phil Katz in the file appnote.txt. This 17 | file (appnote.txt) is distributed with the PKZIP program (even in the 18 | version without encryption capabilities). 19 | 20 | If you don't need crypting in your application, just define symbols 21 | NOCRYPT and NOUNCRYPT. 22 | 23 | This code support the "Traditional PKWARE Encryption". 24 | 25 | The new AES encryption added on Zip format by Winzip (see the page 26 | http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong 27 | Encryption is not supported. 28 | */ 29 | 30 | #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) 31 | 32 | /*********************************************************************** 33 | * Return the next byte in the pseudo-random sequence 34 | */ 35 | static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) 36 | { 37 | unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an 38 | * unpredictable manner on 16-bit systems; not a problem 39 | * with any known compiler so far, though */ 40 | 41 | temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; 42 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); 43 | } 44 | 45 | /*********************************************************************** 46 | * Update the encryption keys with the next byte of plain text 47 | */ 48 | static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) 49 | { 50 | (*(pkeys+0)) = CRC32((*(pkeys+0)), c); 51 | (*(pkeys+1)) += (*(pkeys+0)) & 0xff; 52 | (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; 53 | { 54 | register int keyshift = (int)((*(pkeys+1)) >> 24); 55 | (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); 56 | } 57 | return c; 58 | } 59 | 60 | 61 | /*********************************************************************** 62 | * Initialize the encryption keys and the random header according to 63 | * the given password. 64 | */ 65 | static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) 66 | { 67 | *(pkeys+0) = 305419896L; 68 | *(pkeys+1) = 591751049L; 69 | *(pkeys+2) = 878082192L; 70 | while (*passwd != '\0') { 71 | update_keys(pkeys,pcrc_32_tab,(int)*passwd); 72 | passwd++; 73 | } 74 | } 75 | 76 | #define zdecode(pkeys,pcrc_32_tab,c) \ 77 | (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) 78 | 79 | #define zencode(pkeys,pcrc_32_tab,c,t) \ 80 | (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) 81 | 82 | #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED 83 | 84 | #define RAND_HEAD_LEN 12 85 | /* "last resort" source for second part of crypt seed pattern */ 86 | # ifndef ZCR_SEED2 87 | # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ 88 | # endif 89 | 90 | static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) 91 | const char *passwd; /* password string */ 92 | unsigned char *buf; /* where to write header */ 93 | int bufSize; 94 | unsigned long* pkeys; 95 | const unsigned long* pcrc_32_tab; 96 | unsigned long crcForCrypting; 97 | { 98 | int n; /* index in random header */ 99 | int t; /* temporary */ 100 | int c; /* random byte */ 101 | unsigned char header[RAND_HEAD_LEN-2]; /* random header */ 102 | static unsigned calls = 0; /* ensure different random header each time */ 103 | 104 | if (bufSize> 7) & 0xff; 119 | header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); 120 | } 121 | /* Encrypt random header (last two bytes is high word of crc) */ 122 | init_keys(passwd, pkeys, pcrc_32_tab); 123 | for (n = 0; n < RAND_HEAD_LEN-2; n++) 124 | { 125 | buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); 126 | } 127 | buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); 128 | buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); 129 | return n; 130 | } 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /minizip/ioapi.c: -------------------------------------------------------------------------------- 1 | /* ioapi.c -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "zlib.h" 14 | #include "ioapi.h" 15 | 16 | 17 | 18 | /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ 19 | 20 | #ifndef SEEK_CUR 21 | #define SEEK_CUR 1 22 | #endif 23 | 24 | #ifndef SEEK_END 25 | #define SEEK_END 2 26 | #endif 27 | 28 | #ifndef SEEK_SET 29 | #define SEEK_SET 0 30 | #endif 31 | 32 | voidpf ZCALLBACK fopen_file_func OF(( 33 | voidpf opaque, 34 | const char* filename, 35 | int mode)); 36 | 37 | uLong ZCALLBACK fread_file_func OF(( 38 | voidpf opaque, 39 | voidpf stream, 40 | void* buf, 41 | uLong size)); 42 | 43 | uLong ZCALLBACK fwrite_file_func OF(( 44 | voidpf opaque, 45 | voidpf stream, 46 | const void* buf, 47 | uLong size)); 48 | 49 | long ZCALLBACK ftell_file_func OF(( 50 | voidpf opaque, 51 | voidpf stream)); 52 | 53 | long ZCALLBACK fseek_file_func OF(( 54 | voidpf opaque, 55 | voidpf stream, 56 | uLong offset, 57 | int origin)); 58 | 59 | int ZCALLBACK fclose_file_func OF(( 60 | voidpf opaque, 61 | voidpf stream)); 62 | 63 | int ZCALLBACK ferror_file_func OF(( 64 | voidpf opaque, 65 | voidpf stream)); 66 | 67 | 68 | voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) 69 | voidpf opaque; 70 | const char* filename; 71 | int mode; 72 | { 73 | FILE* file = NULL; 74 | const char* mode_fopen = NULL; 75 | if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) 76 | mode_fopen = "rb"; 77 | else 78 | if (mode & ZLIB_FILEFUNC_MODE_EXISTING) 79 | mode_fopen = "r+b"; 80 | else 81 | if (mode & ZLIB_FILEFUNC_MODE_CREATE) 82 | mode_fopen = "wb"; 83 | 84 | if ((filename!=NULL) && (mode_fopen != NULL)) 85 | file = fopen(filename, mode_fopen); 86 | return file; 87 | } 88 | 89 | 90 | uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) 91 | voidpf opaque; 92 | voidpf stream; 93 | void* buf; 94 | uLong size; 95 | { 96 | uLong ret; 97 | ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); 98 | return ret; 99 | } 100 | 101 | 102 | uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) 103 | voidpf opaque; 104 | voidpf stream; 105 | const void* buf; 106 | uLong size; 107 | { 108 | uLong ret; 109 | ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); 110 | return ret; 111 | } 112 | 113 | long ZCALLBACK ftell_file_func (opaque, stream) 114 | voidpf opaque; 115 | voidpf stream; 116 | { 117 | long ret; 118 | ret = ftell((FILE *)stream); 119 | return ret; 120 | } 121 | 122 | long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) 123 | voidpf opaque; 124 | voidpf stream; 125 | uLong offset; 126 | int origin; 127 | { 128 | int fseek_origin=0; 129 | long ret; 130 | switch (origin) 131 | { 132 | case ZLIB_FILEFUNC_SEEK_CUR : 133 | fseek_origin = SEEK_CUR; 134 | break; 135 | case ZLIB_FILEFUNC_SEEK_END : 136 | fseek_origin = SEEK_END; 137 | break; 138 | case ZLIB_FILEFUNC_SEEK_SET : 139 | fseek_origin = SEEK_SET; 140 | break; 141 | default: return -1; 142 | } 143 | ret = 0; 144 | fseek((FILE *)stream, offset, fseek_origin); 145 | return ret; 146 | } 147 | 148 | int ZCALLBACK fclose_file_func (opaque, stream) 149 | voidpf opaque; 150 | voidpf stream; 151 | { 152 | int ret; 153 | ret = fclose((FILE *)stream); 154 | return ret; 155 | } 156 | 157 | int ZCALLBACK ferror_file_func (opaque, stream) 158 | voidpf opaque; 159 | voidpf stream; 160 | { 161 | int ret; 162 | ret = ferror((FILE *)stream); 163 | return ret; 164 | } 165 | 166 | void fill_fopen_filefunc (pzlib_filefunc_def) 167 | zlib_filefunc_def* pzlib_filefunc_def; 168 | { 169 | pzlib_filefunc_def->zopen_file = fopen_file_func; 170 | pzlib_filefunc_def->zread_file = fread_file_func; 171 | pzlib_filefunc_def->zwrite_file = fwrite_file_func; 172 | pzlib_filefunc_def->ztell_file = ftell_file_func; 173 | pzlib_filefunc_def->zseek_file = fseek_file_func; 174 | pzlib_filefunc_def->zclose_file = fclose_file_func; 175 | pzlib_filefunc_def->zerror_file = ferror_file_func; 176 | pzlib_filefunc_def->opaque = NULL; 177 | } 178 | -------------------------------------------------------------------------------- /minizip/ioapi.h: -------------------------------------------------------------------------------- 1 | /* ioapi.h -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | */ 8 | 9 | #ifndef _ZLIBIOAPI_H 10 | #define _ZLIBIOAPI_H 11 | 12 | 13 | #define ZLIB_FILEFUNC_SEEK_CUR (1) 14 | #define ZLIB_FILEFUNC_SEEK_END (2) 15 | #define ZLIB_FILEFUNC_SEEK_SET (0) 16 | 17 | #define ZLIB_FILEFUNC_MODE_READ (1) 18 | #define ZLIB_FILEFUNC_MODE_WRITE (2) 19 | #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) 20 | 21 | #define ZLIB_FILEFUNC_MODE_EXISTING (4) 22 | #define ZLIB_FILEFUNC_MODE_CREATE (8) 23 | 24 | 25 | #ifndef ZCALLBACK 26 | 27 | #if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) 28 | #define ZCALLBACK CALLBACK 29 | #else 30 | #define ZCALLBACK 31 | #endif 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); 39 | typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); 40 | typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); 41 | typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); 42 | typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); 43 | typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); 44 | typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); 45 | 46 | typedef struct zlib_filefunc_def_s 47 | { 48 | open_file_func zopen_file; 49 | read_file_func zread_file; 50 | write_file_func zwrite_file; 51 | tell_file_func ztell_file; 52 | seek_file_func zseek_file; 53 | close_file_func zclose_file; 54 | testerror_file_func zerror_file; 55 | voidpf opaque; 56 | } zlib_filefunc_def; 57 | 58 | 59 | 60 | void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); 61 | 62 | #define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) 63 | #define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) 64 | #define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) 65 | #define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) 66 | #define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) 67 | #define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) 68 | 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /minizip/iowin32.c: -------------------------------------------------------------------------------- 1 | /* iowin32.c -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | This IO API version uses the Win32 API (for Microsoft Windows) 4 | 5 | Version 1.01e, February 12th, 2005 6 | 7 | Copyright (C) 1998-2005 Gilles Vollant 8 | */ 9 | 10 | #include 11 | 12 | #include "zlib.h" 13 | #include "ioapi.h" 14 | #include "iowin32.h" 15 | 16 | #ifndef INVALID_HANDLE_VALUE 17 | #define INVALID_HANDLE_VALUE (0xFFFFFFFF) 18 | #endif 19 | 20 | #ifndef INVALID_SET_FILE_POINTER 21 | #define INVALID_SET_FILE_POINTER ((DWORD)-1) 22 | #endif 23 | 24 | voidpf ZCALLBACK win32_open_file_func OF(( 25 | voidpf opaque, 26 | const char* filename, 27 | int mode)); 28 | 29 | uLong ZCALLBACK win32_read_file_func OF(( 30 | voidpf opaque, 31 | voidpf stream, 32 | void* buf, 33 | uLong size)); 34 | 35 | uLong ZCALLBACK win32_write_file_func OF(( 36 | voidpf opaque, 37 | voidpf stream, 38 | const void* buf, 39 | uLong size)); 40 | 41 | long ZCALLBACK win32_tell_file_func OF(( 42 | voidpf opaque, 43 | voidpf stream)); 44 | 45 | long ZCALLBACK win32_seek_file_func OF(( 46 | voidpf opaque, 47 | voidpf stream, 48 | uLong offset, 49 | int origin)); 50 | 51 | int ZCALLBACK win32_close_file_func OF(( 52 | voidpf opaque, 53 | voidpf stream)); 54 | 55 | int ZCALLBACK win32_error_file_func OF(( 56 | voidpf opaque, 57 | voidpf stream)); 58 | 59 | typedef struct 60 | { 61 | HANDLE hf; 62 | int error; 63 | } WIN32FILE_IOWIN; 64 | 65 | voidpf ZCALLBACK win32_open_file_func (opaque, filename, mode) 66 | voidpf opaque; 67 | const char* filename; 68 | int mode; 69 | { 70 | const char* mode_fopen = NULL; 71 | DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; 72 | HANDLE hFile = 0; 73 | voidpf ret=NULL; 74 | 75 | dwDesiredAccess = dwShareMode = dwFlagsAndAttributes = 0; 76 | 77 | if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) 78 | { 79 | dwDesiredAccess = GENERIC_READ; 80 | dwCreationDisposition = OPEN_EXISTING; 81 | dwShareMode = FILE_SHARE_READ; 82 | } 83 | else 84 | if (mode & ZLIB_FILEFUNC_MODE_EXISTING) 85 | { 86 | dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; 87 | dwCreationDisposition = OPEN_EXISTING; 88 | } 89 | else 90 | if (mode & ZLIB_FILEFUNC_MODE_CREATE) 91 | { 92 | dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; 93 | dwCreationDisposition = CREATE_ALWAYS; 94 | } 95 | 96 | if ((filename!=NULL) && (dwDesiredAccess != 0)) 97 | hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, 98 | dwCreationDisposition, dwFlagsAndAttributes, NULL); 99 | 100 | if (hFile == INVALID_HANDLE_VALUE) 101 | hFile = NULL; 102 | 103 | if (hFile != NULL) 104 | { 105 | WIN32FILE_IOWIN w32fiow; 106 | w32fiow.hf = hFile; 107 | w32fiow.error = 0; 108 | ret = malloc(sizeof(WIN32FILE_IOWIN)); 109 | if (ret==NULL) 110 | CloseHandle(hFile); 111 | else *((WIN32FILE_IOWIN*)ret) = w32fiow; 112 | } 113 | return ret; 114 | } 115 | 116 | 117 | uLong ZCALLBACK win32_read_file_func (opaque, stream, buf, size) 118 | voidpf opaque; 119 | voidpf stream; 120 | void* buf; 121 | uLong size; 122 | { 123 | uLong ret=0; 124 | HANDLE hFile = NULL; 125 | if (stream!=NULL) 126 | hFile = ((WIN32FILE_IOWIN*)stream) -> hf; 127 | if (hFile != NULL) 128 | if (!ReadFile(hFile, buf, size, &ret, NULL)) 129 | { 130 | DWORD dwErr = GetLastError(); 131 | if (dwErr == ERROR_HANDLE_EOF) 132 | dwErr = 0; 133 | ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; 134 | } 135 | 136 | return ret; 137 | } 138 | 139 | 140 | uLong ZCALLBACK win32_write_file_func (opaque, stream, buf, size) 141 | voidpf opaque; 142 | voidpf stream; 143 | const void* buf; 144 | uLong size; 145 | { 146 | uLong ret=0; 147 | HANDLE hFile = NULL; 148 | if (stream!=NULL) 149 | hFile = ((WIN32FILE_IOWIN*)stream) -> hf; 150 | 151 | if (hFile !=NULL) 152 | if (!WriteFile(hFile, buf, size, &ret, NULL)) 153 | { 154 | DWORD dwErr = GetLastError(); 155 | if (dwErr == ERROR_HANDLE_EOF) 156 | dwErr = 0; 157 | ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; 158 | } 159 | 160 | return ret; 161 | } 162 | 163 | long ZCALLBACK win32_tell_file_func (opaque, stream) 164 | voidpf opaque; 165 | voidpf stream; 166 | { 167 | long ret=-1; 168 | HANDLE hFile = NULL; 169 | if (stream!=NULL) 170 | hFile = ((WIN32FILE_IOWIN*)stream) -> hf; 171 | if (hFile != NULL) 172 | { 173 | DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); 174 | if (dwSet == INVALID_SET_FILE_POINTER) 175 | { 176 | DWORD dwErr = GetLastError(); 177 | ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; 178 | ret = -1; 179 | } 180 | else 181 | ret=(long)dwSet; 182 | } 183 | return ret; 184 | } 185 | 186 | long ZCALLBACK win32_seek_file_func (opaque, stream, offset, origin) 187 | voidpf opaque; 188 | voidpf stream; 189 | uLong offset; 190 | int origin; 191 | { 192 | DWORD dwMoveMethod=0xFFFFFFFF; 193 | HANDLE hFile = NULL; 194 | 195 | long ret=-1; 196 | if (stream!=NULL) 197 | hFile = ((WIN32FILE_IOWIN*)stream) -> hf; 198 | switch (origin) 199 | { 200 | case ZLIB_FILEFUNC_SEEK_CUR : 201 | dwMoveMethod = FILE_CURRENT; 202 | break; 203 | case ZLIB_FILEFUNC_SEEK_END : 204 | dwMoveMethod = FILE_END; 205 | break; 206 | case ZLIB_FILEFUNC_SEEK_SET : 207 | dwMoveMethod = FILE_BEGIN; 208 | break; 209 | default: return -1; 210 | } 211 | 212 | if (hFile != NULL) 213 | { 214 | DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); 215 | if (dwSet == INVALID_SET_FILE_POINTER) 216 | { 217 | DWORD dwErr = GetLastError(); 218 | ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; 219 | ret = -1; 220 | } 221 | else 222 | ret=0; 223 | } 224 | return ret; 225 | } 226 | 227 | int ZCALLBACK win32_close_file_func (opaque, stream) 228 | voidpf opaque; 229 | voidpf stream; 230 | { 231 | int ret=-1; 232 | 233 | if (stream!=NULL) 234 | { 235 | HANDLE hFile; 236 | hFile = ((WIN32FILE_IOWIN*)stream) -> hf; 237 | if (hFile != NULL) 238 | { 239 | CloseHandle(hFile); 240 | ret=0; 241 | } 242 | free(stream); 243 | } 244 | return ret; 245 | } 246 | 247 | int ZCALLBACK win32_error_file_func (opaque, stream) 248 | voidpf opaque; 249 | voidpf stream; 250 | { 251 | int ret=-1; 252 | if (stream!=NULL) 253 | { 254 | ret = ((WIN32FILE_IOWIN*)stream) -> error; 255 | } 256 | return ret; 257 | } 258 | 259 | void fill_win32_filefunc (pzlib_filefunc_def) 260 | zlib_filefunc_def* pzlib_filefunc_def; 261 | { 262 | pzlib_filefunc_def->zopen_file = win32_open_file_func; 263 | pzlib_filefunc_def->zread_file = win32_read_file_func; 264 | pzlib_filefunc_def->zwrite_file = win32_write_file_func; 265 | pzlib_filefunc_def->ztell_file = win32_tell_file_func; 266 | pzlib_filefunc_def->zseek_file = win32_seek_file_func; 267 | pzlib_filefunc_def->zclose_file = win32_close_file_func; 268 | pzlib_filefunc_def->zerror_file = win32_error_file_func; 269 | pzlib_filefunc_def->opaque=NULL; 270 | } 271 | -------------------------------------------------------------------------------- /minizip/iowin32.h: -------------------------------------------------------------------------------- 1 | /* iowin32.h -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | This IO API version uses the Win32 API (for Microsoft Windows) 4 | 5 | Version 1.01e, February 12th, 2005 6 | 7 | Copyright (C) 1998-2005 Gilles Vollant 8 | */ 9 | 10 | #include 11 | 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /minizip/miniunz.c: -------------------------------------------------------------------------------- 1 | /* 2 | miniunz.c 3 | Version 1.01e, February 12th, 2005 4 | 5 | Copyright (C) 1998-2005 Gilles Vollant 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef unix 17 | # include 18 | # include 19 | #else 20 | # include 21 | # include 22 | #endif 23 | 24 | #include "unzip.h" 25 | 26 | #define CASESENSITIVITY (0) 27 | #define WRITEBUFFERSIZE (8192) 28 | #define MAXFILENAME (256) 29 | 30 | #ifdef WIN32 31 | #define USEWIN32IOAPI 32 | #include "iowin32.h" 33 | #endif 34 | /* 35 | mini unzip, demo of unzip package 36 | 37 | usage : 38 | Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] 39 | 40 | list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT 41 | if it exists 42 | */ 43 | 44 | 45 | /* change_file_date : change the date/time of a file 46 | filename : the filename of the file where date/time must be modified 47 | dosdate : the new date at the MSDos format (4 bytes) 48 | tmu_date : the SAME new date at the tm_unz format */ 49 | void change_file_date(filename,dosdate,tmu_date) 50 | const char *filename; 51 | uLong dosdate; 52 | tm_unz tmu_date; 53 | { 54 | #ifdef WIN32 55 | HANDLE hFile; 56 | FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; 57 | 58 | hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE, 59 | 0,NULL,OPEN_EXISTING,0,NULL); 60 | GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); 61 | DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); 62 | LocalFileTimeToFileTime(&ftLocal,&ftm); 63 | SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); 64 | CloseHandle(hFile); 65 | #else 66 | #ifdef unix 67 | struct utimbuf ut; 68 | struct tm newdate; 69 | newdate.tm_sec = tmu_date.tm_sec; 70 | newdate.tm_min=tmu_date.tm_min; 71 | newdate.tm_hour=tmu_date.tm_hour; 72 | newdate.tm_mday=tmu_date.tm_mday; 73 | newdate.tm_mon=tmu_date.tm_mon; 74 | if (tmu_date.tm_year > 1900) 75 | newdate.tm_year=tmu_date.tm_year - 1900; 76 | else 77 | newdate.tm_year=tmu_date.tm_year ; 78 | newdate.tm_isdst=-1; 79 | 80 | ut.actime=ut.modtime=mktime(&newdate); 81 | utime(filename,&ut); 82 | #endif 83 | #endif 84 | } 85 | 86 | 87 | /* mymkdir and change_file_date are not 100 % portable 88 | As I don't know well Unix, I wait feedback for the unix portion */ 89 | 90 | int mymkdir(dirname) 91 | const char* dirname; 92 | { 93 | int ret=0; 94 | #ifdef WIN32 95 | ret = mkdir(dirname); 96 | #else 97 | #ifdef unix 98 | ret = mkdir (dirname,0775); 99 | #endif 100 | #endif 101 | return ret; 102 | } 103 | 104 | int makedir (newdir) 105 | char *newdir; 106 | { 107 | char *buffer ; 108 | char *p; 109 | int len = (int)strlen(newdir); 110 | 111 | if (len <= 0) 112 | return 0; 113 | 114 | buffer = (char*)malloc(len+1); 115 | strcpy(buffer,newdir); 116 | 117 | if (buffer[len-1] == '/') { 118 | buffer[len-1] = '\0'; 119 | } 120 | if (mymkdir(buffer) == 0) 121 | { 122 | free(buffer); 123 | return 1; 124 | } 125 | 126 | p = buffer+1; 127 | while (1) 128 | { 129 | char hold; 130 | 131 | while(*p && *p != '\\' && *p != '/') 132 | p++; 133 | hold = *p; 134 | *p = 0; 135 | if ((mymkdir(buffer) == -1) && (errno == ENOENT)) 136 | { 137 | printf("couldn't create directory %s\n",buffer); 138 | free(buffer); 139 | return 0; 140 | } 141 | if (hold == 0) 142 | break; 143 | *p++ = hold; 144 | } 145 | free(buffer); 146 | return 1; 147 | } 148 | 149 | void do_banner() 150 | { 151 | printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); 152 | printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); 153 | } 154 | 155 | void do_help() 156 | { 157 | printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ 158 | " -e Extract without pathname (junk paths)\n" \ 159 | " -x Extract with pathname\n" \ 160 | " -v list files\n" \ 161 | " -l list files\n" \ 162 | " -d directory to extract into\n" \ 163 | " -o overwrite files without prompting\n" \ 164 | " -p extract crypted file using password\n\n"); 165 | } 166 | 167 | 168 | int do_list(uf) 169 | unzFile uf; 170 | { 171 | uLong i; 172 | unz_global_info gi; 173 | int err; 174 | 175 | err = unzGetGlobalInfo (uf,&gi); 176 | if (err!=UNZ_OK) 177 | printf("error %d with zipfile in unzGetGlobalInfo \n",err); 178 | printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); 179 | printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); 180 | for (i=0;i0) 194 | ratio = (file_info.compressed_size*100)/file_info.uncompressed_size; 195 | 196 | /* display a '*' if the file is crypted */ 197 | if ((file_info.flag & 1) != 0) 198 | charCrypt='*'; 199 | 200 | if (file_info.compression_method==0) 201 | string_method="Stored"; 202 | else 203 | if (file_info.compression_method==Z_DEFLATED) 204 | { 205 | uInt iLevel=(uInt)((file_info.flag & 0x6)/2); 206 | if (iLevel==0) 207 | string_method="Defl:N"; 208 | else if (iLevel==1) 209 | string_method="Defl:X"; 210 | else if ((iLevel==2) || (iLevel==3)) 211 | string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ 212 | } 213 | else 214 | string_method="Unkn. "; 215 | 216 | printf("%7lu %6s%c%7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", 217 | file_info.uncompressed_size,string_method, 218 | charCrypt, 219 | file_info.compressed_size, 220 | ratio, 221 | (uLong)file_info.tmu_date.tm_mon + 1, 222 | (uLong)file_info.tmu_date.tm_mday, 223 | (uLong)file_info.tmu_date.tm_year % 100, 224 | (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, 225 | (uLong)file_info.crc,filename_inzip); 226 | if ((i+1)='a') && (rep<='z')) 326 | rep -= 0x20; 327 | } 328 | while ((rep!='Y') && (rep!='N') && (rep!='A')); 329 | } 330 | 331 | if (rep == 'N') 332 | skip = 1; 333 | 334 | if (rep == 'A') 335 | *popt_overwrite=1; 336 | } 337 | 338 | if ((skip==0) && (err==UNZ_OK)) 339 | { 340 | fout=fopen(write_filename,"wb"); 341 | 342 | /* some zipfile don't contain directory alone before file */ 343 | if ((fout==NULL) && ((*popt_extract_without_path)==0) && 344 | (filename_withoutpath!=(char*)filename_inzip)) 345 | { 346 | char c=*(filename_withoutpath-1); 347 | *(filename_withoutpath-1)='\0'; 348 | makedir(write_filename); 349 | *(filename_withoutpath-1)=c; 350 | fout=fopen(write_filename,"wb"); 351 | } 352 | 353 | if (fout==NULL) 354 | { 355 | printf("error opening %s\n",write_filename); 356 | } 357 | } 358 | 359 | if (fout!=NULL) 360 | { 361 | printf(" extracting: %s\n",write_filename); 362 | 363 | do 364 | { 365 | err = unzReadCurrentFile(uf,buf,size_buf); 366 | if (err<0) 367 | { 368 | printf("error %d with zipfile in unzReadCurrentFile\n",err); 369 | break; 370 | } 371 | if (err>0) 372 | if (fwrite(buf,err,1,fout)!=1) 373 | { 374 | printf("error in writing extracted file\n"); 375 | err=UNZ_ERRNO; 376 | break; 377 | } 378 | } 379 | while (err>0); 380 | if (fout) 381 | fclose(fout); 382 | 383 | if (err==0) 384 | change_file_date(write_filename,file_info.dosDate, 385 | file_info.tmu_date); 386 | } 387 | 388 | if (err==UNZ_OK) 389 | { 390 | err = unzCloseCurrentFile (uf); 391 | if (err!=UNZ_OK) 392 | { 393 | printf("error %d with zipfile in unzCloseCurrentFile\n",err); 394 | } 395 | } 396 | else 397 | unzCloseCurrentFile(uf); /* don't lose the error */ 398 | } 399 | 400 | free(buf); 401 | return err; 402 | } 403 | 404 | 405 | int do_extract(uf,opt_extract_without_path,opt_overwrite,password) 406 | unzFile uf; 407 | int opt_extract_without_path; 408 | int opt_overwrite; 409 | const char* password; 410 | { 411 | uLong i; 412 | unz_global_info gi; 413 | int err; 414 | FILE* fout=NULL; 415 | 416 | err = unzGetGlobalInfo (uf,&gi); 417 | if (err!=UNZ_OK) 418 | printf("error %d with zipfile in unzGetGlobalInfo \n",err); 419 | 420 | for (i=0;i 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef unix 16 | # include 17 | # include 18 | # include 19 | # include 20 | #else 21 | # include 22 | # include 23 | #endif 24 | 25 | #include "zip.h" 26 | 27 | #ifdef WIN32 28 | #define USEWIN32IOAPI 29 | #include "iowin32.h" 30 | #endif 31 | 32 | 33 | 34 | #define WRITEBUFFERSIZE (16384) 35 | #define MAXFILENAME (256) 36 | 37 | #ifdef WIN32 38 | uLong filetime(f, tmzip, dt) 39 | char *f; /* name of file to get info on */ 40 | tm_zip *tmzip; /* return value: access, modific. and creation times */ 41 | uLong *dt; /* dostime */ 42 | { 43 | int ret = 0; 44 | { 45 | FILETIME ftLocal; 46 | HANDLE hFind; 47 | WIN32_FIND_DATA ff32; 48 | 49 | hFind = FindFirstFile(f,&ff32); 50 | if (hFind != INVALID_HANDLE_VALUE) 51 | { 52 | FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); 53 | FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); 54 | FindClose(hFind); 55 | ret = 1; 56 | } 57 | } 58 | return ret; 59 | } 60 | #else 61 | #ifdef unix 62 | uLong filetime(f, tmzip, dt) 63 | char *f; /* name of file to get info on */ 64 | tm_zip *tmzip; /* return value: access, modific. and creation times */ 65 | uLong *dt; /* dostime */ 66 | { 67 | int ret=0; 68 | struct stat s; /* results of stat() */ 69 | struct tm* filedate; 70 | time_t tm_t=0; 71 | 72 | if (strcmp(f,"-")!=0) 73 | { 74 | char name[MAXFILENAME+1]; 75 | int len = strlen(f); 76 | if (len > MAXFILENAME) 77 | len = MAXFILENAME; 78 | 79 | strncpy(name, f,MAXFILENAME-1); 80 | /* strncpy doesnt append the trailing NULL, of the string is too long. */ 81 | name[ MAXFILENAME ] = '\0'; 82 | 83 | if (name[len - 1] == '/') 84 | name[len - 1] = '\0'; 85 | /* not all systems allow stat'ing a file with / appended */ 86 | if (stat(name,&s)==0) 87 | { 88 | tm_t = s.st_mtime; 89 | ret = 1; 90 | } 91 | } 92 | filedate = localtime(&tm_t); 93 | 94 | tmzip->tm_sec = filedate->tm_sec; 95 | tmzip->tm_min = filedate->tm_min; 96 | tmzip->tm_hour = filedate->tm_hour; 97 | tmzip->tm_mday = filedate->tm_mday; 98 | tmzip->tm_mon = filedate->tm_mon ; 99 | tmzip->tm_year = filedate->tm_year; 100 | 101 | return ret; 102 | } 103 | #else 104 | uLong filetime(f, tmzip, dt) 105 | char *f; /* name of file to get info on */ 106 | tm_zip *tmzip; /* return value: access, modific. and creation times */ 107 | uLong *dt; /* dostime */ 108 | { 109 | return 0; 110 | } 111 | #endif 112 | #endif 113 | 114 | 115 | 116 | 117 | int check_exist_file(filename) 118 | const char* filename; 119 | { 120 | FILE* ftestexist; 121 | int ret = 1; 122 | ftestexist = fopen(filename,"rb"); 123 | if (ftestexist==NULL) 124 | ret = 0; 125 | else 126 | fclose(ftestexist); 127 | return ret; 128 | } 129 | 130 | void do_banner() 131 | { 132 | printf("MiniZip 1.01b, demo of zLib + Zip package written by Gilles Vollant\n"); 133 | printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); 134 | } 135 | 136 | void do_help() 137 | { 138 | printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] file.zip [files_to_add]\n\n" \ 139 | " -o Overwrite existing file.zip\n" \ 140 | " -a Append to existing file.zip\n" \ 141 | " -0 Store only\n" \ 142 | " -1 Compress faster\n" \ 143 | " -9 Compress better\n\n"); 144 | } 145 | 146 | /* calculate the CRC32 of a file, 147 | because to encrypt a file, we need known the CRC32 of the file before */ 148 | int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) 149 | { 150 | unsigned long calculate_crc=0; 151 | int err=ZIP_OK; 152 | FILE * fin = fopen(filenameinzip,"rb"); 153 | unsigned long size_read = 0; 154 | unsigned long total_read = 0; 155 | if (fin==NULL) 156 | { 157 | err = ZIP_ERRNO; 158 | } 159 | 160 | if (err == ZIP_OK) 161 | do 162 | { 163 | err = ZIP_OK; 164 | size_read = (int)fread(buf,1,size_buf,fin); 165 | if (size_read < size_buf) 166 | if (feof(fin)==0) 167 | { 168 | printf("error in reading %s\n",filenameinzip); 169 | err = ZIP_ERRNO; 170 | } 171 | 172 | if (size_read>0) 173 | calculate_crc = crc32(calculate_crc,buf,size_read); 174 | total_read += size_read; 175 | 176 | } while ((err == ZIP_OK) && (size_read>0)); 177 | 178 | if (fin) 179 | fclose(fin); 180 | 181 | *result_crc=calculate_crc; 182 | printf("file %s crc %x\n",filenameinzip,calculate_crc); 183 | return err; 184 | } 185 | 186 | int main(argc,argv) 187 | int argc; 188 | char *argv[]; 189 | { 190 | int i; 191 | int opt_overwrite=0; 192 | int opt_compress_level=Z_DEFAULT_COMPRESSION; 193 | int zipfilenamearg = 0; 194 | char filename_try[MAXFILENAME+16]; 195 | int zipok; 196 | int err=0; 197 | int size_buf=0; 198 | void* buf=NULL; 199 | const char* password=NULL; 200 | 201 | 202 | do_banner(); 203 | if (argc==1) 204 | { 205 | do_help(); 206 | return 0; 207 | } 208 | else 209 | { 210 | for (i=1;i='0') && (c<='9')) 224 | opt_compress_level = c-'0'; 225 | 226 | if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) 290 | rep -= 0x20; 291 | } 292 | while ((rep!='Y') && (rep!='N') && (rep!='A')); 293 | if (rep=='N') 294 | zipok = 0; 295 | if (rep=='A') 296 | opt_overwrite = 2; 297 | } 298 | } 299 | 300 | if (zipok==1) 301 | { 302 | zipFile zf; 303 | int errclose; 304 | # ifdef USEWIN32IOAPI 305 | zlib_filefunc_def ffunc; 306 | fill_win32_filefunc(&ffunc); 307 | zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); 308 | # else 309 | zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0); 310 | # endif 311 | 312 | if (zf == NULL) 313 | { 314 | printf("error opening %s\n",filename_try); 315 | err= ZIP_ERRNO; 316 | } 317 | else 318 | printf("creating %s\n",filename_try); 319 | 320 | for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && 327 | (strlen(argv[i]) == 2))) 328 | { 329 | FILE * fin; 330 | int size_read; 331 | const char* filenameinzip = argv[i]; 332 | zip_fileinfo zi; 333 | unsigned long crcFile=0; 334 | 335 | zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = 336 | zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; 337 | zi.dosDate = 0; 338 | zi.internal_fa = 0; 339 | zi.external_fa = 0; 340 | filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); 341 | 342 | /* 343 | err = zipOpenNewFileInZip(zf,filenameinzip,&zi, 344 | NULL,0,NULL,0,NULL / * comment * /, 345 | (opt_compress_level != 0) ? Z_DEFLATED : 0, 346 | opt_compress_level); 347 | */ 348 | if ((password != NULL) && (err==ZIP_OK)) 349 | err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); 350 | 351 | err = zipOpenNewFileInZip3(zf,filenameinzip,&zi, 352 | NULL,0,NULL,0,NULL /* comment*/, 353 | (opt_compress_level != 0) ? Z_DEFLATED : 0, 354 | opt_compress_level,0, 355 | /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ 356 | -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, 357 | password,crcFile); 358 | 359 | if (err != ZIP_OK) 360 | printf("error in opening %s in zipfile\n",filenameinzip); 361 | else 362 | { 363 | fin = fopen(filenameinzip,"rb"); 364 | if (fin==NULL) 365 | { 366 | err=ZIP_ERRNO; 367 | printf("error in opening %s for reading\n",filenameinzip); 368 | } 369 | } 370 | 371 | if (err == ZIP_OK) 372 | do 373 | { 374 | err = ZIP_OK; 375 | size_read = (int)fread(buf,1,size_buf,fin); 376 | if (size_read < size_buf) 377 | if (feof(fin)==0) 378 | { 379 | printf("error in reading %s\n",filenameinzip); 380 | err = ZIP_ERRNO; 381 | } 382 | 383 | if (size_read>0) 384 | { 385 | err = zipWriteInFileInZip (zf,buf,size_read); 386 | if (err<0) 387 | { 388 | printf("error in writing %s in the zipfile\n", 389 | filenameinzip); 390 | } 391 | 392 | } 393 | } while ((err == ZIP_OK) && (size_read>0)); 394 | 395 | if (fin) 396 | fclose(fin); 397 | 398 | if (err<0) 399 | err=ZIP_ERRNO; 400 | else 401 | { 402 | err = zipCloseFileInZip(zf); 403 | if (err!=ZIP_OK) 404 | printf("error in closing %s in the zipfile\n", 405 | filenameinzip); 406 | } 407 | } 408 | } 409 | errclose = zipClose(zf,NULL); 410 | if (errclose != ZIP_OK) 411 | printf("error in closing %s\n",filename_try); 412 | } 413 | else 414 | { 415 | do_help(); 416 | } 417 | 418 | free(buf); 419 | return 0; 420 | } 421 | -------------------------------------------------------------------------------- /minizip/mztools.c: -------------------------------------------------------------------------------- 1 | /* 2 | Additional tools for Minizip 3 | Code: Xavier Roche '2004 4 | License: Same as ZLIB (www.gzip.org) 5 | */ 6 | 7 | /* Code */ 8 | #include 9 | #include 10 | #include 11 | #include "zlib.h" 12 | #include "unzip.h" 13 | 14 | #define READ_8(adr) ((unsigned char)*(adr)) 15 | #define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) 16 | #define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) 17 | 18 | #define WRITE_8(buff, n) do { \ 19 | *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ 20 | } while(0) 21 | #define WRITE_16(buff, n) do { \ 22 | WRITE_8((unsigned char*)(buff), n); \ 23 | WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ 24 | } while(0) 25 | #define WRITE_32(buff, n) do { \ 26 | WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ 27 | WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ 28 | } while(0) 29 | 30 | extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) 31 | const char* file; 32 | const char* fileOut; 33 | const char* fileOutTmp; 34 | uLong* nRecovered; 35 | uLong* bytesRecovered; 36 | { 37 | int err = Z_OK; 38 | FILE* fpZip = fopen(file, "rb"); 39 | FILE* fpOut = fopen(fileOut, "wb"); 40 | FILE* fpOutCD = fopen(fileOutTmp, "wb"); 41 | if (fpZip != NULL && fpOut != NULL) { 42 | int entries = 0; 43 | uLong totalBytes = 0; 44 | char header[30]; 45 | char filename[256]; 46 | char extra[1024]; 47 | int offset = 0; 48 | int offsetCD = 0; 49 | while ( fread(header, 1, 30, fpZip) == 30 ) { 50 | int currentOffset = offset; 51 | 52 | /* File entry */ 53 | if (READ_32(header) == 0x04034b50) { 54 | unsigned int version = READ_16(header + 4); 55 | unsigned int gpflag = READ_16(header + 6); 56 | unsigned int method = READ_16(header + 8); 57 | unsigned int filetime = READ_16(header + 10); 58 | unsigned int filedate = READ_16(header + 12); 59 | unsigned int crc = READ_32(header + 14); /* crc */ 60 | unsigned int cpsize = READ_32(header + 18); /* compressed size */ 61 | unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ 62 | unsigned int fnsize = READ_16(header + 26); /* file name length */ 63 | unsigned int extsize = READ_16(header + 28); /* extra field length */ 64 | filename[0] = extra[0] = '\0'; 65 | 66 | /* Header */ 67 | if (fwrite(header, 1, 30, fpOut) == 30) { 68 | offset += 30; 69 | } else { 70 | err = Z_ERRNO; 71 | break; 72 | } 73 | 74 | /* Filename */ 75 | if (fnsize > 0) { 76 | if (fread(filename, 1, fnsize, fpZip) == fnsize) { 77 | if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { 78 | offset += fnsize; 79 | } else { 80 | err = Z_ERRNO; 81 | break; 82 | } 83 | } else { 84 | err = Z_ERRNO; 85 | break; 86 | } 87 | } else { 88 | err = Z_STREAM_ERROR; 89 | break; 90 | } 91 | 92 | /* Extra field */ 93 | if (extsize > 0) { 94 | if (fread(extra, 1, extsize, fpZip) == extsize) { 95 | if (fwrite(extra, 1, extsize, fpOut) == extsize) { 96 | offset += extsize; 97 | } else { 98 | err = Z_ERRNO; 99 | break; 100 | } 101 | } else { 102 | err = Z_ERRNO; 103 | break; 104 | } 105 | } 106 | 107 | /* Data */ 108 | { 109 | int dataSize = cpsize; 110 | if (dataSize == 0) { 111 | dataSize = uncpsize; 112 | } 113 | if (dataSize > 0) { 114 | char* data = malloc(dataSize); 115 | if (data != NULL) { 116 | if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { 117 | if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { 118 | offset += dataSize; 119 | totalBytes += dataSize; 120 | } else { 121 | err = Z_ERRNO; 122 | } 123 | } else { 124 | err = Z_ERRNO; 125 | } 126 | free(data); 127 | if (err != Z_OK) { 128 | break; 129 | } 130 | } else { 131 | err = Z_MEM_ERROR; 132 | break; 133 | } 134 | } 135 | } 136 | 137 | /* Central directory entry */ 138 | { 139 | char header[46]; 140 | char* comment = ""; 141 | int comsize = (int) strlen(comment); 142 | WRITE_32(header, 0x02014b50); 143 | WRITE_16(header + 4, version); 144 | WRITE_16(header + 6, version); 145 | WRITE_16(header + 8, gpflag); 146 | WRITE_16(header + 10, method); 147 | WRITE_16(header + 12, filetime); 148 | WRITE_16(header + 14, filedate); 149 | WRITE_32(header + 16, crc); 150 | WRITE_32(header + 20, cpsize); 151 | WRITE_32(header + 24, uncpsize); 152 | WRITE_16(header + 28, fnsize); 153 | WRITE_16(header + 30, extsize); 154 | WRITE_16(header + 32, comsize); 155 | WRITE_16(header + 34, 0); /* disk # */ 156 | WRITE_16(header + 36, 0); /* int attrb */ 157 | WRITE_32(header + 38, 0); /* ext attrb */ 158 | WRITE_32(header + 42, currentOffset); 159 | /* Header */ 160 | if (fwrite(header, 1, 46, fpOutCD) == 46) { 161 | offsetCD += 46; 162 | 163 | /* Filename */ 164 | if (fnsize > 0) { 165 | if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { 166 | offsetCD += fnsize; 167 | } else { 168 | err = Z_ERRNO; 169 | break; 170 | } 171 | } else { 172 | err = Z_STREAM_ERROR; 173 | break; 174 | } 175 | 176 | /* Extra field */ 177 | if (extsize > 0) { 178 | if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { 179 | offsetCD += extsize; 180 | } else { 181 | err = Z_ERRNO; 182 | break; 183 | } 184 | } 185 | 186 | /* Comment field */ 187 | if (comsize > 0) { 188 | if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { 189 | offsetCD += comsize; 190 | } else { 191 | err = Z_ERRNO; 192 | break; 193 | } 194 | } 195 | 196 | 197 | } else { 198 | err = Z_ERRNO; 199 | break; 200 | } 201 | } 202 | 203 | /* Success */ 204 | entries++; 205 | 206 | } else { 207 | break; 208 | } 209 | } 210 | 211 | /* Final central directory */ 212 | { 213 | int entriesZip = entries; 214 | char header[22]; 215 | char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; 216 | int comsize = (int) strlen(comment); 217 | if (entriesZip > 0xffff) { 218 | entriesZip = 0xffff; 219 | } 220 | WRITE_32(header, 0x06054b50); 221 | WRITE_16(header + 4, 0); /* disk # */ 222 | WRITE_16(header + 6, 0); /* disk # */ 223 | WRITE_16(header + 8, entriesZip); /* hack */ 224 | WRITE_16(header + 10, entriesZip); /* hack */ 225 | WRITE_32(header + 12, offsetCD); /* size of CD */ 226 | WRITE_32(header + 16, offset); /* offset to CD */ 227 | WRITE_16(header + 20, comsize); /* comment */ 228 | 229 | /* Header */ 230 | if (fwrite(header, 1, 22, fpOutCD) == 22) { 231 | 232 | /* Comment field */ 233 | if (comsize > 0) { 234 | if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { 235 | err = Z_ERRNO; 236 | } 237 | } 238 | 239 | } else { 240 | err = Z_ERRNO; 241 | } 242 | } 243 | 244 | /* Final merge (file + central directory) */ 245 | fclose(fpOutCD); 246 | if (err == Z_OK) { 247 | fpOutCD = fopen(fileOutTmp, "rb"); 248 | if (fpOutCD != NULL) { 249 | int nRead; 250 | char buffer[8192]; 251 | while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { 252 | if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { 253 | err = Z_ERRNO; 254 | break; 255 | } 256 | } 257 | fclose(fpOutCD); 258 | } 259 | } 260 | 261 | /* Close */ 262 | fclose(fpZip); 263 | fclose(fpOut); 264 | 265 | /* Wipe temporary file */ 266 | (void)remove(fileOutTmp); 267 | 268 | /* Number of recovered entries */ 269 | if (err == Z_OK) { 270 | if (nRecovered != NULL) { 271 | *nRecovered = entries; 272 | } 273 | if (bytesRecovered != NULL) { 274 | *bytesRecovered = totalBytes; 275 | } 276 | } 277 | } else { 278 | err = Z_STREAM_ERROR; 279 | } 280 | return err; 281 | } 282 | -------------------------------------------------------------------------------- /minizip/mztools.h: -------------------------------------------------------------------------------- 1 | /* 2 | Additional tools for Minizip 3 | Code: Xavier Roche '2004 4 | License: Same as ZLIB (www.gzip.org) 5 | */ 6 | 7 | #ifndef _zip_tools_H 8 | #define _zip_tools_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #ifndef _ZLIB_H 15 | #include "zlib.h" 16 | #endif 17 | 18 | #include "unzip.h" 19 | 20 | /* Repair a ZIP file (missing central directory) 21 | file: file to recover 22 | fileOut: output file after recovery 23 | fileOutTmp: temporary file name used for recovery 24 | */ 25 | extern int ZEXPORT unzRepair(const char* file, 26 | const char* fileOut, 27 | const char* fileOutTmp, 28 | uLong* nRecovered, 29 | uLong* bytesRecovered); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /minizip/unzip.h: -------------------------------------------------------------------------------- 1 | /* unzip.h -- IO for uncompress .zip files using zlib 2 | Version 1.01e, February 12th, 2005 3 | 4 | Copyright (C) 1998-2005 Gilles Vollant 5 | 6 | This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g 7 | WinZip, InfoZip tools and compatible. 8 | 9 | Multi volume ZipFile (span) are not supported. 10 | Encryption compatible with pkzip 2.04g only supported 11 | Old compressions used by old PKZip 1.x are not supported 12 | 13 | 14 | I WAIT FEEDBACK at mail info@winimage.com 15 | Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution 16 | 17 | Condition of use and distribution are the same than zlib : 18 | 19 | This software is provided 'as-is', without any express or implied 20 | warranty. In no event will the authors be held liable for any damages 21 | arising from the use of this software. 22 | 23 | Permission is granted to anyone to use this software for any purpose, 24 | including commercial applications, and to alter it and redistribute it 25 | freely, subject to the following restrictions: 26 | 27 | 1. The origin of this software must not be misrepresented; you must not 28 | claim that you wrote the original software. If you use this software 29 | in a product, an acknowledgment in the product documentation would be 30 | appreciated but is not required. 31 | 2. Altered source versions must be plainly marked as such, and must not be 32 | misrepresented as being the original software. 33 | 3. This notice may not be removed or altered from any source distribution. 34 | 35 | 36 | */ 37 | 38 | /* for more info about .ZIP format, see 39 | http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip 40 | http://www.info-zip.org/pub/infozip/doc/ 41 | PkWare has also a specification at : 42 | ftp://ftp.pkware.com/probdesc.zip 43 | */ 44 | 45 | #ifndef _unz_H 46 | #define _unz_H 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | #ifndef _ZLIB_H 53 | #include "zlib.h" 54 | #endif 55 | 56 | #ifndef _ZLIBIOAPI_H 57 | #include "ioapi.h" 58 | #endif 59 | 60 | #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) 61 | /* like the STRICT of WIN32, we define a pointer that cannot be converted 62 | from (void*) without cast */ 63 | typedef struct TagunzFile__ { int unused; } unzFile__; 64 | typedef unzFile__ *unzFile; 65 | #else 66 | typedef voidp unzFile; 67 | #endif 68 | 69 | 70 | #define UNZ_OK (0) 71 | #define UNZ_END_OF_LIST_OF_FILE (-100) 72 | #define UNZ_ERRNO (Z_ERRNO) 73 | #define UNZ_EOF (0) 74 | #define UNZ_PARAMERROR (-102) 75 | #define UNZ_BADZIPFILE (-103) 76 | #define UNZ_INTERNALERROR (-104) 77 | #define UNZ_CRCERROR (-105) 78 | 79 | /* tm_unz contain date/time info */ 80 | typedef struct tm_unz_s 81 | { 82 | uInt tm_sec; /* seconds after the minute - [0,59] */ 83 | uInt tm_min; /* minutes after the hour - [0,59] */ 84 | uInt tm_hour; /* hours since midnight - [0,23] */ 85 | uInt tm_mday; /* day of the month - [1,31] */ 86 | uInt tm_mon; /* months since January - [0,11] */ 87 | uInt tm_year; /* years - [1980..2044] */ 88 | } tm_unz; 89 | 90 | /* unz_global_info structure contain global data about the ZIPfile 91 | These data comes from the end of central dir */ 92 | typedef struct unz_global_info_s 93 | { 94 | uLong number_entry; /* total number of entries in 95 | the central dir on this disk */ 96 | uLong size_comment; /* size of the global comment of the zipfile */ 97 | } unz_global_info; 98 | 99 | 100 | /* unz_file_info contain information about a file in the zipfile */ 101 | typedef struct unz_file_info_s 102 | { 103 | uLong version; /* version made by 2 bytes */ 104 | uLong version_needed; /* version needed to extract 2 bytes */ 105 | uLong flag; /* general purpose bit flag 2 bytes */ 106 | uLong compression_method; /* compression method 2 bytes */ 107 | uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ 108 | uLong crc; /* crc-32 4 bytes */ 109 | uLong compressed_size; /* compressed size 4 bytes */ 110 | uLong uncompressed_size; /* uncompressed size 4 bytes */ 111 | uLong size_filename; /* filename length 2 bytes */ 112 | uLong size_file_extra; /* extra field length 2 bytes */ 113 | uLong size_file_comment; /* file comment length 2 bytes */ 114 | 115 | uLong disk_num_start; /* disk number start 2 bytes */ 116 | uLong internal_fa; /* internal file attributes 2 bytes */ 117 | uLong external_fa; /* external file attributes 4 bytes */ 118 | 119 | tm_unz tmu_date; 120 | } unz_file_info; 121 | 122 | extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, 123 | const char* fileName2, 124 | int iCaseSensitivity)); 125 | /* 126 | Compare two filename (fileName1,fileName2). 127 | If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) 128 | If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi 129 | or strcasecmp) 130 | If iCaseSenisivity = 0, case sensitivity is defaut of your operating system 131 | (like 1 on Unix, 2 on Windows) 132 | */ 133 | 134 | 135 | extern unzFile ZEXPORT unzOpen OF((const char *path)); 136 | /* 137 | Open a Zip file. path contain the full pathname (by example, 138 | on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer 139 | "zlib/zlib113.zip". 140 | If the zipfile cannot be opened (file don't exist or in not valid), the 141 | return value is NULL. 142 | Else, the return value is a unzFile Handle, usable with other function 143 | of this unzip package. 144 | */ 145 | 146 | extern unzFile ZEXPORT unzOpen2 OF((const char *path, 147 | zlib_filefunc_def* pzlib_filefunc_def)); 148 | /* 149 | Open a Zip file, like unzOpen, but provide a set of file low level API 150 | for read/write the zip file (see ioapi.h) 151 | */ 152 | 153 | extern int ZEXPORT unzClose OF((unzFile file)); 154 | /* 155 | Close a ZipFile opened with unzipOpen. 156 | If there is files inside the .Zip opened with unzOpenCurrentFile (see later), 157 | these files MUST be closed with unzipCloseCurrentFile before call unzipClose. 158 | return UNZ_OK if there is no problem. */ 159 | 160 | extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, 161 | unz_global_info *pglobal_info)); 162 | /* 163 | Write info about the ZipFile in the *pglobal_info structure. 164 | No preparation of the structure is needed 165 | return UNZ_OK if there is no problem. */ 166 | 167 | 168 | extern int ZEXPORT unzGetGlobalComment OF((unzFile file, 169 | char *szComment, 170 | uLong uSizeBuf)); 171 | /* 172 | Get the global comment string of the ZipFile, in the szComment buffer. 173 | uSizeBuf is the size of the szComment buffer. 174 | return the number of byte copied or an error code <0 175 | */ 176 | 177 | 178 | /***************************************************************************/ 179 | /* Unzip package allow you browse the directory of the zipfile */ 180 | 181 | extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); 182 | /* 183 | Set the current file of the zipfile to the first file. 184 | return UNZ_OK if there is no problem 185 | */ 186 | 187 | extern int ZEXPORT unzGoToNextFile OF((unzFile file)); 188 | /* 189 | Set the current file of the zipfile to the next file. 190 | return UNZ_OK if there is no problem 191 | return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. 192 | */ 193 | 194 | extern int ZEXPORT unzLocateFile OF((unzFile file, 195 | const char *szFileName, 196 | int iCaseSensitivity)); 197 | /* 198 | Try locate the file szFileName in the zipfile. 199 | For the iCaseSensitivity signification, see unzStringFileNameCompare 200 | 201 | return value : 202 | UNZ_OK if the file is found. It becomes the current file. 203 | UNZ_END_OF_LIST_OF_FILE if the file is not found 204 | */ 205 | 206 | 207 | /* ****************************************** */ 208 | /* Ryan supplied functions */ 209 | /* unz_file_info contain information about a file in the zipfile */ 210 | typedef struct unz_file_pos_s 211 | { 212 | uLong pos_in_zip_directory; /* offset in zip file directory */ 213 | uLong num_of_file; /* # of file */ 214 | } unz_file_pos; 215 | 216 | extern int ZEXPORT unzGetFilePos( 217 | unzFile file, 218 | unz_file_pos* file_pos); 219 | 220 | extern int ZEXPORT unzGoToFilePos( 221 | unzFile file, 222 | unz_file_pos* file_pos); 223 | 224 | /* ****************************************** */ 225 | 226 | extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, 227 | unz_file_info *pfile_info, 228 | char *szFileName, 229 | uLong fileNameBufferSize, 230 | void *extraField, 231 | uLong extraFieldBufferSize, 232 | char *szComment, 233 | uLong commentBufferSize)); 234 | /* 235 | Get Info about the current file 236 | if pfile_info!=NULL, the *pfile_info structure will contain somes info about 237 | the current file 238 | if szFileName!=NULL, the filemane string will be copied in szFileName 239 | (fileNameBufferSize is the size of the buffer) 240 | if extraField!=NULL, the extra field information will be copied in extraField 241 | (extraFieldBufferSize is the size of the buffer). 242 | This is the Central-header version of the extra field 243 | if szComment!=NULL, the comment string of the file will be copied in szComment 244 | (commentBufferSize is the size of the buffer) 245 | */ 246 | 247 | /***************************************************************************/ 248 | /* for reading the content of the current zipfile, you can open it, read data 249 | from it, and close it (you can close it before reading all the file) 250 | */ 251 | 252 | extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); 253 | /* 254 | Open for reading data the current file in the zipfile. 255 | If there is no error, the return value is UNZ_OK. 256 | */ 257 | 258 | extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, 259 | const char* password)); 260 | /* 261 | Open for reading data the current file in the zipfile. 262 | password is a crypting password 263 | If there is no error, the return value is UNZ_OK. 264 | */ 265 | 266 | extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, 267 | int* method, 268 | int* level, 269 | int raw)); 270 | /* 271 | Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) 272 | if raw==1 273 | *method will receive method of compression, *level will receive level of 274 | compression 275 | note : you can set level parameter as NULL (if you did not want known level, 276 | but you CANNOT set method parameter as NULL 277 | */ 278 | 279 | extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, 280 | int* method, 281 | int* level, 282 | int raw, 283 | const char* password)); 284 | /* 285 | Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) 286 | if raw==1 287 | *method will receive method of compression, *level will receive level of 288 | compression 289 | note : you can set level parameter as NULL (if you did not want known level, 290 | but you CANNOT set method parameter as NULL 291 | */ 292 | 293 | 294 | extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); 295 | /* 296 | Close the file in zip opened with unzOpenCurrentFile 297 | Return UNZ_CRCERROR if all the file was read but the CRC is not good 298 | */ 299 | 300 | extern int ZEXPORT unzReadCurrentFile OF((unzFile file, 301 | voidp buf, 302 | unsigned len)); 303 | /* 304 | Read bytes from the current file (opened by unzOpenCurrentFile) 305 | buf contain buffer where data must be copied 306 | len the size of buf. 307 | 308 | return the number of byte copied if somes bytes are copied 309 | return 0 if the end of file was reached 310 | return <0 with error code if there is an error 311 | (UNZ_ERRNO for IO error, or zLib error for uncompress error) 312 | */ 313 | 314 | extern z_off_t ZEXPORT unztell OF((unzFile file)); 315 | /* 316 | Give the current position in uncompressed data 317 | */ 318 | 319 | extern int ZEXPORT unzeof OF((unzFile file)); 320 | /* 321 | return 1 if the end of file was reached, 0 elsewhere 322 | */ 323 | 324 | extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, 325 | voidp buf, 326 | unsigned len)); 327 | /* 328 | Read extra field from the current file (opened by unzOpenCurrentFile) 329 | This is the local-header version of the extra field (sometimes, there is 330 | more info in the local-header version than in the central-header) 331 | 332 | if buf==NULL, it return the size of the local extra field 333 | 334 | if buf!=NULL, len is the size of the buffer, the extra header is copied in 335 | buf. 336 | the return value is the number of bytes copied in buf, or (if <0) 337 | the error code 338 | */ 339 | 340 | /***************************************************************************/ 341 | 342 | /* Get the current file offset */ 343 | extern uLong ZEXPORT unzGetOffset (unzFile file); 344 | 345 | /* Set the current file offset */ 346 | extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); 347 | 348 | 349 | 350 | #ifdef __cplusplus 351 | } 352 | #endif 353 | 354 | #endif /* _unz_H */ 355 | -------------------------------------------------------------------------------- /minizip/zip.h: -------------------------------------------------------------------------------- 1 | /* zip.h -- IO for compress .zip files using zlib 2 | Version 1.01e, February 12th, 2005 3 | 4 | Copyright (C) 1998-2005 Gilles Vollant 5 | 6 | This unzip package allow creates .ZIP file, compatible with PKZip 2.04g 7 | WinZip, InfoZip tools and compatible. 8 | Multi volume ZipFile (span) are not supported. 9 | Encryption compatible with pkzip 2.04g only supported 10 | Old compressions used by old PKZip 1.x are not supported 11 | 12 | For uncompress .zip file, look at unzip.h 13 | 14 | 15 | I WAIT FEEDBACK at mail info@winimage.com 16 | Visit also http://www.winimage.com/zLibDll/unzip.html for evolution 17 | 18 | Condition of use and distribution are the same than zlib : 19 | 20 | This software is provided 'as-is', without any express or implied 21 | warranty. In no event will the authors be held liable for any damages 22 | arising from the use of this software. 23 | 24 | Permission is granted to anyone to use this software for any purpose, 25 | including commercial applications, and to alter it and redistribute it 26 | freely, subject to the following restrictions: 27 | 28 | 1. The origin of this software must not be misrepresented; you must not 29 | claim that you wrote the original software. If you use this software 30 | in a product, an acknowledgment in the product documentation would be 31 | appreciated but is not required. 32 | 2. Altered source versions must be plainly marked as such, and must not be 33 | misrepresented as being the original software. 34 | 3. This notice may not be removed or altered from any source distribution. 35 | 36 | 37 | */ 38 | 39 | /* for more info about .ZIP format, see 40 | http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip 41 | http://www.info-zip.org/pub/infozip/doc/ 42 | PkWare has also a specification at : 43 | ftp://ftp.pkware.com/probdesc.zip 44 | */ 45 | 46 | #ifndef _zip_H 47 | #define _zip_H 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | #ifndef _ZLIB_H 54 | #include "zlib.h" 55 | #endif 56 | 57 | #ifndef _ZLIBIOAPI_H 58 | #include "ioapi.h" 59 | #endif 60 | 61 | #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) 62 | /* like the STRICT of WIN32, we define a pointer that cannot be converted 63 | from (void*) without cast */ 64 | typedef struct TagzipFile__ { int unused; } zipFile__; 65 | typedef zipFile__ *zipFile; 66 | #else 67 | typedef voidp zipFile; 68 | #endif 69 | 70 | #define ZIP_OK (0) 71 | #define ZIP_EOF (0) 72 | #define ZIP_ERRNO (Z_ERRNO) 73 | #define ZIP_PARAMERROR (-102) 74 | #define ZIP_BADZIPFILE (-103) 75 | #define ZIP_INTERNALERROR (-104) 76 | 77 | #ifndef DEF_MEM_LEVEL 78 | # if MAX_MEM_LEVEL >= 8 79 | # define DEF_MEM_LEVEL 8 80 | # else 81 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL 82 | # endif 83 | #endif 84 | /* default memLevel */ 85 | 86 | /* tm_zip contain date/time info */ 87 | typedef struct tm_zip_s 88 | { 89 | uInt tm_sec; /* seconds after the minute - [0,59] */ 90 | uInt tm_min; /* minutes after the hour - [0,59] */ 91 | uInt tm_hour; /* hours since midnight - [0,23] */ 92 | uInt tm_mday; /* day of the month - [1,31] */ 93 | uInt tm_mon; /* months since January - [0,11] */ 94 | uInt tm_year; /* years - [1980..2044] */ 95 | } tm_zip; 96 | 97 | typedef struct 98 | { 99 | tm_zip tmz_date; /* date in understandable format */ 100 | uLong dosDate; /* if dos_date == 0, tmu_date is used */ 101 | /* uLong flag; */ /* general purpose bit flag 2 bytes */ 102 | 103 | uLong internal_fa; /* internal file attributes 2 bytes */ 104 | uLong external_fa; /* external file attributes 4 bytes */ 105 | } zip_fileinfo; 106 | 107 | typedef const char* zipcharpc; 108 | 109 | 110 | #define APPEND_STATUS_CREATE (0) 111 | #define APPEND_STATUS_CREATEAFTER (1) 112 | #define APPEND_STATUS_ADDINZIP (2) 113 | 114 | extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); 115 | /* 116 | Create a zipfile. 117 | pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on 118 | an Unix computer "zlib/zlib113.zip". 119 | if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip 120 | will be created at the end of the file. 121 | (useful if the file contain a self extractor code) 122 | if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will 123 | add files in existing zip (be sure you don't add file that doesn't exist) 124 | If the zipfile cannot be opened, the return value is NULL. 125 | Else, the return value is a zipFile Handle, usable with other function 126 | of this zip package. 127 | */ 128 | 129 | /* Note : there is no delete function into a zipfile. 130 | If you want delete file into a zipfile, you must open a zipfile, and create another 131 | Of couse, you can use RAW reading and writing to copy the file you did not want delte 132 | */ 133 | 134 | extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, 135 | int append, 136 | zipcharpc* globalcomment, 137 | zlib_filefunc_def* pzlib_filefunc_def)); 138 | 139 | extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, 140 | const char* filename, 141 | const zip_fileinfo* zipfi, 142 | const void* extrafield_local, 143 | uInt size_extrafield_local, 144 | const void* extrafield_global, 145 | uInt size_extrafield_global, 146 | const char* comment, 147 | int method, 148 | int level)); 149 | /* 150 | Open a file in the ZIP for writing. 151 | filename : the filename in zip (if NULL, '-' without quote will be used 152 | *zipfi contain supplemental information 153 | if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local 154 | contains the extrafield data the the local header 155 | if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global 156 | contains the extrafield data the the local header 157 | if comment != NULL, comment contain the comment string 158 | method contain the compression method (0 for store, Z_DEFLATED for deflate) 159 | level contain the level of compression (can be Z_DEFAULT_COMPRESSION) 160 | */ 161 | 162 | 163 | extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, 164 | const char* filename, 165 | const zip_fileinfo* zipfi, 166 | const void* extrafield_local, 167 | uInt size_extrafield_local, 168 | const void* extrafield_global, 169 | uInt size_extrafield_global, 170 | const char* comment, 171 | int method, 172 | int level, 173 | int raw)); 174 | 175 | /* 176 | Same than zipOpenNewFileInZip, except if raw=1, we write raw file 177 | */ 178 | 179 | extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, 180 | const char* filename, 181 | const zip_fileinfo* zipfi, 182 | const void* extrafield_local, 183 | uInt size_extrafield_local, 184 | const void* extrafield_global, 185 | uInt size_extrafield_global, 186 | const char* comment, 187 | int method, 188 | int level, 189 | int raw, 190 | int windowBits, 191 | int memLevel, 192 | int strategy, 193 | const char* password, 194 | uLong crcForCtypting)); 195 | 196 | /* 197 | Same than zipOpenNewFileInZip2, except 198 | windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 199 | password : crypting password (NULL for no crypting) 200 | crcForCtypting : crc of file to compress (needed for crypting) 201 | */ 202 | 203 | 204 | extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, 205 | const void* buf, 206 | unsigned len)); 207 | /* 208 | Write data in the zipfile 209 | */ 210 | 211 | extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); 212 | /* 213 | Close the current file in the zipfile 214 | */ 215 | 216 | extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, 217 | uLong uncompressed_size, 218 | uLong crc32)); 219 | /* 220 | Close the current file in the zipfile, for fiel opened with 221 | parameter raw=1 in zipOpenNewFileInZip2 222 | uncompressed_size and crc32 are value for the uncompressed size 223 | */ 224 | 225 | extern int ZEXPORT zipClose OF((zipFile file, 226 | const char* global_comment)); 227 | /* 228 | Close the zipfile 229 | */ 230 | 231 | #ifdef __cplusplus 232 | } 233 | #endif 234 | 235 | #endif /* _zip_H */ 236 | --------------------------------------------------------------------------------