import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Set;
public class AES256GCMUtil {
private final static String ALGO = "AES_256/GCM/NOPADDING";
public static final int AES_KEY_SIZE = 256;
public static final int GCM_IV_LENGTH = 12;
public static final int TLEN = 128;
static {
Set<String> algorithms = Security.getAlgorithms("Cipher");
if (!algorithms.contains(ALGO)) {
throw new IllegalArgumentException("AES256 encrypt and decrypy system can not used");
}
}
public static void main(String[] args) throws Exception {
/* Check Option Format.Option or parameters must is true then process next code*/
if(args.length == 0) {
System.out.println("Option error!You need to enter three parameters.Enter -h or --help to get some tips.");
System.exit(1);
}else if(args.length == 1 && (args[0].equals("-h") || args[0].equals("--help"))) {
System.out.println();
System.out.println("You need to enter three parameters, namely type, text and key.\n");
System.out.println("Type : \n\t-e or --encrypt for encrypt.");
System.out.println("\t-d or --decrypt for decrypt.");
System.out.println("\nFor example : \n");
System.out.println("\t\"D:\\>java AES256GCMUtil -e yzysdtc 123456\" For encrypt,source text is \"yzystdc\",Key is \"123456\"\n");
System.out.println("\t\"D:\\>java AES256GCMUtil -d 2ddb531030ad15b168d4cb32b8e2e3c78b6683cca6dcf15e3f4c148f47943e62b974ef 123456\" For decrypt,encrypted text is \"2ddb531030ad15b168d4cb32b8e2e3c78b6683cca6dcf15e3f4c148f47943e62b974ef\",Key is \"123456\"");
System.exit(1);
}else if(args.length != 3) {
System.out.println("Option error!You need to enter three parameters.Enter -h or --help to get some tips.");
System.exit(1);
}else if(!(args[0].equals("-e") || args[0].equals("--encrypt") || args[0].equals("-d") || args[0].equals("--decrypt"))) {
System.out.println("Option error!You need to enter three parameters.Enter -h or --help to get some tips.");
System.out.println("First option error,only have -e or --encrypt or -d or --decrypt");
System.exit(1);
}
/* Check Option Format.Option and parameters all is True*/
AES256GCMUtil app = new AES256GCMUtil();
if(args[0].equals("-e") || args[0].equals("--encrypt")) {
System.out.println("\nEncryption:\n");
System.out.println(app.encrypt(args[1], args[2]));
System.out.println("");
System.exit(0);
}else if(args[0].equals("-d") || args[0].equals("--decrypt")) {
System.out.println("\nDecryption:\n");
System.out.println(app.decrypt(args[1], args[2]));
System.out.println("");
System.exit(0);
}
}
public String encrypt(String txt, String pwd) throws Exception {
Cipher cipher = Cipher.getInstance(ALGO);
byte[] iv = new byte[GCM_IV_LENGTH];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, generateKey(pwd), new GCMParameterSpec(TLEN, iv));
byte[] txtBytes = txt.getBytes(StandardCharsets.UTF_8);
byte[] enctyptBytes = cipher.doFinal(txtBytes);
byte[] message = new byte[GCM_IV_LENGTH + enctyptBytes.length];
System.arraycopy(iv, 0, message, 0, GCM_IV_LENGTH);
System.arraycopy(enctyptBytes, 0, message, GCM_IV_LENGTH, enctyptBytes.length);
return bytearrayToHex(message);
}
public String decrypt(String txt, String pwd) throws Exception {
byte[] txtBytes = hexStringToByteArray(txt);
byte[] iv = new byte[GCM_IV_LENGTH];
byte[] content = new byte[txtBytes.length - GCM_IV_LENGTH];
System.arraycopy(txtBytes, 0, iv, 0, GCM_IV_LENGTH);
System.arraycopy(txtBytes, GCM_IV_LENGTH, content, 0, content.length);
Cipher cipher = Cipher.getInstance(ALGO);
GCMParameterSpec params = new GCMParameterSpec(TLEN, iv);
cipher.init(Cipher.DECRYPT_MODE, generateKey(pwd), params);
return new String(cipher.doFinal(content), StandardCharsets.UTF_8);
}
public Key generateKey(String keystr) throws Exception {
KeyGenerator kg = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
secureRandom.setSeed(keystr.getBytes(StandardCharsets.UTF_8));
kg.init(AES_KEY_SIZE, secureRandom);
return kg.generateKey();
}
public static byte[] hexStringToByteArray(String hexString) {
hexString = hexString.replaceAll(" ", "");
int len = hexString.length();
byte[] bytes = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
.digit(hexString.charAt(i+1), 16));
}
return bytes;
}
public static String byteToHex(byte b){
String hex = Integer.toHexString(b & 0xFF);
if(hex.length() < 2){
hex = "0" + hex;
}
return hex;
}
public static String bytearrayToHex(byte[] b) {
String hex= new String("");
int lengthofb;
for(lengthofb=0;lengthofb<b.length;lengthofb++) {
hex=hex + byteToHex(b[lengthofb]);
}
return hex;
}
}
用法,将上面的代码复制粘贴到文本文件中,并且保存为 AES256GCMUtil.java 。然后,在保存该文件的目录打开命令行(cmd)或者打开命令行之后,转移到保存该文件的目录。
-e 加密,后需两个参数,一个被加密的原文,一个密钥
-d 解密,后需两个参数,一个被解密的密文,一个密钥
由于伽罗瓦计数器模式(GCM)的的AES算法,会在原文头部当中填充一个随机数,所以每次加密后的密文都不一致。不用担心,解密后,随机数会被删除的。