@onekeyfe/react-native-bundle-crypto 3.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/ReactNativeBundleCrypto.podspec +35 -0
- package/android/CMakeLists.txt +24 -0
- package/android/build.gradle +136 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/margelo/nitro/reactnativebundlecrypto/BundleCryptoCore.kt +526 -0
- package/android/src/main/java/com/margelo/nitro/reactnativebundlecrypto/ReactNativeBundleCrypto.kt +110 -0
- package/android/src/main/java/com/margelo/nitro/reactnativebundlecrypto/ReactNativeBundleCryptoPackage.kt +24 -0
- package/ios/BundleCryptoCore.swift +529 -0
- package/ios/Frameworks/Gopenpgp.xcframework/Info.plist +52 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Gopenpgp +0 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Armor.objc.h +96 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Constants.objc.h +197 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Crypto.objc.h +1963 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Gopenpgp.h +23 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Mime.objc.h +59 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Mobile.objc.h +252 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Profile.objc.h +107 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Universe.objc.h +29 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/ref.h +35 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Info.plist +20 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Modules/module.modulemap +13 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Gopenpgp +0 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Armor.objc.h +96 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Constants.objc.h +197 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Crypto.objc.h +1963 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Gopenpgp.h +23 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Mime.objc.h +59 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Mobile.objc.h +252 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Profile.objc.h +107 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Universe.objc.h +29 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/ref.h +35 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Info.plist +20 -0
- package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Modules/module.modulemap +13 -0
- package/ios/ReactNativeBundleCrypto.swift +104 -0
- package/lib/module/ReactNativeBundleCrypto.nitro.js +4 -0
- package/lib/module/ReactNativeBundleCrypto.nitro.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/ReactNativeBundleCrypto.nitro.d.ts +35 -0
- package/lib/typescript/src/ReactNativeBundleCrypto.nitro.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/nitro.json +17 -0
- package/nitrogen/generated/android/c++/JDirHashEntry.hpp +61 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeBundleCryptoSpec.cpp +240 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeBundleCryptoSpec.hpp +74 -0
- package/nitrogen/generated/android/c++/JSha256Result.hpp +62 -0
- package/nitrogen/generated/android/c++/JVerifyDetachedAscResult.hpp +66 -0
- package/nitrogen/generated/android/c++/JVerifyGpgCleartextResult.hpp +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/DirHashEntry.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/HybridReactNativeBundleCryptoSpec.kt +94 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/Sha256Result.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/VerifyDetachedAscResult.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/VerifyGpgCleartextResult.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/reactnativebundlecryptoOnLoad.kt +35 -0
- package/nitrogen/generated/android/reactnativebundlecrypto+autolinking.cmake +81 -0
- package/nitrogen/generated/android/reactnativebundlecrypto+autolinking.gradle +27 -0
- package/nitrogen/generated/android/reactnativebundlecryptoOnLoad.cpp +44 -0
- package/nitrogen/generated/android/reactnativebundlecryptoOnLoad.hpp +25 -0
- package/nitrogen/generated/ios/ReactNativeBundleCrypto+autolinking.rb +60 -0
- package/nitrogen/generated/ios/ReactNativeBundleCrypto-Swift-Cxx-Bridge.cpp +97 -0
- package/nitrogen/generated/ios/ReactNativeBundleCrypto-Swift-Cxx-Bridge.hpp +429 -0
- package/nitrogen/generated/ios/ReactNativeBundleCrypto-Swift-Cxx-Umbrella.hpp +59 -0
- package/nitrogen/generated/ios/ReactNativeBundleCryptoAutolinking.mm +33 -0
- package/nitrogen/generated/ios/ReactNativeBundleCryptoAutolinking.swift +25 -0
- package/nitrogen/generated/ios/c++/HybridReactNativeBundleCryptoSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridReactNativeBundleCryptoSpecSwift.hpp +162 -0
- package/nitrogen/generated/ios/swift/DirHashEntry.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_Sha256Result.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_VerifyDetachedAscResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_VerifyGpgCleartextResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_DirHashEntry_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeBundleCryptoSpec.swift +65 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeBundleCryptoSpec_cxx.swift +314 -0
- package/nitrogen/generated/ios/swift/Sha256Result.swift +85 -0
- package/nitrogen/generated/ios/swift/VerifyDetachedAscResult.swift +96 -0
- package/nitrogen/generated/ios/swift/VerifyGpgCleartextResult.swift +96 -0
- package/nitrogen/generated/shared/c++/DirHashEntry.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeBundleCryptoSpec.cpp +30 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeBundleCryptoSpec.hpp +84 -0
- package/nitrogen/generated/shared/c++/Sha256Result.hpp +80 -0
- package/nitrogen/generated/shared/c++/VerifyDetachedAscResult.hpp +84 -0
- package/nitrogen/generated/shared/c++/VerifyGpgCleartextResult.hpp +84 -0
- package/package.json +169 -0
- package/src/ReactNativeBundleCrypto.nitro.ts +56 -0
- package/src/index.tsx +8 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import CommonCrypto
|
|
3
|
+
import Gopenpgp
|
|
4
|
+
import ReactNativeNativeLogger
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// BundleCryptoCore (iOS)
|
|
8
|
+
//
|
|
9
|
+
// P3a refactor: the real GPG/sha256/path-safety/secure-file logic lives here as
|
|
10
|
+
// plain, synchronous, throwing static functions returning plain Swift types
|
|
11
|
+
// (tuples / [DirHashEntry-like] / Bool / throws). This is the single source of
|
|
12
|
+
// truth for the security logic — the Nitro HybridObject (ReactNativeBundleCrypto)
|
|
13
|
+
// is a thin shell that calls these functions and assembles the generated Nitro
|
|
14
|
+
// Result structs.
|
|
15
|
+
//
|
|
16
|
+
// This split lets other native code (e.g. the bundle-update downloader) call the
|
|
17
|
+
// security core directly and synchronously, without going through a Nitro Promise.
|
|
18
|
+
//
|
|
19
|
+
// Behavior is IDENTICAL to the previous in-method implementation:
|
|
20
|
+
// - Verification failures always return invalid + reason — never a false pass.
|
|
21
|
+
// - sha256 failureReason taxonomy preserved verbatim
|
|
22
|
+
// (FILE_NOT_FOUND / FILE_DISAPPEARED / IO_<code>).
|
|
23
|
+
//
|
|
24
|
+
// Single source of truth for the OneKey GPG public key lives here (below).
|
|
25
|
+
// This module does NOT expose the public key to JS.
|
|
26
|
+
//
|
|
27
|
+
// Cleartext form (verifyGpgCleartext) <- ReactNativeBundleUpdate.swift
|
|
28
|
+
// verifyGPGAndExtractSha256 (CryptoPGP
|
|
29
|
+
// verifyCleartext, body JSON -> sha256)
|
|
30
|
+
// Detached form (verifyDetachedAsc) <- aligned to Android
|
|
31
|
+
// ReactNativeAppUpdate.kt
|
|
32
|
+
// verifyAscContentAndExtractSha256
|
|
33
|
+
// (cleartext-signed SHA256SUMS, first
|
|
34
|
+
// hex token). The on-disk SHA256SUMS.asc
|
|
35
|
+
// is a PGP CLEARTEXT SIGNED MESSAGE, so
|
|
36
|
+
// Gopenpgp verifyCleartext is reused;
|
|
37
|
+
// only the body parsing differs.
|
|
38
|
+
// ============================================================================
|
|
39
|
+
|
|
40
|
+
// OneKey GPG public key for signature verification.
|
|
41
|
+
// SINGLE AUTHORITATIVE COPY for the bundle-crypto module.
|
|
42
|
+
private let GPG_PUBLIC_KEY = """
|
|
43
|
+
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
44
|
+
|
|
45
|
+
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
|
|
105
|
+
=HlTQ
|
|
106
|
+
-----END PGP PUBLIC KEY BLOCK-----
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
/// Plain, synchronous, throwing security core for the bundle-crypto module.
|
|
110
|
+
/// The Nitro HybridObject delegates to these functions.
|
|
111
|
+
public enum BundleCryptoCore {
|
|
112
|
+
|
|
113
|
+
// Plain value type mirroring the (relativePath, sha256) pair the Nitro layer
|
|
114
|
+
// exposes as `DirHashEntry`. Kept separate so the core has zero Nitro deps.
|
|
115
|
+
// `public` (incl. an explicit public init) so other modules — e.g.
|
|
116
|
+
// react-native-bundle-update — can construct entries to pass into
|
|
117
|
+
// verifyDirAgainstHashes across the module boundary.
|
|
118
|
+
public struct DirHash {
|
|
119
|
+
public let relativePath: String
|
|
120
|
+
public let sha256: String
|
|
121
|
+
|
|
122
|
+
public init(relativePath: String, sha256: String) {
|
|
123
|
+
self.relativePath = relativePath
|
|
124
|
+
self.sha256 = sha256
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// MARK: - GPG cleartext (bundle form): body JSON -> sha256
|
|
129
|
+
// Ported verbatim from ReactNativeBundleUpdate.verifyGPGAndExtractSha256.
|
|
130
|
+
|
|
131
|
+
public static func verifyGpgCleartext(_ signedMessage: String) -> (valid: Bool, sha256: String?, reason: String?) {
|
|
132
|
+
// Check if this looks like a PGP signed message
|
|
133
|
+
guard signedMessage.contains("-----BEGIN PGP SIGNED MESSAGE-----") else {
|
|
134
|
+
return (false, nil, "NOT_PGP_SIGNED_MESSAGE")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 1. Load public key
|
|
138
|
+
guard let pubKey = CryptoKey(fromArmored: GPG_PUBLIC_KEY) else {
|
|
139
|
+
OneKeyLog.error("BundleCrypto", "Failed to parse GPG public key")
|
|
140
|
+
return (false, nil, "PUBKEY_PARSE_FAILED")
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 2. Get PGP handle
|
|
144
|
+
guard let pgp = CryptoPGP() else {
|
|
145
|
+
OneKeyLog.error("BundleCrypto", "Failed to create PGPHandle")
|
|
146
|
+
return (false, nil, "PGP_HANDLE_FAILED")
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 3. Build verify handle: pgp.verify().verificationKey(pubKey).new()
|
|
150
|
+
guard let verifyBuilder = pgp.verify() else {
|
|
151
|
+
OneKeyLog.error("BundleCrypto", "Failed to get verify builder")
|
|
152
|
+
return (false, nil, "VERIFY_BUILDER_FAILED")
|
|
153
|
+
}
|
|
154
|
+
guard let builderWithKey = verifyBuilder.verificationKey(pubKey) else {
|
|
155
|
+
OneKeyLog.error("BundleCrypto", "Failed to set verification key")
|
|
156
|
+
return (false, nil, "VERIFY_KEY_FAILED")
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let verifyHandle: any CryptoPGPVerifyProtocol
|
|
160
|
+
do {
|
|
161
|
+
verifyHandle = try builderWithKey.new()
|
|
162
|
+
} catch {
|
|
163
|
+
OneKeyLog.error("BundleCrypto", "Failed to create verify handle: \(error.localizedDescription)")
|
|
164
|
+
return (false, nil, "VERIFY_HANDLE_FAILED")
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 4. Verify cleartext
|
|
168
|
+
guard let signatureData = signedMessage.data(using: .utf8) else {
|
|
169
|
+
return (false, nil, "ENCODING_FAILED")
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let cleartextResult: CryptoVerifyCleartextResult
|
|
173
|
+
do {
|
|
174
|
+
cleartextResult = try verifyHandle.verifyCleartext(signatureData)
|
|
175
|
+
} catch {
|
|
176
|
+
OneKeyLog.error("BundleCrypto", "GPG verification error: \(error.localizedDescription)")
|
|
177
|
+
return (false, nil, "VERIFY_ERROR")
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 5. Check signature error
|
|
181
|
+
do {
|
|
182
|
+
try cleartextResult.signatureError()
|
|
183
|
+
} catch {
|
|
184
|
+
OneKeyLog.error("BundleCrypto", "GPG signature invalid: \(error.localizedDescription)")
|
|
185
|
+
return (false, nil, "SIGNATURE_INVALID")
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 6. Get cleartext
|
|
189
|
+
guard let cleartextData = cleartextResult.cleartext() else {
|
|
190
|
+
OneKeyLog.error("BundleCrypto", "Failed to extract cleartext from GPG result")
|
|
191
|
+
return (false, nil, "CLEARTEXT_EXTRACT_FAILED")
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
guard let text = String(data: cleartextData, encoding: .utf8) else {
|
|
195
|
+
return (false, nil, "CLEARTEXT_DECODE_FAILED")
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 7. Parse JSON and extract sha256
|
|
199
|
+
guard let jsonData = text.data(using: .utf8),
|
|
200
|
+
let json = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
|
|
201
|
+
let sha256 = json["sha256"] as? String else {
|
|
202
|
+
OneKeyLog.error("BundleCrypto", "Failed to parse cleartext JSON")
|
|
203
|
+
return (false, nil, "JSON_PARSE_FAILED")
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
OneKeyLog.info("BundleCrypto", "GPG cleartext verification succeeded")
|
|
207
|
+
return (true, sha256, nil)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// MARK: - Detached ASC (APK form): cleartext-signed SHA256SUMS -> first hex token
|
|
211
|
+
// The SHA256SUMS.asc on disk is a PGP CLEARTEXT SIGNED MESSAGE, so the same
|
|
212
|
+
// Gopenpgp verifyCleartext path is reused; only the body parsing differs
|
|
213
|
+
// (no JSON — the verified body's first whitespace token must be a 64-char
|
|
214
|
+
// lowercase hex sha256).
|
|
215
|
+
|
|
216
|
+
public static func verifyDetachedAsc(_ ascContent: String) -> (valid: Bool, sha256: String?, reason: String?) {
|
|
217
|
+
guard ascContent.contains("-----BEGIN PGP SIGNED MESSAGE-----") else {
|
|
218
|
+
return (false, nil, "NOT_PGP_SIGNED_MESSAGE")
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
guard let pubKey = CryptoKey(fromArmored: GPG_PUBLIC_KEY) else {
|
|
222
|
+
OneKeyLog.error("BundleCrypto", "Failed to parse GPG public key")
|
|
223
|
+
return (false, nil, "PUBKEY_PARSE_FAILED")
|
|
224
|
+
}
|
|
225
|
+
guard let pgp = CryptoPGP() else {
|
|
226
|
+
return (false, nil, "PGP_HANDLE_FAILED")
|
|
227
|
+
}
|
|
228
|
+
guard let verifyBuilder = pgp.verify() else {
|
|
229
|
+
return (false, nil, "VERIFY_BUILDER_FAILED")
|
|
230
|
+
}
|
|
231
|
+
guard let builderWithKey = verifyBuilder.verificationKey(pubKey) else {
|
|
232
|
+
return (false, nil, "VERIFY_KEY_FAILED")
|
|
233
|
+
}
|
|
234
|
+
let verifyHandle: any CryptoPGPVerifyProtocol
|
|
235
|
+
do {
|
|
236
|
+
verifyHandle = try builderWithKey.new()
|
|
237
|
+
} catch {
|
|
238
|
+
return (false, nil, "VERIFY_HANDLE_FAILED")
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
guard let signatureData = ascContent.data(using: .utf8) else {
|
|
242
|
+
return (false, nil, "ENCODING_FAILED")
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
let cleartextResult: CryptoVerifyCleartextResult
|
|
246
|
+
do {
|
|
247
|
+
cleartextResult = try verifyHandle.verifyCleartext(signatureData)
|
|
248
|
+
} catch {
|
|
249
|
+
OneKeyLog.error("BundleCrypto", "ASC verification error: \(error.localizedDescription)")
|
|
250
|
+
return (false, nil, "VERIFY_ERROR")
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
do {
|
|
254
|
+
try cleartextResult.signatureError()
|
|
255
|
+
} catch {
|
|
256
|
+
OneKeyLog.error("BundleCrypto", "ASC signature invalid: \(error.localizedDescription)")
|
|
257
|
+
return (false, nil, "SIGNATURE_INVALID")
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
guard let cleartextData = cleartextResult.cleartext(),
|
|
261
|
+
let text = String(data: cleartextData, encoding: .utf8) else {
|
|
262
|
+
return (false, nil, "CLEARTEXT_EXTRACT_FAILED")
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Mirror Android: first whitespace token of the verified SHA256SUMS body,
|
|
266
|
+
// lowercased, must be exactly 64 hex chars.
|
|
267
|
+
let sha256 = text
|
|
268
|
+
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
269
|
+
.split(whereSeparator: { $0 == " " || $0 == "\t" || $0 == "\n" || $0 == "\r" })
|
|
270
|
+
.first
|
|
271
|
+
.map { String($0).lowercased() } ?? ""
|
|
272
|
+
let isHex = sha256.count == 64 && sha256.unicodeScalars.allSatisfy {
|
|
273
|
+
($0 >= "0" && $0 <= "9") || ($0 >= "a" && $0 <= "f")
|
|
274
|
+
}
|
|
275
|
+
guard isHex else {
|
|
276
|
+
OneKeyLog.error("BundleCrypto", "ASC body sha256 token invalid")
|
|
277
|
+
return (false, nil, "SHA256_TOKEN_INVALID")
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
OneKeyLog.info("BundleCrypto", "ASC detached verification succeeded")
|
|
281
|
+
return (true, sha256, nil)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// MARK: - sha256 (CommonCrypto streaming) — ported from calculateSHA256
|
|
285
|
+
// + lastSHA256FailureReason. failureReason taxonomy preserved verbatim
|
|
286
|
+
// (FILE_NOT_FOUND / FILE_DISAPPEARED / IO_<code>).
|
|
287
|
+
|
|
288
|
+
public static func sha256OfFile(_ filePath: String) -> (sha256: String?, failureReason: String?) {
|
|
289
|
+
let fm = FileManager.default
|
|
290
|
+
if !fm.fileExists(atPath: filePath) {
|
|
291
|
+
OneKeyLog.error("BundleCrypto", "sha256OfFile: file not found: \(filePath)")
|
|
292
|
+
return (nil, "FILE_NOT_FOUND")
|
|
293
|
+
}
|
|
294
|
+
guard let fileHandle = FileHandle(forReadingAtPath: filePath) else {
|
|
295
|
+
OneKeyLog.error("BundleCrypto", "sha256OfFile: open failed (file disappeared between stat and open): \(filePath)")
|
|
296
|
+
return (nil, "FILE_DISAPPEARED")
|
|
297
|
+
}
|
|
298
|
+
defer { fileHandle.closeFile() }
|
|
299
|
+
|
|
300
|
+
var context = CC_SHA256_CTX()
|
|
301
|
+
CC_SHA256_Init(&context)
|
|
302
|
+
var threwError: Error?
|
|
303
|
+
// safeRead routes reads through FileHandle.read(upToCount:) on iOS 13.4+,
|
|
304
|
+
// surfacing disk failures as throwing NSError. On pre-13.4 OS versions the
|
|
305
|
+
// fallback raises NSFileHandleOperationException (uncatchable in Swift) —
|
|
306
|
+
// accepted on the floor since 13.4+ is the long-standing deployment target.
|
|
307
|
+
while autoreleasepool(invoking: {
|
|
308
|
+
do {
|
|
309
|
+
let data = try Self.safeRead(fileHandle: fileHandle, length: 8192)
|
|
310
|
+
if data.count > 0 {
|
|
311
|
+
data.withUnsafeBytes { CC_SHA256_Update(&context, $0.baseAddress, CC_LONG(data.count)) }
|
|
312
|
+
return true
|
|
313
|
+
}
|
|
314
|
+
return false
|
|
315
|
+
} catch {
|
|
316
|
+
threwError = error
|
|
317
|
+
return false
|
|
318
|
+
}
|
|
319
|
+
}) {}
|
|
320
|
+
if let err = threwError {
|
|
321
|
+
let nsErr = err as NSError
|
|
322
|
+
// Keep failure tag low-cardinality (`IO_<code>`); full detail logged locally.
|
|
323
|
+
OneKeyLog.error("BundleCrypto", "sha256OfFile: read failed: \(nsErr.domain) \(nsErr.code) \(nsErr.localizedDescription)")
|
|
324
|
+
return (nil, "IO_\(nsErr.code)")
|
|
325
|
+
}
|
|
326
|
+
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
|
|
327
|
+
CC_SHA256_Final(&hash, &context)
|
|
328
|
+
let hex = hash.map { String(format: "%02x", $0) }.joined()
|
|
329
|
+
return (hex, nil)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/// Throwing wrapper around FileHandle.read(upToCount:) so disk I/O failures
|
|
333
|
+
/// become catchable Swift errors rather than NSFileHandleOperationException.
|
|
334
|
+
private static func safeRead(fileHandle: FileHandle, length: Int) throws -> Data {
|
|
335
|
+
if #available(iOS 13.4, macOS 10.15.4, *) {
|
|
336
|
+
return try fileHandle.read(upToCount: length) ?? Data()
|
|
337
|
+
} else {
|
|
338
|
+
return fileHandle.readData(ofLength: length)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// MARK: - Constant-time hex compare — ported from String.secureCompare.
|
|
343
|
+
|
|
344
|
+
public static func secureEqualHex(_ a: String, _ b: String) -> Bool {
|
|
345
|
+
return secureCompare(a, b)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private static func secureCompare(_ a: String, _ b: String) -> Bool {
|
|
349
|
+
let lhs = Array(a.utf8)
|
|
350
|
+
let rhs = Array(b.utf8)
|
|
351
|
+
guard lhs.count == rhs.count else { return false }
|
|
352
|
+
var result: UInt8 = 0
|
|
353
|
+
for i in 0..<lhs.count {
|
|
354
|
+
result |= lhs[i] ^ rhs[i]
|
|
355
|
+
}
|
|
356
|
+
return result == 0
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/// Synchronous sha256 used internally by dir hashing — returns nil on any
|
|
360
|
+
/// failure (used where only the hex/nil distinction matters).
|
|
361
|
+
private static func calculateSHA256Sync(_ filePath: String) -> String? {
|
|
362
|
+
let fm = FileManager.default
|
|
363
|
+
guard fm.fileExists(atPath: filePath),
|
|
364
|
+
let fileHandle = FileHandle(forReadingAtPath: filePath) else { return nil }
|
|
365
|
+
defer { fileHandle.closeFile() }
|
|
366
|
+
var context = CC_SHA256_CTX()
|
|
367
|
+
CC_SHA256_Init(&context)
|
|
368
|
+
var threwError: Error?
|
|
369
|
+
while autoreleasepool(invoking: {
|
|
370
|
+
do {
|
|
371
|
+
let data = try Self.safeRead(fileHandle: fileHandle, length: 8192)
|
|
372
|
+
if data.count > 0 {
|
|
373
|
+
data.withUnsafeBytes { CC_SHA256_Update(&context, $0.baseAddress, CC_LONG(data.count)) }
|
|
374
|
+
return true
|
|
375
|
+
}
|
|
376
|
+
return false
|
|
377
|
+
} catch {
|
|
378
|
+
threwError = error
|
|
379
|
+
return false
|
|
380
|
+
}
|
|
381
|
+
}) {}
|
|
382
|
+
if threwError != nil { return nil }
|
|
383
|
+
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
|
|
384
|
+
CC_SHA256_Final(&hash, &context)
|
|
385
|
+
return hash.map { String(format: "%02x", $0) }.joined()
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// MARK: - Per-entry directory hash verification — ported from
|
|
389
|
+
// validateAllFilesInDir. Caller passes the expected relativePath -> sha256
|
|
390
|
+
// entries (the JS layer derives these from verified metadata). Verifies every
|
|
391
|
+
// on-disk file matches AND every expected entry exists (completeness).
|
|
392
|
+
|
|
393
|
+
public static func verifyDirAgainstHashes(dirPath: String, entries: [DirHash]) -> Bool {
|
|
394
|
+
let fm = FileManager.default
|
|
395
|
+
var isDir: ObjCBool = false
|
|
396
|
+
guard fm.fileExists(atPath: dirPath, isDirectory: &isDir), isDir.boolValue else {
|
|
397
|
+
OneKeyLog.error("BundleCrypto", "[bundle-verify] dir not found: \(dirPath)")
|
|
398
|
+
return false
|
|
399
|
+
}
|
|
400
|
+
// Normalize the directory prefix so relative paths match.
|
|
401
|
+
let normalizedDir = (dirPath as NSString).hasSuffix("/") ? dirPath : dirPath + "/"
|
|
402
|
+
|
|
403
|
+
var expected: [String: String] = [:]
|
|
404
|
+
for entry in entries { expected[entry.relativePath] = entry.sha256 }
|
|
405
|
+
|
|
406
|
+
guard let enumerator = fm.enumerator(atPath: dirPath) else { return false }
|
|
407
|
+
while let file = enumerator.nextObject() as? String {
|
|
408
|
+
if file.contains("metadata.json") || file.contains(".DS_Store") { continue }
|
|
409
|
+
let fullPath = (dirPath as NSString).appendingPathComponent(file)
|
|
410
|
+
var entryIsDir: ObjCBool = false
|
|
411
|
+
if fm.fileExists(atPath: fullPath, isDirectory: &entryIsDir), entryIsDir.boolValue { continue }
|
|
412
|
+
|
|
413
|
+
let relativePath = fullPath.replacingOccurrences(of: normalizedDir, with: "")
|
|
414
|
+
guard let expectedSHA256 = expected[relativePath] else {
|
|
415
|
+
OneKeyLog.error("BundleCrypto", "[bundle-verify] File on disk not found in metadata: \(relativePath)")
|
|
416
|
+
return false
|
|
417
|
+
}
|
|
418
|
+
guard let actualSHA256 = Self.calculateSHA256Sync(fullPath) else {
|
|
419
|
+
OneKeyLog.error("BundleCrypto", "[bundle-verify] Failed to calculate SHA256 for file: \(relativePath)")
|
|
420
|
+
return false
|
|
421
|
+
}
|
|
422
|
+
if !Self.secureCompare(expectedSHA256, actualSHA256) {
|
|
423
|
+
OneKeyLog.error("BundleCrypto", "[bundle-verify] SHA256 mismatch for \(relativePath)")
|
|
424
|
+
return false
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Verify completeness: every expected entry must exist on disk.
|
|
429
|
+
for (relativePath, _) in expected {
|
|
430
|
+
let expectedFilePath = normalizedDir + relativePath
|
|
431
|
+
if !fm.fileExists(atPath: expectedFilePath) {
|
|
432
|
+
OneKeyLog.error("BundleCrypto", "[bundle-verify] File listed in metadata but missing on disk: \(relativePath)")
|
|
433
|
+
return false
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return true
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// MARK: - Hash a whole dir into relativePath -> sha256 entries (new helper,
|
|
440
|
+
// same enumeration/skip rules as verifyDirAgainstHashes). Throws HASH_FAILED
|
|
441
|
+
// if any file cannot be hashed.
|
|
442
|
+
|
|
443
|
+
public static func hashDir(_ dirPath: String) throws -> [DirHash] {
|
|
444
|
+
let fm = FileManager.default
|
|
445
|
+
let normalizedDir = (dirPath as NSString).hasSuffix("/") ? dirPath : dirPath + "/"
|
|
446
|
+
var results: [DirHash] = []
|
|
447
|
+
guard let enumerator = fm.enumerator(atPath: dirPath) else { return [] }
|
|
448
|
+
while let file = enumerator.nextObject() as? String {
|
|
449
|
+
if file.contains("metadata.json") || file.contains(".DS_Store") { continue }
|
|
450
|
+
let fullPath = (dirPath as NSString).appendingPathComponent(file)
|
|
451
|
+
var entryIsDir: ObjCBool = false
|
|
452
|
+
if fm.fileExists(atPath: fullPath, isDirectory: &entryIsDir), entryIsDir.boolValue { continue }
|
|
453
|
+
guard let sha256 = Self.calculateSHA256Sync(fullPath) else {
|
|
454
|
+
OneKeyLog.error("BundleCrypto", "hashDir: failed to hash \(file)")
|
|
455
|
+
throw NSError(domain: "BundleCrypto", code: -1, userInfo: [NSLocalizedDescriptionKey: "HASH_FAILED"])
|
|
456
|
+
}
|
|
457
|
+
let relativePath = fullPath.replacingOccurrences(of: normalizedDir, with: "")
|
|
458
|
+
results.append(DirHash(relativePath: relativePath, sha256: sha256))
|
|
459
|
+
}
|
|
460
|
+
return results
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// MARK: - Symlink / path-traversal guard — ported from
|
|
464
|
+
// validateExtractedPathSafety.
|
|
465
|
+
|
|
466
|
+
public static func validateExtractedPathSafety(_ destination: String) -> Bool {
|
|
467
|
+
let fm = FileManager.default
|
|
468
|
+
let resolvedDestination = (destination as NSString).resolvingSymlinksInPath
|
|
469
|
+
|
|
470
|
+
guard let enumerator = fm.enumerator(atPath: destination) else { return true }
|
|
471
|
+
while let file = enumerator.nextObject() as? String {
|
|
472
|
+
let fullPath = (destination as NSString).appendingPathComponent(file)
|
|
473
|
+
if let attrs = enumerator.fileAttributes,
|
|
474
|
+
attrs[.type] as? FileAttributeType == .typeSymbolicLink {
|
|
475
|
+
OneKeyLog.error("BundleCrypto", "Symlink detected in extracted bundle: \(file)")
|
|
476
|
+
return false
|
|
477
|
+
}
|
|
478
|
+
let resolvedPath = (fullPath as NSString).resolvingSymlinksInPath
|
|
479
|
+
if !resolvedPath.hasPrefix(resolvedDestination) {
|
|
480
|
+
OneKeyLog.error("BundleCrypto", "Path traversal detected in extracted bundle: \(file)")
|
|
481
|
+
return false
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return true
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// MARK: - Safe file verbs — atomic write / safe rename / version-dir listing.
|
|
488
|
+
// Consolidates the FileManager write/move/enumerate patterns scattered through
|
|
489
|
+
// ReactNativeBundleUpdate (writeSignatureFile atomic write, downloadBundle
|
|
490
|
+
// remove-then-move, listLocalBundles contentsOfDirectory) into explicit APIs.
|
|
491
|
+
|
|
492
|
+
public static func atomicWriteFile(filePath: String, contentUtf8: String) throws {
|
|
493
|
+
let dir = (filePath as NSString).deletingLastPathComponent
|
|
494
|
+
let fm = FileManager.default
|
|
495
|
+
if !fm.fileExists(atPath: dir) {
|
|
496
|
+
try fm.createDirectory(atPath: dir, withIntermediateDirectories: true)
|
|
497
|
+
}
|
|
498
|
+
// Foundation's atomically:true writes to a temp file then renames into place.
|
|
499
|
+
try contentUtf8.write(toFile: filePath, atomically: true, encoding: .utf8)
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
public static func safeRename(fromPath: String, toPath: String) throws {
|
|
503
|
+
let fm = FileManager.default
|
|
504
|
+
let destDir = (toPath as NSString).deletingLastPathComponent
|
|
505
|
+
if !fm.fileExists(atPath: destDir) {
|
|
506
|
+
try fm.createDirectory(atPath: destDir, withIntermediateDirectories: true)
|
|
507
|
+
}
|
|
508
|
+
// Same pattern as downloadBundle: remove existing target, then move.
|
|
509
|
+
if fm.fileExists(atPath: toPath) {
|
|
510
|
+
try fm.removeItem(atPath: toPath)
|
|
511
|
+
}
|
|
512
|
+
try fm.moveItem(at: URL(fileURLWithPath: fromPath), to: URL(fileURLWithPath: toPath))
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
public static func listVersionDirs(_ parentDir: String) -> [String] {
|
|
516
|
+
let fm = FileManager.default
|
|
517
|
+
guard let contents = try? fm.contentsOfDirectory(atPath: parentDir) else {
|
|
518
|
+
return []
|
|
519
|
+
}
|
|
520
|
+
var results: [String] = []
|
|
521
|
+
for name in contents {
|
|
522
|
+
let fullPath = (parentDir as NSString).appendingPathComponent(name)
|
|
523
|
+
var isDir: ObjCBool = false
|
|
524
|
+
guard fm.fileExists(atPath: fullPath, isDirectory: &isDir), isDir.boolValue else { continue }
|
|
525
|
+
results.append(name)
|
|
526
|
+
}
|
|
527
|
+
return results
|
|
528
|
+
}
|
|
529
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>AvailableLibraries</key>
|
|
6
|
+
<array>
|
|
7
|
+
<dict>
|
|
8
|
+
<key>BinaryPath</key>
|
|
9
|
+
<string>Gopenpgp.framework/Gopenpgp</string>
|
|
10
|
+
<key>LibraryIdentifier</key>
|
|
11
|
+
<string>ios-arm64_x86_64-simulator</string>
|
|
12
|
+
<key>LibraryPath</key>
|
|
13
|
+
<string>Gopenpgp.framework</string>
|
|
14
|
+
<key>SupportedArchitectures</key>
|
|
15
|
+
<array>
|
|
16
|
+
<string>arm64</string>
|
|
17
|
+
<string>x86_64</string>
|
|
18
|
+
</array>
|
|
19
|
+
<key>SupportedPlatform</key>
|
|
20
|
+
<string>ios</string>
|
|
21
|
+
<key>SupportedPlatformVariant</key>
|
|
22
|
+
<string>simulator</string>
|
|
23
|
+
<key>MinimumOSVersion</key>
|
|
24
|
+
<string>15.5</string>
|
|
25
|
+
</dict>
|
|
26
|
+
<dict>
|
|
27
|
+
<key>BinaryPath</key>
|
|
28
|
+
<string>Gopenpgp.framework/Gopenpgp</string>
|
|
29
|
+
<key>LibraryIdentifier</key>
|
|
30
|
+
<string>ios-arm64</string>
|
|
31
|
+
<key>LibraryPath</key>
|
|
32
|
+
<string>Gopenpgp.framework</string>
|
|
33
|
+
<key>SupportedArchitectures</key>
|
|
34
|
+
<array>
|
|
35
|
+
<string>arm64</string>
|
|
36
|
+
</array>
|
|
37
|
+
<key>SupportedPlatform</key>
|
|
38
|
+
<string>ios</string>
|
|
39
|
+
<key>MinimumOSVersion</key>
|
|
40
|
+
<string>15.5</string>
|
|
41
|
+
</dict>
|
|
42
|
+
</array>
|
|
43
|
+
<key>CFBundlePackageType</key>
|
|
44
|
+
<string>XFWK</string>
|
|
45
|
+
<key>RCTNewArchEnabled</key>
|
|
46
|
+
<true/>
|
|
47
|
+
<key>XCFrameworkFormatVersion</key>
|
|
48
|
+
<string>1.0</string>
|
|
49
|
+
<key>MinimumOSVersion</key>
|
|
50
|
+
<string>15.5</string>
|
|
51
|
+
</dict>
|
|
52
|
+
</plist>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Objective-C API for talking to github.com/ProtonMail/gopenpgp/v3/armor Go package.
|
|
2
|
+
// gobind -lang=objc github.com/ProtonMail/gopenpgp/v3/armor
|
|
3
|
+
//
|
|
4
|
+
// File is generated by gobind. Do not edit.
|
|
5
|
+
|
|
6
|
+
#ifndef __Armor_H__
|
|
7
|
+
#define __Armor_H__
|
|
8
|
+
|
|
9
|
+
@import Foundation;
|
|
10
|
+
#include "ref.h"
|
|
11
|
+
#include "Universe.objc.h"
|
|
12
|
+
|
|
13
|
+
#include "Constants.objc.h"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* ArmorKey armors input as a public key.
|
|
17
|
+
*/
|
|
18
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorKey(NSData* _Nullable input, NSError* _Nullable* _Nullable error);
|
|
19
|
+
|
|
20
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorPGPMessage(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
|
|
21
|
+
|
|
22
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorArmorPGPMessageBytes(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
|
|
23
|
+
|
|
24
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorArmorPGPMessageBytesChecksum(NSData* _Nullable signature, BOOL checksum, NSError* _Nullable* _Nullable error);
|
|
25
|
+
|
|
26
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorPGPMessageChecksum(NSData* _Nullable signature, BOOL checksum, NSError* _Nullable* _Nullable error);
|
|
27
|
+
|
|
28
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorPGPSignature(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
|
|
29
|
+
|
|
30
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorArmorPGPSignatureBinary(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
|
|
31
|
+
|
|
32
|
+
// skipped function ArmorReader with unsupported parameter or return types
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* ArmorWithType armors input with the given armorType.
|
|
37
|
+
*/
|
|
38
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithType(NSData* _Nullable input, NSString* _Nullable armorType, NSError* _Nullable* _Nullable error);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* ArmorWithTypeAndCustomHeaders armors input with the given armorType and
|
|
42
|
+
headers.
|
|
43
|
+
*/
|
|
44
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithTypeAndCustomHeaders(NSData* _Nullable input, NSString* _Nullable armorType, NSString* _Nullable version, NSString* _Nullable comment, NSError* _Nullable* _Nullable error);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* ArmorWithTypeAndCustomHeadersBytes armors input with the given armorType and
|
|
48
|
+
headers.
|
|
49
|
+
*/
|
|
50
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorArmorWithTypeAndCustomHeadersBytes(NSData* _Nullable input, NSString* _Nullable armorType, NSString* _Nullable version, NSString* _Nullable comment, NSError* _Nullable* _Nullable error);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* ArmorWithTypeAndCustomHeadersChecksum armors input with the given armorType and
|
|
54
|
+
headers and checksum option.
|
|
55
|
+
*/
|
|
56
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithTypeAndCustomHeadersChecksum(NSData* _Nullable input, NSString* _Nullable armorType, NSString* _Nullable version, NSString* _Nullable comment, BOOL checksum, NSError* _Nullable* _Nullable error);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* ArmorWithTypeBytes armors input with the given armorType.
|
|
60
|
+
*/
|
|
61
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorArmorWithTypeBytes(NSData* _Nullable input, NSString* _Nullable armorType, NSError* _Nullable* _Nullable error);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* ArmorWithTypeBytesChecksum armors input with the given armorType and checksum option.
|
|
65
|
+
*/
|
|
66
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorArmorWithTypeBytesChecksum(NSData* _Nullable input, NSString* _Nullable armorType, BOOL checksum, NSError* _Nullable* _Nullable error);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* ArmorWithTypeChecksum armors input with the given armorType.
|
|
70
|
+
The checksum option determines if an armor checksum is written at the end.
|
|
71
|
+
*/
|
|
72
|
+
FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithTypeChecksum(NSData* _Nullable input, NSString* _Nullable armorType, BOOL checksum, NSError* _Nullable* _Nullable error);
|
|
73
|
+
|
|
74
|
+
// skipped function ArmorWriterWithType with unsupported parameter or return types
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
// skipped function ArmorWriterWithTypeAndCustomHeaders with unsupported parameter or return types
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
// skipped function ArmorWriterWithTypeChecksum with unsupported parameter or return types
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
// skipped function IsPGPArmored with unsupported parameter or return types
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Unarmor unarmors an armored input into a byte array.
|
|
88
|
+
*/
|
|
89
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorUnarmor(NSString* _Nullable input, NSError* _Nullable* _Nullable error);
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* UnarmorBytes unarmors an armored input into a byte array.
|
|
93
|
+
*/
|
|
94
|
+
FOUNDATION_EXPORT NSData* _Nullable ArmorUnarmorBytes(NSData* _Nullable input, NSError* _Nullable* _Nullable error);
|
|
95
|
+
|
|
96
|
+
#endif
|