Smart #1 API / Smart Home Integration

  • OpenWB und SHM ist Plug@Play.. wegen dem SMA Multicast muss die OpenWB nur am Switch mit den WR und dem SHM dran hängen.

    Meine OpenWB muss seitens des Elektriker noch mit dem SHM verbunden werden. Insofern muss ich erst mal abwarten. Aber, für was, bzw für welche Kommunikation wird den da Multicast benötigt? Ich dachte, die OpenWB spricht mit dem SHM oder dem WR auf irgendeinem (TCP/UDP) Port. Wie läuft den die Kommunikation im Detail? Am selben Switch hängt bei mir aber auch alles und Multicast wird nicht geblockt, daher sollte es ja funktionieren.

  • Wenn Multicast vom Switch nicht geblockt wird ist alles gut. Aber ansonsten funktioniert die Kommunikation immer nur mit einer Gegenstelle. Und wenn die OpenWB dann auch mitreden will kommt es zu Problemen.

    #1 Premium Solar Silver Metallic - Touch - Version 1.5.0 EU

    Liefertermin: 22.06.2023

    --------------------------------

    22 kW Wallbox openWb Pro mit 1-3 Phasenumschaltung

    7 kWp PV Anlage

  • Zu Beginn des Threads hatten wir die Frage, wie die Signatur für den Request gegen die API generiert wird. In einem ersten Schritt habe ich den Bytecode der Android App decompiliert. Das Ergebnis:


    Im nächsten Schritt wäre zu untersuchen, was die Methode genau macht. Falls sich jemand mit Reverse Engineering auskennt? :) Entscheidend:

    var6 = var13.huandk(zhedk.u().f(), var10, var11, var5, var18, var12, var6);

  • Meine OpenWB muss seitens des Elektriker noch mit dem SHM verbunden werden. Insofern muss ich erst mal abwarten.

    Wenn Du in einem Browser in deinem Netzwerk die IP Adresse der Open WB aufrufst bist du im Einrichtmenue, Dort gibst Du die Seriennummer des SHM ein, damit open WB ihn findet.

    Dann (hoffe ich) reden die miteinander.

    Leider kann ich das noch nicht ausprobieren…

  • johnnyger


    Dekomiliert habe ich auch schon vor längerer Zeit. Gescheitert bin ich nach wie vor an der Berechnung der Signatur bzw. dem hierfür benötigten Secret.


    Ein Interceptor funktioniert automatisch, indem er sich z.B. wie oben in die HTTP Kommunikation dazwischen schaltet. Er überwacht sozusagen die HTTP Requests nach außen, fängt sie ab und ergänzt noch einige Dinge. In diesem Fall in erster Linie die Header "X-Signature",, "X-Timestamp" und "X-FILE-LENGTH".


    Die File Length kann man ignorieren, die ist nur relevant, wenn tatsächlich Dateien verschickt werden als Body (binary). Der Timestamp ist logisch, die aktuelle Zeit in Millisekunden. Die Signatur wird berechnet, indem diverse Parameter als String hintereinander gekettet werden und mit einem Secret verschlüsselt werden, Algorithmus ist hier HMAC-SHA1.


    var10 → die bereits vorhandenen Header vom http request, der "intercepted" wird

    var11 → eine Key/Value Liste (TreeMap), in der sämtliche Query-Parameter der Ziel-URL gesammelt werden.

    Beispiel Ziel-URL: hxxp://smart.com/api?bla=blub&forum=smart1

    var11 = { bla=blubb, forum=smart }

    var5 → Dateiname des Anhangs (bei uns leer, also X-FILENAME: "", siehe Zeile 26)

    var18 → aktueller Timestamp (aktuelle Zeit in Millisekunden seit 1.1.1970, auch bekannt als Unix Timestamp)

    var12 → die http Methode des Requests, also bei uns "GET"

    var6 → die vollständige Ziel-URL, inklusive aller Query Parameter


    Das geht alles in die Methode huandk() rein, die natürlich anders heißt, aber aufgrund des Decompilierens jetzt so komisch aussieht.


    Du wirst dann auch eine andere Methode finden, in der die Signatur berechnet wird. Ich suche die Stelle nochmal raus. Da werden im Prinzip diese Eingangsparameter in bestimmter Reihenfolge hintereinander gekettet als String und dann eben verschlüsselt. Die Frage ist nur, mit welchem Key.

  • Ich habe es nochmal rausgesucht. Einen besseren Überblick bekommt man übrigens mit dem Mobile Security Framework. Hierzu einfach den Docker Container starten, Browser öffnen und per Web Oberfläche die App (apk) laden.


    Die entscheidende Klasse SignInterceptor.java


    Das Secret zur Verschlüsselung wird in den Zeilen 44-47 gesetzt:

    Code
    String signSecret = CommonOpenApi.getInstance().getCommonConfig().getSignSecret();
    if (!ComUtils.checkString(signSecret)) {
        signSecret = JniUtils.getInstance().getAppSecret();
    }

    Die Methode zum signieren ist dann in Zeile 48:

    str3 = signUtil.sign(signSecret, headers, treeMap, str, valueOf, method, httpUrl, body instanceof MultipartBody ? 1 : 0);


    Die Implementierung der sign-Methode sieht so aus:

    Code
    public String sign(String str, Headers headers, TreeMap<String, String> treeMap, String str2, String str3, String str4, String str5, int i) throws NoSuchAlgorithmException, InvalidKeyException {
            String url = getUrl(str5);
            String md5 = getMD5(str2, i);
            String str6 = getHeaders(headers) + EdgeConstants.Defaults.jiangdk + getParam(treeMap) + EdgeConstants.Defaults.jiangdk + md5 + str3 + EdgeConstants.Defaults.jiangdk + str4 + EdgeConstants.Defaults.jiangdk + url;
            Mac mac = Mac.getInstance("HMACSHA1");
            mac.init(new SecretKeySpec(str.getBytes(Charset.forName("utf-8")), "HMACSHA1"));
            return Base64.encodeToString(mac.doFinal(str6.getBytes(Charset.forName("utf-8"))), 0);
        }
  • Hi,


    danke für den Link zum MobSF, das kannte ich noch nicht.


    Ihr seid dann ja schon deutlich weiter. Ich lese heraus, dass die noch zu lösende Herausforderung in dem AppSecret besteht. Ich selbst bin an der Stelle kein Experte, weder für C Code, noch für Reverse Engineering. Hilfreich ist möglicherweise, dass es die libAppSecret sowohl in 64 bit als auch in 32 vorliegt. Ich habe die 32 Bit Version nur mal auf die Schnelle hier https://dogbolt.org durch einen Ghidra gejagt.

    Wäre vermutlich zu einfach, wenn das Secret dort einfach als String hinterlegt ist und im Output Parameter param_2 folgender Methode abgelegt wird, im File passiert viel mehr. Vermutlich appid != AppSecret.

  • Diesen String habe ich auch schon gefunden. Bekommt man auf der Konsole z. B. mit dem Befehl:

    strings -a libAppSecret.so


    Ich bin so vorgegangen, dass ich mir eine gültige Abfrage aus der App per proxy mitgeschnitten habe (in Proxyman) und dann diesen Request inklusive der gültigen Signatur als Basis genommen habe fur die eigene Signaturberechnung. Ich habe also versucht, die Signatur selbst zu berechnen und auf den gleichen Wert zu kommen wie beim gesnifften Request.


    Habe mir eine eigene Funktion gebaut fur diesen JS Fiddle Playground und dann mit allen moglichen Keys versucht, die gleiche Signatur zu berechnen fur die entsprechende Payload. Hier das snippet, welches man im verlinkten Playground nutzen kann: