]> git.basschouten.com Git - openhab-addons.git/blob
1b4d5422628c6b34f1d456dc9b2d53f2fffb98da
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.kostalinverter.internal.thirdgeneration;
14
15 import static org.openhab.binding.kostalinverter.internal.thirdgeneration.ThirdGenerationBindingConstants.*;
16
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;
23
24 import javax.crypto.Mac;
25 import javax.crypto.SecretKeyFactory;
26 import javax.crypto.spec.PBEKeySpec;
27 import javax.crypto.spec.SecretKeySpec;
28
29 /**
30  * The {@link ThirdGenerationEncryptionHelper} is responsible for handling the encryption for the authentication
31  * handlers.
32  *
33  * @author RenĂ© Stakemeier - Initial contribution
34  */
35 final class ThirdGenerationEncryptionHelper {
36
37     private ThirdGenerationEncryptionHelper() {
38     }
39
40     /**
41      * This method generates the HMACSha256 encrypted value of the given value
42      *
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
48      */
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);
53         mac.init(signingKey);
54         mac.update(valueToEncrypt.getBytes());
55         return mac.doFinal();
56     }
57
58     /**
59      * This methods generates the client proof.
60      * It is calculated as XOR between the {@link clientSignature} and the {@link serverSignature}
61      *
62      * @param clientSignature client signature
63      * @param serverSignature server signature
64      * @return client proof
65      */
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]));
70         }
71         return Base64.getEncoder().encodeToString(result);
72     }
73
74     /**
75      * Create the PBKDF2 hash
76      *
77      * @param password password
78      * @param salt salt
79      * @param rounds rounds
80      * @return hash
81      * @throws NoSuchAlgorithmException if PBKDF2WithHmacSHA256 is not supported
82      * @throws InvalidKeySpecException if the key specification is not supported
83      */
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();
89     }
90
91     /**
92      * Create the SHA256 hash value for the given byte array
93      *
94      * @param valueToHash byte array to get the hash value for
95      * @return the hash value
96      * @throws NoSuchAlgorithmException if SHA256 is not supported
97      */
98     static byte[] getSha256Hash(byte[] valueToHash) throws NoSuchAlgorithmException {
99         return MessageDigest.getInstance(SHA_256_HASH).digest(valueToHash);
100     }
101
102     /**
103      * Create the nonce (numbers used once) for the client for communication
104      *
105      * @return nonce
106      */
107     static String createClientNonce() {
108         Random generator = new Random();
109
110         // Randomize the random generator
111         byte[] randomizeArray = new byte[1024];
112         generator.nextBytes(randomizeArray);
113
114         // 3 words of 4 bytes are required for the handshake
115         byte[] nonceArray = new byte[12];
116         generator.nextBytes(nonceArray);
117
118         // return the base64 encoded value of the random words
119         return Base64.getMimeEncoder().encodeToString(nonceArray);
120     }
121 }