-
Notifications
You must be signed in to change notification settings - Fork 1
How to
We are going to create an iOS project that integrates SecureCommunications library and communicates with a backend that uses SecureCommunicationsVapor. Please, visit its Wiki to implement the backend example in Vapor.
Open Xcode 12 and create a new Project -> iOS -> App. Put the name you want, selecting SwiftUI on Interface, SwiftUI App on Life Cycle and Swift on Language and create it.
On File menu, select Swift Packages and Add Package Dependency. Introduce the URL of the library repository https://github.com/supakonoha/SecureCommunications and select Up to Next Major version 1.0.0 and add it to your app target.
We are going to create a new Swift class into the project ContentViewModel that will manage the communication with the server:
import Foundation
import Combine
import SecureCommunications
class ContentViewModel: ObservableObject {
@Published var message: String = "No Response"
var publisher: URLSession.DataTaskPublisher?
var cancellable: Cancellable? = nil
init() {
guard let url = URL(string: "http://192.168.0.2:8080/hello") else {
self.message = "Error loading url"
return
}
guard let publicKey = try? KeyStore().publicKeyInPemRepresentation() else {
self.message = "Error loading my public key"
return
}
guard let publicKeyBase64 = publicKey.data(using: .utf8)?.base64EncodedString() else {
self.message = "Error loading my public key"
return
}
var request = URLRequest(url: url)
request.addValue(publicKeyBase64, forHTTPHeaderField: "X-PublicKey")
publisher = URLSession.shared.dataTaskPublisher(for: request)
hello()
}
}
extension ContentViewModel {
func hello() {
message = "Loading"
let senderPemPublicKey = """
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2qk3lQHFQ0PEp8/TcKAnD3VmGXOr
bpi8VRLHlfbq/yDTm32AOAtVQ7rF7dsKen0d+sRJxQIMG3Q+/wejozGhvA==
-----END PUBLIC KEY-----
"""
guard let senderPublicKey = try? KeyStore.publicKey(pemRepresentation: senderPemPublicKey) else {
self.message = "Error loading sender public key"
return
}
let salt = "This is our salt"
cancellable = publisher?.tryMap { element -> Data in
guard let httpResponse = element.response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return element.data
}
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { (subscriber) in
switch subscriber {
case .failure(let error):
self.message = "Error: \(error.localizedDescription)"
case .finished:
break
}
}) {[unowned self] (message) in
guard let encryptedMessage = String(data: message, encoding: .utf8) else {
self.message = "No Data Decrypted"
return
}
guard let decryptedMessage = encryptedMessage.openAES(senderPublicKey: senderPublicKey, salt: salt) else {
self.message = "No Data Decrypted"
return
}
self.message = decryptedMessage
}
}
}You should have into consideration:
- In this class we define
messagethat will be used on the view and updates the view when we receive data from server. - We are using
192.168.0.2as IP address of our server. Please, modify with your server IP address. - We are adding a
X-PublicKeyheader into the request where we are passing our public key in PEM representation and encoded on Base64. The server is waiting this header. - For decrypting we are using the server public key. This is an example but in your final project, please, manage it in a secure way.
- The salt is the same in both parts
We are modifying ContentView to use the ContentViewModel and update the text in the view when data is received
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel = ContentViewModel()
var body: some View {
VStack {
Text(viewModel.message)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}Remember, you cannot use Simulator with this app because Secure Enclave works only on real devices.
You can launch on a real device with iOS 14 and if everything works fine, you should see a Hello, world! on the screen.