3

I'm trying to create a application/vnd.wfa.wsc payload in Swift. I found this post here for Android: Creating an NDEF WiFi record using application/vnd.wfa.wsc in Android

I'm stuck with creating the payload that I want to write on a NFC Tag. I tried to translate the java code to swift and wrote the payload on an NFC Tag but I'm not able to read the data with an android phone.

let VERSION: [UInt8] = [0x10, 0x4A]
let CREDENTIAL: [UInt8] = [0x10, 0x0e]
let AUTH_TYPE: [UInt8]    = [0x10, 0x03]
let CRYPT_TYPE: [UInt8]   = [0x10, 0x0F]
let MAC_ADDRESS: [UInt8]  = [0x10, 0x20]
let NETWORK_IDX: [UInt8]  = [0x10, 0x26]
let NETWORK_KEY: [UInt8]  = [0x10, 0x27]
let NETWORK_NAME: [UInt8] = [0x10, 0x45]
let OOB_PASSWORD: [UInt8] = [0x10, 0x2C]
let VENDOR_EXT: [UInt8]   = [0x10, 0x49]
let VENDOR_WFA: [UInt8]   = [0x00, 0x37, 0x2A]
let VERSION2: [UInt8]     = [0x00]
let KEY_SHAREABLE: [UInt8] = [0x02]
let AUTH_OPEN: [UInt8] = [0x00, 0x01]
let AUTH_WPA_PERSONAL: [UInt8] = [0x00, 0x02]
let AUTH_SHARED: [UInt8] = [0x00, 0x04]
let AUTH_WPA_ENTERPRISE: [UInt8] = [0x00, 0x08]
let AUTH_WPA2_ENTERPRISE: [UInt8] = [0x00, 0x10]
let AUTH_WPA2_PERSONAL: [UInt8] = [0x00, 0x20]
let AUTH_WPA_WPA2_PERSONAL: [UInt8] = [0x00, 0x22]
let CRYPT_NONE: [UInt8] = [0x00, 0x01]
let CRYPT_WEP: [UInt8] = [0x00, 0x02]
let CRYPT_TKIP: [UInt8] = [0x00, 0x04]
let CRYPT_AES: [UInt8] = [0x00, 0x08]
let CRYPT_AES_TKIP: [UInt8] = [0x00, 0x0C]

let credential: [UInt8] = [0x00, 0x36]
let idx: [UInt8] = [0x00, 0x01, 0x01]

let ssid = "TestWifi"
let password = "Test12345"

let ssidBytes: [UInt8] = Array(ssid.utf8)
let passwordBytes: [UInt8] = Array(password.utf8)
let authBytes: [UInt8] = Array("WPA PSK".utf8)

let lengthSSID: [UInt8] = [UInt8(ssid.lengthOfBytes(using: .utf8))]
let lengthPassword: [UInt8] = [UInt8(password.lengthOfBytes(using: .utf8))]

let cred: [UInt8] = CREDENTIAL + credential
let index: [UInt8] = NETWORK_IDX + idx
let network: [UInt8] = NETWORK_NAME + lengthSSID + ssidBytes
let auth: [UInt8] = AUTH_TYPE + AUTH_WPA_PERSONAL + authBytes
let crypt: [UInt8] = CRYPT_TYPE + CRYPT_WEP + CRYPT_AES_TKIP
let netw: [UInt8] = NETWORK_KEY + lengthPassword + passwordBytes

let foo1 = cred + index
let foo2 = network + auth
let foo3 = crypt + netw

let payload = foo1 + foo2 + foo3

let type = Data(base64Encoded: "application/vnd.wfa.wsc".base64Encoded()!)!
let identifier = Data(base64Encoded: "".base64Encoded()!)!
let payloadData = Data(bytes: payload, count: payload.count)
let payload = NFCNDEFPayload(format: .media, type: type, identifier: identifier, payload: payloadData)

Can someone point out what I'm doing wrong?

Nico S.
  • 3,056
  • 1
  • 30
  • 64

3 Answers3

2

