fix: iOS: ITMS-90338: Replace non-public CCCryptorGCMOneshot APIs with CryptoKit
This commit is contained in:
@@ -0,0 +1,98 @@
|
|||||||
|
import Foundation
|
||||||
|
import CryptoKit
|
||||||
|
import CommonCrypto
|
||||||
|
|
||||||
|
@objc class CryptoHelper: NSObject {
|
||||||
|
|
||||||
|
private static let cryptoVersion: UInt8 = 0x01
|
||||||
|
private static let saltLen = 16
|
||||||
|
private static let ivLen = 12
|
||||||
|
private static let gcmTagLen = 16
|
||||||
|
private static let pbkdf2Iterations: UInt32 = 100_000
|
||||||
|
private static let keyLen = 32 // AES-256
|
||||||
|
|
||||||
|
@objc static func encryptData(_ plaintext: Data, passphrase: String) throws -> Data {
|
||||||
|
var salt = Data(count: saltLen)
|
||||||
|
var iv = Data(count: ivLen)
|
||||||
|
try salt.withUnsafeMutableBytes { buf in
|
||||||
|
guard SecRandomCopyBytes(kSecRandomDefault, saltLen, buf.baseAddress!) == errSecSuccess else {
|
||||||
|
throw NSError(domain: "CryptoHelper", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to generate random salt"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try iv.withUnsafeMutableBytes { buf in
|
||||||
|
guard SecRandomCopyBytes(kSecRandomDefault, ivLen, buf.baseAddress!) == errSecSuccess else {
|
||||||
|
throw NSError(domain: "CryptoHelper", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to generate random IV"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let derivedKey = try deriveKey(passphrase: passphrase, salt: salt)
|
||||||
|
let symmetricKey = SymmetricKey(data: derivedKey)
|
||||||
|
let nonce = try AES.GCM.Nonce(data: iv)
|
||||||
|
let sealedBox = try AES.GCM.seal(plaintext, using: symmetricKey, nonce: nonce)
|
||||||
|
|
||||||
|
// Wire format: [version][salt][iv][ciphertext][tag]
|
||||||
|
var output = Data()
|
||||||
|
output.append(cryptoVersion)
|
||||||
|
output.append(salt)
|
||||||
|
output.append(iv)
|
||||||
|
output.append(sealedBox.ciphertext)
|
||||||
|
output.append(sealedBox.tag)
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc static func decryptData(_ fileData: Data, passphrase: String) throws -> Data {
|
||||||
|
let minLen = 1 + saltLen + ivLen + gcmTagLen
|
||||||
|
guard fileData.count >= minLen else {
|
||||||
|
throw NSError(domain: "CryptoHelper", code: -2, userInfo: [NSLocalizedDescriptionKey: "File too small to be a valid encrypted backup"])
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = fileData[fileData.startIndex]
|
||||||
|
guard version == cryptoVersion else {
|
||||||
|
throw NSError(domain: "CryptoHelper", code: -3, userInfo: [NSLocalizedDescriptionKey: "Unsupported encryption version: \(version)"])
|
||||||
|
}
|
||||||
|
|
||||||
|
let saltStart = fileData.startIndex + 1
|
||||||
|
let ivStart = saltStart + saltLen
|
||||||
|
let ciphertextStart = ivStart + ivLen
|
||||||
|
let tagStart = fileData.endIndex - gcmTagLen
|
||||||
|
|
||||||
|
let salt = fileData[saltStart..<ivStart]
|
||||||
|
let iv = fileData[ivStart..<ciphertextStart]
|
||||||
|
let ciphertext = fileData[ciphertextStart..<tagStart]
|
||||||
|
let tag = fileData[tagStart..<fileData.endIndex]
|
||||||
|
|
||||||
|
let derivedKey = try deriveKey(passphrase: passphrase, salt: Data(salt))
|
||||||
|
let symmetricKey = SymmetricKey(data: derivedKey)
|
||||||
|
let nonce = try AES.GCM.Nonce(data: iv)
|
||||||
|
let sealedBox = try AES.GCM.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag)
|
||||||
|
return try AES.GCM.open(sealedBox, using: symmetricKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func deriveKey(passphrase: String, salt: Data) throws -> Data {
|
||||||
|
guard let passphraseData = passphrase.data(using: .utf8) else {
|
||||||
|
throw NSError(domain: "CryptoHelper", code: -4, userInfo: [NSLocalizedDescriptionKey: "Failed to encode passphrase"])
|
||||||
|
}
|
||||||
|
var derivedKey = Data(count: keyLen)
|
||||||
|
let status = derivedKey.withUnsafeMutableBytes { keyBuf in
|
||||||
|
salt.withUnsafeBytes { saltBuf in
|
||||||
|
passphraseData.withUnsafeBytes { passBuf in
|
||||||
|
CCKeyDerivationPBKDF(
|
||||||
|
CCPBKDFAlgorithm(kCCPBKDF2),
|
||||||
|
passBuf.baseAddress?.assumingMemoryBound(to: Int8.self),
|
||||||
|
passphraseData.count,
|
||||||
|
saltBuf.baseAddress?.assumingMemoryBound(to: UInt8.self),
|
||||||
|
saltLen,
|
||||||
|
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
|
||||||
|
pbkdf2Iterations,
|
||||||
|
keyBuf.baseAddress?.assumingMemoryBound(to: UInt8.self),
|
||||||
|
keyLen
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guard status == kCCSuccess else {
|
||||||
|
throw NSError(domain: "CryptoHelper", code: -5, userInfo: [NSLocalizedDescriptionKey: "Key derivation failed"])
|
||||||
|
}
|
||||||
|
return derivedKey
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,8 @@ typealias Callback = (Data?, Error?) -> Void
|
|||||||
typealias StreamCallback = (Data?, Error?) -> Void
|
typealias StreamCallback = (Data?, Error?) -> Void
|
||||||
|
|
||||||
// Used internally in this class to deal with Lndmobile/Go
|
// Used internally in this class to deal with Lndmobile/Go
|
||||||
|
// Renamed in ObjC to avoid collision with Lndmobile.xcframework's own LndmobileCallback
|
||||||
|
@objc(ZeusLndmobileCallback)
|
||||||
class LndmobileCallback: NSObject, LndmobileCallbackProtocol {
|
class LndmobileCallback: NSObject, LndmobileCallbackProtocol {
|
||||||
var method: String
|
var method: String
|
||||||
var callback: Callback
|
var callback: Callback
|
||||||
|
|||||||
+9
-134
@@ -1,28 +1,6 @@
|
|||||||
#import "ZipUtils.h"
|
#import "ZipUtils.h"
|
||||||
#import <zlib.h>
|
#import <zlib.h>
|
||||||
#import <CommonCrypto/CommonCryptor.h>
|
#import "zeus-Swift.h"
|
||||||
#import <CommonCrypto/CommonKeyDerivation.h>
|
|
||||||
|
|
||||||
// These GCM oneshot functions are available since iOS 13 but are not
|
|
||||||
// declared in the public CommonCrypto headers. Provide explicit
|
|
||||||
// prototypes so the build succeeds under -Wimplicit-function-declaration.
|
|
||||||
CCCryptorStatus CCCryptorGCMOneshotEncrypt(
|
|
||||||
CCAlgorithm alg, const void *key, size_t keyLength,
|
|
||||||
const void *iv, size_t ivLen,
|
|
||||||
const void *aData, size_t aDataLen,
|
|
||||||
const void *dataIn, size_t dataInLength,
|
|
||||||
void *dataOut,
|
|
||||||
void *tagOut, size_t tagLength
|
|
||||||
) __attribute__((weak_import));
|
|
||||||
|
|
||||||
CCCryptorStatus CCCryptorGCMOneshotDecrypt(
|
|
||||||
CCAlgorithm alg, const void *key, size_t keyLength,
|
|
||||||
const void *iv, size_t ivLen,
|
|
||||||
const void *aData, size_t aDataLen,
|
|
||||||
const void *dataIn, size_t dataInLength,
|
|
||||||
void *dataOut,
|
|
||||||
const void *tagIn, size_t tagLength
|
|
||||||
) __attribute__((weak_import));
|
|
||||||
|
|
||||||
// Minizip-compatible local file header constants
|
// Minizip-compatible local file header constants
|
||||||
#define ZIP_LOCAL_HEADER_SIGNATURE 0x04034b50
|
#define ZIP_LOCAL_HEADER_SIGNATURE 0x04034b50
|
||||||
@@ -323,15 +301,6 @@ RCT_EXPORT_METHOD(unzipFile:(NSString *)zipPath
|
|||||||
return decompressed;
|
return decompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Encryption constants
|
|
||||||
|
|
||||||
static const uint8_t CRYPTO_VERSION = 0x01;
|
|
||||||
static const size_t SALT_LEN = 16;
|
|
||||||
static const size_t IV_LEN = 12;
|
|
||||||
static const size_t GCM_TAG_LEN = 16;
|
|
||||||
static const uint32_t PBKDF2_ITERATIONS = 100000;
|
|
||||||
static const size_t KEY_LEN = 32; // AES-256
|
|
||||||
|
|
||||||
#pragma mark - Encrypt
|
#pragma mark - Encrypt
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(encryptFile:(NSString *)inputPath
|
RCT_EXPORT_METHOD(encryptFile:(NSString *)inputPath
|
||||||
@@ -347,59 +316,13 @@ RCT_EXPORT_METHOD(encryptFile:(NSString *)inputPath
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate random salt and IV
|
NSError *error = nil;
|
||||||
uint8_t salt[SALT_LEN];
|
NSData *output = [CryptoHelper encryptData:plaintext passphrase:passphrase error:&error];
|
||||||
uint8_t iv[IV_LEN];
|
if (!output) {
|
||||||
if (SecRandomCopyBytes(kSecRandomDefault, SALT_LEN, salt) != errSecSuccess ||
|
reject(@"ERR_ENCRYPT", error.localizedDescription ?: @"Encryption failed", error);
|
||||||
SecRandomCopyBytes(kSecRandomDefault, IV_LEN, iv) != errSecSuccess) {
|
|
||||||
reject(@"ERR_ENCRYPT", @"Failed to generate random bytes", nil);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive key with PBKDF2-SHA256
|
|
||||||
NSData *passphraseData = [passphrase dataUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
uint8_t derivedKey[KEY_LEN];
|
|
||||||
CCStatus kdfStatus = CCKeyDerivationPBKDF(
|
|
||||||
kCCPBKDF2,
|
|
||||||
passphraseData.bytes, passphraseData.length,
|
|
||||||
salt, SALT_LEN,
|
|
||||||
kCCPRFHmacAlgSHA256,
|
|
||||||
PBKDF2_ITERATIONS,
|
|
||||||
derivedKey, KEY_LEN
|
|
||||||
);
|
|
||||||
if (kdfStatus != kCCSuccess) {
|
|
||||||
reject(@"ERR_ENCRYPT", @"Key derivation failed", nil);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// AES-256-GCM encrypt
|
|
||||||
size_t ciphertextLen = plaintext.length;
|
|
||||||
NSMutableData *ciphertext = [NSMutableData dataWithLength:ciphertextLen];
|
|
||||||
uint8_t tag[GCM_TAG_LEN];
|
|
||||||
|
|
||||||
CCCryptorStatus status = CCCryptorGCMOneshotEncrypt(
|
|
||||||
kCCAlgorithmAES,
|
|
||||||
derivedKey, KEY_LEN,
|
|
||||||
iv, IV_LEN,
|
|
||||||
NULL, 0, // no AAD
|
|
||||||
plaintext.bytes, plaintext.length,
|
|
||||||
ciphertext.mutableBytes,
|
|
||||||
tag, GCM_TAG_LEN
|
|
||||||
);
|
|
||||||
|
|
||||||
if (status != kCCSuccess) {
|
|
||||||
reject(@"ERR_ENCRYPT", [NSString stringWithFormat:@"Encryption failed with status: %d", status], nil);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write: [version][salt][iv][ciphertext][tag]
|
|
||||||
NSMutableData *output = [NSMutableData data];
|
|
||||||
[output appendBytes:&CRYPTO_VERSION length:1];
|
|
||||||
[output appendBytes:salt length:SALT_LEN];
|
|
||||||
[output appendBytes:iv length:IV_LEN];
|
|
||||||
[output appendData:ciphertext];
|
|
||||||
[output appendBytes:tag length:GCM_TAG_LEN];
|
|
||||||
|
|
||||||
if ([output writeToFile:outputPath atomically:YES]) {
|
if ([output writeToFile:outputPath atomically:YES]) {
|
||||||
resolve(nil);
|
resolve(nil);
|
||||||
} else {
|
} else {
|
||||||
@@ -423,58 +346,10 @@ RCT_EXPORT_METHOD(decryptFile:(NSString *)inputPath
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t minLen = 1 + SALT_LEN + IV_LEN + GCM_TAG_LEN;
|
NSError *error = nil;
|
||||||
if (fileData.length < minLen) {
|
NSData *plaintext = [CryptoHelper decryptData:fileData passphrase:passphrase error:&error];
|
||||||
reject(@"ERR_DECRYPT", @"File too small to be a valid encrypted backup", nil);
|
if (!plaintext) {
|
||||||
return;
|
reject(@"ERR_DECRYPT", error.localizedDescription ?: @"Decryption failed. Incorrect seed or corrupted file.", error);
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *bytes = fileData.bytes;
|
|
||||||
|
|
||||||
uint8_t version = bytes[0];
|
|
||||||
if (version != CRYPTO_VERSION) {
|
|
||||||
reject(@"ERR_DECRYPT", [NSString stringWithFormat:@"Unsupported encryption version: %d", version], nil);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *salt = bytes + 1;
|
|
||||||
const uint8_t *iv = bytes + 1 + SALT_LEN;
|
|
||||||
size_t headerLen = 1 + SALT_LEN + IV_LEN;
|
|
||||||
size_t ciphertextLen = fileData.length - headerLen - GCM_TAG_LEN;
|
|
||||||
const uint8_t *ciphertextBytes = bytes + headerLen;
|
|
||||||
const uint8_t *tagBytes = bytes + headerLen + ciphertextLen;
|
|
||||||
|
|
||||||
// Derive key with PBKDF2-SHA256
|
|
||||||
NSData *passphraseData = [passphrase dataUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
uint8_t derivedKey[KEY_LEN];
|
|
||||||
CCStatus kdfStatus = CCKeyDerivationPBKDF(
|
|
||||||
kCCPBKDF2,
|
|
||||||
passphraseData.bytes, passphraseData.length,
|
|
||||||
salt, SALT_LEN,
|
|
||||||
kCCPRFHmacAlgSHA256,
|
|
||||||
PBKDF2_ITERATIONS,
|
|
||||||
derivedKey, KEY_LEN
|
|
||||||
);
|
|
||||||
if (kdfStatus != kCCSuccess) {
|
|
||||||
reject(@"ERR_DECRYPT", @"Key derivation failed", nil);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// AES-256-GCM decrypt
|
|
||||||
NSMutableData *plaintext = [NSMutableData dataWithLength:ciphertextLen];
|
|
||||||
|
|
||||||
CCCryptorStatus status = CCCryptorGCMOneshotDecrypt(
|
|
||||||
kCCAlgorithmAES,
|
|
||||||
derivedKey, KEY_LEN,
|
|
||||||
iv, IV_LEN,
|
|
||||||
NULL, 0, // no AAD
|
|
||||||
ciphertextBytes, ciphertextLen,
|
|
||||||
plaintext.mutableBytes,
|
|
||||||
tagBytes, GCM_TAG_LEN
|
|
||||||
);
|
|
||||||
|
|
||||||
if (status != kCCSuccess) {
|
|
||||||
reject(@"ERR_DECRYPT", @"Decryption failed. Incorrect seed or corrupted file.", nil);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
4A9A9C2189D54ED78D4029E2 /* Wrench.svg in Resources */ = {isa = PBXBuildFile; fileRef = C18B7331C6704C59A8BB7DCA /* Wrench.svg */; };
|
4A9A9C2189D54ED78D4029E2 /* Wrench.svg in Resources */ = {isa = PBXBuildFile; fileRef = C18B7331C6704C59A8BB7DCA /* Wrench.svg */; };
|
||||||
4F7B0DD5ACBD432DB04374DC /* Speedometer.svg in Resources */ = {isa = PBXBuildFile; fileRef = 4B58C327668640C881703E94 /* Speedometer.svg */; };
|
4F7B0DD5ACBD432DB04374DC /* Speedometer.svg in Resources */ = {isa = PBXBuildFile; fileRef = 4B58C327668640C881703E94 /* Speedometer.svg */; };
|
||||||
5100FA362F75348D009D640A /* ZipUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5100FA352F75348D009D640A /* ZipUtils.m */; };
|
5100FA362F75348D009D640A /* ZipUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5100FA352F75348D009D640A /* ZipUtils.m */; };
|
||||||
|
5100FA382F75348D009D640A /* CryptoHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5100FA372F75348D009D640A /* CryptoHelper.swift */; };
|
||||||
5134B5512EB7C1B000A6AD03 /* ShareQR.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 5134B5472EB7C1B000A6AD03 /* ShareQR.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
5134B5512EB7C1B000A6AD03 /* ShareQR.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 5134B5472EB7C1B000A6AD03 /* ShareQR.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
51BF29FE2ED5FC770044B4FB /* ShareBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 51BF29FC2ED5FB940044B4FB /* ShareBridge.m */; };
|
51BF29FE2ED5FC770044B4FB /* ShareBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 51BF29FC2ED5FB940044B4FB /* ShareBridge.m */; };
|
||||||
541A24C3CF314FAF9DAFEE06 /* Arrow_down.svg in Resources */ = {isa = PBXBuildFile; fileRef = 16305D1EA8FA48288C57F6A7 /* Arrow_down.svg */; };
|
541A24C3CF314FAF9DAFEE06 /* Arrow_down.svg in Resources */ = {isa = PBXBuildFile; fileRef = 16305D1EA8FA48288C57F6A7 /* Arrow_down.svg */; };
|
||||||
@@ -513,6 +514,7 @@
|
|||||||
5014345A129344348443D20F /* zeus-pay.svg */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "zeus-pay.svg"; path = "../assets/images/SVG/zeus-pay.svg"; sourceTree = "<group>"; };
|
5014345A129344348443D20F /* zeus-pay.svg */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "zeus-pay.svg"; path = "../assets/images/SVG/zeus-pay.svg"; sourceTree = "<group>"; };
|
||||||
5100FA342F75348D009D640A /* ZipUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZipUtils.h; sourceTree = "<group>"; };
|
5100FA342F75348D009D640A /* ZipUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZipUtils.h; sourceTree = "<group>"; };
|
||||||
5100FA352F75348D009D640A /* ZipUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZipUtils.m; sourceTree = "<group>"; };
|
5100FA352F75348D009D640A /* ZipUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZipUtils.m; sourceTree = "<group>"; };
|
||||||
|
5100FA372F75348D009D640A /* CryptoHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoHelper.swift; sourceTree = "<group>"; };
|
||||||
51184C7F24744DCB90D53B8C /* wordmark-black.svg */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "wordmark-black.svg"; path = "../assets/images/SVG/wordmark-black.svg"; sourceTree = "<group>"; };
|
51184C7F24744DCB90D53B8C /* wordmark-black.svg */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "wordmark-black.svg"; path = "../assets/images/SVG/wordmark-black.svg"; sourceTree = "<group>"; };
|
||||||
5134B5472EB7C1B000A6AD03 /* ShareQR.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareQR.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
5134B5472EB7C1B000A6AD03 /* ShareQR.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareQR.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
51BF29FB2ED5FB940044B4FB /* ShareBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareBridge.h; sourceTree = "<group>"; };
|
51BF29FB2ED5FB940044B4FB /* ShareBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareBridge.h; sourceTree = "<group>"; };
|
||||||
@@ -849,6 +851,7 @@
|
|||||||
children = (
|
children = (
|
||||||
5100FA342F75348D009D640A /* ZipUtils.h */,
|
5100FA342F75348D009D640A /* ZipUtils.h */,
|
||||||
5100FA352F75348D009D640A /* ZipUtils.m */,
|
5100FA352F75348D009D640A /* ZipUtils.m */,
|
||||||
|
5100FA372F75348D009D640A /* CryptoHelper.swift */,
|
||||||
51BF29FB2ED5FB940044B4FB /* ShareBridge.h */,
|
51BF29FB2ED5FB940044B4FB /* ShareBridge.h */,
|
||||||
51BF29FC2ED5FB940044B4FB /* ShareBridge.m */,
|
51BF29FC2ED5FB940044B4FB /* ShareBridge.m */,
|
||||||
B1C2D3E42D36C99900000001 /* LdkNodeMobile */,
|
B1C2D3E42D36C99900000001 /* LdkNodeMobile */,
|
||||||
@@ -1963,6 +1966,7 @@
|
|||||||
745388492A54C2B6000927CE /* walletunlocker.pb.swift in Sources */,
|
745388492A54C2B6000927CE /* walletunlocker.pb.swift in Sources */,
|
||||||
7453884A2A54C2B6000927CE /* LndMobileTools.m in Sources */,
|
7453884A2A54C2B6000927CE /* LndMobileTools.m in Sources */,
|
||||||
5100FA362F75348D009D640A /* ZipUtils.m in Sources */,
|
5100FA362F75348D009D640A /* ZipUtils.m in Sources */,
|
||||||
|
5100FA382F75348D009D640A /* CryptoHelper.swift in Sources */,
|
||||||
745388472A54C2B6000927CE /* LndMobileScheduledSync.m in Sources */,
|
745388472A54C2B6000927CE /* LndMobileScheduledSync.m in Sources */,
|
||||||
745388462A54C2B6000927CE /* LndMobile.m in Sources */,
|
745388462A54C2B6000927CE /* LndMobile.m in Sources */,
|
||||||
7453884B2A54C2B6000927CE /* Lnd.swift in Sources */,
|
7453884B2A54C2B6000927CE /* Lnd.swift in Sources */,
|
||||||
|
|||||||
Reference in New Issue
Block a user