/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.satel.internal.protocol; import java.security.GeneralSecurityException; import java.security.Key; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; /** * Helper class for encrypting ETHM-1 messages. * * @author Krzysztof Goworek * @since 1.7.0 */ public class EncryptionHelper { private Key key; private Cipher encipher; private Cipher decipher; /** * Creates new instance of encryption helper with given key. * * @param keyString * key for integration encryption * @throws GeneralSecurityException on JCE errors */ public EncryptionHelper(String keyString) throws GeneralSecurityException { // we have to check if 192bit support is enabled if (Cipher.getMaxAllowedKeyLength("AES") < 192) { throw new GeneralSecurityException("JCE does not support 192-bit keys"); } // build encryption/decryption key based on given password byte passwordBytes[] = keyString.getBytes(); byte[] keyBytes = new byte[24]; for (int i = 0; i < 12; ++i) { keyBytes[i] = keyBytes[i + 12] = (i < passwordBytes.length) ? passwordBytes[i] : 0x20; } // create objects for encryption/decryption this.key = new SecretKeySpec(keyBytes, "AES"); this.encipher = Cipher.getInstance("AES/ECB/NoPadding"); this.encipher.init(Cipher.ENCRYPT_MODE, this.key); this.decipher = Cipher.getInstance("AES/ECB/NoPadding"); this.decipher.init(Cipher.DECRYPT_MODE, this.key); } /** * Decrypts given buffer of bytes in place. * * @param buffer * bytes to decrypt * @throws GeneralSecurityException * on decryption errors */ public void decrypt(byte buffer[]) throws GeneralSecurityException { byte[] CV = new byte[16]; byte[] C = new byte[16]; byte[] TEMP = new byte[16]; int count = buffer.length; CV = this.encipher.doFinal(CV); for (int index = 0; count > 0;) { if (count > 15) { count -= 16; System.arraycopy(buffer, index, TEMP, 0, 16); System.arraycopy(buffer, index, C, 0, 16); C = this.decipher.doFinal(C); for (int i = 0; i < 16; ++i) { C[i] ^= CV[i]; CV[i] = TEMP[i]; } System.arraycopy(C, 0, buffer, index, 16); index += 16; } else { System.arraycopy(buffer, index, C, 0, count); CV = this.encipher.doFinal(CV); for (int i = 0; i < 16; ++i) { C[i] ^= CV[i]; } System.arraycopy(C, 0, buffer, index, count); count = 0; } } } /** * Encrypts given buffer of bytes in place. * * @param buffer * bytes to encrypt * @throws GeneralSecurityException * on encryption errors */ public void encrypt(byte buffer[]) throws GeneralSecurityException { byte[] CV = new byte[16]; byte[] P = new byte[16]; int count = buffer.length; CV = this.encipher.doFinal(CV); for (int index = 0; count > 0;) { if (count > 15) { count -= 16; System.arraycopy(buffer, index, P, 0, 16); for (int i = 0; i < 16; ++i) { P[i] ^= CV[i]; } P = this.encipher.doFinal(P); System.arraycopy(P, 0, CV, 0, 16); System.arraycopy(P, 0, buffer, index, 16); index += 16; } else { System.arraycopy(buffer, index, P, 0, count); CV = this.encipher.doFinal(CV); for (int i = 0; i < 16; ++i) { P[i] ^= CV[i]; } System.arraycopy(P, 0, buffer, index, count); count = 0; } } } }