Skip to content

Commit

Permalink
feat: esign repo importing support
Browse files Browse the repository at this point in the history
Esign repo importing support - this required extracting the esign decryption key from kravasign and reverse engineering how they decrypt the codes to be able to see what repos are listed.

ESign has no reason to be doing ANY of this apart from trying to be a pain in the ass for its users, however we got it done after a long time.

Co-Authored-By: HAHALOSAH <[email protected]>
Co-Authored-By: nekohaxx <[email protected]>
  • Loading branch information
3 people committed Jan 20, 2025
1 parent 39d24f1 commit 9b04852
Show file tree
Hide file tree
Showing 39 changed files with 722 additions and 199 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
434 changes: 434 additions & 0 deletions Shared/Magic/esign/ESignRepoKey.swift

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions Shared/Magic/esign/ESignRepoParser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// ESignParser.swift
// feather
//
// Created by samara on 20.01.2025.
//

import Foundation

class EsignDecryptor {
private let input: String

init(input: String) {
self.input = input
}

func extractBase64() -> Data? {
let pattern = #"source\[(.*?)\]"#

if let regex = try? NSRegularExpression(pattern: pattern),
let match = regex.firstMatch(in: input, range: NSRange(input.startIndex..., in: input)),
let range = Range(match.range(at: 1), in: input) {

let base64String = String(input[range])

if let decodedData = Data(base64Encoded: base64String) {
return decodedData
} else {
Debug.shared.log(message: "Failed to decode base64 string.", type: .error)
}
} else {
Debug.shared.log(message: "Base64 string not found.", type: .error)
}

return nil
}

func decrypt(key: [UInt8], keyLength: Int) -> [String]? {
guard let data = extractBase64() else {
Debug.shared.log(message: "EsignDecryptor.decrypt: Not valid data?", type: .error)
return nil
}

let encryptedBytes = [UInt8](data)
var decryptedData = Data()
var keyIndex = 0

for encryptedByte in encryptedBytes {
let decryptedByte = encryptedByte ^ key[keyIndex]
decryptedData.append(decryptedByte)
keyIndex = (keyIndex + 1) % keyLength
}

if let decryptedString = String(data: decryptedData, encoding: .utf8) {
return decryptedString.components(separatedBy: "\n")
} else {
return nil
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Use this file to import your target's public headers that you would like to expose to Swift.
//

#include "zsign.hpp"
#include "p12_password_check.hpp"
#include "UISheetPresentationControllerDetent+Private.h"

#include "LSApplicationWorkspace.h"

#include "zsign.hpp"
#include "openssl_tools.hpp"
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern "C" {
#endif
bool p12_password_check(NSString *file, NSString *pass);
void password_check_fix_WHAT_THE_FUCK(NSString *path);
void generate_root_ca_pair(const char* basename);
#ifdef __cplusplus
}
#endif
131 changes: 131 additions & 0 deletions Shared/Magic/openssl_tools.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//
// p12_password_check.cpp
// feather
//
// Created by HAHALOSAH on 8/6/24.
//

#include "openssl_tools.hpp"
#include "zsign/Utils.hpp"
#include "zsign/common/common.h"

#include <openssl/pem.h>
#include <openssl/cms.h>
#include <openssl/err.h>
#include <openssl/provider.h>
#include <openssl/pkcs12.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/x509.h>

#include <string>

EVP_PKEY* generate_root_ca_key(const char* basename, const char* output_path);
X509* generate_root_ca_cert(EVP_PKEY* pkey, const char* basename, const char* output_path);

using namespace std;

bool p12_password_check(NSString *file, NSString *pass) {
BIO *in = BIO_new(BIO_s_mem());
d2i_CMS_bio(in, NULL);
const string strSignerPKeyFile = [file cStringUsingEncoding:NSUTF8StringEncoding];
const string strPassword = [pass cStringUsingEncoding:NSUTF8StringEncoding];
X509 *x509Cert = NULL;
EVP_PKEY *evpPKey = NULL;
BIO *bioPKey = BIO_new_file(strSignerPKeyFile.c_str(), "r");
OSSL_PROVIDER_load(NULL, "legacy");
PKCS12 *p12 = d2i_PKCS12_bio(bioPKey, NULL);
if (NULL != p12)
{
if (0 == PKCS12_parse(p12, strPassword.c_str(), &evpPKey, &x509Cert, NULL))
{
return false;
}
PKCS12_free(p12);
BIO_free(bioPKey);
return true;
} else {
BIO_free(bioPKey);
return false;
}
}

// This is fucking bullshit IMO.
//
// In total, I probably wasted a total of 1.5 hours on this
// Feel free to increment the counter until someone finds a proper fix
//
// hours_wasted = 1.5
//
// TODO: FIX
void password_check_fix_WHAT_THE_FUCK(NSString *path) {
string strProvisionFile = [path cStringUsingEncoding:NSUTF8StringEncoding];
string strProvisionData;
ReadFile(strProvisionFile.c_str(), strProvisionData);

BIO *in = BIO_new(BIO_s_mem());
OPENSSL_assert((size_t)BIO_write(in, strProvisionData.data(), (int)strProvisionData.size()) == strProvisionData.size());
d2i_CMS_bio(in, NULL);
}

void generate_root_ca_pair(const char* basename) {
const char* documentsPath = getDocumentsDirectory();

RSA *rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL);
EVP_PKEY *pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);

X509* x509 = X509_new();
X509_set_version(x509, 2);
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);

X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 315360000L);

X509_set_pubkey(x509, pkey);

