]> git.basschouten.com Git - openhab-addons.git/blob
ca0d40993553dd9b485db9126284c2d97c4cb573
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.tapocontrol.internal.helpers;
14
15 import java.security.KeyFactory;
16 import java.security.PrivateKey;
17 import java.security.spec.PKCS8EncodedKeySpec;
18
19 import javax.crypto.Cipher;
20 import javax.crypto.spec.IvParameterSpec;
21 import javax.crypto.spec.SecretKeySpec;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * TAPO-CIPHER
29  * Based on K4CZP3R's p100-java-poc
30  * 
31  * @author Christian Wild - Initial Initial contribution
32  */
33 @NonNullByDefault
34 public class TapoCipher {
35     private final Logger logger = LoggerFactory.getLogger(TapoCipher.class);
36     protected static final String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
37     protected static final String CIPHER_ALGORITHM = "AES";
38     protected static final String CIPHER_CHARSET = "UTF-8";
39     protected static final String HANDSHAKE_TRANSFORMATION = "RSA/ECB/PKCS1Padding";
40     protected static final String HANDSHAKE_ALGORITHM = "RSA";
41     protected static final String HANDSHAKE_CHARSET = "UTF-8";
42
43     @NonNullByDefault({})
44     private Cipher encodeCipher;
45     @NonNullByDefault({})
46     private Cipher decodeCipher;
47     @NonNullByDefault({})
48     private MimeEncode mimeEncode;
49
50     /**
51      * CREATE NEW EMPTY CIPHER
52      */
53     public TapoCipher() {
54     }
55
56     /**
57      * CREATE NEW CIPHER WITH KEY AND CREDENTIALS
58      * 
59      * @param handshakeKey Key from Handshake-Request
60      * @param credentials TapoCredentials
61      */
62     public TapoCipher(String handshakeKey, TapoCredentials credentials) {
63         setKey(handshakeKey, credentials);
64     }
65
66     /**
67      * SET NEW KEY AND CREDENTIALS
68      * 
69      * @param handshakeKey
70      * @param credentials
71      */
72     public void setKey(String handshakeKey, TapoCredentials credentials) {
73         logger.trace("Init TapoCipher with key: {} ", handshakeKey);
74         MimeEncode mimeEncode = new MimeEncode();
75         try {
76             byte[] decode = mimeEncode.decode(handshakeKey.getBytes(HANDSHAKE_CHARSET));
77             byte[] decode2 = mimeEncode.decode(credentials.getPrivateKeyBytes());
78             Cipher instance = Cipher.getInstance(HANDSHAKE_TRANSFORMATION);
79             KeyFactory kf = KeyFactory.getInstance(HANDSHAKE_ALGORITHM);
80             PrivateKey p = kf.generatePrivate(new PKCS8EncodedKeySpec(decode2));
81             instance.init(Cipher.DECRYPT_MODE, p);
82             byte[] doFinal = instance.doFinal(decode);
83             byte[] bArr = new byte[16];
84             byte[] bArr2 = new byte[16];
85             System.arraycopy(doFinal, 0, bArr, 0, 16);
86             System.arraycopy(doFinal, 16, bArr2, 0, 16);
87             initCipher(bArr, bArr2);
88         } catch (Exception ex) {
89             logger.warn("Something went wrong: {}", ex.getMessage());
90         }
91     }
92
93     /**
94      * INIT ENCODE/DECDE-CIPHERS
95      * 
96      * @param bArr
97      * @param bArr2
98      * @throws Exception
99      */
100     protected void initCipher(byte[] bArr, byte[] bArr2) throws Exception {
101         try {
102             mimeEncode = new MimeEncode();
103             SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, CIPHER_ALGORITHM);
104             IvParameterSpec ivParameterSpec = new IvParameterSpec(bArr2);
105             this.encodeCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
106             this.decodeCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
107             this.encodeCipher.init(1, secretKeySpec, ivParameterSpec);
108             this.decodeCipher.init(2, secretKeySpec, ivParameterSpec);
109         } catch (Exception e) {
110             logger.warn("initChiper failed: {}", e.getMessage());
111             this.encodeCipher = null;
112             this.decodeCipher = null;
113         }
114     }
115
116     /**
117      * ENCODE STRING
118      * 
119      * @param str source string to encode
120      * @return encoded string
121      * @throws Exception
122      */
123     public String encode(String str) throws Exception {
124         byte[] doFinal;
125         doFinal = this.encodeCipher.doFinal(str.getBytes(CIPHER_CHARSET));
126         String encrypted = mimeEncode.encodeToString(doFinal);
127         return encrypted.replace("\r\n", "");
128     }
129
130     /**
131      * DECODE STRING
132      * 
133      * @param str source string to decode
134      * @return decoded string
135      * @throws Exception
136      */
137     public String decode(String str) throws Exception {
138         byte[] data = mimeEncode.decode(str.getBytes(CIPHER_CHARSET));
139         byte[] doFinal;
140         doFinal = this.decodeCipher.doFinal(data);
141         return new String(doFinal);
142     }
143 }