1) Credential TLV consists of sub-TLV[enter image description here

Following is the Swift code to create the payload. TODO: (1) I may have to check the required endian and reorder individual fields (2) You may want to check other args of this API

import Foundation
import Glibc

/* TotalLen is count of all bytes in parenthesis.  

CREDENTIAL + totallen +   
(  
NETWORK_IDX + Idxlen + idx  
NETWORK_NAME + Namelen + ssidBytes  
AUTH_TYPE + Authlen + AUTH_WPA_PERSONAL  
CRYPT_TYPE + Cryptlen + AUTH_MIXED  
NETWORK_KEY + Keylen + passwordBytes  
MAC_ADDRESS + Maclen + addr  
)  

0x100E + **TotalLen** +  
(0x1026 + 0x0001 + 01 +  
0x1045 + 0x0008 + TestWifi +  
0x1003 + 0x0002 + 0x0002 +  
0x100F + 0x0002 + 0x000C (Mixed mode supporting TKIP, AES) + 
0x1027 + 0x0009 + Test12345 +
0x1020 + 0x0006 + address) */

//Attributes
let VERSION: [UInt8] = [0x10, 0x4A]
let CREDENTIAL: [UInt8] = [0x10, 0x0e]
let AUTH_TYPE: [UInt8]    = [0x10, 0x03]
let CRYPT_TYPE: [UInt8]   = [0x10, 0x0F]
let MAC_ADDRESS: [UInt8]  = [0x10, 0x20]
let NETWORK_IDX: [UInt8]  = [0x10, 0x26]
let NETWORK_KEY: [UInt8]  = [0x10, 0x27]
let NETWORK_NAME: [UInt8] = [0x10, 0x45]
let OOB_PASSWORD: [UInt8] = [0x10, 0x2C]
let VENDOR_EXT: [UInt8]   = [0x10, 0x49]
let VENDOR_WFA: [UInt8]   = [0x00, 0x37, 0x2A]
let VERSION2: [UInt8]     = [0x00]
let KEY_SHAREABLE: [UInt8] = [0x02]
let AUTH_OPEN: [UInt8] = [0x00, 0x01]
let AUTH_WPA_PERSONAL: [UInt8] = [0x00, 0x02]
let AUTH_SHARED: [UInt8] = [0x00, 0x04]
let AUTH_WPA_ENTERPRISE: [UInt8] = [0x00, 0x08]
let AUTH_MIXED: [UInt8] = [0x00, 0x0C]
let AUTH_WPA2_ENTERPRISE: [UInt8] = [0x00, 0x10]
let AUTH_WPA2_PERSONAL: [UInt8] = [0x00, 0x20]
let AUTH_WPA_WPA2_PERSONAL: [UInt8] = [0x00, 0x22]
let CRYPT_NONE: [UInt8] = [0x00, 0x01]
let CRYPT_WEP: [UInt8] = [0x00, 0x02]
let CRYPT_TKIP: [UInt8] = [0x00, 0x04]
let CRYPT_AES: [UInt8] = [0x00, 0x08]
let CRYPT_AES_TKIP: [UInt8] = [0x00, 0x0C]

//Values
let idx: [UInt8] = [0x01]
let ssid = "TestWifi"
let ssidBytes: [UInt8] = Array(ssid.utf8)
let password = "Test12345"
let passwordBytes: [UInt8] = Array(password.utf8)
let addr: [UInt8] = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66]

let authBytes: [UInt8] = Array("WPA PSK".utf8)

//Lengths
let Idxlen: [UInt8] = [0x00, 0x01]
var temp = ssid.lengthOfBytes(using: .utf8)
let Namelen: [UInt8] = [UInt8(temp >> 8), UInt8(temp)]
let Authlen: [UInt8] = [0x00, 0x02]
let Cryptlen: [UInt8] = [0x00, 0x02]
temp = password.lengthOfBytes(using: .utf8)
let Keylen: [UInt8] = [UInt8(temp >> 8), UInt8(temp)]
let Maclen: [UInt8] = [0x00, 0x06]

//Packet formation
let id = NETWORK_IDX + Idxlen + idx
let name = NETWORK_NAME + Namelen + ssidBytes
let aut = AUTH_TYPE + Authlen + AUTH_WPA_PERSONAL
let cry = CRYPT_TYPE + Cryptlen + AUTH_MIXED
let key = NETWORK_KEY + Keylen + passwordBytes
let mac = MAC_ADDRESS + Maclen + addr
var payload: [UInt8] = id + name + aut + cry + key + mac

