From a6022133c4665d0885c4efe7dbc9746a32ca1f3b Mon Sep 17 00:00:00 2001 From: Zhivka Dimova Date: Thu, 1 Aug 2024 11:36:52 +0200 Subject: [PATCH] [gree] Add support for ASC/GCM encryption (#16950) * [gree] support for ASC/GCM encryption Signed-off-by: Zhivka Dimova Signed-off-by: Ciprian Pascu --- .../binding/gree/internal/GreeCryptoUtil.java | 124 ++++++++++++++++++ .../internal/discovery/GreeDeviceFinder.java | 8 +- .../gree/internal/gson/GreeBaseDTO.java | 29 ++++ .../internal/gson/GreeBindRequestPackDTO.java | 2 +- .../internal/gson/GreeBindResponseDTO.java | 13 +- .../gson/GreeBindResponsePackDTO.java | 2 +- .../internal/gson/GreeExecResponseDTO.java | 13 +- .../gson/GreeExecResponsePackDTO.java | 2 +- .../gson/GreeExecuteCommandPackDTO.java | 2 +- .../gree/internal/gson/GreeReqStatusDTO.java | 10 +- .../internal/gson/GreeReqStatusPackDTO.java | 3 +- .../gree/internal/gson/GreeRequestDTO.java | 13 +- .../internal/gson/GreeResponseBaseDTO.java | 23 ++++ .../internal/gson/GreeScanRequestDTO.java | 2 +- .../internal/gson/GreeScanResponseDTO.java | 13 +- ...kDTO.java => GreeScanResponsePackDTO.java} | 5 +- .../internal/gson/GreeStatusResponseDTO.java | 13 +- .../gson/GreeStatusResponsePackDTO.java | 2 +- .../gree/internal/handler/GreeAirDevice.java | 34 +++-- 19 files changed, 224 insertions(+), 89 deletions(-) create mode 100644 bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBaseDTO.java create mode 100644 bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeResponseBaseDTO.java rename bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/{GreeScanReponsePackDTO.java => GreeScanResponsePackDTO.java} (88%) diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeCryptoUtil.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeCryptoUtil.java index 7e58f002055..f51678788bc 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeCryptoUtil.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/GreeCryptoUtil.java @@ -13,18 +13,22 @@ package org.openhab.binding.gree.internal; import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.util.Base64; +import java.util.HexFormat; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.gree.internal.gson.GreeBaseDTO; /** * The CryptoUtil class provides functionality for encrypting and decrypting @@ -36,11 +40,68 @@ import org.eclipse.jdt.annotation.NonNullByDefault; @NonNullByDefault public class GreeCryptoUtil { private static final String AES_KEY = "a3K8Bx%2r8Y7#xDh"; + private static final String GCM_KEY = "{yxAHAY_Lm6pbC/<"; + private static final String GCM_IV = "5440784449675a516c5e6313"; + private static final String GCM_ADD = "qualcomm-test"; + private static final int TAG_LENGTH = 16; + + public enum EncryptionTypes { + ECB, + GCM + }; public static byte[] getAESGeneralKeyByteArray() { return AES_KEY.getBytes(StandardCharsets.UTF_8); } + public static byte[] getGCMGeneralKeyByteArray() { + return GCM_KEY.getBytes(StandardCharsets.UTF_8); + } + + public static byte[] getGeneralKeyByteArray(EncryptionTypes encType) { + if (encType == EncryptionTypes.GCM) { + return getGCMGeneralKeyByteArray(); + } + return getAESGeneralKeyByteArray(); + } + + public static byte[] getGCMIVByteArray() { + return HexFormat.of().parseHex(GCM_IV); + } + + public static byte[] getGCMADDByteArray() { + return GCM_ADD.getBytes(StandardCharsets.UTF_8); + } + + public static EncryptionTypes getEncryptionType(T response) { + return response.tag != null ? EncryptionTypes.GCM : EncryptionTypes.ECB; + } + + public static String decrypt(T response) throws GreeException { + return decrypt(response, getEncryptionType(response)); + } + + public static String decrypt(byte[] keyarray, T response) throws GreeException { + return decrypt(keyarray, response, getEncryptionType(response)); + } + + public static String decrypt(T response, EncryptionTypes encType) throws GreeException { + if (encType == EncryptionTypes.GCM) { + return decrypt(getGCMGeneralKeyByteArray(), response, encType); + } else { + return decrypt(getAESGeneralKeyByteArray(), response, encType); + } + } + + public static String decrypt(byte[] keyarray, T response, EncryptionTypes encType) + throws GreeException { + if (encType == EncryptionTypes.GCM) { + return decryptGCMPack(keyarray, response.pack, response.tag); + } else { + return decryptPack(keyarray, response.pack); + } + } + public static String decryptPack(byte[] keyarray, String message) throws GreeException { try { Key key = new SecretKeySpec(keyarray, "AES"); @@ -58,6 +119,41 @@ public class GreeCryptoUtil { } } + public static String decryptGCMPack(byte[] keyBytes, String pack, String tag) throws GreeException { + try { + Key key = new SecretKeySpec(keyBytes, "AES"); + Base64.Decoder decoder = Base64.getDecoder(); + + byte[] packBytes = decoder.decode(pack); + byte[] tagBytes = decoder.decode(tag); + + byte[] messageBytes = new byte[packBytes.length + tagBytes.length]; + System.arraycopy(packBytes, 0, messageBytes, 0, packBytes.length); + System.arraycopy(tagBytes, 0, messageBytes, packBytes.length, tagBytes.length); + + Cipher gcmCipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, getGCMIVByteArray()); + gcmCipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec); + gcmCipher.updateAAD(getGCMADDByteArray()); + + byte[] bytePlainText = gcmCipher.doFinal(messageBytes); + return new String(bytePlainText, StandardCharsets.UTF_8); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | InvalidKeyException + | IllegalBlockSizeException | InvalidAlgorithmParameterException ex) { + throw new GreeException("GCM decryption of recieved data failed", ex); + } + } + + public static String[] encrypt(byte[] keyarray, String message, EncryptionTypes encType) throws GreeException { + if (encType == EncryptionTypes.GCM) { + return encryptGCMPack(keyarray, message); + } else { + String[] res = new String[1]; + res[0] = encryptPack(keyarray, message); + return res; + } + } + public static String encryptPack(byte[] keyarray, String message) throws GreeException { try { Key key = new SecretKeySpec(keyarray, "AES"); @@ -72,4 +168,32 @@ public class GreeCryptoUtil { throw new GreeException("Unable to encrypt outbound data", ex); } } + + public static String[] encryptGCMPack(byte[] keyarray, String message) throws GreeException { + try { + Key key = new SecretKeySpec(keyarray, "AES"); + + Cipher gcmCipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, getGCMIVByteArray()); + gcmCipher.init(Cipher.ENCRYPT_MODE, key, gcmParameterSpec); + gcmCipher.updateAAD(getGCMADDByteArray()); + + byte[] encrypted = gcmCipher.doFinal(message.getBytes(StandardCharsets.UTF_8)); + + int packLength = encrypted.length - TAG_LENGTH; + byte[] pack = new byte[packLength]; + byte[] tag = new byte[TAG_LENGTH]; + System.arraycopy(encrypted, 0, pack, 0, packLength); + System.arraycopy(encrypted, packLength, tag, 0, TAG_LENGTH); + + Base64.Encoder encoder = Base64.getEncoder(); + String[] encryptedData = new String[2]; + encryptedData[0] = new String(encoder.encode(pack), StandardCharsets.UTF_8); + encryptedData[1] = new String(encoder.encode(tag), StandardCharsets.UTF_8); + return encryptedData; + } catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | InvalidKeyException + | IllegalBlockSizeException | InvalidAlgorithmParameterException ex) { + throw new GreeException("Unable to encrypt (gcm) outbound data", ex); + } + } } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/discovery/GreeDeviceFinder.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/discovery/GreeDeviceFinder.java index 61b0cb8e50e..bc277d7034e 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/discovery/GreeDeviceFinder.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/discovery/GreeDeviceFinder.java @@ -28,9 +28,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.gree.internal.GreeCryptoUtil; import org.openhab.binding.gree.internal.GreeException; -import org.openhab.binding.gree.internal.gson.GreeScanReponsePackDTO; import org.openhab.binding.gree.internal.gson.GreeScanRequestDTO; import org.openhab.binding.gree.internal.gson.GreeScanResponseDTO; +import org.openhab.binding.gree.internal.gson.GreeScanResponsePackDTO; import org.openhab.binding.gree.internal.handler.GreeAirDevice; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -103,12 +103,12 @@ public class GreeDeviceFinder { } // Decrypt message - a GreeException is thrown when something went wrong - String decryptedMsg = scanResponseGson.decryptedPack = GreeCryptoUtil - .decryptPack(GreeCryptoUtil.getAESGeneralKeyByteArray(), scanResponseGson.pack); + String decryptedMsg = scanResponseGson.decryptedPack = GreeCryptoUtil.decrypt(scanResponseGson); + logger.debug("Response received from address {}: {}", remoteAddress.getHostAddress(), decryptedMsg); // Create the JSON to hold the response values - scanResponseGson.packJson = GSON.fromJson(decryptedMsg, GreeScanReponsePackDTO.class); + scanResponseGson.packJson = GSON.fromJson(decryptedMsg, GreeScanResponsePackDTO.class); // Now make sure the device is reported as a Gree device if ("gree".equalsIgnoreCase(scanResponseGson.packJson.brand)) { diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBaseDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBaseDTO.java new file mode 100644 index 00000000000..a758de6db71 --- /dev/null +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBaseDTO.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.gree.internal.gson; + +/** + * + * The GreeBaseDTO class is used as a base class for request and response classes + * + * @author Zhivka Dimvoa - Initial contribution + */ +public class GreeBaseDTO { + public String t = null; + public int i = 0; + public int uid = 0; + public String cid = null; + public String tcid = null; + public String tag = null; + public String pack = null; +} diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindRequestPackDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindRequestPackDTO.java index 78bf49d6bd7..3791a6722ea 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindRequestPackDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindRequestPackDTO.java @@ -14,7 +14,7 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeBindRequestPack4Gson class is used by Gson to hold values to be send to + * The GreeBindRequestPackDTO class is used by Gson to hold values to be send to * the Air Conditioner during Binding * * @author John Cunha - Initial contribution diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponseDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponseDTO.java index 4a3ca6b11a8..9ed9ddc6048 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponseDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponseDTO.java @@ -14,20 +14,11 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeBindResponse4Gson class is used by Gson to hold values returned from + * The GreeBindResponseDTO class is used by Gson to hold values returned from * the Air Conditioner during Binding * * @author John Cunha - Initial contribution */ -public class GreeBindResponseDTO { - - public String t = null; - public int i = 0; - public int uid = 0; - public String cid = null; - public String tcid = null; - public String pack = null; - - public transient String decryptedPack = null; +public class GreeBindResponseDTO extends GreeResponseBaseDTO { public transient GreeBindResponsePackDTO packJson = null; } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponsePackDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponsePackDTO.java index 1ec5335eae8..8c05b3c9b6a 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponsePackDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeBindResponsePackDTO.java @@ -14,7 +14,7 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeBindResponsePack4Gson class is used by Gson to hold values returned from + * The GreeBindResponsePackDTO class is used by Gson to hold values returned from * the Air Conditioner during Binding * * @author John Cunha - Initial contribution diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponseDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponseDTO.java index e37cfc2d276..34c3bec9cb1 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponseDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponseDTO.java @@ -14,21 +14,12 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeExecResponse4Gson class is used by Gson to hold values returned from + * The GreeExecResponseDTO class is used by Gson to hold values returned from * the Air Conditioner during requests for Execution of Commands to the * Air Conditioner. * * @author John Cunha - Initial contribution */ -public class GreeExecResponseDTO { - - public String t = null; - public int i = 0; - public int uid = 0; - public String cid = null; - public String tcid = null; - public String pack = null; - - public transient String decryptedPack = null; +public class GreeExecResponseDTO extends GreeResponseBaseDTO { public transient GreeExecResponsePackDTO packJson = null; } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponsePackDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponsePackDTO.java index b6d595f2606..e97e81c15e7 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponsePackDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecResponsePackDTO.java @@ -14,7 +14,7 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeExecResponsePack4Gson class is used by Gson to hold values returned from + * The GreeExecResponsePackDTO class is used by Gson to hold values returned from * the Air Conditioner during requests for Execution of Commands to the * Air Conditioner. * diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecuteCommandPackDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecuteCommandPackDTO.java index 7e17ef545f4..dd34dedf378 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecuteCommandPackDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeExecuteCommandPackDTO.java @@ -14,7 +14,7 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeExecuteCommandPack4Gson class is used by Gson to hold values to be send to + * The GreeExecuteCommandPackDTO class is used by Gson to hold values to be send to * the Air Conditioner during requests for Execution of Commands to the * Air Conditioner. * diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusDTO.java index 69c49ae2ad8..d77571babac 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusDTO.java @@ -14,17 +14,11 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeReqStatus4Gson class is used by Gson to hold values to be send to + * The GreeReqStatusDTO class is used by Gson to hold values to be send to * the Air Conditioner during requests for Status Updates to the * Air Conditioner. * * @author John Cunha - Initial contribution */ -public class GreeReqStatusDTO { - public String cid = null; - public int i = 0; - public String t = null; - public int uid = 0; - public String pack = null; - public String tcid = null; +public class GreeReqStatusDTO extends GreeRequestDTO { } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusPackDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusPackDTO.java index b2655595cfa..9c06ca53513 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusPackDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeReqStatusPackDTO.java @@ -14,14 +14,13 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeReqStatusPack4Gson class is used by Gson to hold values to be send to + * The GreeReqStatusPackDTO class is used by Gson to hold values to be send to * the Air Conditioner during requests for Status Updates to the * Air Conditioner. * * @author John Cunha - Initial contribution */ public class GreeReqStatusPackDTO { - public String t = null; public String[] cols = null; public String mac = null; diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeRequestDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeRequestDTO.java index 4207e0c4c56..cd3cc8fbb1a 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeRequestDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeRequestDTO.java @@ -14,17 +14,10 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeBindRequest4Gson class is used by Gson to hold values to be send to - * the Air Conditioner during Binding + * The GreeRequestDTO class is used by Gson to hold values to be send to + * the Air Conditioner during Binding and as a base class for other request classes * * @author John Cunha - Initial contribution */ -public class GreeRequestDTO { - - public int uid = 0; - public String t = null; - public int i = 0; - public String pack = null; - public String cid = null; - public String tcid = null; +public class GreeRequestDTO extends GreeBaseDTO { } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeResponseBaseDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeResponseBaseDTO.java new file mode 100644 index 00000000000..17042a6d953 --- /dev/null +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeResponseBaseDTO.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.gree.internal.gson; + +/** + * + * The GreeResponseBaseDTO class is used as a base class for response classes + * + * @author Zhivka Dimvoa - Initial contribution + */ +public class GreeResponseBaseDTO extends GreeBaseDTO { + public transient String decryptedPack = null; +} diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanRequestDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanRequestDTO.java index a823ffe35b8..f9e9dfb6083 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanRequestDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanRequestDTO.java @@ -14,7 +14,7 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeScanRequest4Gson class is used by Gson to hold values sent to + * The GreeScanRequestDTO class is used by Gson to hold values sent to * the Air Conditioner during Scan Requests to the Air Conditioner. * * @author John Cunha - Initial contribution diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanResponseDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanResponseDTO.java index 2a631052830..601139bf181 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanResponseDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanResponseDTO.java @@ -14,18 +14,11 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeScanResponse4Gson class is used by Gson to hold values returned by + * The GreeScanResponseDTO class is used by Gson to hold values returned by * the Air Conditioner during Scan Requests to the Air Conditioner. * * @author John Cunha - Initial contribution */ -public class GreeScanResponseDTO { - public String t = null; - public int i = 0; - public int uid = 0; - public String cid = null; - public String tcid = null; - public String pack = null; - public transient String decryptedPack = null; - public transient GreeScanReponsePackDTO packJson = null; +public class GreeScanResponseDTO extends GreeResponseBaseDTO { + public transient GreeScanResponsePackDTO packJson = null; } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanReponsePackDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanResponsePackDTO.java similarity index 88% rename from bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanReponsePackDTO.java rename to bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanResponsePackDTO.java index a7cf2e2ba0a..89746a0d327 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanReponsePackDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeScanResponsePackDTO.java @@ -14,13 +14,12 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeScanReponsePack4Gson class is used by Gson to hold values returned by + * The GreeScanReponsePackDTO class is used by Gson to hold values returned by * the Air Conditioner during Scan Requests to the Air Conditioner. * * @author John Cunha - Initial contribution */ -public class GreeScanReponsePackDTO { - +public class GreeScanResponsePackDTO { public String t = null; public String cid = null; public String bc = null; diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponseDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponseDTO.java index 14f358ff1f2..9e7f6c10176 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponseDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponseDTO.java @@ -14,21 +14,12 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeStatusResponse4Gson class is used by Gson to hold values returned from + * The GreeStatusResponseDTO class is used by Gson to hold values returned from * the Air Conditioner during requests for Status Updates to the * Air Conditioner. * * @author John Cunha - Initial contribution */ -public class GreeStatusResponseDTO { - - public String t = null; - public int i = 0; - public int uid = 0; - public String cid = null; - public String tcid = null; - public String pack = null; - - public transient String decryptedPack = null; +public class GreeStatusResponseDTO extends GreeResponseBaseDTO { public transient GreeStatusResponsePackDTO packJson = null; } diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponsePackDTO.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponsePackDTO.java index 6daac5a8724..5ec5bb5a2b2 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponsePackDTO.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/gson/GreeStatusResponsePackDTO.java @@ -14,7 +14,7 @@ package org.openhab.binding.gree.internal.gson; /** * - * The GreeStatusResponsePack4Gson class is used by Gson to hold values returned from + * The GreeStatusResponsePackDTO class is used by Gson to hold values returned from * the Air Conditioner during requests for Status Updates to the * Air Conditioner. * diff --git a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java index 8ef42783bf4..2a7db2a5c59 100644 --- a/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java +++ b/bundles/org.openhab.binding.gree/src/main/java/org/openhab/binding/gree/internal/handler/GreeAirDevice.java @@ -64,6 +64,7 @@ public class GreeAirDevice { private final InetAddress ipAddress; private int port = 0; private String encKey = ""; + private GreeCryptoUtil.EncryptionTypes encType = GreeCryptoUtil.EncryptionTypes.ECB; private Optional scanResponseGson = Optional.empty(); private Optional statusResponseGson = Optional.empty(); private Optional prevStatusResponsePackGson = Optional.empty(); @@ -76,6 +77,7 @@ public class GreeAirDevice { this.ipAddress = ipAddress; this.port = port; this.scanResponseGson = Optional.of(scanResponse); + this.encType = GreeCryptoUtil.getEncryptionType(scanResponse); } public void getDeviceStatus(DatagramSocket clientSocket) throws GreeException { @@ -117,9 +119,8 @@ public class GreeAirDevice { String reqStatusPackStr = GSON.toJson(reqStatusPackGson); // Encrypt and send the Status Request pack - String encryptedStatusReqPacket = GreeCryptoUtil.encryptPack(getKey(), reqStatusPackStr); - DatagramPacket sendPacket = createPackRequest(0, - new String(encryptedStatusReqPacket.getBytes(), StandardCharsets.UTF_8)); + String[] encryptedStatusReqData = GreeCryptoUtil.encrypt(getKey(), reqStatusPackStr, encType); + DatagramPacket sendPacket = createPackRequest(0, encryptedStatusReqData); clientSocket.send(sendPacket); // Keep a copy of the old response to be used to check if values have changed @@ -131,7 +132,7 @@ public class GreeAirDevice { // Read the response, create the JSON to hold the response values GreeStatusResponseDTO resp = receiveResponse(clientSocket, GreeStatusResponseDTO.class); - resp.decryptedPack = GreeCryptoUtil.decryptPack(getKey(), resp.pack); + resp.decryptedPack = GreeCryptoUtil.decrypt(getKey(), resp, encType); logger.debug("Response from device: {}", resp.decryptedPack); resp.packJson = GSON.fromJson(resp.decryptedPack, GreeStatusResponsePackDTO.class); @@ -157,14 +158,14 @@ public class GreeAirDevice { String bindReqPackStr = GSON.toJson(bindReqPackGson); // Encrypt and send the Binding Request pack - String encryptedBindReqPacket = GreeCryptoUtil.encryptPack(GreeCryptoUtil.getAESGeneralKeyByteArray(), - bindReqPackStr); - DatagramPacket sendPacket = createPackRequest(1, encryptedBindReqPacket); + String[] encryptedBindReqData = GreeCryptoUtil.encrypt(GreeCryptoUtil.getGeneralKeyByteArray(encType), + bindReqPackStr, encType); + DatagramPacket sendPacket = createPackRequest(1, encryptedBindReqData); clientSocket.send(sendPacket); // Recieve a response, create the JSON to hold the response values GreeBindResponseDTO resp = receiveResponse(clientSocket, GreeBindResponseDTO.class); - resp.decryptedPack = GreeCryptoUtil.decryptPack(GreeCryptoUtil.getAESGeneralKeyByteArray(), resp.pack); + resp.decryptedPack = GreeCryptoUtil.decrypt(resp, encType); resp.packJson = GSON.fromJson(resp.decryptedPack, GreeBindResponsePackDTO.class); // Now set the key and flag to indicate the bind was successful @@ -424,13 +425,13 @@ public class GreeAirDevice { String execCmdPackStr = GSON.toJson(execCmdPackGson); // Now encrypt and send the Command Request pack - String encryptedCommandReqPacket = GreeCryptoUtil.encryptPack(getKey(), execCmdPackStr); - DatagramPacket sendPacket = createPackRequest(0, encryptedCommandReqPacket); + String[] encryptedCommandReqData = GreeCryptoUtil.encrypt(getKey(), execCmdPackStr, encType); + DatagramPacket sendPacket = createPackRequest(0, encryptedCommandReqData); clientSocket.send(sendPacket); // Receive and decode result GreeExecResponseDTO execResponseGson = receiveResponse(clientSocket, GreeExecResponseDTO.class); - execResponseGson.decryptedPack = GreeCryptoUtil.decryptPack(getKey(), execResponseGson.pack); + execResponseGson.decryptedPack = GreeCryptoUtil.decrypt(getKey(), execResponseGson, encType); // Create the JSON to hold the response values execResponseGson.packJson = GSON.fromJson(execResponseGson.decryptedPack, GreeExecResponsePackDTO.class); @@ -451,14 +452,21 @@ public class GreeAirDevice { executeCommand(clientSocket, Map.of(command, value)); } - private DatagramPacket createPackRequest(int i, String pack) { + private DatagramPacket createPackRequest(int i, String[] data) { GreeRequestDTO request = new GreeRequestDTO(); request.cid = GREE_CID; request.i = i; request.t = GREE_CMDT_PACK; request.uid = 0; request.tcid = getId(); - request.pack = pack; + request.pack = data[0]; + if (encType == GreeCryptoUtil.EncryptionTypes.GCM) { + if (data.length > 1) { + request.tag = data[1]; + } else { + logger.warn("Missing string for tag property for GCM encryption data"); + } + } byte[] sendData = GSON.toJson(request).getBytes(StandardCharsets.UTF_8); return new DatagramPacket(sendData, sendData.length, ipAddress, port); }