/** * This file is part of Waarp Project. * * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the * COPYRIGHT.txt in the distribution for a full listing of individual contributors. * * All Waarp Project 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. * * Waarp 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 Waarp . If not, see * <http://www.gnu.org/licenses/>. */ package org.waarp.common.crypto; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.Key; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.SecretKeySpec; import org.waarp.common.digest.FilesystemBasedDigest; import org.waarp.common.exception.CryptoException; import org.waarp.common.logging.WaarpLogger; import org.waarp.common.logging.WaarpLoggerFactory; import org.waarp.common.utility.WaarpStringUtils; /** * This class handles method to crypt and decrypt using the chosen algorithm.<br> * * <br> * Usage:<br> * <ul> * <li>Create a Key object: KeyObject key = new KeyObject();</li> * <li>Create a key: * <ul> * <li>Generate: key.generateKey();<br> * The method key.getSecretKeyInBytes() allow getting the key in Bytes.</li> * <li>From an external source: key.setSecretKey(arrayOfBytes);</li> * </ul> * </li> * <li>To crypt a String in a Hex format: String myStringCrypt = key.cryptToHex(myString);</li> * <li>To decrypt one string from Hex format to the original String: String myStringDecrypt = * key.decryptHexInString(myStringCrypte);</li> * </ul> * * @author frederic bregier * */ public abstract class KeyObject { /** * Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory .getLogger(KeyObject.class); /** * The True Key associated with this object */ Key secretKey = null; /** * Empty constructor */ public KeyObject() { } /** * * @return the algorithm used (Java name) */ public abstract String getAlgorithm(); /** * * @return the instance used (Java name) */ public abstract String getInstance(); /** * * @return the size for the algorithm key */ public abstract int getKeySize(); /** * * @return the filename extension to use for this kind of key */ public abstract String getFileExtension(); /** * @return the key associated with this object */ public Key getSecretKey() { return secretKey; } /** * * @return True if this key is ready to be used */ public boolean keyReady() { return secretKey != null; } /** * Returns the key as an array of bytes in order to be stored somewhere else and retrieved using * the setSecretKey(byte[] keyData) method. * * @return the key as an array of bytes (or null if not ready) */ public byte[] getSecretKeyInBytes() { if (keyReady()) { return secretKey.getEncoded(); } else { return null; } } /** * Set the secretKey * * @param secretKey */ public void setSecretKey(Key secretKey) { this.secretKey = secretKey; } /** * Reconstruct a key from an array of bytes */ public void setSecretKey(byte[] keyData) { secretKey = new SecretKeySpec(keyData, getAlgorithm()); } /** * Create a Key from a File * * @param file * @throws CryptoException * @throws IOException */ public void setSecretKey(File file) throws CryptoException, IOException { if (file.canRead()) { int len = (int) file.length(); byte[] key = new byte[len]; FileInputStream inputStream = null; inputStream = new FileInputStream(file); DataInputStream dis = new DataInputStream(inputStream); try { dis.readFully(key); } finally { dis.close(); } this.setSecretKey(key); } else { throw new CryptoException("Cannot read crypto file: " + file); } } /** * Save a Key to a File * * @param file * @throws CryptoException * @throws IOException */ public void saveSecretKey(File file) throws CryptoException, IOException { if (keyReady() && ((!file.exists()) || file.canWrite())) { byte[] key = getSecretKeyInBytes(); FileOutputStream outputStream = new FileOutputStream(file); try { outputStream.write(key); outputStream.flush(); } finally { outputStream.close(); } } else { throw new CryptoException("Cannot read crypto file"); } } /** * Generate a key from nothing * * @throws Exception */ public void generateKey() throws Exception { try { KeyGenerator keyGen = KeyGenerator.getInstance(getAlgorithm()); keyGen.init(getKeySize()); secretKey = keyGen.generateKey(); } catch (Exception e) { logger.warn("GenerateKey Error", e); throw e; } } /** * Returns a cipher for encryption associated with the key * * @return the cipher for encryption or null if it fails in case Encryption method or key is * incorrect */ public Cipher toCrypt() { Cipher cipher; try { cipher = Cipher.getInstance(getInstance()); cipher.init(Cipher.ENCRYPT_MODE, secretKey); } catch (Exception e) { logger.warn("Crypt Error", e); return null; } return cipher; } /** * Crypt one array of bytes and returns the crypted array of bytes * * @param plaintext * @return the crypted array of bytes * @throws Exception */ public byte[] crypt(byte[] plaintext) throws Exception { if (!keyReady()) { throw new CryptoException("Key not Ready"); } try { Cipher cipher = Cipher.getInstance(getInstance()); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(plaintext); } catch (Exception e) { logger.warn("Crypt Error", e); throw e; } } /** * Crypt one array of bytes and returns the crypted String as HEX format * * @param plaintext * @return the crypted String as HEX format * @throws Exception */ public String cryptToHex(byte[] plaintext) throws Exception { byte[] result = crypt(plaintext); return encodeHex(result); } /** * Crypt one String and returns the crypted array of bytes * * @param plaintext * @return the crypted array of bytes * @throws Exception */ public byte[] crypt(String plaintext) throws Exception { return crypt(plaintext.getBytes(WaarpStringUtils.UTF8)); } /** * Crypt one String and returns the crypted String as HEX format * * @param plaintext * @return the crypted String as HEX format * @throws Exception */ public String cryptToHex(String plaintext) throws Exception { return cryptToHex(plaintext.getBytes(WaarpStringUtils.UTF8)); } /** * Returns a cipher for decryption associated with the key * * @return the cipher for decryption or null if it fails in case Encryption method or key is * incorrect */ public Cipher toDecrypt() { Cipher cipher; try { cipher = Cipher.getInstance(getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, secretKey); } catch (Exception e) { logger.warn("Uncrypt Error", e); return null; } return cipher; } /** * Decrypt an array of bytes and returns the uncrypted array of bytes * * @param ciphertext * @return the uncrypted array of bytes * @throws Exception */ public byte[] decrypt(byte[] ciphertext) throws Exception { if (!keyReady()) { throw new CryptoException("Key not Ready"); } try { Cipher cipher = Cipher.getInstance(getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(ciphertext); } catch (Exception e) { logger.warn("Decrypt Error", e); throw e; } } /** * Decrypt an array of bytes and returns the uncrypted String * * @param ciphertext * @return the uncrypted array of bytes * @throws Exception */ public String decryptInString(byte[] ciphertext) throws Exception { return new String(decrypt(ciphertext), WaarpStringUtils.UTF8); } /** * Decrypt a String as HEX format representing a crypted array of bytes and returns the * uncrypted array of bytes * * @param ciphertext * @return the uncrypted array of bytes * @throws Exception */ public byte[] decryptHexInBytes(String ciphertext) throws Exception { byte[] arrayBytes = decodeHex(ciphertext); return decrypt(arrayBytes); } /** * Decrypt an array of bytes as HEX format representing a crypted array of bytes and returns the * uncrypted array of bytes * * @param ciphertext * @return the uncrypted array of bytes * @throws Exception */ public byte[] decryptHexInBytes(byte[] ciphertext) throws Exception { byte[] arrayBytes = decodeHex(new String(ciphertext, WaarpStringUtils.UTF8)); return decrypt(arrayBytes); } /** * Decrypt a String as HEX format representing a crypted array of bytes and returns the * uncrypted String * * @param ciphertext * @return the uncrypted String * @throws Exception */ public String decryptHexInString(String ciphertext) throws Exception { return new String(decryptHexInBytes(ciphertext), WaarpStringUtils.UTF8); } /** * Decode from a file containing a HEX crypted string * * @param file * @return the decoded uncrypted content of the file * @throws Exception */ public byte[] decryptHexFile(File file) throws Exception { if (file.length() > Integer.MAX_VALUE) { throw new IOException("File too big to be decoded into an array of bytes"); } byte[] byteKeys = new byte[(int) file.length()]; FileInputStream inputStream = null; DataInputStream dis = null; try { inputStream = new FileInputStream(file); dis = new DataInputStream(inputStream); dis.readFully(byteKeys); dis.close(); String skey = new String(byteKeys, WaarpStringUtils.UTF8); // decrypt it byteKeys = decryptHexInBytes(skey); return byteKeys; } catch (IOException e) { try { if (dis != null) { dis.close(); } else if (inputStream != null) inputStream.close(); } catch (IOException e1) { } throw e; } } /** * * @param encoded * @return the array of bytes from encoded String (HEX) */ public byte[] decodeHex(String encoded) { return FilesystemBasedDigest.getFromHex(encoded); } /** * * @param bytes * @return The encoded array of bytes in HEX */ public String encodeHex(byte[] bytes) { return FilesystemBasedDigest.getHex(bytes); } }