From 3c452ebd937b2585e13662b3097933bd9758f047 Mon Sep 17 00:00:00 2001 From: Pawel Pieczul Date: Fri, 17 Sep 2021 08:40:11 +0200 Subject: [PATCH] Support for SHA-256 (#11240) Signed-off-by: Pawel Pieczul Signed-off-by: Dave J Schoepel --- .../loxone/internal/security/LxWsSecurity.java | 8 +++++--- .../internal/security/LxWsSecurityHash.java | 2 +- .../internal/security/LxWsSecurityToken.java | 16 ++++++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurity.java b/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurity.java index a4b37d26723b..ac12a29b8971 100644 --- a/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurity.java +++ b/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurity.java @@ -126,16 +126,18 @@ boolean checkResponse(LxResponse response) { * * @param string string to be hashed * @param hashKeyHex hash key received from the Miniserver in hex format + * @param sha256 if SHA-256 algorithm should be used (SHA-1 otherwise) * @return hashed string or null if failed */ - String hashString(String string, String hashKeyHex) { + String hashString(String string, String hashKeyHex, boolean sha256) { if (string == null || hashKeyHex == null) { return null; } try { + String alg = sha256 ? "HmacSHA256" : "HmacSHA1"; byte[] hashKeyBytes = HexUtils.hexToBytes(hashKeyHex); - SecretKeySpec signKey = new SecretKeySpec(hashKeyBytes, "HmacSHA1"); - Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec signKey = new SecretKeySpec(hashKeyBytes, alg); + Mac mac = Mac.getInstance(alg); mac.init(signKey); byte[] rawData = mac.doFinal(string.getBytes()); return HexUtils.bytesToHex(rawData); diff --git a/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityHash.java b/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityHash.java index 2993ac5a0c34..d90e37833948 100644 --- a/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityHash.java +++ b/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityHash.java @@ -57,7 +57,7 @@ boolean execute() { if (!checkResponse(resp)) { return false; } - String hash = hashString(user + ":" + password, resp.getValueAsString()); + String hash = hashString(user + ":" + password, resp.getValueAsString(), false); if (hash == null) { return setError(LxErrorCode.INTERNAL_ERROR, "Error hashing credentials."); } diff --git a/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityToken.java b/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityToken.java index 1a8601aea1bf..b9e54ec633d5 100644 --- a/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityToken.java +++ b/bundles/org.openhab.binding.loxone/src/main/java/org/openhab/binding/loxone/internal/security/LxWsSecurityToken.java @@ -86,6 +86,7 @@ class LxWsSecurityToken extends LxWsSecurity { private class LxResponseKeySalt { String key; String salt; + String hashAlg; } /** @@ -148,6 +149,7 @@ private class LxResponseToken { private int tokenRefreshRetryCount; private ScheduledFuture tokenRefreshTimer; private final Lock tokenRefreshLock = new ReentrantLock(); + private boolean sha256 = false; private final byte[] initVector = new byte[IV_LENGTH_BYTES]; private final Logger logger = LoggerFactory.getLogger(LxWsSecurityToken.class); @@ -352,14 +354,14 @@ private byte[] generateSessionKey(Cipher rsaCipher) { } } - private String hashCredentials(LxResponseKeySalt keySalt) { + private String hashCredentials(LxResponseKeySalt keySalt, boolean sha256) { try { - MessageDigest msgDigest = MessageDigest.getInstance("SHA-1"); + MessageDigest msgDigest = MessageDigest.getInstance(sha256 ? "SHA-256" : "SHA-1"); String pwdHashStr = password + ":" + keySalt.salt; byte[] rawData = msgDigest.digest(pwdHashStr.getBytes(StandardCharsets.UTF_8)); String pwdHash = HexUtils.bytesToHex(rawData).toUpperCase(); logger.debug("[{}] PWDHASH: {}", debugId, pwdHash); - return hashString(user + ":" + pwdHash, keySalt.key); + return hashString(user + ":" + pwdHash, keySalt.key, sha256); } catch (NoSuchAlgorithmException e) { logger.debug("[{}] Error hashing token credentials: {}", debugId, e.getMessage()); return null; @@ -376,10 +378,12 @@ private boolean acquireToken() { if (keySalt == null) { return setError(null, "Error parsing hash key/salt json: " + resp.getValueAsString()); } - + if ("SHA256".equals(keySalt.hashAlg)) { + sha256 = true; + } logger.debug("[{}] Hash key: {}, salt: {}", debugId, keySalt.key, keySalt.salt); // Hash user name, password, key and salt - String hash = hashCredentials(keySalt); + String hash = hashCredentials(keySalt, sha256); if (hash == null) { return false; } @@ -436,7 +440,7 @@ private String hashToken() { try { String hashKey = resp.getValueAsString(); // here is a difference to the API spec, which says the string to hash is "user:token", but this is "token" - String hash = hashString(token, hashKey); + String hash = hashString(token, hashKey, sha256); if (hash == null) { setError(null, "Error hashing token."); }