X509_NAME* name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char*)"US", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char*)"Root CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)"Root CA", -1, -1, 0);

X509_set_issuer_name(x509, name);

X509V3_CTX ctx;
X509V3_set_ctx_nodb(&ctx);
X509V3_set_ctx(&ctx, x509, x509, NULL, NULL, 0);

X509_EXTENSION *ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, "critical,CA:TRUE,pathlen:0");
X509_add_ext(x509, ext, -1);
X509_EXTENSION_free(ext);

ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_key_usage, "critical,keyCertSign,cRLSign");
X509_add_ext(x509, ext, -1);
X509_EXTENSION_free(ext);

ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, "hash");
X509_add_ext(x509, ext, -1);
X509_EXTENSION_free(ext);

X509_sign(x509, pkey, EVP_sha256());

string keyfile = std::string(documentsPath) + "/" + string(basename) + ".pem";
string certfile = std::string(documentsPath) + "/" + string(basename) + ".crt";

BIO *bio = BIO_new_file(keyfile.c_str(), "w");
if (bio) {
PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL);
BIO_free(bio);
printf("Private key written to: %s\n", keyfile.c_str());
}

FILE* f = fopen(certfile.c_str(), "wb");
if (f) {
PEM_write_X509(f, x509);
fclose(f);
printf("Certificate written to: %s\n", certfile.c_str());
}

EVP_PKEY_free(pkey);
X509_free(x509);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
55 changes: 0 additions & 55 deletions Shared/Server/DownloadCertificate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,6 @@

import Foundation

func downloadCertificatesOnline(from urlStrings: [String], completion: @escaping (Result<[URL], Error>) -> Void) {
var downloadedURLs: [URL] = []
let dispatchGroup = DispatchGroup()

for urlString in urlStrings {
guard let url = URL(string: urlString) else {
Debug.shared.log(message: "Invalid URL: \(urlString).")
completion(.failure(NSError(domain: "Invalid URL", code: -1, userInfo: nil)))
return
}

let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let destinationURL = documentsDirectory.appendingPathComponent(url.lastPathComponent)

dispatchGroup.enter()
Debug.shared.log(message: "Downloading file from \(url)")
let task = URLSession.shared.downloadTask(with: url) { tempLocalURL, response, error in
defer { dispatchGroup.leave() }

if let error = error {
completion(.failure(error))
return
}

guard let tempLocalURL = tempLocalURL else {
Debug.shared.log(message: "Failed to download file from \(urlString).")
completion(.failure(NSError(domain: "Download failed", code: -1, userInfo: nil)))
return
}

do {
if FileManager.default.fileExists(atPath: destinationURL.path) {
try FileManager.default.removeItem(at: destinationURL)
}

try FileManager.default.moveItem(at: tempLocalURL, to: destinationURL)
downloadedURLs.append(destinationURL)
} catch {
completion(.failure(error))
return
}
}

task.resume()
}

dispatchGroup.notify(queue: .main) {
if downloadedURLs.count == urlStrings.count {
completion(.success(downloadedURLs))
} else {
completion(.failure(NSError(domain: "Some downloads failed", code: -1, userInfo: nil)))
}
}
}

func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
Expand Down
10 changes: 10 additions & 0 deletions Shared/Server/Server+Compute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
import Foundation

extension Installer {

var pongEndpoint: URL {
var comps = URLComponents()
comps.scheme = Preferences.userSelectedServer ? "http" : "https"
comps.host = Self.sni
comps.path = "/ping"
comps.port = port
return comps.url!
}

var plistEndpoint: URL {
var comps = URLComponents()
comps.scheme = Preferences.userSelectedServer ? "http" : "https"
Expand Down
19 changes: 5 additions & 14 deletions Shared/Server/Server+TLS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,14 @@ func getLocalIPAddress() -> String? {


extension Installer {
static let sni = Preferences.userSelectedServer ? (getLocalIPAddress() ?? "127.0.0.1") : "app.localhost.direct"
static let sni = Preferences.userSelectedServer ? (getLocalIPAddress() ?? "0.0.0.0") : "0.0.0.0"

static let bundleKeyURL = Bundle.main.url(forResource: "localhost.direct", withExtension: "pem")
static let bundleCrtURL = Bundle.main.url(forResource: "localhost.direct", withExtension: "crt")

static let documentsKeyURL = getDocumentsDirectory().appendingPathComponent("localhost.direct.pem")
static let documentsCrtURL = getDocumentsDirectory().appendingPathComponent("localhost.direct.crt")
static let documentsKeyURL = getDocumentsDirectory().appendingPathComponent("server.pem")
static let documentsCrtURL = getDocumentsDirectory().appendingPathComponent("server.crt")

static func setupTLS() throws -> TLSConfiguration {
let keyURL = FileManager.default.fileExists(atPath: documentsKeyURL.path) ? documentsKeyURL : bundleKeyURL
let crtURL = FileManager.default.fileExists(atPath: documentsCrtURL.path) ? documentsCrtURL : bundleCrtURL

guard let crtURL, let keyURL else {
throw NSError(domain: "Installer", code: 0, userInfo: [
NSLocalizedDescriptionKey: "Failed to load SSL certificates",
])
}
let keyURL = documentsKeyURL
let crtURL = documentsCrtURL

return try TLSConfiguration.makeServerConfiguration(
certificateChain: NIOSSLCertificate
Expand Down
64 changes: 0 additions & 64 deletions Shared/Signing/p12_password_check.mm

This file was deleted.

Loading

0 comments on commit 9b04852

Please sign in to comment.