Skip to content

Commit 7484839

Browse files
committed
Add crypto impl for iOS
1 parent 09554aa commit 7484839

File tree

4 files changed

+156
-3
lines changed

4 files changed

+156
-3
lines changed

ios/Podfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ target 'Runner' do
3232
use_modular_headers!
3333

3434
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35+
36+
pod 'CryptoSwift', '~> 1.2.0'
3537
end
3638

3739
post_install do |installer|

ios/Podfile.lock

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
PODS:
2+
- CryptoSwift (1.2.0)
23
- Flutter (1.0.0)
34
- image_picker_ios (0.0.1):
45
- Flutter
56
- shared_preferences_ios (0.0.1):
67
- Flutter
78

89
DEPENDENCIES:
10+
- CryptoSwift (~> 1.2.0)
911
- Flutter (from `Flutter`)
1012
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
1113
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
1214

15+
SPEC REPOS:
16+
trunk:
17+
- CryptoSwift
18+
1319
EXTERNAL SOURCES:
1420
Flutter:
1521
:path: Flutter
@@ -19,10 +25,11 @@ EXTERNAL SOURCES:
1925
:path: ".symlinks/plugins/shared_preferences_ios/ios"
2026

2127
SPEC CHECKSUMS:
28+
CryptoSwift: 40e374e45291d8dceedcb0d6184da94533eaabdf
2229
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
2330
image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb
2431
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
2532

26-
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
33+
PODFILE CHECKSUM: 28949384d1a9817c5c0092fcf6ffc3a836337eb0
2734

2835
COCOAPODS: 1.11.2

ios/Runner.xcodeproj/project.pbxproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 50;
6+
objectVersion = 51;
77
objects = {
88

99
/* Begin PBXBuildFile section */
@@ -68,7 +68,6 @@
6868
81B81E118F31476FA4045A87 /* Pods-Runner.release.xcconfig */,
6969
A4FEFEB72D9AAEB411E9065F /* Pods-Runner.profile.xcconfig */,
7070
);
71-
name = Pods;
7271
path = Pods;
7372
sourceTree = "<group>";
7473
};

ios/Runner/AppDelegate.swift

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,158 @@
11
import UIKit
22
import Flutter
3+
import CryptoSwift
4+
5+
private extension String {
6+
static let CRYPTO_CHANNEL = "com.hoc.node_auth/crypto"
7+
static let CRYPTO_ERROR_CODE = "com.hoc.node_auth/crypto_error"
8+
static let ENCRYPT_METHOD = "encrypt"
9+
static let DECRYPT_METHOD = "decrypt"
10+
}
311

412
@UIApplicationMain
513
@objc class AppDelegate: FlutterAppDelegate {
614
override func application(
715
_ application: UIApplication,
816
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
917
) -> Bool {
18+
let flutterVC = window?.rootViewController as! FlutterViewController
19+
20+
let cryptoChannel = FlutterMethodChannel(
21+
name: .CRYPTO_CHANNEL,
22+
binaryMessenger: flutterVC.binaryMessenger
23+
)
24+
cryptoChannel.setMethodCallHandler { call, result in
25+
switch call.method {
26+
case .ENCRYPT_METHOD: encrypt(call: call, result: result)
27+
case .DECRYPT_METHOD: decrypt(call: call, result: result)
28+
default:
29+
result(FlutterMethodNotImplemented)
30+
}
31+
}
32+
1033
GeneratedPluginRegistrant.register(with: self)
1134
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
1235
}
1336
}
37+
38+
private enum AESConfig {
39+
static let iv: [UInt8] = "_hoc081098_auth_".bytes
40+
static let key: [UInt8] = "__hoc081098_nodejs_auth_rxdart__".bytes
41+
42+
static let backgroundQueue = DispatchQueue.global(qos: .userInitiated)
43+
44+
static func gcm() -> GCM { GCM(iv: AESConfig.iv, mode: .combined) }
45+
}
46+
47+
private func complete(result: @escaping FlutterResult, with error: Error) {
48+
debugPrint("[NODE_AUTH] Error: ", error)
49+
50+
executeOnMain {
51+
result(
52+
FlutterError(
53+
code: .CRYPTO_ERROR_CODE,
54+
message: error.localizedDescription,
55+
details: nil
56+
)
57+
)
58+
}
59+
}
60+
61+
private func executeOnMain(block: @escaping () -> Void) {
62+
if Thread.isMainThread {
63+
block()
64+
} else {
65+
DispatchQueue.main.async {
66+
block()
67+
}
68+
}
69+
}
70+
71+
private func useAES(
72+
input: String,
73+
result: @escaping FlutterResult,
74+
inputToBytes: (String) -> [UInt8]?,
75+
bytesToString: @escaping ([UInt8]) -> String?,
76+
block: @escaping (AES, [UInt8]) throws -> [UInt8]
77+
) {
78+
guard let inputBytes = inputToBytes(input) else {
79+
print("[NODE_AUTH] Error: inputToBytes returns nil")
80+
81+
executeOnMain {
82+
result(
83+
FlutterError(
84+
code: .CRYPTO_ERROR_CODE,
85+
message: "An unexpected error occurred!",
86+
details: nil
87+
)
88+
)
89+
}
90+
return
91+
}
92+
93+
AESConfig.backgroundQueue.async {
94+
let start = DispatchTime.now()
95+
96+
do {
97+
let aes = try AES(
98+
key: AESConfig.key,
99+
blockMode: AESConfig.gcm(),
100+
padding: .noPadding
101+
)
102+
103+
let outputBytes = try block(aes, inputBytes)
104+
guard let stringResult = bytesToString(outputBytes) else {
105+
print("[NODE_AUTH] Error: bytesToString returns nil")
106+
107+
executeOnMain {
108+
result(
109+
FlutterError(
110+
code: .CRYPTO_ERROR_CODE,
111+
message: "An unexpected error occurred!",
112+
details: nil
113+
)
114+
)
115+
}
116+
return
117+
}
118+
119+
let end = DispatchTime.now()
120+
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
121+
let millisTime = Double(nanoTime) / 1_000_000
122+
print("[NODE_AUTH] Input: \(input)")
123+
print("[NODE_AUTH] Output: \(stringResult)")
124+
print("[NODE_AUTH] Time: \(millisTime) ms")
125+
126+
executeOnMain { result(stringResult) }
127+
} catch {
128+
complete(result: result, with: error)
129+
}
130+
}
131+
}
132+
133+
private func encrypt(call: FlutterMethodCall, result: @escaping FlutterResult) {
134+
useAES(
135+
input: call.arguments as! String,
136+
result: result,
137+
inputToBytes: { $0.bytes },
138+
bytesToString: base64Encode(bytes:)
139+
) { aes, bytes in try aes.encrypt(bytes) }
140+
}
141+
142+
143+
private func decrypt(call: FlutterMethodCall, result: @escaping FlutterResult) {
144+
useAES(
145+
input: call.arguments as! String,
146+
result: result,
147+
inputToBytes: base64Decode(s:),
148+
bytesToString: { .init(bytes: $0, encoding: .utf8) }
149+
) { aes, bytes in try aes.decrypt(bytes) }
150+
}
151+
152+
func base64Decode(s: String) -> [UInt8]? {
153+
Data(base64Encoded: s)?.bytes
154+
}
155+
156+
func base64Encode(bytes: [UInt8]) -> String {
157+
Data(bytes).base64EncodedString()
158+
}

0 commit comments

Comments
 (0)