/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.km200.internal; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.xml.bind.DatatypeConverter; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The KM200Device representing the device with its all capabilities * * @author Markus Eckhardt * * @since 1.9.0 */ class KM200Device { private static final Logger logger = LoggerFactory.getLogger(KM200Device.class); /* valid IPv4 address of the KMxxx. */ protected String ip4Address = null; /* The gateway password which is provided on the type sign of the KMxxx. */ protected String gatewayPassword = null; /* The private password which has been defined by the user via EasyControl. */ protected String privatePassword = null; /* The returned device charset for communication */ protected String charSet = null; /* Needed keys for the communication */ protected byte[] cryptKeyInit = null; protected byte[] cryptKeyPriv = null; /* Buderus_MD5Salt */ protected byte[] MD5Salt = null; /* Device services */ HashMap<String, KM200CommObject> serviceMap = null; /* Device services blacklist */ List<String> blacklistMap = null; /* List of virtual services */ List<KM200CommObject> virtualList = null; /* Is the first INIT done */ protected Boolean inited = false; public KM200Device() { serviceMap = new HashMap<String, KM200CommObject>(); blacklistMap = new ArrayList<String>(); blacklistMap.add("/gateway/firmware"); virtualList = new ArrayList<KM200CommObject>(); } public Boolean isConfigured() { if (StringUtils.isNotBlank(ip4Address) && cryptKeyPriv != null) { return true; } else { return false; } } /** * This function creates the private key from the MD5Salt, the device and the private password * * @author Markus Eckhardt * * @since 1.9.0 */ @SuppressWarnings("null") private void RecreateKeys() { if (StringUtils.isNotBlank(gatewayPassword) && StringUtils.isNotBlank(privatePassword) && MD5Salt != null) { byte[] MD5_K1 = null; byte[] MD5_K2_Init = null; byte[] MD5_K2_Private = null; byte[] bytesOfGatewayPassword = null; byte[] bytesOfPrivatePassword = null; MessageDigest md = null; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { logger.error("No such algorithm, MD5: {}", e.getMessage()); } /* First half of the key: MD5 of (GatewayPassword . Salt) */ try { bytesOfGatewayPassword = gatewayPassword.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { logger.error("No such encoding, UTF-8: {}", e.getMessage()); } byte[] CombParts1 = new byte[bytesOfGatewayPassword.length + MD5Salt.length]; System.arraycopy(bytesOfGatewayPassword, 0, CombParts1, 0, bytesOfGatewayPassword.length); System.arraycopy(MD5Salt, 0, CombParts1, bytesOfGatewayPassword.length, MD5Salt.length); MD5_K1 = md.digest(CombParts1); /* Second half of the key: - Initial: MD5 of ( Salt) */ MD5_K2_Init = md.digest(MD5Salt); /* Second half of the key: - private: MD5 of ( Salt . PrivatePassword) */ try { bytesOfPrivatePassword = privatePassword.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { logger.error("No such encoding, UTF-8: {}", e.getMessage()); } byte[] CombParts2 = new byte[bytesOfPrivatePassword.length + MD5Salt.length]; System.arraycopy(MD5Salt, 0, CombParts2, 0, MD5Salt.length); System.arraycopy(bytesOfPrivatePassword, 0, CombParts2, MD5Salt.length, bytesOfPrivatePassword.length); MD5_K2_Private = md.digest(CombParts2); /* Create Keys */ cryptKeyInit = new byte[MD5_K1.length + MD5_K2_Init.length]; System.arraycopy(MD5_K1, 0, cryptKeyInit, 0, MD5_K1.length); System.arraycopy(MD5_K2_Init, 0, cryptKeyInit, MD5_K1.length, MD5_K2_Init.length); cryptKeyPriv = new byte[MD5_K1.length + MD5_K2_Private.length]; System.arraycopy(MD5_K1, 0, cryptKeyPriv, 0, MD5_K1.length); System.arraycopy(MD5_K2_Private, 0, cryptKeyPriv, MD5_K1.length, MD5_K2_Private.length); } } // getter public String getIP4Address() { return ip4Address; } public String getGatewayPassword() { return gatewayPassword; } public String getPrivatePassword() { return privatePassword; } public byte[] getCryptKeyInit() { return cryptKeyInit; } public byte[] getCryptKeyPriv() { return cryptKeyPriv; } public String getCharSet() { return charSet; } public Boolean getInited() { return inited; } /** * This function outputs a ";" separated list of all on the device available services with its capabilities * */ public void listAllServices() { if (serviceMap != null) { logger.info("##################################################################"); logger.info("List of avalible services"); logger.info("readable;writeable;recordable;virtual;type;service;value;allowed;min;max"); for (KM200CommObject object : serviceMap.values()) { if (object != null) { String val = "", type, valPara = ""; logger.debug("List type: {} service: {}", object.getServiceType(), object.getFullServiceName()); type = object.getServiceType(); if (type == null) { type = new String(); } if (type.equals("stringValue") || type.equals("floatValue")) { val = object.getValue().toString(); if (object.getValueParameter() != null) { if (type.equals("stringValue")) { @SuppressWarnings("unchecked") List<String> valParas = (List<String>) object.getValueParameter(); for (int i = 0; i < valParas.size(); i++) { if (i > 0) { valPara += "|"; } valPara += valParas.get(i); } valPara += ";;"; } if (type.equals("floatValue")) { @SuppressWarnings("unchecked") List<Float> valParas = (List<Float>) object.getValueParameter(); valPara += ";"; if (valParas.size() == 2) { valPara += valParas.get(0); valPara += ";"; valPara += valParas.get(1); } else { logger.debug("Value parameter for float != 2, this shouldn't happen"); valPara += ";"; } } } else { valPara += ";;"; } } else { val = ""; valPara = ";"; } logger.info("{};{};{};{};{};{};{};{}", object.getReadable().toString(), object.getWriteable().toString(), object.getRecordable().toString(), object.getVirtual().toString(), type, object.getFullServiceName(), val, valPara); } } logger.info("##################################################################"); } } /** * This function resets the update state on all service objects * */ public void resetAllUpdates() { if (serviceMap != null) { for (KM200CommObject object : serviceMap.values()) { if (object != null) { object.setUpdated(false); } } } } // setter public void setIP4Address(String ip) { ip4Address = ip; } public void setGatewayPassword(String password) { gatewayPassword = password; RecreateKeys(); } public void setPrivatePassword(String password) { privatePassword = password; RecreateKeys(); } public void setMD5Salt(String salt) { MD5Salt = DatatypeConverter.parseHexBinary(salt); RecreateKeys(); } public void setCryptKeyPriv(String key) { cryptKeyPriv = DatatypeConverter.parseHexBinary(key); } public void setCharSet(String charset) { charSet = charset; } public void setInited(Boolean Init) { inited = Init; } }