Move encrypt and decrypt routines into tplink_utils.
authorScott Gasch <[email protected]>
Wed, 23 Feb 2022 22:40:50 +0000 (14:40 -0800)
committerScott Gasch <[email protected]>
Wed, 23 Feb 2022 22:40:50 +0000 (14:40 -0800)
smart_home/tplink_utils.py

index 91cdd755903670d0013d5de7e19353c8cc119b70..d8a75a2c3dd6d1b67808e88f62c4b6c037b885c9 100644 (file)
@@ -1,6 +1,25 @@
 #!/usr/bin/env python3
 
-"""Wrapper functions for calling tplink.py"""
+"""Wrapper functions for dealing with TPLink devices.  Based on code
+written by Lubomir Stroetmann and Copyright 2016 softScheck GmbH which
+was covered by the Apache 2.0 license:
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Modifications by Scott Gasch Copyright 2020-2022 also released under
+the Apache 2.0 license as required by the license (see above).
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
 
 import json
 import logging
@@ -8,6 +27,7 @@ import os
 import re
 import subprocess
 import sys
+from struct import pack
 from typing import Dict, Optional
 
 import logging_utils
@@ -51,3 +71,45 @@ def tplink_get_info(cmd: str) -> Optional[Dict]:
         logger.exception(e)
         print(out, file=sys.stderr)
         return None
+
+
+def encrypt(string: str) -> bytes:
+    """Encryption and Decryption of TP-Link Smart Home Protocol.
+
+    XOR Autokey Cipher with starting key = 171
+
+    >>> " ".join(hex(b).replace('0x', '') for b in encrypt('{"system":{"get_sysinfo":{}}}'))
+    '0 0 0 1d d0 f2 81 f8 8b ff 9a f7 d5 ef 94 b6 d1 b4 c0 9f ec 95 e6 8f e1 87 e8 ca f0 8b f6 8b f6'
+
+    """
+    key = 171
+    result = pack(">I", len(string))
+    for i in string:
+        a = key ^ ord(i)
+        key = a
+        result += bytes([a])
+    return result
+
+
+def decrypt(string: bytes) -> str:
+    """Opposite of encrypt (above).
+
+    >>> b = encrypt('hi, mom')
+    >>> s = decrypt(b[4:])
+    >>> s
+    'hi, mom'
+
+    """
+    key = 171
+    result = ""
+    for i in string:
+        a = key ^ i
+        key = i
+        result += chr(a)
+    return result
+
+
+if __name__ == '__main__':
+    import doctest
+
+    doctest.testmod()