Problems Setting Wifi Credentials on Photon From a Non-mobile Device

So, I’m trying to create a Windows setup wizard for simply entering Wifi credentials on a claimed photon and am hitting some snags. I have looked at the source for the iOS and Android setup wizards and it seems pretty straight forward, but for some reason I am having some issues. Here is where things stand:

  1. I put the device into listening mode (it is blinking blue and broadcasting its SSID)

  2. I am able to send commands and receive responses (e.g scan command, device id command, etc.) without any issues

  3. This is where the wheels come off. I am able to send the wifi connection credentials, but don’t get back a response code. Instead, I get back “\n\n” but no response follows.

  4. I am then able to send a “connect to AP” command and receive a response code of 0, indicating all is well, but it never connects and never exits listening mode. After reading some other posts, I have tried hitting reset after receiving the connection response, but to no avail.

A couple more points. I am only interested in setting the wifi credentials. The device is already claimed and the claim code in the "device id " response is 1. I am starting to suspect that it may have something to do with me not having sent a claim code to the device prior to trying to establish a connection, but I’m unsure. I don’t want to use the CLI because I would like to run this on a customer’s computer without installing unnecessary software.

Has anyone had a similar issues or have any ideas as to where I’m going off the rails here? Any help would be greatly appreciated!

Do you use RSA encryption?

1 Like

I am currently just sending the passcode in plain text. The iOS SDK does this if as a fallback, so I believe it should work without RSA encrypting the passcode? The reason for doing this twofold. First, I am trying to limit my bug surface and can tackle that afterward. Lastly, I am unsure of the format of the public key. It must have a modulus and an exponent, but I haven't started to dig into where one ends and the other begins.

Regardless, I also wondered if this might be part of the problem and so enabled an open guest network and had identical results.

