Java tutorial
/** * GFW.Press Chat * Copyright (C) 2016 chinashiyu ( chinashiyu@gfw.press ; http://gfw.press ) * <p/> * 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. * <p/> * 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. * <p/> * 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 press.gfw.chat; import java.io.UnsupportedEncodingException; 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; import android.annotation.SuppressLint; public class Encrypt { public static final String GB = "GB18030"; public static final String ISO = "ISO-8859-1"; public static final String UTF = "UTF-8"; public static final int IV_SIZE = 16; // IV16 public static void main(String[] args) throws Exception { Encrypt aes = new Encrypt(); // // aes.testSecureRandom(); aes.testEncrypt(); } private Cipher cipher = null; private KeyGenerator keyGenerator = null; private SecureRandom secureRandom = null; @SuppressLint("TrulyRandom") public Encrypt() { super(); secureRandom = new SecureRandom(); try { cipher = Cipher.getInstance("AES/CFB/NoPadding"); // Advanced // Encryption // Standard - // Cipher // Feedback Mode // - No Padding keyGenerator = KeyGenerator.getInstance("AES"); } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) { throw new RuntimeException(ex); } } /** * * * @param key * SecretKey * @param encrypt_bytes * ?16IV? * * @return ? * */ public byte[] decrypt(SecretKey key, byte[] encrypt_bytes) { if (key == null || encrypt_bytes == null || encrypt_bytes.length < IV_SIZE) { 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 ? * */ public 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 * @param cipher * @return */ public String decryptMessage(String md5, String cipher) { if (cipher == null || (cipher = cipher.trim()).length() == 0) { return null; } SecretKey key = getSecretKey(md5); if (key == null) { return null; } try { byte[] bytes = decrypt(key, Base64.decodeBase64(cipher.getBytes(ISO))); if (bytes != null) { return new String(bytes, GB); } } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } return null; } /** * * * @param key * SecretKey * @param data * ? * * @return ? * */ public 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 md5 * @param message * @return */ public String encryptMessage(String md5, String message) { if (message == null || (message = message.trim()).length() == 0) { return null; } SecretKey key = getSecretKey(md5); if (key == null) { return null; } try { byte[] bytes = encrypt(key, message.getBytes(GB)); if (bytes != null) { return new String(Base64.encodeBase64(bytes), ISO).replaceAll("=*$", ""); } } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } return null; } /** * ?256?SecretKey * * @return 256?SecretKey * */ public SecretKey getKey() { return getKey(256); } /** * ??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; } } /** * ??MD5 * * @param password * @return */ public String getMD5(String password) { if (password == null || (password = password.trim()).length() == 0) { return null; } try { return DigestUtils.md5Hex((password + " GFW.Press Chat").getBytes(UTF)); } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } return null; } /** * ??SecretKey * * @param password * ??isPassword()? * * @return SecretKey * */ public SecretKey getPasswordKey(String password) { if (!isPassword(password)) { return null; } try { return getSecretKey(DigestUtils.md5Hex(password.getBytes(UTF))); } catch (UnsupportedEncodingException ex) { log("??SecretKey"); ex.printStackTrace(); return null; } } /** * SecretKeySecretKey * * @param stringKey * SecretKey * * @return SecretKey * */ public SecretKey getSecretKey(String stringKey) { if (stringKey == null || (stringKey = stringKey.trim()).length() < 24) { 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()); } /** * ??? * * ?4? * * @param password * @return */ public boolean isPassword(String password) { return !(password == null || !password.matches("[0-9a-zA-Z]{4,}$")); // 1? 2?? 3??? 4???? 5??? // password.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$"); } /** * ?? * * @param o */ private void log(Object o) { String time = (new Timestamp(System.currentTimeMillis())).toString().substring(0, 19); System.out.println("[" + time + "] " + o.toString()); } public void testEncrypt() throws Exception { String password = "Abc12345"; log(""); String message = "?????????????A"; log("?" + message); log("?" + message.length()); log("?" + message.getBytes(GB).length); long start = System.currentTimeMillis(); String cipher = encryptMessage(password, message); log("?" + cipher); log("?" + cipher.length()); long end = System.currentTimeMillis(); log("" + (end - start)); log("\n"); start = System.currentTimeMillis(); String _message = decryptMessage(password, cipher); end = System.currentTimeMillis(); log("?" + _message); log("" + (end - start)); } public void testIsPassword() { String password = "xxXxab12"; log(isPassword(password)); } public void testSecureRandom() { // secureRandom.nextBytes(bytes); // secureRandom.nextBytes(bytes); long start = System.currentTimeMillis(); byte[] bytes = this.getSecureRandom(1024); long end = System.currentTimeMillis(); log("" + (end - start)); try { log(new String(bytes, UTF)); } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } } }