/* * Copyright (C) 2014 Serverfrog.de * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.serverfrog.pw.crypt; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.Security; import java.security.spec.InvalidKeySpecException; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * * @author Bastian Venz */ public class SerpentUtil { static { Security.addProvider(new BouncyCastleProvider()); } private static final String CIPHER_ALGORITHM = "Serpent"; private static final String KEY_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC"; /** * This Method builds a CipherOutputStream with the Serpent Cipher. * * @param os is the output Stream where the Encrypted Data should went. * @param key is the Key for the Encryption. * @return a CipherOutputStream with the Serpent Cipher. */ public static CipherOutputStream getOutputStream(OutputStream os, Key key) { try { Cipher instance = Cipher.getInstance(CIPHER_ALGORITHM, "BC"); instance.init(Cipher.ENCRYPT_MODE, key, generateIV(instance)); return new CipherOutputStream(os, instance); } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidAlgorithmParameterException ex) { Logger.getLogger(SerpentUtil.class.getName()).log(Level.SEVERE, null, ex); } return null; } /** * Creates a CipherInputStream which reads from a InputStream where exist * Data which is encrypted with Serpent. * * @param is is the InputStream which contains the encrypted Data. * @param key is the Key for the encryption * @return a CipherInputStream which wraps the given InputStream. * @throws IOException if the Password is wrong. */ public static CipherInputStream getInputStream(InputStream is, Key key) throws IOException { try { Cipher instance = Cipher.getInstance(CIPHER_ALGORITHM, "BC"); instance.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[instance.getBlockSize()])); return new CipherInputStream(is, instance); } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException ex) { throw new IOException(ex); } catch (InvalidKeyException ex) { throw new IOException("Invalid Key", ex); } } /** * Generate the key for the en-/decryption from the password and the Salt. * * @param password is the password for the en-/decryption. * @param salt is the salt for the en-/decryption. * @return the SecretKey for the en-/decryption. * @throws IOException is thrown if Something went wrong while the Key is * generated. Should not happend. */ public static SecretKey generateKey(byte[] password, byte[] salt) throws IOException { try { SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM, "BC"); PBEKeySpec spec = new PBEKeySpec(new String(password).toCharArray(), salt, 100000); SecretKey temp = factory.generateSecret(spec); byte[] keybytes = new byte[16]; System.arraycopy(temp.getEncoded(), 0, keybytes, 0, keybytes.length); return new SecretKeySpec(keybytes, CIPHER_ALGORITHM); } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException ex) { Logger.getLogger(SerpentUtil.class.getName()).log(Level.SEVERE, null, ex); throw new IOException(ex); } } /** * Generate the IvParameterSpec. * * @param c is the Cipher for the en-/decryption. * @return the IvParameterSpec for the given Cipher. */ private static IvParameterSpec generateIV(Cipher c) { try { byte[] iv = new byte[c.getBlockSize()]; SecureRandom.getInstanceStrong().nextBytes(iv); return new IvParameterSpec(iv); } catch (NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } } }