{"id":56,"date":"2015-02-24T00:21:51","date_gmt":"2015-02-24T00:21:51","guid":{"rendered":"https:\/\/stikonas.eu\/wordpress\/?p=56"},"modified":"2018-04-01T23:38:02","modified_gmt":"2018-04-01T23:38:02","slug":"reverse-engineering-orvibo-s20-socket","status":"publish","type":"post","link":"https:\/\/stikonas.eu\/wordpress\/2015\/02\/24\/reverse-engineering-orvibo-s20-socket\/","title":{"rendered":"Reverse engineering Orvibo S20 socket"},"content":{"rendered":"<p>I have bought Orvibo S20 (<a title=\"Picture is not mine, it is taken by Matt.\" href=\"https:\/\/sites.google.com\/site\/orvibos20\/_\/rsrc\/1421924384231\/hardware\/IMG_20150122_103631.jpg?height=400&amp;width=300\" target=\"_blank\" rel=\"noopener\">picture<\/a>) smart socket. You can find them on Amazon, eBay and probably many other online shops. The socket comes with an app for Android and\u00a0iOS that is used to control the socket. Unfortunately, the app is proprietary and also not available for\u00a0normal computers. I wanted to have some <a title=\"What is free software\" href=\"https:\/\/www.gnu.org\/philosophy\/free-sw.html\" target=\"_blank\" rel=\"noopener\">free software<\/a>\u00a0solution. Also, the original app didn&#8217;t work too reliably,\u00a0and of course you can&#8217;t fix it without having a code. Again, this shows why it is important to have free software&#8230;<\/p>\n<p>After searching a bit I found some code on <a href=\"https:\/\/github.com\/Grayda\/ninja-allone\" target=\"_blank\" rel=\"noopener\">GitHub<\/a> written for Ninja Blocks. It also came with some <a title=\"Original reverse engineering\" href=\"http:\/\/pastebin.com\/LfUhsbcS\" target=\"_blank\" rel=\"noopener\">reverse engineering data<\/a>\u00a0(I will refer to this as the original reverse engineering later and will assume that you briefly looked at it). That file might look slightly scary\u00a0initially if you are not used to that kind of stuff but actually everything is quite simple. It seems that the socket can be controlled by simply sending UDP packets over the network and listening for replies. You can even try to play a bit with netcat but of course it is not too convenient. So I decided to write my own program using <a href=\"https:\/\/en.wikipedia.org\/wiki\/Qt_%28software%29\" target=\"_blank\" rel=\"noopener\">Qt 5<\/a>. It provides a lot of convenient functions in its QtNetwork module and also it would make it easy to write GUI if I ever decide to do so in the future. Also, I&#8217;m familiar with Qt because it is used by <a href=\"https:\/\/www.kde.org\/\">KDE\u00a0Applications<\/a>. Another reason for choosing Qt was it&#8217;s support for sockets and slots and I expected them to be useful.<\/p>\n<p>As you can see in the reverse engineering file, there are commands to discover the socket, subscribe to it (which is required before doing anything else), power it on\/off and read some tables (Socket Data contains information about the socket and Timing Data stores when to turn the socket on or off).\u00a0They all follow similar pattern. You have to send<\/p>\n<p><em>Magic\u00a0Key+ message length + command id + rest of the message<\/em><\/p>\n<p>where <em>Magic Key<\/em> is 68 64 (hexadecimals) and is used to\u00a0distinguish these UDP packets from any other packets that are send over UDP port 10000. Every time you send a message the socket replies with\u00a0another message confirming the action of the first message. Or the socket doesn&#8217;t reply. We are using UDP protocol for networking. So there is no guarantee that message is received and later I had to write some code to make sure packets are received. Hence, I implemented message queue and resend every command until\u00a0I get a proper reply before sending another command. This finally made my program more reliable.<\/p>\n<h2>Writing Socket Data<\/h2>\n<p>I quickly managed to get some basic stuff working (for example powering it on and off) and soon I implemented most of the commands from the file with reversed engineered commands (reading Timing Table is still not completed but shouldn&#8217;t be too hard). Since I wanted to do more than that, I started <a href=\"https:\/\/www.wireshark.org\/\" target=\"_blank\" rel=\"noopener\">Wireshark<\/a> and analyzed a few more packets. I quickly learned how to write Socket Data Table too. Apparently, you send command very similar to what you receive when you request Socket Data but with different Command ID (74\u00a06d instead of 72\u00a074 in hexadecimals).<\/p>\n<p>So to write\u00a0Socket Data I send the following packet<\/p>\n<p><em>Magic\u00a0Key + message length + 74 6d\u00a0+\u00a0mac + mac padding\u00a0+ 00 00 00 00\u00a0\u00a0+ AA\u00a000 BB\u00a0+ recordLength + record;<\/em><\/p>\n<p>where<\/p>\n<p><em>record = 01 00 \/* record number = 1*\/ + versionID + mac + mac padding\u00a0+ reversed mac\u00a0+ mac padding\u00a0+ remote password + socket name + icon + hardwareVersion + firmwareVersion + wifiFirmwareVersion + port + staticServerIP + port + domainServerName + localIP + localGatewayIP + localNetMask + dhcpNode + discoverable + timeZoneSet + timezone + countdownStatus + countdown + 00 (repeated twelve times) + 30 (repeated 30 times, note that hex 30 corresponds to 0 in ASCII);<\/em><\/p>\n<p>countdownStatus is 00 ff when countdown is disabled and 01 00 when countdown is enabled.<\/p>\n<p>AA\u00a000 BB is actually table number and version flag. E.g. 04 00 01. 4 stands for table number (Socket Data is Table number 4) I don&#8217;t completely understand what is version flag, so if you know please tell me in the comments.<\/p>\n<p>Then socket replies with:<\/p>\n<p><em>Magic\u00a0Key + message length + 74 6d\u00a0+\u00a0mac + mac padding + 01 00 00 00 00;<\/em><\/p>\n<p>Now just send an already documented Socket Table packet (see:\u00a0<a title=\"Original reverse engineering\" href=\"http:\/\/pastebin.com\/LfUhsbcS\" target=\"_blank\" rel=\"noopener\">http:\/\/pastebin.com\/LfUhsbcS<\/a>) to update your variables.<\/p>\n<h2>Writing Timing\u00a0Data<\/h2>\n<p>Writing Timing\u00a0Data is exactly the same (even Command ID is still 74 6d) as writing Socket Data but you must specify 03 a a table number<\/p>\n<p><em>Magic\u00a0Key + message length + 74 6d\u00a0+\u00a0mac + mac padding\u00a0+ 00 00 00 00\u00a0\u00a0+ AA\u00a000 BB\u00a0+ record1Length + record 1+\u00a0<\/em><em>record2Length + record2 +\u00a0<\/em><em>record3Length + record3 + &#8230;<\/em>;<\/p>\n<p><em>record<\/em>\u00a0again contains the same data as what socket sends when you request <a href=\"http:\/\/pastebin.com\/LfUhsbcS\">timing data<\/a>.<\/p>\n<h2><strong>Initial pairing of the socket<\/strong><\/h2>\n<p>The authors of the original Ninja Blocks orvibo-allone driver\u00a0assume that socket was already paired using the proprietary Android\/iOS application. Their original reverse engineering also contains no information how to do that. I expected\u00a0that this might be a bit tricky to do because unpaired socket is not connected to the router and you have to somehow transmit your wifi configuration into the socket. I think there are at least two ways to pair that proprietary Android\/iOS app implements. If you press the socket button for a few second it switches to a rapidly blinking red led mode. Then long press it again and it switches to rapidly blinking blue led and the socket creates an unencrypted wifi network (it was called WiWo-S20).<\/p>\n<p>Then I created the\u00a0wifi network with the same name on my laptop and tricked the proprietary app into believing that it is the socket&#8217;s wifi network. I was able to intercept the following message on UDP port 48899 (everything is in ASCII in the section, not in hex):<\/p>\n<p>HF-A11ASSISTHREAD<\/p>\n<p>So apparently, Orvibo S20 has HF-LPB100\u00a0Wifi chip inside.\u00a0This chip can be controlled by the AT+ commands (you can find them online but I will write a brief summary here) and I was able to do initial socket configuration!<\/p>\n<ul>\n<li>Switch S20 to rapidly blinking blue led more. Connect your computer to WiWo-S20 network.<\/li>\n<li>\u00a0Send &#8220;HF-A11ASSISTHREAD&#8221;\u00a0on\u00a0UDP port 48899 to the broadcast address (don&#8217;t include\u00a0&#8221; in the message).<\/li>\n<li>\u00a0S20 will reply with &#8220;IP address,MAC Address,Hostname&#8221;. The socket always replies to the same port as the <em>source<\/em> port of your\u00a0message.<\/li>\n<li>Acknowledge that you got the previous message by sending &#8220;+ok&#8221;.<\/li>\n<li>Send &#8220;AT+WSSSID=ssid\\r&#8221; where you replace ssid with your WiFi network name. \\r is the carriage return (CR) symbol.<\/li>\n<li>The socket will reply with &#8220;+ok\\n\\n&#8221; (\\n in this case is\u00a0carriage return + line feed) if everything is correct or &#8220;+ERR\\n\\n&#8221; if something is wrong.<\/li>\n<li>Send your Wifi security settings: &#8220;AT+WSKEY=WPA2PSK,AES,PASSWORD\\r&#8221;. \u00a0The socket will again reply with &#8220;+ok\\n\\n&#8221;.<\/li>\n<li>Switch HF-A11 chip to station mode by sending &#8220;AT+WMODE=STA\\r&#8221;. Again, wait for &#8220;+ok\\n\\n&#8221;<\/li>\n<li>Reboot your socket with &#8220;AT+Z\\r&#8221;.<\/li>\n<li>Connect your computer back to your router. Wait until the socket boots. Now you can find it using normal discovery packet on port 10000, then change socket name, timezone, etc. with Write Socket Data packet&#8230;<\/li>\n<\/ul>\n<p>I did some investigation and it seems that we need to send a slightly modified\u00a0Table Data and Socket Data packets immediately after pairing to set them to default values. More information will be published later.<\/p>\n<p><a href=\"http:\/\/blog.slange.co.uk\/orvibo-s20-wifi-power-socket\/\">Another way<\/a> to pair the socket from the rapidly blinking red mode. It is slighly less reliable than this method but on the other hand does not require you to disconnect from your wireless. Actually, it doesn&#8217;t require your computer to have any wireless\u00a0at all.<\/p>\n<p>Unfortunately, it seems that either way WPA encryption key is transferred in an insecure way, i.e. the socket is not able to use any public key cryptography. Slightly safer way to do it manually is to first change your WPA key to something temporary and pair the socket. Then use AT+ commands to change WPA password to the real one and change your router&#8217;s WPA password back.<\/p>\n<p>Also, note that this socket doesn&#8217;t support WPA Enterprise. So if you would like to use it at home then create two Wifi networks: WPA-PSK for the socket and WPA-EAP for everything else (OpenWrt can do this easily).<\/p>\n<h2>Code<\/h2>\n<p>I released all code under the GNU General Public License version 3, so the code is freely available to everybody. Git repository is available at:<\/p>\n<p><a href=\"https:\/\/git.stikonas.eu\/andrius\/s20\">https:\/\/git.stikonas.eu\/andrius\/s20<\/a>\u00a0(feel free to create an account here and fork the code)<\/p>\n<h4>Windows binaries<\/h4>\n<p>I compiled windows binaries.\u00a0There is also a\u00a0very limited GUI that does not yet have all the features of console app but if you prefer GUI then it might be useful.<\/p>\n<table>\n<tbody>\n<tr>\n<td>Console<\/td>\n<td><a href=\"\/files\/s20.exe\">64-bit<\/a><\/td>\n<td><a href=\"\/files\/s20-win32.exe\">32-bit<\/a><\/td>\n<\/tr>\n<tr>\n<td>GUI<\/td>\n<td><a href=\"\/files\/s20-gui.exe\">64-bit<\/a><\/td>\n<td><a href=\"\/files\/s20-gui-win32.exe\">32-bit<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4>Donations<\/h4>\n<p>If you find this work useful then tips are very welcome. You can send Bitcoin tips to bc1qe2dfqjwgse5v6cl6rhtk352ru90t0hnve45f2c.<\/p>\n<p>I was able to buy the second socket which already resulted in improved multiple socket support. Thanks for the donations!<br \/>\n<a href=\"https:\/\/www.patreon.com\/stikonas\"><img decoding=\"async\" src=\"https:\/\/c5.patreon.com\/external\/logo\/become_a_patron_button.png\" alt=\"Become a patron\" \/><\/a>\r\n<a href=\"https:\/\/liberapay.com\/stikonas\/donate\"><img decoding=\"async\" alt=\"Donate using Liberapay\" src=\"https:\/\/liberapay.com\/assets\/widgets\/donate.svg\"><\/a>\r\n Bitcoin: bc1qe2dfqjwgse5v6cl6rhtk352ru90t0hnve45f2c<\/p>\n<h4>Bugs<\/h4>\n<p>Bugs are tracked in the <a href=\"https:\/\/git.stikonas.eu\/andrius\/s20\/issues\">Gitlab issue tracker<\/a>.<\/p>\n<h3>See also<\/h3>\n<p><a href=\"https:\/\/github.com\/Grayda\/go-orvibo\">Go code by Grayda<\/a> (basic support for S20 but also supports Orvibo AllOne devices)<\/p>\n<p><a href=\"https:\/\/github.com\/fernadosilva\/orvfms\">PHP code by Fernano Silva<\/a> (supports most features of S20). See also his <a href=\"https:\/\/github.com\/fernadosilva\/orvfms\/blob\/master\/TECHNICAL_DATA.txt\">technical data<\/a> file.<\/p>\n<p><a href=\"http:\/\/pastebin.com\/7wwe64m9\">Perl code by Branislav Vartik<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have bought Orvibo S20 (picture) smart socket. You can find them on Amazon, eBay and probably many other online shops. The socket comes with an app for Android and\u00a0iOS that is used to control the socket. Unfortunately, the app is proprietary and also not available for\u00a0normal computers. I wanted to have some free software\u00a0solution. &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[14],"tags":[11,15,16,17],"class_list":["post-56","post","type-post","status-publish","format-standard","hentry","category-software","tag-free-software","tag-orvibo","tag-s20","tag-smart-socket"],"_links":{"self":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts\/56","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/comments?post=56"}],"version-history":[{"count":4,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts\/56\/revisions"}],"predecessor-version":[{"id":563,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts\/56\/revisions\/563"}],"wp:attachment":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/media?parent=56"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/categories?post=56"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/tags?post=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}