flash-ota: add AES-support for culfw-devices
authorMichael Gernoth <michael@gernoth.net>
Fri, 11 Sep 2015 11:00:34 +0000 (13:00 +0200)
committerMichael Gernoth <michael@gernoth.net>
Fri, 11 Sep 2015 11:00:34 +0000 (13:00 +0200)
.gitignore
Makefile
flash-ota.c
hm.c [new file with mode: 0644]
hm.h

index d1ea703..df1fea6 100644 (file)
@@ -10,6 +10,8 @@ flash-ota.d
 flash-ota.o
 firmware.d
 firmware.o
+hm.d
+hm.o
 hmcfgusb.d
 hmcfgusb.o
 hmland
index 4af4fe7..bd8fbf7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ CC=gcc
 HMLAN_OBJS=hmcfgusb.o hmland.o util.o
 HMSNIFF_OBJS=hmcfgusb.o hmsniff.o
 FLASH_HMCFGUSB_OBJS=hmcfgusb.o firmware.o util.o flash-hmcfgusb.o
-FLASH_OTA_OBJS=hmcfgusb.o culfw.o firmware.o util.o flash-ota.o
+FLASH_OTA_OBJS=hmcfgusb.o culfw.o firmware.o util.o flash-ota.o hm.o aes.o
 
 OBJS=$(HMLAN_OBJS) $(HMSNIFF_OBJS) $(FLASH_HMCFGUSB_OBJS) $(FLASH_OTA_OBJS)
 
index 9ffdeb8..953ed34 100644 (file)
@@ -1,6 +1,6 @@
 /* flasher for HomeMatic-devices supporting OTA updates
  *
- * Copyright (c) 2014 Michael Gernoth <michael@gernoth.net>
+ * Copyright (c) 2014-15 Michael Gernoth <michael@gernoth.net>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -51,7 +51,7 @@ extern char *optarg;
 
 uint32_t hmid = 0;
 uint32_t my_hmid = 0;
-char key[16] = {0};
+uint8_t key[16] = {0};
 int32_t kNo = -1;
 
 /* Maximum payloadlen supported by IO */
@@ -179,6 +179,13 @@ static int parse_culfw(uint8_t *buf, int buf_len, void *data)
                                rdata->version |= v;
                        }
                        break;
+               case 'E':
+                       {
+                               if (!strncmp((char*)buf, "ERR:CCA", 7)) {
+                                       fprintf(stderr, "CCA didn't complete, too much traffic\n");
+                               }
+                               break;
+                       }
                default:
                        fprintf(stderr, "Unknown response from CUL: %s", buf);
                        return 0;
@@ -270,7 +277,7 @@ int send_hm_message(struct ota_dev *dev, struct recv_data *rdata, uint8_t *msg)
                                }
 
                                if (msg[CTL] & 0x20) {
-                                       int cnt = 3;
+                                       int cnt = 5;
                                        int pfd;
                                        do {
                                                errno = 0;
@@ -284,18 +291,44 @@ int send_hm_message(struct ota_dev *dev, struct recv_data *rdata, uint8_t *msg)
                                                if (rdata->message_type == MESSAGE_TYPE_E) {
                                                        if (rdata->message[TYPE] == 0x02) {
                                                                if (rdata->message[PAYLOAD] == 0x04) {
-                                                                       printf("AES request received but not implemented for culfw!\n");
+                                                                       int32_t req_kNo;
+                                                                       uint8_t challenge[6];
+                                                                       uint8_t respbuf[16];
+                                                                       uint8_t *resp;
+
+                                                                       req_kNo = rdata->message[rdata->message[LEN]] / 2;
+                                                                       memcpy(challenge, &(rdata->message[PAYLOAD+1]), 6);
+
+                                                                       if (req_kNo != kNo) {
+                                                                               fprintf(stderr, "AES request for unknown key %d!\n", req_kNo);
+                                                                       } else {
+                                                                               resp = hm_sign(key, challenge, msg, NULL, respbuf);
+                                                                               if (resp) {
+                                                                                       uint8_t rbuf[64];
+
+                                                                                       memset(rbuf, 0, sizeof(rbuf));
+                                                                                       rbuf[MSGID] = rdata->message[MSGID];
+                                                                                       rbuf[CTL] = rdata->message[CTL];
+                                                                                       rbuf[TYPE] = 0x03;
+                                                                                       SET_SRC(rbuf, DST(rdata->message));
+                                                                                       SET_DST(rbuf, SRC(rdata->message));
+                                                                                       memcpy(&(rbuf[PAYLOAD]), resp, 16);
+                                                                                       SET_LEN_FROM_PAYLOADLEN(rbuf, 16);
+
+                                                                                       return send_hm_message(dev, rdata, rbuf);
+                                                                               }
+                                                                       }
                                                                } else if (rdata->message[PAYLOAD] >= 0x80 && rdata->message[PAYLOAD] <= 0x8f) {
-                                                                       printf("NACK\n");
+                                                                       fprintf(stderr, "NACK\n");
                                                                } else {        /* ACK or ACKinfo */
                                                                        break;
                                                                }
                                                        } else {
-                                                               printf("Unexpected message received: ");
+                                                               fprintf(stderr, "Unexpected message received: ");
                                                                for (i = 0; i < rdata->message[LEN]; i++) {
-                                                                       printf("%02x", rdata->message[i+1]);
+                                                                       fprintf(stderr, "%02x", rdata->message[i+1]);
                                                                }
-                                                               printf("\n");
+                                                               fprintf(stderr, "\n");
                                                        }
                                                }
                                        } while(cnt--);
@@ -368,7 +401,6 @@ void flash_ota_syntax(char *prog)
        fprintf(stderr, "\t-C\t\tHMID of central (3 hex-bytes, no prefix, e.g. ABCDEF)\n");
        fprintf(stderr, "\t-D\t\tHMID of device (3 hex-bytes, no prefix, e.g. 123456)\n");
        fprintf(stderr, "\t-K\t\tKNO:KEY AES key-number and key (hex) separated by colon (Fhem hmKey attribute)\n");
-       fprintf(stderr, "\t\t\tAES is currently not supported when using a culfw-device!\n");
 }
 
 int main(int argc, char **argv)
