package com.gdh.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import com.gdh.main.Constants; /** * * CipherAgentImpl is a utility class for encrypting and decrypting messages. * The key used is symmetric, * * which means the same key is used for both encryption and decryption. * * It is not part of the key exchange process. Once a key is obtained from * GDHVertex this class can be used * * as part of a protocol to exchange messages between the participating parties. * * @author Max Amelchenko * */ public class CipherAgentImpl implements CipherAgent { private final Cipher encryptCipher; private final Cipher decryptCipher; public CipherAgentImpl(String instance) throws NoSuchAlgorithmException, NoSuchPaddingException { encryptCipher = Cipher.getInstance(instance); decryptCipher = Cipher.getInstance(instance); } /** * Encrypt a value with a key and initial vector * * @param value * the String value to encrypt * @param iv * the initial vector. Must be a random 128 bit value and the * same one used in decryption * @param key * the key for encryption * * @return the encrypted bytes */ public byte[] encrypt(String value, byte[] iv, SecretKey key) throws InvalidKeyException, InvalidAlgorithmParameterException, IOException { byte[] encryptedBytes = null; IvParameterSpec ivspec = new IvParameterSpec(iv); encryptCipher.init(Cipher.ENCRYPT_MODE, key, ivspec); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, encryptCipher); cipherOutputStream.write(value.getBytes(StandardCharsets.UTF_8)); cipherOutputStream.flush(); cipherOutputStream.close(); encryptedBytes = outputStream.toByteArray(); return encryptedBytes; } /** * Decrypt an encrypted byte array with a key and initial vector * * @param encryptedBytes * the byte array to decrypt * @param iv * the initial vector. Must be a random 128 bit value and the * same one used in encryption * @param key * the key for decryption * * @return the decrypted string */ @SuppressFBWarnings("UC_USELESS_OBJECT") public String decrypt(byte[] encryptedBytes, byte[] iv, SecretKey key) throws InvalidKeyException, InvalidAlgorithmParameterException, IOException { byte[] buf = new byte[Constants.CIPHER_SIZE]; ByteArrayOutputStream outputStream = null; IvParameterSpec ivspec = new IvParameterSpec(iv); decryptCipher.init(Cipher.DECRYPT_MODE, key, ivspec); outputStream = new ByteArrayOutputStream(); ByteArrayInputStream inStream = new ByteArrayInputStream(encryptedBytes); CipherInputStream cipherInputStream = new CipherInputStream(inStream, decryptCipher); int bytesRead = 0; while ((bytesRead = cipherInputStream.read(buf)) >= 0) { outputStream.write(buf, 0, bytesRead); } cipherInputStream.close(); return outputStream.toString(StandardCharsets.UTF_8.name()); } }