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.SecureRandom;
21 import java.security.spec.InvalidKeySpecException;
22 import java.util.Base64;
23 import java.util.Random;
25 import javax.crypto.Mac;
26 import javax.crypto.SecretKeyFactory;
27 import javax.crypto.spec.PBEKeySpec;
28 import javax.crypto.spec.SecretKeySpec;
31 * The {@link ThirdGenerationEncryptionHelper} is responsible for handling the encryption for the authentication
34 * @author René Stakemeier - Initial contribution
36 final class ThirdGenerationEncryptionHelper {
38 private ThirdGenerationEncryptionHelper() {
42 * This method generates the HMACSha256 encrypted value of the given value
44 * @param password Password used for encryption
45 * @param valueToEncrypt value to encrypt
46 * @return encrypted value
47 * @throws InvalidKeyException thrown if the key generated from the password is invalid
48 * @throws NoSuchAlgorithmException thrown if HMAC SHA 256 is not supported
50 static byte[] getHMACSha256(byte[] password, String valueToEncrypt)
51 throws InvalidKeyException, NoSuchAlgorithmException {
52 SecretKeySpec signingKey = new SecretKeySpec(password, HMAC_SHA256_ALGORITHM);
53 Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
55 mac.update(valueToEncrypt.getBytes());
60 * This methods generates the client proof.
61 * It is calculated as XOR between the {@link clientSignature} and the {@link serverSignature}
63 * @param clientSignature client signature
64 * @param serverSignature server signature
65 * @return client proof
67 static String createClientProof(byte[] clientSignature, byte[] serverSignature) {
68 byte[] result = new byte[clientSignature.length];
69 for (int i = 0; i < clientSignature.length; i++) {
70 result[i] = (byte) (0xff & (clientSignature[i] ^ serverSignature[i]));
72 return Base64.getEncoder().encodeToString(result);
76 * Create the PBKDF2 hash
78 * @param password password
80 * @param rounds rounds
82 * @throws NoSuchAlgorithmException if PBKDF2WithHmacSHA256 is not supported
83 * @throws InvalidKeySpecException if the key specification is not supported
85 static byte[] getPBKDF2Hash(String password, byte[] salt, int rounds)
86 throws NoSuchAlgorithmException, InvalidKeySpecException {
87 PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, rounds, 256);
88 SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
89 return skf.generateSecret(spec).getEncoded();
93 * Create the SHA256 hash value for the given byte array
95 * @param valueToHash byte array to get the hash value for
96 * @return the hash value
97 * @throws NoSuchAlgorithmException if SHA256 is not supported
99 static byte[] getSha256Hash(byte[] valueToHash) throws NoSuchAlgorithmException {
100 return MessageDigest.getInstance(SHA_256_HASH).digest(valueToHash);
104 * Create the nonce (numbers used once) for the client for communication
108 static String createClientNonce() {
109 Random generator = new SecureRandom();
111 // Randomize the random generator
112 byte[] randomizeArray = new byte[1024];
113 generator.nextBytes(randomizeArray);
115 // 3 words of 4 bytes are required for the handshake
116 byte[] nonceArray = new byte[12];
117 generator.nextBytes(nonceArray);
119 // return the base64 encoded value of the random words
120 return Base64.getMimeEncoder().encodeToString(nonceArray);