I see. i don’t know if it works unencrypted - if i remember right it didn’t when i tried to do it in .net (otherwise i would’ve spared myself all the trouble in this thread :smile:

@smnnekho I can’t believe I didn’t come across this in all of my searching :open_mouth:. This looks incredibly promising. I will try it out tonight to see if I can get things moving. I really can’t thank you enough, especially after smashing my head against the wall for the last few days!

The first code i posted is as simple as possible (in vb.net though - but easy to convert) and it worked. so that should definatly get you started:

Imports System.Net
Imports System.Runtime.InteropServices
Imports System.Security.Cryptography
Imports System.Text
Imports System.Web.Script.Serialization
Imports PCLCrypto

Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Dim jss As New JavaScriptSerializer

    Dim devID = jss.Deserialize(Of device_idResponse)(getData(RequestType.DeviceID))

    Dim pubKey = jss.Deserialize(Of publicKeyResponse)(getData(RequestType.PublicKey))

    Debug.WriteLine(String.Format("Device ID: {0}", devID.id))

    Debug.WriteLine(String.Format("Public Key: {0} | {1}", pubKey.b, pubKey.r))

    Dim d = System.Text.Encoding.UTF8.GetBytes(pubKey.b)

    Dim EncryptedKey = EncryptString(">password_here<", StringToByteArray(pubKey.b))

    Debug.WriteLine(EncryptedKey.ToString)

    Dim EncryptedKeyString = ByteArrayToString(EncryptedKey)

    Debug.WriteLine(String.Format("Encrypted PWD: {0}", EncryptedKeyString))

    Debug.WriteLine("Scanned APs:")

    Dim scans = jss.Deserialize(Of scanAPResult)(getData(RequestType.ScannedWifi))

    For Each i In scans.scans
        Debug.WriteLine(i.ssid)
        If i.ssid.ToLower.Contains("office") Then              ' just testing out!

            Using client As New WebClient

                Dim apData As New configAP

                With apData

                    .ch = i.ch
                    .idx = 0
                    .pwd = EncryptedKeyString
                    .sec = i.sec
                    .ssid = i.ssid

                End With

                Dim apDataStr = jss.Serialize(apData)

                client.UploadString("http://192.168.0.1/configure-ap", apDataStr)

                System.Threading.Thread.Sleep(1000)

                Dim connectData As New connectAP

                connectData.idx = 0

                client.UploadString("http://192.168.0.1/connect-ap", jss.Serialize(connectData))

            End Using

        End If
    Next

End Sub

Public Function EncryptString(inputString As String, keyBuffer As Byte()) As Byte()
    Dim algorithm = WinRTCrypto.AsymmetricKeyAlgorithmProvider.OpenAlgorithm(PCLCrypto.AsymmetricAlgorithm.RsaPkcs1)
    Dim publicKey = algorithm.ImportPublicKey(keyBuffer)
    Dim plainBuffer = WinRTCrypto.CryptographicBuffer.ConvertStringToBinary(inputString, Encoding.UTF8)
    Return WinRTCrypto.CryptographicEngine.Encrypt(publicKey, plainBuffer)
End Function

Private Function getData(req As RequestType) As String

    Using client As New WebClient

        Select Case req

            Case RequestType.DeviceID

                Return client.DownloadString("http://192.168.0.1/device-id")

            Case RequestType.PublicKey

                Return client.DownloadString("http://192.168.0.1/public-key")

            Case RequestType.ScannedWifi

                Return client.DownloadString("http://192.168.0.1/scan-ap")

            Case Else

                Return ""

        End Select

    End Using

End Function

Public Shared Function StringToByteArray(hex As String) As Byte()
    Return Enumerable.Range(0, hex.Length).Where(Function(x) x Mod 2 = 0).[Select](Function(x) Convert.ToByte(hex.Substring(x, 2), 16)).ToArray()
End Function

Public Shared Function ByteArrayToString(ba As Byte()) As String
    Dim hex As New StringBuilder(ba.Length * 2)
    For Each b As Byte In ba
        hex.AppendFormat("{0:x2}", b)
    Next
    Return hex.ToString()
End Function

End Class

Public Enum RequestType
    DeviceID
    PublicKey
    ScannedWifi
End Enum

<Serializable> Public Class device_idResponse
    Public Property id As String
    Public Property c As String

End Class

<Serializable> Public Class publicKeyResponse
    Public Property b As String
    Public Property r As Integer
End Class

<Serializable> Public Class scanAPResult
    Public Property scans As ObjectModel.Collection(Of Scan)
End Class

<Serializable> Public Class Scan
   Public Property ssid As String
   Public Property rssi As Integer
   Public Property sec As Integer
   Public Property ch As Integer
   Public Property mdr As Integer
End Class

Public Class configAP
   Public Property idx As Integer
   Public Property ssid As String
   Public Property sec As Integer
   Public Property ch As Integer
   Public Property pwd As String
End Class

Public Class connectAP
    Public Property idx As Integer
End Class

Just to confirm that sending the password as plaintext is not supported. It was part of a very early revision.

1 Like

I have tried the code, but am still not having any luck. I get a white flash now, but that’s about it. Using a webclient I am also getting a response code for the “configure-ap” command (which is 0 indicating success).

After running the key bytes and plaintext passcode through the encryption function, I am also getting a key length of 258 like in the linked post, but unfortunately trimming the first two characters from the ciphertext is not leading to success in my case.

Does anyone else have any other ideas?

do you use PCLCrypto?

it’s basically just

Dim EncryptedKey = EncryptString(">password_here<", StringToByteArray(pubKey.b))

Public Function EncryptString(inputString As String, keyBuffer As Byte()) As Byte()
    Dim algorithm = WinRTCrypto.AsymmetricKeyAlgorithmProvider.OpenAlgorithm(PCLCrypto.AsymmetricAlgorithm.RsaPkcs1)
    Dim publicKey = algorithm.ImportPublicKey(keyBuffer)
    Dim plainBuffer = WinRTCrypto.CryptographicBuffer.ConvertStringToBinary(inputString, Encoding.UTF8)
    Return WinRTCrypto.CryptographicEngine.Encrypt(publicKey, plainBuffer)
End Function

and converting the ByteArray.

Dim EncryptedKeyString = ByteArrayToString(EncryptedKey)

Public Shared Function ByteArrayToString(ba As Byte()) As String
    Dim hex As New StringBuilder(ba.Length * 2)
    For Each b As Byte In ba
        hex.AppendFormat("{0:x2}", b)
    Next
    Return hex.ToString()
End Function

in vb.net. which language/runtime are you trying to use anyways?

Yes, I am using PCLCrypto. I am also using C#/WPF. Here are the encryption functions I’m using.

private static string ByteArrayToString (byte[] data)
    {
        StringBuilder hex = new StringBuilder(data.Length * 2);
        foreach (byte b in data)
        {
            hex.AppendFormat("{0:x2}", b);
        }
        return hex.ToString();
    }

    private static byte[] StringToByteArray(string hex)
    {

        return Enumerable.Range(0, hex.Length).Where(x => x % 2 == 0).Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();

       //Old Way
        /*hex = hex.Substring(0, 512);

        int l = hex.Length;
        byte[] bytes = new byte[l / 2];
        for(int i = 0; i < l; i+=2)
        {
            bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        }

        return bytes;*/
    }

    private string EncryptAndEncodeToHex(string inputString, string keyString)
    {
        var algorithm = WinRTCrypto.AsymmetricKeyAlgorithmProvider.OpenAlgorithm(PCLCrypto.AsymmetricAlgorithm.RsaPkcs1);
        var keyBytes = StringToByteArray(keyString);
        var publicKey = algorithm.ImportPublicKey(keyBytes);
        var plainBuffer = WinRTCrypto.CryptographicBuffer.ConvertStringToBinary(inputString, Encoding.UTF8);
        return ByteArrayToString(WinRTCrypto.CryptographicEngine.Encrypt(publicKey, plainBuffer));           
    }