@@ -476,12 +508,6 @@ int main(int argc, char **argv)
        memset(&dev, 0, sizeof(struct ota_dev));
 
        if (culfw_dev) {
-               if (kNo != -1) {
-                       fprintf(stderr, "\nAES currently not supported with culfw-device!\n");
-                       flash_ota_syntax(argv[0]);
-                       exit(EXIT_FAILURE);
-               }
-
                printf("Opening culfw-device at path %s with speed %u\n", culfw_dev, bps);
                dev.culfw = culfw_init(culfw_dev, bps, parse_culfw, &rdata);
                if (!dev.culfw) {
diff --git a/hm.c b/hm.c
new file mode 100644 (file)
index 0000000..818081f
--- /dev/null
+++ b/hm.c
@@ -0,0 +1,114 @@
+/* HomeMatic protocol-functions
+ *
+ * Copyright (c) 2014-15 Michael Gernoth <michael@gernoth.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "aes.h"
+#include "hexdump.h"
+#include "hm.h"
+
+static int debug = 0;
+
+uint8_t* hm_sign(uint8_t *key, uint8_t *challenge, uint8_t *m_frame, uint8_t *exp_auth, uint8_t *resp)
+{
+       uint8_t signkey[16];
+       WORD ks[60];
+       struct timeval tv;
+       int i;
+
+       printf("AES-request with challenge: %02x%02x%02x%02x%02x%02x\n",
+                       challenge[0], challenge[1], challenge[2],
+                       challenge[3], challenge[4], challenge[5]);
+
+       /*
+        * Build signing key by XORing the first 6 bytes of
+        * the key with the challenge.
+        */
+       memcpy(signkey, key, sizeof(signkey));
+       for (i = 0; i < 6; i++) {
+               signkey[i] ^= challenge[i];
+       }
+       aes_key_setup(signkey, ks, 128);
+
+       /*
+        * Generate payload for first encryption.
+        */
+       gettimeofday(&tv, NULL);
+       resp[0] = tv.tv_sec >> 24 & 0xff;
+       resp[1] = tv.tv_sec >> 16 & 0xff;
+       resp[2] = tv.tv_sec >> 8 & 0xff;
+       resp[3] = tv.tv_sec & 0xff;
+       resp[4] = tv.tv_usec >> 8 & 0xff;
+       resp[5] = tv.tv_usec & 0xff;
+       memcpy(&(resp[6]), &(m_frame[MSGID]), 10);
+
+       if (debug)
+               hexdump(resp, 16, "P   > ");
+
+       aes_encrypt(resp, resp, ks, 128);
+
+       if (debug)
+               hexdump(resp, 16, "Pe  > ");
+
+       /*
+        * Device has to answer with the first 4 bytes of the
+        * encrypted payload to authenticate, so pass them to
+        * the caller.
+        */
+
+       if (exp_auth) {
+               memcpy(exp_auth, resp, 4);
+       }
+
+       /*
+        * XOR parameters of the m_frame to the payload.
+        */
+       for (i = 0; i < PAYLOADLEN(m_frame) - 1; i++) {
+               if (i == 16) {
+                       break;
+               }
+
+               resp[i] ^= m_frame[PAYLOAD + 1+ i];
+       }
+
+       if (debug)
+               hexdump(resp, 16, "Pe^ > ");
+
+       /*
+        * Encrypt payload again
+        */
+       aes_encrypt(resp, resp, ks, 128);
+
+       if (debug)
+               hexdump(resp, 16, "Pe^e> ");
+
+       return resp;
+}
diff --git a/hm.h b/hm.h
index d0d7147..af98626 100644 (file)
--- a/hm.h
+++ b/hm.h
@@ -1,6 +1,6 @@
-/* HomeMatic defines
+/* HomeMatic defines and functions
  *
- * Copyright (c) 2014 Michael Gernoth <michael@gernoth.net>
+ * Copyright (c) 2014-15 Michael Gernoth <michael@gernoth.net>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -34,3 +34,6 @@
 #define SET_DST(buf, dst)      do { buf[0x07] = (dst >> 16) & 0xff; buf[0x08] = (dst >> 8) & 0xff; buf[0x09] = dst & 0xff; } while(0)
 
 #define SET_LEN_FROM_PAYLOADLEN(buf, payloadlen)       do { buf[0x00] = payloadlen + 0x09; } while(0)
+#define PAYLOADLEN(buf)                                        (buf[0x00] - 0x09)
+
+uint8_t* hm_sign(uint8_t *key, uint8_t *challenge, uint8_t *m_frame, uint8_t *exp_auth, uint8_t *resp);
Impressum, Datenschutz