//Prepend Credential Attribute header
let totallen = payload.count
var totallenBytes = [UInt8(totallen >> 8), UInt8(totallen)]
var cred = CREDENTIAL + totallenBytes
payload.insert(contentsOf:cred, at: 0)
print(payload)```
Padmanabha V
  • 430
  • 4
  • 11
2

I created the following solution by using version 2.0.7 of the Wi-Fi Simple Configuration Technical Specification

let type = "application/vnd.wfa.wsc".data(using: .utf8)!

let authenticationTypesString = ["Open", "WPA-Personal", "Shared", "WPA-Enterprise", "WPA2-Enterprise", "WPA2-Personal"]
let encryptionTypesString = ["None", "WEP", "TKIP", "AES", "AES/TKIP (mixed)"]

let authenticationTypes: [[UInt8]] = [[0x00, 0x01], [0x00, 0x02], [0x00, 0x04], [0x00, 0x08], [0x00, 0x10], [0x00, 0x20]]
let encryptionTypes: [[UInt8]] = [[0x00, 0x01], [0x00, 0x02], [0x00, 0x04], [0x00, 0x08], [0x00, 0x0c]]

let ssidString = "Network Name"
let networkKeyString = "Network Key"

let ssidBytes: [UInt8] = Array(ssidString.utf8)
let networkKeyBytes: [UInt8] = Array(networkKeyString.utf8)

let ssidLength = UInt8(ssidBytes.count)
let networkKeyLength = UInt8(networkKeyBytes.count)

let authenticationTypeBytes = authenticationTypes[5]
let encryptionTypeBytes = encryptionTypes[3]

let networkIndex: [UInt8]       = [0x10, 0x26, 0x00, 0x01, 0x01]
let ssid: [UInt8]               = [0x10, 0x45, 0x00, ssidLength] + ssidBytes
let authenticationType: [UInt8] = [0x10, 0x03, 0x00, 0x02] + authenticationTypeBytes
let encryptionType: [UInt8]     = [0x10, 0x0F, 0x00, 0x02] + encryptionTypeBytes
let networkKey: [UInt8]         = [0x10, 0x27, 0x00, networkKeyLength] + networkKeyBytes
let macAddress: [UInt8]         = [0x10, 0x20, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]

let credential = networkIndex + ssid + authenticationType + encryptionType + networkKey + macAddress
let credentialLength = UInt8(credential.count)

let bytes = [0x10, 0x0E, 0x00, credentialLength] + credential
let payload = Data(bytes: bytes, count: bytes.count)

let ndefPayload = NFCNDEFPayload(format: .media, type: type, identifier: Data(), payload: payload)

let ndefMessage = NFCNDEFMessage(records: [ndefPayload])

I hope this will help!

0

The original Android code shows that lengthSSID and lengthPassword are 2-byte arrays, with the MSB in the first element and the LSB in the second element. Your code is creating a single element [UInt8] for both of those, so the binary format doesn't match. This code will pad the SSID length value out to 2 bytes:

let lengthSSIDVal = ssid.lengthOfBytes(using: .utf8)
let lengthSSID: [UInt8] = [UInt8(lengthSSIDVal / 256), UInt8(lengthSSIDVal % 256)]

Do the same for lengthPassword.

The rest of the code looks like an accurate port, so I suspect the above is the issue, but also make sure the NDEF is being written with the application/vnd.wfa.wsc MIME type.

Evan Deaubl
  • 709
  • 6
  • 10
  • Hi, thanks for your answer. I tried your mentioned fix but it is not working... for more clarification I added the payload creation as well. – Nico S. Sep 16 '19 at 17:17
  • A couple of things looking back over the linked solution: (1) are you creating and prepending the handover select record as well? (2) The auth and crypt fields look wrong per the spec, which should only have one value each. Try dropping the second value in each of those lines. – Evan Deaubl Sep 16 '19 at 18:57
  • (1) I don't understand what you mean, (2) done, didn't help – Nico S. Sep 16 '19 at 21:36
  • Can you post the Card dump by reading it using the TagInfo application ( https://apps.apple.com/us/app/nfc-taginfo-by-nxp/id1246143596) or similar – Padmanabha V Sep 17 '19 at 11:08