]> git.basschouten.com Git - openhab-addons.git/blob
84374d65af14e83eadd65bf4f1024f177530727b
[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.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      * @throws Exception
62      */
63     public TapoCipher(String handshakeKey, TapoCredentials credentials) {
64         setKey(handshakeKey, credentials);
65     }
66
67     /**
68      * SET NEW KEY AND CREDENTIALS
69      * 
70      * @param handshakeKey
71      * @param credentials
72      */
73     public void setKey(String handshakeKey, TapoCredentials credentials) {
74         logger.trace("Init TapoCipher with key: {} ", handshakeKey);
75         MimeEncode mimeEncode = new MimeEncode();
76         try {
77             byte[] decode = mimeEncode.decode(handshakeKey.getBytes(HANDSHAKE_CHARSET));
78             byte[] decode2 = mimeEncode.decode(credentials.getPrivateKeyBytes());
79             Cipher instance = Cipher.getInstance(HANDSHAKE_TRANSFORMATION);
80             KeyFactory kf = KeyFactory.getInstance(HANDSHAKE_ALGORITHM);
81             PrivateKey p = kf.generatePrivate(new PKCS8EncodedKeySpec(decode2));
82             instance.init(Cipher.DECRYPT_MODE, p);
83             byte[] doFinal = instance.doFinal(decode);
84             byte[] bArr = new byte[16];
85             byte[] bArr2 = new byte[16];
86             System.arraycopy(doFinal, 0, bArr, 0, 16);
87             System.arraycopy(doFinal, 16, bArr2, 0, 16);
88             initCipher(bArr, bArr2);
89         } catch (Exception ex) {
90             logger.warn("Something went wrong: {}", ex.getMessage());
91         }
92     }
93
94     /**
95      * INIT ENCODE/DECDE-CIPHERS
96      * 
97      * @param bArr
98      * @param bArr2
99      * @throws Exception
100      */
101     protected void initCipher(byte[] bArr, byte[] bArr2) throws Exception {
102         try {
103             mimeEncode = new MimeEncode();
104             SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, CIPHER_ALGORITHM);
105             IvParameterSpec ivParameterSpec = new IvParameterSpec(bArr2);
106             this.encodeCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
107             this.decodeCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
108             this.encodeCipher.init(1, secretKeySpec, ivParameterSpec);
109             this.decodeCipher.init(2, secretKeySpec, ivParameterSpec);
110         } catch (Exception e) {
111             logger.warn("initChiper failed: {}", e.getMessage());
112             this.encodeCipher = null;
113             this.decodeCipher = null;
114         }
115     }
116
117     /**
118      * ENCODE STRING
119      * 
120      * @param str source string to encode
121      * @return encoded string
122      * @throws Exception
123      */
124     public String encode(String str) throws Exception {
125         byte[] doFinal;
126         doFinal = this.encodeCipher.doFinal(str.getBytes(CIPHER_CHARSET));
127         String encrypted = mimeEncode.encodeToString(doFinal);
128         return encrypted.replace("\r\n", "");
129     }
130
131     /**
132      * DECODE STRING
133      * 
134      * @param str source string to decode
135      * @return decoded string
136      * @throws Exception
137      */
138     public String decode(String str) throws Exception {
139         byte[] data = mimeEncode.decode(str.getBytes(CIPHER_CHARSET));
140         byte[] doFinal;
141         doFinal = this.decodeCipher.doFinal(data);
142         return new String(doFinal);
143     }
144 }