com.gfw.press.encrypt.Encrypt.java Source code

Java tutorial

Introduction

Here is the source code for com.gfw.press.encrypt.Encrypt.java

Source

/**
* 
*    GFW.Press
*    Copyright (C) 2016  chinashiyu ( chinashiyu@gfw.press ; http://gfw.press )
*
*    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 com.gfw.press.encrypt;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.sql.Timestamp;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

/**
 * GFW.Press??
 * 
 * @author chinashiyu ( chinashiyu@gfw.press ; http://gfw.press )
 *
 */
public class Encrypt {
    public static final String CHARSET = "UTF-8";
    public static final int BLOCK_MAX_FILE = 64 * 1024 * 1024; // 64MB??
    public static final int ENCRYPT_SIZE = 30; // ??30?14
    public static final int IV_SIZE = 16; // IV16
    public static final int NOISE_MAX = 1024 * 4; // ?4K
    private SecureRandom secureRandom = null;
    private Cipher cipher = null;
    private KeyGenerator keyGenerator = null;

    public Encrypt() {
        super();
        secureRandom = new SecureRandom();
        try {
            cipher = Cipher.getInstance("AES/CFB/NoPadding");
            keyGenerator = KeyGenerator.getInstance("AES");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 
     * 
     * @param key
     *            SecretKey
     * @param encrypt_bytes
     *            ?16IV?
     * 
     * @return ?
     * 
     */
    public byte[] decrypt(String nodePwd, byte[] encrypt_bytes) {
        if (encrypt_bytes == null || encrypt_bytes.length < IV_SIZE) {
            return null;
        }
        SecretKey key = null;
        try {
            key = getSecretKey(DigestUtils.md5Hex(nodePwd.getBytes(CHARSET)));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if (null == key) {
            System.out.println("key!");
            return null;
        }
        byte[] IV = new byte[IV_SIZE];
        byte[] part2 = new byte[encrypt_bytes.length - IV_SIZE];
        System.arraycopy(encrypt_bytes, 0, IV, 0, IV.length);
        System.arraycopy(encrypt_bytes, IV.length, part2, 0, part2.length);
        return decrypt(key, part2, IV);
    }

    /**
     * 
     * 
     * @param key
     *            SecretKey
     * @param cipher_data
     *            ?
     * @param IV
     *            IV
     * 
     * @return ?
     * 
     */
    private byte[] decrypt(SecretKey key, byte[] cipher_data, byte[] IV) {
        if (key == null || cipher_data == null || cipher_data.length == 0 || IV == null || IV.length == 0) {
            return null;
        }
        IvParameterSpec IVSpec = new IvParameterSpec(IV);
        try {
            cipher.init(Cipher.DECRYPT_MODE, key, IVSpec);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException ex) {
            log("?Cipher");
            ex.printStackTrace();
            return null;
        }
        try {
            return cipher.doFinal(cipher_data);
        } catch (IllegalBlockSizeException | BadPaddingException ex) {
            log("?");
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * 
     * 
     * @param key
     *            SecretKey
     * @param data
     *            ?
     * 
     * @return ?
     * 
     */
    private byte[] encrypt(SecretKey key, byte[] data) {
        if (key == null || data == null) {
            return null;
        }
        byte[] IV = getSecureRandom(IV_SIZE);
        IvParameterSpec IVSpec = new IvParameterSpec(IV);
        try {
            cipher.init(Cipher.ENCRYPT_MODE, key, IVSpec);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException ex) {
            log("?Cipher");
            ex.printStackTrace();
            return null;
        }
        byte[] cipher_bytes = null;
        try {
            cipher_bytes = cipher.doFinal(data);
        } catch (IllegalBlockSizeException | BadPaddingException ex) {
            log("?");
            ex.printStackTrace();
            return null;
        }
        byte[] iv_cipher_bytes = new byte[cipher_bytes.length + IV_SIZE];
        System.arraycopy(IV, 0, iv_cipher_bytes, 0, IV.length);
        System.arraycopy(cipher_bytes, 0, iv_cipher_bytes, IV.length, cipher_bytes.length);
        return iv_cipher_bytes;
    }

    /**
     * ?
     * 
     * @param key
     *            SecretKey
     * 
     * @param bytes
     *            ?
     * 
     * @return [?+?]? + [? + ?]
     * 
     */
    public byte[] encryptNet(String nodePwd, byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        SecretKey key = null;
        try {
            key = getSecretKey(DigestUtils.md5Hex(nodePwd.getBytes(CHARSET)));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if (null == key) {
            System.out.println("key!");
            return null;
        }
        byte[] IV = getSecureRandom(IV_SIZE);
        IvParameterSpec IVSpec = new IvParameterSpec(IV);
        try {
            cipher.init(Cipher.ENCRYPT_MODE, key, IVSpec);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException ex) {
            log("?Cipher");
            ex.printStackTrace();
            return null;
        }
        // ?
        byte[] cipher_bytes = null;
        try {
            cipher_bytes = cipher.doFinal(bytes);
        } catch (IllegalBlockSizeException | BadPaddingException ex) {
            log("?");
            ex.printStackTrace();
            return null;
        }
        // ?
        byte[] noise_bytes = (cipher_bytes.length < NOISE_MAX / 2)
                ? getSecureRandom(secureRandom.nextInt(NOISE_MAX))
                : new byte[0];
        byte[] size_bytes = encrypt(key, getBlockSizeBytes((IV_SIZE + cipher_bytes.length), noise_bytes.length));
        if (size_bytes == null || size_bytes.length != ENCRYPT_SIZE) {
            return null;
        }
        byte[] all_cipher = new byte[size_bytes.length + IV_SIZE + cipher_bytes.length + noise_bytes.length];
        System.arraycopy(size_bytes, 0, all_cipher, 0, size_bytes.length);
        System.arraycopy(IV, 0, all_cipher, size_bytes.length, IV.length);
        System.arraycopy(cipher_bytes, 0, all_cipher, size_bytes.length + IV.length, cipher_bytes.length);
        if (noise_bytes.length > 0) { // ??
            System.arraycopy(noise_bytes, 0, all_cipher, size_bytes.length + IV.length + cipher_bytes.length,
                    noise_bytes.length);
        }
        size_bytes = null;
        IV = null;
        cipher_bytes = null;
        noise_bytes = null;
        return all_cipher;
    }

    /**
     * ?
     * 
     * @param bytes
     *            ?
     * 
     * @return ?
     * 
     */
    public int getBlockSize(byte[] bytes) {
        if (bytes == null) {
            return 0;
        }
        try {
            String size = new String(bytes, CHARSET);
            if (!size.matches("\\d+")) {
                return 0;
            }
            return Integer.valueOf(size);
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
            return 0;
        }
    }

    /**
     * ??
     * 
     * @param size
     *            ?
     * @return ?
     */
    public byte[] getBlockSizeBytes(int size) {
        try {
            return String.format("%08d", size).getBytes(CHARSET);
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * ??
     * 
     * @param size
     *            ???
     * 
     * @param noise_size
     *            ???
     * 
     * @return ?
     */
    public byte[] getBlockSizeBytes(int data_size, int noise_size) {
        try {
            return String.format("%08d,%05d", data_size, noise_size).getBytes(CHARSET);
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * ?
     * 
     * @param bytes
     *            ? %08d,%05d
     * @return int[2]
     */
    public int[] getBlockSizes(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        try {
            String size = new String(bytes, CHARSET);
            if (!size.matches("\\d+,\\d+")) {
                return null;
            }
            String[] sizes = size.split(",");
            return new int[] { Integer.valueOf(sizes[0]), Integer.valueOf(sizes[1]) };
        } catch (UnsupportedEncodingException | NumberFormatException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * ??AES SecretKey
     * 
     * @param bits
     *            ?
     * 
     * @return SecretKey
     * 
     */
    public SecretKey getKey(int bits) {
        if (bits < 128) {
            return null;
        }
        try {
            keyGenerator.init(bits);
            return keyGenerator.generateKey();
        } catch (InvalidParameterException ex) {
            log("?AES SecretKey");
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * SecretKeySecretKey
     * 
     * @param stringKey
     *            SecretKey
     * 
     * @return SecretKey
     * 
     */
    public SecretKey getSecretKey(String stringKey) {
        if (stringKey == null || (stringKey = stringKey.trim()).length() == 0) {
            return null;
        }
        byte[] bytes = Base64.decodeBase64(stringKey);
        return new SecretKeySpec(bytes, 0, bytes.length, "AES");
    }

    /**
     * ?SecureRandom
     * 
     * @param size
     *            
     * @return
     */
    public byte[] getSecureRandom(int size) {
        byte[] bytes = new byte[size];
        secureRandom.nextBytes(bytes);
        return bytes;
    }

    /**
     * ?SecretKey
     * 
     * @param secretKey
     *            SecretKey
     * 
     * @return SecretKey
     * 
     */
    public String getStringKey(SecretKey secretKey) {
        if (secretKey == null) {
            return null;
        }
        return Base64.encodeBase64String(secretKey.getEncoded());
    }

    /**
     * ??
     * 
     * @param o
     */
    private void log(Object o) {
        String time = (new Timestamp(System.currentTimeMillis())).toString().substring(0, 19);
        System.out.println("[" + time + "] " + o.toString());
    }

    /**
     * ?
     *
     * @param content
     *            ?
     * @return ??
     */
    public static String simpleEncrypt(String content, String key) {
        int SIMPLE_ENCRYPT_KEY_LENGTH = 16;
        byte[] keyBytes = null;
        byte[] encrypt = null;
        byte[] allData = null;
        try {
            keyBytes = key.getBytes(CHARSET);
            byte[] _keyBytes = new byte[SIMPLE_ENCRYPT_KEY_LENGTH];
            if (keyBytes.length < SIMPLE_ENCRYPT_KEY_LENGTH) {
                SecureRandom secureRandom = new SecureRandom();
                secureRandom.nextBytes(_keyBytes);
                System.arraycopy(keyBytes, 0, _keyBytes, 0, keyBytes.length);
            } else {
                System.arraycopy(keyBytes, 0, _keyBytes, 0, SIMPLE_ENCRYPT_KEY_LENGTH);
            }
            keyBytes = _keyBytes;
            Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
            IvParameterSpec IVSpec = new IvParameterSpec(keyBytes);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES"), IVSpec);
            encrypt = cipher.doFinal(content.getBytes(CHARSET));
            allData = new byte[encrypt.length + keyBytes.length];
            System.arraycopy(keyBytes, 0, allData, 0, keyBytes.length);
            System.arraycopy(encrypt, 0, allData, keyBytes.length, encrypt.length);
            return encodeBase64(allData);
        } catch (Exception e) {
        } finally {
            keyBytes = encrypt = allData = null;
        }
        return "";
    }

    /**
     * ?
     *
     * @param content
     *            ?
     * @return ??
     */

    public static String simpleDecrypt(String content, String key) {
        int SIMPLE_ENCRYPT_KEY_LENGTH = 16;
        byte[] keyBytes = new byte[SIMPLE_ENCRYPT_KEY_LENGTH];
        byte[] decrypt = null;
        byte[] encrypt = null;
        byte[] allData = null;
        try {
            allData = decodeBase64(content);
            encrypt = new byte[allData.length - keyBytes.length];
            System.arraycopy(allData, 0, keyBytes, 0, keyBytes.length);
            System.arraycopy(allData, keyBytes.length, encrypt, 0, encrypt.length);
            byte[] _keyBytes = key.getBytes(CHARSET);
            if (_keyBytes.length < SIMPLE_ENCRYPT_KEY_LENGTH) {
                System.arraycopy(_keyBytes, 0, keyBytes, 0, _keyBytes.length);
            } else {
                System.arraycopy(_keyBytes, 0, keyBytes, 0, SIMPLE_ENCRYPT_KEY_LENGTH);
            }
            Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
            IvParameterSpec IVSpec = new IvParameterSpec(keyBytes);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES"), IVSpec);
            decrypt = cipher.doFinal(encrypt);
            return new String(decrypt, CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            keyBytes = decrypt = encrypt = allData = null;
        }
        return "";
    }

    public static String encodeBase64(byte[] b) {
        return Base64.encodeBase64String(b);
    }

    public static byte[] decodeBase64(String base64String) throws Exception {
        return Base64.decodeBase64(base64String.getBytes(CHARSET));
    }

}