Skip to content

Commit 36fa999

Browse files
authored
Merge pull request #37 from hoc081098/crypto_ios
Add crypto impl for iOS
2 parents 7014f65 + aa028d8 commit 36fa999

File tree

4 files changed

+154
-3
lines changed

4 files changed

+154
-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: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,156 @@
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+
NSLog("\n[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+
NSLog("\n[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+
NSLog("\n[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+
NSLog("\n[NODE_AUTH] Time: \(millisTime) ms")
123+
124+
executeOnMain { result(stringResult) }
125+
} catch {
126+
complete(result: result, with: error)
127+
}
128+
}
129+
}
130+
131+
private func encrypt(call: FlutterMethodCall, result: @escaping FlutterResult) {
132+
useAES(
133+
input: call.arguments as! String,
134+
result: result,
135+
inputToBytes: { $0.bytes },
136+
bytesToString: base64Encode(bytes:)
137+
) { aes, bytes in try aes.encrypt(bytes) }
138+
}
139+
140+
141+
private func decrypt(call: FlutterMethodCall, result: @escaping FlutterResult) {
142+
useAES(
143+
input: call.arguments as! String,
144+
result: result,
145+
inputToBytes: base64Decode(s:),
146+
bytesToString: { .init(bytes: $0, encoding: .utf8) }
147+
) { aes, bytes in try aes.decrypt(bytes) }
148+
}
149+
150+
func base64Decode(s: String) -> [UInt8]? {
151+
Data(base64Encoded: s)?.bytes
152+
}
153+
154+
func base64Encode(bytes: [UInt8]) -> String {
155+
Data(bytes).base64EncodedString()
156+
}

0 commit comments

Comments
 (0)