package com.nova.sankuai.domain.api.jiniu; import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.Charset; import java.util.Arrays; /** * 参数加密 * * Created by an on 15/12/16. */ public class ParamAESCodec { public static final Charset CHARSET = Charset.forName("utf-8"); public static final String ALGORITHM = "AES"; public static final String AES_CBC_NOPADDING = "AES/CBC/NoPadding"; /** * 为了平台的通用,选择 AES/CBC/NoPadding 的模式,然后手动 padding * 对应PHP 平台为 mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv) *

* AES/CBC/NoPadding encrypt * 16 bytes secretKeyStr * 16 bytes intVector * * @param secretKeyBytes * @param intVectorBytes * @param input * @return */ public static byte[] encryptCBCNoPadding(byte[] secretKeyBytes, byte[] intVectorBytes, byte[] input) { try { IvParameterSpec iv = new IvParameterSpec(intVectorBytes); SecretKey secretKey = new SecretKeySpec(secretKeyBytes, ALGORITHM); int inputLength = input.length; int srcLength; Cipher cipher = Cipher.getInstance(AES_CBC_NOPADDING); int blockSize = cipher.getBlockSize(); byte[] srcBytes; if (0 != inputLength % blockSize) { srcLength = inputLength + (blockSize - inputLength % blockSize); srcBytes = new byte[srcLength]; System.arraycopy(input, 0, srcBytes, 0, inputLength); } else { srcBytes = input; } cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); byte[] encryptBytes = cipher.doFinal(srcBytes); return encryptBytes; } catch (Exception e) { e.printStackTrace(); } return null; } /** * AES/CBC/NoPadding decrypt * 16 bytes secretKeyStr * 16 bytes intVector * * @param input * @return */ public static byte[] decryptCBCNoPadding(byte[] secretKeyBytes, byte[] intVectorBytes, byte[] input) { try { IvParameterSpec iv = new IvParameterSpec(intVectorBytes); SecretKey secretKey = new SecretKeySpec(secretKeyBytes, ALGORITHM); Cipher cipher = Cipher.getInstance(AES_CBC_NOPADDING); cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); byte[] encryptBytes = cipher.doFinal(input); return encryptBytes; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 用 AES 算法加密 inputStr。 * 使用 secretStr 作为 key,secretStr 的前 16 个字节作为 iv。 * * @param secretStr * @param inputStr * @return */ public static byte[] encode(String secretStr, String inputStr) { byte[] secretKeyBytes = secretStr.getBytes(CHARSET); byte[] ivBytes = Arrays.copyOfRange(secretKeyBytes, 0, 16); byte[] inputBytes = inputStr.getBytes(CHARSET); byte[] outputBytes = encryptCBCNoPadding(secretKeyBytes, ivBytes, inputBytes); return outputBytes; } public static void main(String[] args) { } /** * 用 AES 算法加密 inputStr。 * 使用 secretStr 作为 key,secretStr 的前 16 个字节作为 iv。 * 并对加密后的字节数组调用 sun.misc.BASE64Encoder.encode 方法, * 转换成 base64 字符串返回。 * * @param secretStr * @param inputStr * @return */ public static String strEncodBase64(String secretStr, String inputStr) { String base64Str = Base64.encodeBase64String(encode(secretStr, inputStr)); return base64Str; } /** * 用 AES 算法加密 inputStr。 * 使用 secretStr 作为 key,secretStr 的前 16 个字节作为 iv。 * * @param secretStr * @return */ public static byte[] decode(String secretStr, byte[] inputBytes) { byte[] secretKeyBytes = secretStr.getBytes(CHARSET); byte[] ivBytes = Arrays.copyOfRange(secretKeyBytes, 0, 16); byte[] outputBytes = decryptCBCNoPadding(secretKeyBytes, ivBytes, inputBytes); return outputBytes; } /** * 用 AES 算法加密 inputStr。 * 使用 secretStr 作为 key,secretStr 的前 16 个字节作为 iv。 * 并对加密后的字节数组调用 sun.misc.BASE64Encoder.encode 方法, * 转换成 base64 字符串返回。 *

* (仅作为测试用途,具体加密流程以接口文档为准) * * @param secretStr * @param inputStr * @return */ public static String base64StrDecode(String secretStr, String inputStr) { byte[] inputBytes; inputBytes = Base64.decodeBase64(inputStr); String outputStr = new String(decode(secretStr, inputBytes), CHARSET).trim(); return outputStr; } // 加密(小赢卡贷h5流程回写合作结构接口) public static String encrypt(String sSrc, String sKey) throws Exception { if (sKey == null) { System.out.print("Key为空null"); return null; } // 判断Key是否为16位 if (sKey.length() != 16) { System.out.print("Key长度不是16位"); return null; } byte[] raw = sKey.getBytes("utf-8"); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式" cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8")); return new Base64().encodeToString(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。 } // 解密(小赢卡贷h5流程回写合作结构接口) public static String decrypt(String sSrc, String sKey) throws Exception { try { // 判断Key是否正确 if (sKey == null) { System.out.print("Key为空null"); return null; } // 判断Key是否为16位 if (sKey.length() != 16) { System.out.print("Key长度不是16位"); return null; } byte[] raw = sKey.getBytes("utf-8"); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] encrypted1 = new Base64().decode(sSrc);//先用base64解密 try { byte[] original = cipher.doFinal(encrypted1); String originalString = new String(original, "utf-8"); return originalString; } catch (Exception e) { System.out.println(e.toString()); return null; } } catch (Exception ex) { System.out.println(ex.toString()); return null; } } }