To learn the client-server communication, a practical approach is to setup the connection between an iOS device (Client) and a Raspberry Pi (Server):
Client: iOS device with app developed in Swift
Server: Raspberry Pi with socket server programmed in Python
Requirements
1. Setup a Raspberry Pi
2. Mac + Xcode + iPhone/iPad
===============
The three sections below will explain how to:
1. Setup the basic client-server socket communication architecture.
2. Encrypt/decrypt a message with RSA public/private keys.
3. Combine sections 1 and 2 to setup the secure socket communication.
1. Basic Socket Communication
The basic form of client-server communication between an iPhone/iPad and a Python socket server built on a Raspberry Pi is shown in this tutorial:
Connect an iPhone to a Simple Python Socket Server (Raspberry Pi Part) (iOS Part)
The above tutorial must be fully understood, because it is the basis for the tutorials in the 3. Secure Socket Communication section.
2. RSA
The data transmitted between the client and the server in the above example are not encrypted and hence are insecure. Therefore, using RSA (Rivest-Shamir-Adleman) cryptosystem for secure communications is a good topic to be studied for understanding asymmetric public-private key cryptosystem.
All examples below follow this procedure:
1. Generate or obtain an RSA private and public key pair.
2. Encrypt a message with the public key.
3. Decrypt the encrypted message with the private key.
2.1 Basic OpenSSL commands
In order to understand how to use RSA keys for encryption/decryption, try the basic OpenSSL RSA commands:
OpenSSL RSA commands to encrypt/decrypt a message in terminal (Raspberry Pi and Mac)
You should notice that RSA uses different keys of the same key pair for encrypting and decrypting a message. This is known as asymmetric since different keys are used.
Now let's start programming with RSA keys!!
2.2 Importing External RSA keys
Here are Python (Raspberry Pi) and Swift (iOS) examples showing how to import external OpenSSL-generated RSA keys in PEM file format:
Encrypt/decrypt a string with external public/private keys (Raspberry Pi Part) (iOS Part)
2.3 Using Code-generatd RSA keys
External RSA key files are fixed. If different key pairs are required while the program is running, try to generate keys in Python/Swift code:
Encrypt/decrypt a string with code-generated public/private keys (Raspberry Pi Part) (iOS Part)
Now let's move on to implement code-generated RSA keys in the client-server architecture.
3. Secure Socket Communication
Remember that:
Client: iOS device with app developed in Swift
Server: Raspberry Pi with socket server programmed in Python
There are two tutorials in this section. Both of them will explain how to transmit an encrypted message between a client and a server. The difference between the two tutorials is the opposite direction of data transmission. The principle of sending encrypted message is as below:
1. The receiving device generates an RSA private-public key pair and sends the public key to the transmitting device.
2. The transmitting device encrypts a message using the public key provided by the receiving device and sends the encrypted message to the receiving device.
3. The receiving device decrypts the encrypted message from the transmitting device using the private key.
The two tutorials with different directions of transmitting encrypted data are as below:
1. From iOS device to Python socket server (Raspberry Pi Part) (iOS Part)
2. From Python socket server to iOS device (Raspberry Pi Part) (iOS Part)
Or in terms of encrypt/decrypt in Python/Swift programming languages:
1. Encrypt in Swift and decrypt in Python (Raspberry Pi Part) (iOS Part)
2. Encrypt in Python and decrypt in Swift (Raspberry Pi Part) (iOS Part)
Note:
For Tutorial 2. Encrypt in Python and decrypt in Swift (iOS Part), you need to understand how to manage the iOS keychain in this tutorial:
Store/Retrieve/Delete RSA public/private keys with keychain (iOS Swift)
More Information:
Crypto 101 ebook (pdf)
This blog is about Apple's Swift programming language with iOS, Xcode, and iPhone.
Related Information: Electrical and Computer Engineering - StudyEECC
Biomedical Engineering -
StudyBME
Python - Study Raspberry Pi
Showing posts with label security. Show all posts
Showing posts with label security. Show all posts
Friday, March 4, 2016
Sending RSA encrypted message - From Python socket server to iOS device (iOS Part)
Secure Data Transmission: Raspberry Pi -> iOS device
Secure communication between a mobile device client and a server is important. This tutorial selects an iPhone as the server and uses a Raspberry Pi as the client. The communication procedure is as below:
1. iPhone generates an RSA private / public key pair and sends the public key to server.
2. Server encrypts a message using the public key provided by iPhone and sends the encrypted message to iPhone
3. iPhone decrypts the encrypted message from server using the private key
This tutorial is derived from the basic communication between an iPhone and a Python socket server built on a Raspberry Pi without encryption:
Connect an iPhone to a Simple Python Socket Server (Raspberry Pi Part) (iOS Part)
For an overview on client-server communications, see this:
Communication between iOS device (Client) and Raspberry Pi (Server)
Raspberry Pi Part
Setup a socket server in Python:
Sending RSA encrypted message - From Python socket server to iOS device (Raspberry Pi Part)
Result
Run both the socket server on Raspberry Pi and iOS simulator on Mac. Press the four app buttons from top to bottom. The message "Secret message from RPi server" sent by Raspberry Pi should be displayed on the iOS app and Xcode debug console:
Reference:
CryptoExportImportManager on GitHub.
Go back to Communication between iOS device (Client) and Raspberry Pi (Server)
Secure communication between a mobile device client and a server is important. This tutorial selects an iPhone as the server and uses a Raspberry Pi as the client. The communication procedure is as below:
1. iPhone generates an RSA private / public key pair and sends the public key to server.
2. Server encrypts a message using the public key provided by iPhone and sends the encrypted message to iPhone
3. iPhone decrypts the encrypted message from server using the private key
This tutorial is derived from the basic communication between an iPhone and a Python socket server built on a Raspberry Pi without encryption:
Connect an iPhone to a Simple Python Socket Server (Raspberry Pi Part) (iOS Part)
For an overview on client-server communications, see this:
Communication between iOS device (Client) and Raspberry Pi (Server)
Raspberry Pi Part
Setup a socket server in Python:
Sending RSA encrypted message - From Python socket server to iOS device (Raspberry Pi Part)
iOS Part
The Xcode version used is 7.2.1 (Swift 2.1.1).
1. Download CryptoExportImportManager. Find out the CryptoExportImportManager.swift file in the downloaded folder.
2. Create a new Single View Application project in Xcode.
3. Add CryptoExportImportManager.swift to the project just created.
4. Modify ViewController.swift as below:
import UIKit
class ViewController: UIViewController, NSStreamDelegate {
//Button
var buttonConnect : UIButton!
var buttonSendKey : UIButton!
var buttonDecryptMsg : UIButton!
var buttonQuit : UIButton!
//Label
var label : UILabel!
var labelConnection : UILabel!
//Socket server
let addr = "192.168.xx.xx"
let port = xxxx
//Network variables
var inStream : NSInputStream?
var outStream: NSOutputStream?
//Data received
var buffer = [UInt8](count: 200, repeatedValue: 0)
var inStreamLength : Int!
//Key variables and constants
var publicKey, privateKey: SecKey?
var publicKeyString = ""
let keySize = 1024
let tagPrivate = "com.mycompany.tagPrivate"
let tagPublic = "com.mycompany.tagPublic"
override func viewDidLoad() {
super.viewDidLoad()
ButtonSetup()
LabelSetup()
KeySetup()
}
//Button Functions
func ButtonSetup() {
buttonConnect = UIButton(frame: CGRectMake(20, 50, 300, 30))
buttonConnect.setTitle("Connect to server", forState: UIControlState.Normal)
buttonConnect.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
buttonConnect.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
buttonConnect.addTarget(self, action: "btnConnectPressed:", forControlEvents: UIControlEvents.TouchUpInside)
view.addSubview(buttonConnect)
buttonSendKey = UIButton(frame: CGRectMake(20, 100, 300, 30))
buttonSendKey.setTitle("Send public key to server", forState: UIControlState.Normal)
buttonSendKey.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
buttonSendKey.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
buttonSendKey.addTarget(self, action: "btnSendKey:", forControlEvents: UIControlEvents.TouchUpInside)
buttonSendKey.alpha = 0.3
buttonSendKey.enabled = false
view.addSubview(buttonSendKey)
buttonDecryptMsg = UIButton(frame: CGRectMake(20, 150, 300, 30))
buttonDecryptMsg.setTitle("Decrypt message", forState: UIControlState.Normal)
buttonDecryptMsg.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
buttonDecryptMsg.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
buttonDecryptMsg.addTarget(self, action: "btnDecryptMsg:", forControlEvents: UIControlEvents.TouchUpInside)
buttonDecryptMsg.alpha = 0.3
buttonDecryptMsg.enabled = false
view.addSubview(buttonDecryptMsg)
buttonQuit = UIButton(frame: CGRectMake(20, 200, 300, 30))
buttonQuit.setTitle("Send \"Quit\"", forState: UIControlState.Normal)
buttonQuit.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
buttonQuit.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
buttonQuit.addTarget(self, action: "btnQuitPressed:", forControlEvents: UIControlEvents.TouchUpInside)
buttonQuit.alpha = 0.3
buttonQuit.enabled = false
view.addSubview(buttonQuit)
}
func btnConnectPressed(sender: UIButton) {
NetworkEnable()
buttonConnect.alpha = 0.3
buttonConnect.enabled = false
}
func btnSendKey(sender: UIButton) {
let publicKeyTypeStr = "public_key=\(publicKeyString)"
let data : NSData = publicKeyTypeStr.dataUsingEncoding(NSUTF8StringEncoding)!
outStream?.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
}
func btnDecryptMsg(sender: UIButton) {
let dataEncryptedSize : Int = inStreamLength
var arrayDecrypted = [UInt8](count: dataEncryptedSize, repeatedValue: 0)
var arrayDecryptedSize = dataEncryptedSize
let status = SecKeyDecrypt(privateKey!, SecPadding.PKCS1, &buffer, dataEncryptedSize, &arrayDecrypted, &arrayDecryptedSize)
if status == errSSLCrypto {
print("errSSLCrypto") //-9809 error
return
} else if status != noErr {
print("Decryption Error! \(status.description)")
return
}
let messageStr = NSString(bytes: &arrayDecrypted, length: arrayDecryptedSize, encoding: NSUTF8StringEncoding)!
label.text = "Server sent:\n\(messageStr)"
print("Decrypt successfully:\n\(messageStr)")
buttonDecryptMsg.alpha = 0.3
buttonDecryptMsg.enabled = false
buttonQuit.alpha = 1
buttonQuit.enabled = true
}
func btnQuitPressed(sender: UIButton) {
let data : NSData = "Quit".dataUsingEncoding(NSUTF8StringEncoding)!
outStream?.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
buttonQuit.alpha = 0.3
buttonQuit.enabled = false
}
//Label setup function
func LabelSetup() {
label = UILabel(frame: CGRectMake(0,0,300,150))
label.center = CGPointMake(view.center.x, view.center.y+100)
label.textAlignment = NSTextAlignment.Center
label.numberOfLines = 0 //Multi-lines
label.font = UIFont(name: "Helvetica-Bold", size: 20)
view.addSubview(label)
labelConnection = UILabel(frame: CGRectMake(0,0,300,30))
labelConnection.center = view.center
labelConnection.textAlignment = NSTextAlignment.Center
labelConnection.text = "Please connect to server"
view.addSubview(labelConnection)
}
//Get keys from keychain or generate new keys
func KeySetup() {
//Reset keychain
//deleteAllKeysInKeyChain()
if (GetKeysFromKeychain()) {
print("Key pair retrieved successfully!")
} else {
print("No valid key pair")
deleteAllKeysInKeyChain()
GenerateKeyPair()
}
GetPublicKeyStr()
}
//Other key functions - Check Keychain and get keys
func GetKeysFromKeychain() -> Bool {
privateKey = GetKeyTypeInKeyChain(tagPrivate)
publicKey = GetKeyTypeInKeyChain(tagPublic)
return ((privateKey != nil)&&(publicKey != nil))
}
func GetKeyTypeInKeyChain(tag : String) -> SecKey? {
let query: [String: AnyObject] = [
String(kSecClass) : kSecClassKey,
String(kSecAttrKeyType) : kSecAttrKeyTypeRSA,
String(kSecAttrApplicationTag): tag,
String(kSecReturnRef) : true
]
var result : AnyObject?
let status = SecItemCopyMatching(query, &result)
if status == errSecSuccess {
print("\(keyTypeStr(tag)) Key existed!")
return result as! SecKey?
}
print("no \(keyTypeStr(tag)) key")
return nil
}
//Get public key string from keychain
func GetPublicKeyStr() {
var unsafeData : AnyObject?
let parameters = [
kSecClass as String: kSecClassKey,
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
kSecReturnData as String: true
]
//Get public key string
let status = SecItemCopyMatching(parameters, &unsafeData)
if status != noErr {
print("Get Key Error!")
return
}
//Need CryptoExportImportManager.swift from GitHub.
let manager = CryptoExportImportManager()
publicKeyString = manager.exportRSAPublicKeyToPEM(unsafeData as! NSData, keyType: kSecAttrKeyTypeRSA as String, keySize: keySize)
//print(publicKeyString) //Check this with server
}
//Generate private and public keys
func GenerateKeyPair() {
let privateKeyAttr: [NSString: AnyObject] = [
kSecAttrIsPermanent: true,
kSecAttrApplicationTag: tagPrivate
]
let publicKeyAttr: [NSString: AnyObject] = [
kSecAttrIsPermanent: true,
kSecAttrApplicationTag: tagPublic
]
let parameters: [String: AnyObject] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: keySize,
kSecPrivateKeyAttrs as String: privateKeyAttr,
kSecPublicKeyAttrs as String: publicKeyAttr
]
//Generate new keys and store them in keychain
let status = SecKeyGeneratePair(parameters, &publicKey, &privateKey)
if status != noErr {
print("SecKeyGeneratePair Error! \(status.description)")
return
}
print("Key pair generated successfully")
}
//key type string
func keyTypeStr(tag: String) -> String {
return tag.stringByReplacingOccurrencesOfString("com.mycompany.tag", withString: "")
}
//Delete keys when required.
func deleteAllKeysInKeyChain() {
let query : [String: AnyObject] = [
String(kSecClass) : kSecClassKey
]
let status = SecItemDelete(query)
switch status {
case errSecItemNotFound:
print("No key in keychain")
case noErr:
print("All Keys Deleted!")
default:
print("SecItemDelete error! \(status.description)")
}
}
//Network functions
func NetworkEnable() {
print("NetworkEnable")
NSStream.getStreamsToHostWithName(addr, port: port, inputStream: &inStream, outputStream: &outStream)
inStream?.delegate = self
outStream?.delegate = self
inStream?.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outStream?.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
inStream?.open()
outStream?.open()
buffer = [UInt8](count: 200, repeatedValue: 0)
}
func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
switch eventCode {
case NSStreamEvent.EndEncountered:
print("EndEncountered")
labelConnection.text = "Connection stopped by server"
label.text = ""
inStream?.close()
inStream?.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outStream?.close()
print("Stop outStream currentRunLoop")
outStream?.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
buttonConnect.alpha = 1
buttonConnect.enabled = true
buffer.removeAll(keepCapacity: true)
case NSStreamEvent.ErrorOccurred:
print("ErrorOccurred")
inStream?.close()
inStream?.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outStream?.close()
outStream?.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
labelConnection.text = "Failed to connect to server"
buttonConnect.alpha = 1
buttonConnect.enabled = true
label.text = ""
case NSStreamEvent.HasBytesAvailable:
print("HasBytesAvailable")
if aStream == inStream {
inStreamLength = inStream!.read(&buffer, maxLength: buffer.count)
//If data received
if inStreamLength > 0 {
label.text = "Encrypted message received!"
buttonSendKey.alpha = 0.3
buttonSendKey.enabled = false
buttonDecryptMsg.alpha = 1.0
buttonDecryptMsg.enabled = true
}
}
case NSStreamEvent.HasSpaceAvailable:
print("HasSpaceAvailable")
case NSStreamEvent.None:
print("None")
case NSStreamEvent.OpenCompleted:
print("OpenCompleted")
labelConnection.text = "Connected to server"
buttonSendKey.alpha = 1.0
buttonSendKey.enabled = true
default:
print("Unknown")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Reference:
CryptoExportImportManager on GitHub.
Go back to Communication between iOS device (Client) and Raspberry Pi (Server)
Subscribe to:
Posts (Atom)
