Java AES512加密算法
AES - 高级加密标准:
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一
AES 算法在工作中使用很频繁, 借着这次项目中使用做一下总结, 本次主要是正对 AES512 来讲解。
开发前准备工作:
由于Java 运行环境中的 policy文件是受限的,对AES512不支持。解决方案如下:
1:policy文件位于${java_home}/jre/lib/security目录下
2: 去除该限制需下载 Java Cryptography Extension (JCE) Unlimited Strength JurisdictionPolicy Files,
覆盖上述目录下的对应jar文件(local_policy.jar,US_export_policy.jar)
3: jar 官方下载路径
JDK6 http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
JDK7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
做完这三步 下面直接上代码:
AES512 加密方法
1 import java.io.UnsupportedEncodingException; 2 import java.security.InvalidAlgorithmParameterException; 3 import java.security.InvalidKeyException; 4 import java.security.NoSuchAlgorithmException; 5 6 import javax.crypto.BadPaddingException; 7 import javax.crypto.Cipher; 8 import javax.crypto.IllegalBlockSizeException; 9 import javax.crypto.NoSuchPaddingException; 10 import javax.crypto.spec.IvParameterSpec; 11 import javax.crypto.spec.SecretKeySpec; 12 13 import org.message.encrypt.tool.Encode; 14 import org.message.encrypt.tool.Numeric; 15 16 import com.google.common.io.BaseEncoding; 17 18 public class AESCipher { 19 private static final String ALGORITHM_AES256 = "AES/CBC/PKCS5Padding";// "AES/CBC/PKCS7Padding"; 20 private final SecretKeySpec secretKeySpec; 21 private static final String CHARSET = "UTF-8"; 22 private static final String DEFAULT_IV = "iv is default value"; 23 private Cipher cipher; 24 private IvParameterSpec iv; 25 26 27 public AESCipher(String key) { 28 this(key, DEFAULT_IV); 29 } 30 31 public AESCipher(String key, String iv) { 32 this(Numeric.hexStringToByteArray(key), Numeric.hexStringToByteArray(iv)); 33 } 34 35 private AESCipher(byte[] key, byte[] iv) { 36 // Security.addProvider(new BouncyCastleProvider()); 37 if (null == key || key.length != 32) { 38 throw new RuntimeException("input params key must be 32bit bytes array"); 39 } 40 if (null == iv || iv.length != 16) { 41 throw new RuntimeException("input params iv must be 16bit bytes array"); 42 } 43 this.secretKeySpec = new SecretKeySpec(key, "AES"); 44 this.iv = new IvParameterSpec(iv); 45 try { 46 this.cipher = Cipher.getInstance(ALGORITHM_AES256); 47 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 48 throw new RuntimeException("instantiation objects Cipher exception"); 49 } 50 } 51 52 /** 53 * AES Encrypt algorithm 54 * 55 * @param encryptSource 56 * not null string 57 * @return after AES encrypt result , the type of the string 58 */ 59 public String getEncryptedMessage(final String encryptSource) { 60 Cipher cipher = getCipher(Cipher.ENCRYPT_MODE); 61 byte[] encryptedTextBytes = null; 62 try { 63 encryptedTextBytes = cipher.doFinal(encryptSource.getBytes(CHARSET)); 64 } catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException e) { 65 throw new RuntimeException("AES encrypt exception"); 66 } 67 return Encode.baseEncode(encryptedTextBytes); 68 } 69 70 /** 71 * AES decrypt algorithm 72 * 73 * @param decryptSource 74 * AES encrypted cipher, type of String 75 * @return decrypted plaintext, type of string 76 */ 77 public String getDecryptMessage(String decryptSource) { 78 79 Cipher cipher = getCipher(Cipher.DECRYPT_MODE); 80 byte[] encryptedTextBytes = null; 81 String decryptResult = null; 82 try { 83 encryptedTextBytes = cipher.doFinal(BaseEncoding.base64().decode(decryptSource)); 84 } catch (IllegalBlockSizeException | BadPaddingException e) { 85 throw new RuntimeException("AES decrypt exception"); 86 } 87 try { 88 decryptResult = new String(encryptedTextBytes, CHARSET); 89 } catch (UnsupportedEncodingException e) { 90 throw new RuntimeException("bytes array convert into string exception"); 91 } 92 return decryptResult; 93 } 94 95 private Cipher getCipher(int encryptMode) { 96 try { 97 cipher.init(encryptMode, secretKeySpec, iv); 98 } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { 99 throw new RuntimeException("init objects Cipher exception"); 100 } 101 return cipher; 102 } 103 }
Encode 工具类
1 import com.google.common.io.BaseEncoding; 2 3 public class Encode { 4 5 /** 6 * byte[] convert into string ,use base encode default value BASE64 7 * 8 * @param encodeMassage 9 * not null byte[] 10 * @return after encode result 11 */ 12 public static String baseEncode(final byte[] encodeMassage) { 13 return baseEncode(encodeMassage, BaseType.BASE64); 14 } 15 16 /** 17 * byte[] convert into string ,use base encode default value BASE64 18 * 19 * @param encodeMassage 20 * not null byte[] 21 * @param encoder 22 * of type please see enum type of inner class , the class name 23 * 'BaseType' 24 * @return after encode result , the type of string 25 */ 26 public static String baseEncode(final byte[] encodeMassage, final BaseType encoder) { 27 String baseResult = null; 28 switch (encoder) { 29 case BASE64: 30 baseResult = BaseEncoding.base64().encode(encodeMassage); 31 break; 32 case BASE32: 33 baseResult = BaseEncoding.base32().encode(encodeMassage); 34 break; 35 case BASE32HEX: 36 baseResult = BaseEncoding.base32Hex().encode(encodeMassage); 37 break; 38 case BASE16: 39 baseResult = BaseEncoding.base16().encode(encodeMassage); 40 break; 41 default: 42 break; 43 } 44 return baseResult; 45 } 46 47 /** 48 * string convert into byte[], use base decode 49 * 50 * @param decodeMassage 51 * not null string 52 * @return after decode result , the type of byte[] 53 */ 54 public static byte[] baseDecode(final String decodeMassage) { 55 return baseDecode(decodeMassage, BaseType.BASE64); 56 } 57 58 public static byte[] baseDecode(final String decodeMassage, final BaseType encoder) { 59 byte[] baseResult = null; 60 switch (encoder) { 61 case BASE64: 62 baseResult = BaseEncoding.base64().decode(decodeMassage); 63 break; 64 case BASE32: 65 baseResult = BaseEncoding.base32().decode(decodeMassage); 66 break; 67 case BASE32HEX: 68 baseResult = BaseEncoding.base32Hex().decode(decodeMassage); 69 break; 70 case BASE16: 71 baseResult = BaseEncoding.base16().decode(decodeMassage); 72 break; 73 default: 74 break; 75 } 76 return baseResult; 77 } 78 79 enum BaseType { 80 BASE64, BASE32, BASE32HEX, BASE16; 81 } 82 }
Numeric 工具类
1 import java.math.BigDecimal; 2 import java.math.BigInteger; 3 import java.util.Arrays; 4 5 /** 6 * <p>Message codec functions.</p> 7 * 8 * <p>Implementation as per https://github.com/ethereum/wiki/wiki/JSON-RPC#hex-value-encoding</p> 9 */ 10 public final class Numeric { 11 12 private static final String HEX_PREFIX = "0x"; 13 14 private Numeric() { 15 } 16 17 public static String encodeQuantity(BigInteger value) { 18 if (value.signum() != -1) { 19 return HEX_PREFIX + value.toString(16); 20 } else { 21 throw new RuntimeException("Negative values are not supported"); 22 } 23 } 24 25 public static BigInteger decodeQuantity(String value) { 26 if (!isValidHexQuantity(value)) { 27 throw new RuntimeException("Value must be in format 0x[1-9]+[0-9]* or 0x0"); 28 } 29 try { 30 return new BigInteger(value.substring(2), 16); 31 } catch (NumberFormatException e) { 32 throw new RuntimeException("Negative ", e); 33 } 34 } 35 36 private static boolean isValidHexQuantity(String value) { 37 if (value == null) { 38 return false; 39 } 40 41 if (value.length() < 3) { 42 return false; 43 } 44 45 if (!value.startsWith(HEX_PREFIX)) { 46 return false; 47 } 48 49 // If TestRpc resolves the following issue, we can reinstate this code 50 // https://github.com/ethereumjs/testrpc/issues/220 51 // if (value.length() > 3 && value.charAt(2) == '0') { 52 // return false; 53 // } 54 55 return true; 56 } 57 58 public static String cleanHexPrefix(String input) { 59 if (containsHexPrefix(input)) { 60 return input.substring(2); 61 } else { 62 return input; 63 } 64 } 65 66 public static String prependHexPrefix(String input) { 67 if (!containsHexPrefix(input)) { 68 return HEX_PREFIX + input; 69 } else { 70 return input; 71 } 72 } 73 74 public static boolean containsHexPrefix(String input) { 75 return input.length() > 1 && input.charAt(0) == '0' && input.charAt(1) == 'x'; 76 } 77 78 public static BigInteger toBigInt(byte[] value, int offset, int length) { 79 return toBigInt((Arrays.copyOfRange(value, offset, offset + length))); 80 } 81 82 public static BigInteger toBigInt(byte[] value) { 83 return new BigInteger(1, value); 84 } 85 86 public static BigInteger toBigInt(String hexValue) { 87 String cleanValue = cleanHexPrefix(hexValue); 88 return new BigInteger(cleanValue, 16); 89 } 90 91 public static String toHexStringWithPrefix(BigInteger value) { 92 return HEX_PREFIX + value.toString(16); 93 } 94 95 public static String toHexStringNoPrefix(BigInteger value) { 96 return value.toString(16); 97 } 98 99 public static String toHexStringWithPrefixZeroPadded(BigInteger value, int size) { 100 return toHexStringZeroPadded(value, size, true); 101 } 102 103 public static String toHexStringNoPrefixZeroPadded(BigInteger value, int size) { 104 return toHexStringZeroPadded(value, size, false); 105 } 106 107 private static String toHexStringZeroPadded(BigInteger value, int size, boolean withPrefix) { 108 String result = toHexStringNoPrefix(value); 109 110 int length = result.length(); 111 if (length > size) { 112 throw new UnsupportedOperationException( 113 "Value " + result + "is larger then length " + size); 114 } else if (value.signum() < 0) { 115 throw new UnsupportedOperationException("Value cannot be negative"); 116 } 117 118 if (length < size) { 119 result = Strings.zeros(size - length) + result; 120 } 121 122 if (withPrefix) { 123 return HEX_PREFIX + result; 124 } else { 125 return result; 126 } 127 } 128 129 public static byte[] toBytesPadded(BigInteger value, int length) { 130 byte[] result = new byte[length]; 131 byte[] bytes = value.toByteArray(); 132 133 int bytesLength; 134 int srcOffset; 135 if (bytes[0] == 0) { 136 bytesLength = bytes.length - 1; 137 srcOffset = 1; 138 } else { 139 bytesLength = bytes.length; 140 srcOffset = 0; 141 } 142 143 if (bytesLength > length) { 144 throw new RuntimeException("Input is too large to put in byte array of size " + length); 145 } 146 147 int destOffset = length - bytesLength; 148 System.arraycopy(bytes, srcOffset, result, destOffset, bytesLength); 149 return result; 150 } 151 152 public static byte[] hexStringToByteArray(String input) { 153 String cleanInput = cleanHexPrefix(input); 154 155 int len = cleanInput.length(); 156 157 if (len == 0) { 158 return new byte[] {}; 159 } 160 161 byte[] data; 162 int startIdx; 163 if (len % 2 != 0) { 164 data = new byte[(len / 2) + 1]; 165 data[0] = (byte) Character.digit(cleanInput.charAt(0), 16); 166 startIdx = 1; 167 } else { 168 data = new byte[len / 2]; 169 startIdx = 0; 170 } 171 172 for (int i = startIdx; i < len; i += 2) { 173 data[(i + 1) / 2] = (byte) ((Character.digit(cleanInput.charAt(i), 16) << 4) 174 + Character.digit(cleanInput.charAt(i+1), 16)); 175 } 176 return data; 177 } 178 179 public static String toHexString(byte[] input, int offset, int length, boolean withPrefix) { 180 StringBuilder stringBuilder = new StringBuilder(); 181 if (withPrefix) { 182 stringBuilder.append("0x"); 183 } 184 for (int i = offset; i < offset + length; i++) { 185 stringBuilder.append(String.format("%02x", input[i] & 0xFF)); 186 } 187 188 return stringBuilder.toString(); 189 } 190 191 public static String toHexStringNoPrefix(byte[] input) { 192 return toHexString(input, 0, input.length, false); 193 } 194 195 public static String toHexString(byte[] input) { 196 return toHexString(input, 0, input.length, true); 197 } 198 199 public static byte b(int m, int n) { 200 return (byte) ( (m << 4) | n); 201 } 202 203 public static boolean isIntegerValue(BigDecimal value) { 204 return value.signum() == 0 || 205 value.scale() <= 0 || 206 value.stripTrailingZeros().scale() <= 0; 207 } 208 }
好了 这样 AES512 就实现了, 测试方法我在这就写了, 自己可以写个test 测试下。