Zingly, or how to design a multi-banking app Petr Dvorak joshis@tweets Lime
Zingly, or how to design a multi-banking app
Petr Dvorak joshis@tweets Lime
A big change is comming …
PSD2 Legislation
Access to account information and
payment service initiation
Banking API Server
Multi-Banking Hub Services
Bank A
Ban
ksU
sers
Inte
grat
ors
Banking API Server
Bank B
Banking API Server
Bank C
Zingly
Simple, faster and more secure
mobile banking for your bank
Extra fast login with
PIN or Touch ID
Quick account
overview
Comprehensive
transaction list
Pay your friends
and family
Mobile e-commerce
payments (with SDK)
Design
There is only one chance
to do your app right…
Showing only the nice things
("dictator rule")
Architecture
Open-source
Architecture
• PowerAuth 2.0 Server
• Zingly API Server
• Zingly Multi-banking Hub
• Zingly Mobile App
• Native iOS app (Android later)
• Written in Swift 2.0
• Native PowerAuth 2.0 core (C/C++)
• Cocoapods for library management
Zingly server components play nice
with existing banking systems
PowerAuth 2.0 Server
Zingly API Server
Zingly Multi-Banking Hub
Bank A
Internet bankingB
anks
Use
rsZ
ingl
y
CoreServices
Custom API
Bank B
Custom Security and Core Services
SOAP SOAP
REST
REST + WebSockets
PowerAuth 2.0
Security
What is so hard on mobile banking apps?
Multi-banking
• Storing data from multiple banks
• Authentication to multiple banks
• Data transport security
3rd parties
• People don’t trust them
• Cannot provide huge guarantees
• Can play no, positive or negative role
… back to PowerAuth
Mobile libraries soon But I will show you today !
Authentication Secure Storage E2E Encryption
Authentication
• Secure app activation
• Activation life-cycle
• Multi-factor data signature
Authentication How to …
Step 1: Set up your app
• Application key
• Application secret
• Master Public Key
#define APP_KEY "QvTX+lSRTNNJ9zAT8bC8iw=="
#define APP_SECRET "1zNNJNgP0RBGCJWuoHwKqw=="
#define APP_MASTER_KEY "BKltWgFa0U0qlef0c9ll3y3E4lGWrFPTBvrB+gv9tQ3wIwI aEeBnonH9HuSo/6eJKhCJcse6wHXQl8bQ="
class SecurityContext { let session = PA2Session() static let sharedInstance = SecurityContext() func initSecurityContext() { let setup = PA2SessionSetup() setup.applicationKey = APP_KEY setup.applicationSecret = APP_SECRET setup.masterServerPublicKey = APP_MASTER_KEY self.session.initializeSessionWithSetup(setup) } }
Step 2: Read the "activation code"
XC651-AB231-13891-DE123
Short activation ID Activation OTP
Step 3: Securely exchange public keys
Request - POST: /pa/activation/create
{ "requestObject": { "activationName": "My iPhone", "applicationKey": "UNfS0VZX3JhbmRvbQ==", "activationIdShort": "XDA57-24TBC", "activationNonce": "hbmRvbQRUNESF9QVUJMSUNfS0VZX3J==", "applicationSignature": "SF9QRUNEVUJMSUNfS0VZX3JhbmRvbQ==", "encryptedDevicePublicKey": "RUNESF9QVUJMSUNfS0VZX3JhbmRvbQ==", "extras": "Any custom data in any format (XML, JSON, ...)" } }
let session = SecurityContext.sharedInstance.session
let step1Param = PA2ActivationStep1Param() step1Param.activationIdShort = activationIdShort step1Param.activationOtp = activationOtp let step1Result = session.startActivation(step1Param)! // if (session.lastErrorCode == PA2ErrorCode.Ok) { let activationNonce = step1Result.activationNonce let applicationSignature = step1Result.applicationSignature let encryptedDevicePublicKey = step1Result.cDevicePublicKey
Response - HTTP 200 - OK
{ "status": "OK", "responseObject": { "activationId": "c564e700-7e86-4a87-b6c8-a5a0cc89683f", "activationNonce": "vbQRUNESF9hbmRQVUJMSUNfS0VZX3J==", "ephemeralPublicKey": "MSUNfS0VZX3JhbmRvbQNESF9QVUJMSUNfS0VZX3JhbmRvbQNESF9QVUJ==", "encryptedServerPublicKey": "NESF9QVUJMSUNfS0VZX3JhbmRvbQNESF9QVUJMSUNfS0VZX3JhbmRvbQ==", "serverDataSignature": "QNESF9QVUJMSUNfS0VZX3JhbmRvbQ==" } }
let step2Param = PA2ActivationStep2Param() let response = entity.responseObject step2Param.activationId = response.activationId step2Param.ephemeralNonce = response.activationNonce step2Param.encryptedServerPublicKey = response.encryptedServerPublicKey step2Param.ephemeralPublicKey = response.ephemeralPublicKey step2Param.serverDataSignature = response.serverDataSignature let step2Result = session.validateActivationResponse(step2Param)
if (session.lastErrorCode == PA2ErrorCode.Ok) { // ... continue to next step }
Step 4: Ask user for a PIN code
• Short PIN code (4 digits) can be used
• Check for simple combinations
• Ask user to use Touch ID
Step 5: Generate keys and get session state
// we need keys for three authentication factors ... let possessionKey = session.generateSignatureUnlockKey() let biometryKey = session.generateSignatureUnlockKey()
let unlockKeys = PA2SignatureUnlockKeys() unlockKeys.biometryUnlockKey = biometryKey unlockKeys.possessionUnlockKey = possessionKey unlockKeys.userPassword = PA2Password(string: "1234") session.completeActivation(unlockKeys)
let sessionState = session.serializedState()
Step 6: Store session and keys to keychain
// KeychainAccess for Swift // created by Kishikawa Katsumi // see https://github.com/kishikawakatsumi/KeychainAccess
let keychain = Keychain(service: "com.example.myServiceId")
keychain[data: "PA_SESSION_STATE"] = sessionState keychain[data: "PA_KEY_POSSESSION"] = possessionKey do { try keychain .accessibility( .WhenPasscodeSetThisDeviceOnly, authenticationPolicy: .TouchIDAny ) .set(biometryKey, key: "PA_KEY_BIOMETRY") } catch _ { // Error handling... } }
Step 6: Complete activation on web
12345 67890
Step 8: Sign data, make payments, heureka!
!
// Initialize session after app launch let sessionState = keychain[data: "PA_SESSION_STATE"] if (sessionState != nil) { self.session.deserializeState(sessionState!) }
PA2SignatureUnlockKeys keys; keys.possessionUnlockKey = keychain[data: "PA_KEY_POSSESSION"]
// ... ask for PIN code keys.userPassword = cc7::MakeRange("1234")
// ... or use TouchID instead of PIN like so // keys.biometryUnlockKey = keychain[data: "PA_KEY_BIOMETRY"];
// send data on server with the correct HTTP header let paHeaderName = session.httpAuthHeaderName let paHeaderValue = session.httpAuthHeaderValueForBody( data, httpMethod: "POST", uri: "/account/payment/commit", keys: keys, factor: PA2SignatureFactor_Possession_Knowledge )
X-PowerAuth-Authorization: PowerAuth pa_activation_id="7a24c6e9-48e9-43c2-ab4a-aed6270e924d", pa_application_key="Z19gyYaW5kb521fYWN0aXZ==", pa_nonce="kYjzVBB8Y0ZFabxSWbWovY==", pa_signature_type="possession_knowledge" pa_signature="46782479-37298320", pa_version="2.0"
That wasn't that hard, right?
How about multi-banking?
Many banks, one PIN code
activation id
PIN(x)
knowledge
Bank A Bank B
activation id
knowledge
activation id
PIN(x)
activation id
PIN(x)
knowledge knowledge
Bank A Bank B
Authentication Secure Storage E2E Encryption
Secure Storage
• Data encrypted with remote key
• Authentication needed
• Enables secure mobile multi-banking
PowerAuth 2.0 Server
Zingly API Server
Zingly Multi-Banking Hub
Bank A
Internet bankingB
anks
Use
rsZ
ingl
y
CoreServices
SOAP SOAP
REST
REST + WebSockets
PowerAuth 2.0 Server
Zingly API Server
Bank B
Internet banking
CoreServices
SOAP SOAP
REST
PowerAuth 2.0 Server
Zingly API Server
Zingly Multi-Banking Hub
Bank A
Internet bankingB
anks
Use
rsZ
ingl
y
CoreServices
SOAP SOAP
REST
REST + WebSockets
PowerAuth 2.0 Server
Zingly API Server
Bank B
Internet banking
CoreServices
SOAP SOAP
REST
PowerAuth 2.0 Server
PowerAuth 2.0 Server
Zingly API Server
Zingly Multi-Banking Hub
Bank A
Internet bankingB
anks
Use
rsZ
ingl
y
CoreServices
SOAP SOAP
REST
REST + WebSockets
PowerAuth 2.0 Server
Zingly API Server
Bank B
Internet banking
CoreServices
SOAP SOAP
REST
PowerAuth 2.0 Server
PowerAuth 2.0 Client
activation id
PIN(x)
activation id
PIN(x)
knowledge knowledge
PowerAuth 2.0 Server
Zingly API Server
Zingly Multi-Banking Hub
Bank A
Internet bankingB
anks
Use
rsZ
ingl
y
CoreServices
SOAP SOAP
REST
REST + WebSockets
PowerAuth 2.0 Server
Zingly API Server
Bank B
Internet banking
CoreServices
SOAP SOAP
REST
PowerAuth 2.0 Server
PowerAuth 2.0 Client
knowledge
activation id
PIN(x)
activation id
PIN(x)
activation id
PIN(x)
knowledge knowledge
PowerAuth 2.0 Server
Zingly API Server
Zingly Multi-Banking Hub
Bank A
Internet bankingB
anks
Use
rsZ
ingl
y
CoreServices
SOAP SOAP
REST
REST + WebSockets
PowerAuth 2.0 Server
Zingly API Server
Bank B
Internet banking
CoreServices
SOAP SOAP
REST
PowerAuth 2.0 Server
PowerAuth 2.0 Client SECURE VAULT
knowledge
activation id
PIN(x)
activation id
PIN(x)
activation id
PIN(x)
knowledge knowledge
Authentication Secure Storage E2E Encryption
That was nice… What's in it for me?
• Build secure apps with PowerAuth 2.0
• Mobile e-commerce with Zingly payments
• Use banking API to access banking services
• Steal code, contribute, comment, live! !