2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.kostalinverter.internal.thirdgeneration;
15 import static org.openhab.binding.kostalinverter.internal.thirdgeneration.ThirdGenerationBindingConstants.*;
17 import java.security.InvalidKeyException;
18 import java.security.MessageDigest;
19 import java.security.NoSuchAlgorithmException;
20 import java.security.spec.InvalidKeySpecException;
21 import java.util.Base64;
22 import java.util.Random;
24 import javax.crypto.Mac;
25 import javax.crypto.SecretKeyFactory;
26 import javax.crypto.spec.PBEKeySpec;
27 import javax.crypto.spec.SecretKeySpec;
30 * The {@link ThirdGenerationEncryptionHelper} is responsible for handling the encryption for the authentication
33 * @author René Stakemeier - Initial contribution
35 final class ThirdGenerationEncryptionHelper {
37 private ThirdGenerationEncryptionHelper() {
41 * This method generates the HMACSha256 encrypted value of the given value
43 * @param password Password used for encryption
44 * @param valueToEncrypt value to encrypt
45 * @return encrypted value
46 * @throws InvalidKeyException thrown if the key generated from the password is invalid
47 * @throws NoSuchAlgorithmException thrown if HMAC SHA 256 is not supported
49 static byte[] getHMACSha256(byte[] password, String valueToEncrypt)
50 throws InvalidKeyException, NoSuchAlgorithmException {
51 SecretKeySpec signingKey = new SecretKeySpec(password, HMAC_SHA256_ALGORITHM);
52 Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
54 mac.update(valueToEncrypt.getBytes());
59 * This methods generates the client proof.
60 * It is calculated as XOR between the {@link clientSignature} and the {@link serverSignature}
62 * @param clientSignature client signature
63 * @param serverSignature server signature
64 * @return client proof
66 static String createClientProof(byte[] clientSignature, byte[] serverSignature) {
67 byte[] result = new byte[clientSignature.length];
68 for (int i = 0; i < clientSignature.length; i++) {
69 result[i] = (byte) (0xff & (clientSignature[i] ^ serverSignature[i]));
71 return Base64.getEncoder().encodeToString(result);
75 * Create the PBKDF2 hash
77 * @param password password
79 * @param rounds rounds
81 * @throws NoSuchAlgorithmException if PBKDF2WithHmacSHA256 is not supported
82 * @throws InvalidKeySpecException if the key specification is not supported
84 static byte[] getPBKDF2Hash(String password, byte[] salt, int rounds)
85 throws NoSuchAlgorithmException, InvalidKeySpecException {
86 PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, rounds, 256);
87 SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
88 return skf.generateSecret(spec).getEncoded();
92 * Create the SHA256 hash value for the given byte array
94 * @param valueToHash byte array to get the hash value for
95 * @return the hash value
96 * @throws NoSuchAlgorithmException if SHA256 is not supported
98 static byte[] getSha256Hash(byte[] valueToHash) throws NoSuchAlgorithmException {
99 return MessageDigest.getInstance(SHA_256_HASH).digest(valueToHash);
103 * Create the nonce (numbers used once) for the client for communication
107 static String createClientNonce() {
108 Random generator = new Random();
110 // Randomize the random generator
111 byte[] randomizeArray = new byte[1024];
112 generator.nextBytes(randomizeArray);
114 // 3 words of 4 bytes are required for the handshake
115 byte[] nonceArray = new byte[12];
116 generator.nextBytes(nonceArray);
118 // return the base64 encoded value of the random words
119 return Base64.getMimeEncoder().encodeToString(nonceArray);