·您当前的位置:首页 > 技术教程 > AS2与AS3技术 >

[as3]as3类的加密与java之间的通信(as3crypto类AES加密解密)(2)

时间:2015-02-25 09:36酷播
Java: 依赖包:commons-lang, commons-codec, slf4j importjava.io.UnsupportedEncodingException; importjava.security.InvalidAlgorithmParameterException; importjava.security.InvalidKeyException; importjav

Java:
依赖包:commons-lang, commons-codec, slf4j

  1. import java.io.UnsupportedEncodingException; 
  2. import java.security.InvalidAlgorithmParameterException; 
  3. import java.security.InvalidKeyException; 
  4. import java.security.NoSuchAlgorithmException; 
  5. import java.util.HashMap; 
  6. import java.util.Map; 
  7.  
  8. import javax.crypto.Cipher; 
  9. import javax.crypto.NoSuchPaddingException; 
  10. import javax.crypto.spec.IvParameterSpec; 
  11. import javax.crypto.spec.SecretKeySpec; 
  12.  
  13. import org.apache.commons.codec.CharEncoding; 
  14. import org.apache.commons.codec.DecoderException; 
  15. import org.apache.commons.codec.binary.Base64; 
  16. import org.apache.commons.codec.binary.Hex; 
  17. import org.apache.commons.lang.ArrayUtils; 
  18. import org.apache.commons.lang.StringUtils; 
  19. import org.slf4j.Logger; 
  20. import org.slf4j.LoggerFactory; 
  21.  
  22. /** 
  23.  * 提供AES的所有核心加密解密。 
  24.  * <p /> 
  25.  * 使用 {@code AES/CBC/NoPadding} 模式时,解密后的原文后会有多余的空格字符需要去除。 
  26.  * <p /> 
  27.  * <b>该类是线程安全的。</b> 
  28.  *  
  29.  * @author fuchun 
  30.  * @since 2.0 
  31.  */ 
  32. public class Rijndael { 
  33.  
  34.     private static final Logger LOGGER = LoggerFactory.getLogger(Rijndael.class); 
  35.  
  36.     private static final Map<String, Rijndael> AES_CACHES = new HashMap<String, Rijndael>(); 
  37.  
  38.     /** 算法名称 - {@code AES}。 */ 
  39.     public static final String ALGORITHM = "AES"
  40.  
  41.     /** 默认的128位时的密钥长度。 */ 
  42.     public static final int KEY_LENGTH = 16
  43.  
  44.     /** 默认的128位时的向量长度。 */ 
  45.     public static final int IV_LENGTH = KEY_LENGTH
  46.  
  47.     /** 
  48.      * 根据给定的私密密钥和默认的 {@code AES/ECB/PKCS5Padding}填充方式,获得一个 {@code Rijndael}。 
  49.      *  
  50.      * @param key 私密密钥。 
  51.      * @return 给定的私密密钥和默认的 {@code AES/ECB/PKCS5Padding}填充方式的 {@code Rijndael}。 
  52.      */ 
  53.     public static Rijndael getInstance(byte[] key) { 
  54.         return getInstance(key, AESMode.ECB_PKCS5); 
  55.     } 
  56.  
  57.     /** 
  58.      * 根据给定的私密密钥和给定的填充方式,获得一个 {@code Rijndael}。 
  59.      *  
  60.      * @param key 私密密钥。 
  61.      * @param mode 模式与填充方式。 
  62.      * @return 给定的私密密钥和给定的填充方式的 {@code Rijndael}。 
  63.      */ 
  64.     public static Rijndael getInstance(byte[] key, AESMode mode) { 
  65.         final String hexKey = Hex.encodeHexString(key); 
  66.         final String cacheKey = StringUtils.join(new Object[] { 
  67.                 hexKey, StringUtils.replace(mode.getName(), "/", "_") 
  68.         }, "_"); 
  69.         if (AES_CACHES.containsKey(cacheKey)) { 
  70.             return AES_CACHES.get(cacheKey); 
  71.         } 
  72.         Rijndael o = new Rijndael(key, mode); 
  73.         AES_CACHES.put(cacheKey, o); 
  74.         return o; 
  75.     } 
  76.  
  77.     /** 
  78.      * 根据给定的私密密钥、IV向量和默认的 {@code AES/CBC/PKCS5Padding} 填充方式,获得一个 {@code Rijndael}。 
  79.      *  
  80.      * @param key 私密密钥。 
  81.      * @param iv IV 向量。 
  82.      * @return 给定的私密密钥、IV向量和默认的 {@code AES/CBC/PKCS5Padding} 填充方式的 {@code Rijndael}。 
  83.      */ 
  84.     public static Rijndael getInstance(byte[] key, byte[] iv) { 
  85.         return getInstance(key, iv, AESMode.CBC_PKCS5); 
  86.     } 
  87.  
  88.     /** 
  89.      * 根据给定的私密密钥、IV向量和指定的填充方式,获得一个 {@code Rijndael}。 
  90.      *  
  91.      * @param key 私密密钥。 
  92.      * @param iv IV向量。 
  93.      * @param mode 模式与填充方式。 
  94.      * @return 返回给定的私密密钥、IV向量和指定的填充方式的 {@code Rijndael}。 
  95.      */ 
  96.     public static Rijndael getInstance(byte[] key, byte[] iv, AESMode mode) { 
  97.         final String hexKey = Hex.encodeHexString(key); 
  98.         final String hexIV = Hex.encodeHexString(iv); 
  99.         final String cacheKey = StringUtils.join(new Object[] { 
  100.                 hexKey, hexIV, StringUtils.replace(mode.getName(), "/", "_") 
  101.         }, "_"); 
  102.         if (AES_CACHES.containsKey(cacheKey)) { 
  103.             return AES_CACHES.get(cacheKey); 
  104.         } 
  105.         Rijndael o = new Rijndael(key, iv, mode); 
  106.         AES_CACHES.put(cacheKey, o); 
  107.         return o; 
  108.     } 
  109.  
  110.     private final AESMode mode; 
  111.     private final SecretKeySpec keySpec; 
  112.     private final IvParameterSpec ivSpec; 
  113.  
  114.     private Cipher enc; 
  115.     private Cipher dec; 
  116.  
  117.     /** 
  118.      * 根据给定的私密密钥和默认的 {@code AES/ECB/PKCS5Padding}填充方式,构造一个新的 {@code Rijndael}。 
  119.      *  
  120.      * @param key 私密密钥。 
  121.      */ 
  122.     public Rijndael(byte[] key) { 
  123.         this(key, AESMode.ECB_PKCS5); 
  124.     } 
  125.  
  126.     /** 
  127.      * 根据给定的私密密钥和给定的填充方式,构造一个新的 {@code Rijndael}。 
  128.      *  
  129.      * @param key 私密密钥。 
  130.      * @param mode 模式与填充方式。 
  131.      */ 
  132.     public Rijndael(byte[] key, AESMode mode) { 
  133.         validateKey(key); 
  134.  
  135.         byte[] aesKey = ArrayUtils.subarray(key, 0, KEY_LENGTH); 
  136.         this.keySpec = new SecretKeySpec(aesKey, ALGORITHM); 
  137.         this.ivSpec = null
  138.         this.mode = mode; 
  139.  
  140.         initEncryptionCipher(); 
  141.         initDecryptionCipher(); 
  142.     } 
  143.  
  144.     /** 
  145.      * 根据给定的私密密钥、IV向量和默认的 {@code AES/CBC/PKCS5Padding} 填充方式,构造一个新的 {@code Rijndael}。 
  146.      *  
  147.      * @param key 私密密钥。 
  148.      * @param iv IV 向量。 
  149.      */ 
  150.     public Rijndael(byte[] key, byte[] iv) { 
  151.         this(key, iv, AESMode.CBC_PKCS5); 
  152.     } 
  153.  
  154.     /** 
  155.      * 根据给定的私密密钥、IV向量和指定的填充方式,构造一个新的 {@code Rijndael}。 
  156.      *  
  157.      * @param key 私密密钥。 
  158.      * @param iv IV向量。 
  159.      * @param mode 模式与填充方式。 
  160.      */ 
  161.     public Rijndael(byte[] key, byte[] iv, AESMode mode) { 
  162.         validateKey(key); 
  163.         validateIV(iv); 
  164.  
  165.         byte[] aesKey = ArrayUtils.subarray(key, 0, KEY_LENGTH); 
  166.         byte[] aesIV = ArrayUtils.subarray(iv, 0, IV_LENGTH); 
  167.         this.keySpec = new SecretKeySpec(aesKey, ALGORITHM); 
  168.         this.ivSpec = new IvParameterSpec(aesIV); 
  169.         this.mode = mode; 
  170.  
  171.         initEncryptionCipher(); 
  172.         initDecryptionCipher(); 
  173.     } 
  174.  
  175.     /** 校验密钥格式。 */ 
  176.     private void validateKey(byte[] key) { 
  177.         if (key == null || key.length < KEY_LENGTH) { 
  178.             throw new IllegalArgumentException(String.format("Invalid AES key length: %s bytes", 
  179.                     key == null ? 0 : key.length)); 
  180.         } 
  181.     } 
  182.  
  183.     /** 校验向量格式。 */ 
  184.     private void validateIV(byte[] iv) { 
  185.         if (iv == null || iv.length < IV_LENGTH) { 
  186.             throw new IllegalArgumentException(String.format("Wrong IV length: must be %s bytes long", 
  187.                     IV_LENGTH)); 
  188.         } 
  189.     } 
  190.  
  191.     /** 
  192.      * 返回明文加密后的最大长度。 
  193.      *  
  194.      * @param sourceLen 明文长度。 
  195.      * @return 明文加密后的最大长度。 
  196.      */ 
  197.     public int getCihperLength(int sourceLen) { 
  198.         int base = 0
  199.         if (!StringUtils.endsWith(mode.getName(), "NoPadding")) { 
  200.             base = 16
  201.         } 
  202.         int pad = sourceLen % 16; 
  203.         if (pad == 0) { 
  204.             return sourceLen + base; 
  205.         } 
  206.         return sourceLen - pad + base; 
  207.     } 
  208.  
  209.     /** 
  210.      * 对指定的数据进行 {@code AES} 算法加密。如果加密发生错误,则返回长度为 0 的 {@code byte} 数组。 
  211.      * <p /> 
  212.      * 处理 {@code data} 缓冲区中的字节以及可能在上一次 {@code update} 
  213.      * 操作中已缓存的任何输入字节,其中应用了填充(如果请求)。结果存储在新缓冲区中。 
  214.      * <p /> 
  215.      * 结束时,此方法将把此类中的 {@code cipher} 加密对象重置为上一次调用 {@code init} 
  216.      * 初始化得到的状态。即重置该对象,可供加密或解密(取决于调用 init 时指定的操作模式)更多的数据。 
  217.      *  
  218.      * @param data 要加密的数据。 
  219.      * @return 加密后的数据。 
  220.      */ 
  221.     public byte[] encrypt(byte[] data) { 
  222.         if (ArrayUtils.isEmpty(data)) { 
  223.             return ArrayUtils.EMPTY_BYTE_ARRAY; 
  224.         } 
  225.         byte[] input; 
  226.         if (StringUtils.endsWith(mode.getName(), "NoPadding")) { 
  227.             input = padding(data); 
  228.         } else { 
  229.             input = data
  230.         } 
  231.         try { 
  232.             return enc.doFinal(input); 
  233.         } catch (Exception ex) { 
  234.             writeEncryptLogger(ex); 
  235.         } 
  236.         return ArrayUtils.EMPTY_BYTE_ARRAY; 
  237.     } 
  238.  
  239.     /** 
  240.      * 对指定的数据进行 {@code AES} 算法解密。如果解密发生错误,则返回长度为 0 的 {@code byte} 数组。 
  241.      * <p /> 
  242.      * 处理 {@code data} 缓冲区中的字节以及可能在上一次 {@code update} 
  243.      * 操作中已缓存的任何输入字节,其中应用了填充(如果请求)。结果存储在新缓冲区中。 
  244.      * <p /> 
  245.      * 结束时,此方法将把此类中的 {@code cipher} 加密对象重置为上一次调用 {@code init} 
  246.      * 初始化得到的状态。即重置该对象,可供加密或解密(取决于调用 init 时指定的操作模式)更多的数据。 
  247.      *  
  248.      * @param data 要解密的数据。 
  249.      * @return 解密后的数据。 
  250.      */ 
  251.     public byte[] decrypt(byte[] data) { 
  252.         try { 
  253.             byte[] result = dec.doFinal(data); 
  254.             if (StringUtils.endsWith(mode.getName(), "NoPadding")) { 
  255.                 int idx = result.length; 
  256.                 for (int i = result.length; --i >= 0;) { 
  257.                     if (result[i] == (byte) 0) { 
  258.                         iidx = i; 
  259.                     } else { 
  260.                         break; 
  261.                     } 
  262.                 } 
  263.                 ArrayUtils.subarray(result, 0, idx); 
  264.             } 
  265.             return result; 
  266.         } catch (Exception ex) { 
  267.             writeDecryptLogger(ex); 
  268.         } 
  269.         return ArrayUtils.EMPTY_BYTE_ARRAY; 
  270.     } 
  271.  
  272.     /** 
  273.      * 使用 {@code AES} 算法对指定的数据进行加密操作。如果加密发生错误,则返回长度为 0 的 {@code byte} 数组。 
  274.      * <p /> 
  275.      * 处理 data 缓冲区中从 {@code offset} 开始(包含)的前 {@code length} 个字节以及可能在上一次 {@code update} 
  276.      * 操作过程中已缓存的任何输入字节,其中应用了填充(如果需要)。结果存储在新缓冲区中。 
  277.      * <p /> 
  278.      * 结束时,此方法将把此类中的 {@code cipher} 加密对象重置为上一次调用 {@code init} 
  279.      * 初始化得到的状态。即重置该对象,可供加密或解密(取决于调用 init 时指定的操作模式)更多的数据。 
  280.      *  
  281.      * @param data 输入缓冲区。 
  282.      * @param offset {@code data} 中输入开始位置的偏移量。 
  283.      * @param length 输入长度。 
  284.      * @return 存储结果的新缓冲区,即加密后的数据。 
  285.      */ 
  286.     public byte[] encrypt(byte[] data, int offset, int length) { 
  287.         try { 
  288.             return enc.doFinal(data, offset, length); 
  289.         } catch (Exception ex) { 
  290.             writeEncryptLogger(ex); 
  291.         } 
  292.         return ArrayUtils.EMPTY_BYTE_ARRAY; 
  293.     } 
  294.  
  295.     /** 
  296.      * 使用 {@code AES} 算法对指定的数据进行解密操作。如果解密发生错误,则返回长度为 0 的 {@code byte} 数组。 
  297.      * <p /> 
  298.      * 处理 data 缓冲区中从 {@code offset} 开始(包含)的前 {@code length} 个字节以及可能在上一次 {@code update} 
  299.      * 操作过程中已缓存的任何输入字节,其中应用了填充(如果需要)。结果存储在新缓冲区中。 
  300.      * <p /> 
  301.      * 结束时,此方法将把此类中的 {@code cipher} 加密对象重置为上一次调用 {@code init} 
  302.      * 初始化得到的状态。即重置该对象,可供加密或解密(取决于调用 init 时指定的操作模式)更多的数据。 
  303.      *  
  304.      * @param data 输入缓冲区。 
  305.      * @param offset {@code data} 中输入开始位置的偏移量。 
  306.      * @param length 输入长度。 
  307.      * @return 存储结果的新缓冲区,即解密后的数据。 
  308.      */ 
  309.     public byte[] decrypt(byte[] data, int offset, int length) { 
  310.         try { 
  311.             return dec.doFinal(data, offset, length); 
  312.         } catch (Exception ex) { 
  313.             writeDecryptLogger(ex); 
  314.         } 
  315.         return ArrayUtils.EMPTY_BYTE_ARRAY; 
  316.     } 
  317.  
  318.     /** 
  319.      * 使用 {@code AES} 算法对指定的数据进行加密操作。如果加密发生错误,则返回 0。 
  320.      * <p /> 
  321.      * 处理 {@code inputData} 缓冲区中从 {@code inputOffset} 开始(包含)的前 {@code inputLen} 
  322.      * 个字节以及可能在上一次 {@code update} 操作过程中已缓存的任何输入字节,其中应用了填充(如果需要)。结果存储在 {@code outputData} 
  323.      * 缓冲区中从 {@code outputOffset}(包含)开始的位置。 
  324.      * <p /> 
  325.      * 如果 {@code outputData} 缓冲区太小无法保存该结果,则返回 0。 
  326.      *  
  327.      * @param inputData 要加密的数据。 
  328.      * @param inputOffset {@code inputData} 中输入开始位置的偏移量。 
  329.      * @param inputLen 输入长度。 
  330.      * @param outputData 保存结果的缓冲区。 
  331.      * @param outputOffset {@code outputData} 中存储结果的位置的偏移量。 
  332.      * @return {@code outputData} 中存储的字节数。 
  333.      */ 
  334.     public int encrypt(byte[] inputData, int inputOffset, int inputLen, byte[] outputData, int outputOffset) { 
  335.         try { 
  336.             return enc.doFinal(inputData, inputOffset, inputLen, outputData, outputOffset); 
  337.         } catch (Exception ex) { 
  338.             writeEncryptLogger(ex); 
  339.         } 
  340.         return 0; 
  341.     } 
  342.  
  343.     /** 
  344.      * 使用 {@code AES} 算法对指定的数据进行解密操作。如果解密发生错误,则返回 0。 
  345.      * <p /> 
  346.      * 处理 {@code inputData} 缓冲区中从 {@code inputOffset} 开始(包含)的前 {@code inputLen} 
  347.      * 个字节以及可能在上一次 {@code update} 操作过程中已缓存的任何输入字节,其中应用了填充(如果需要)。结果存储在 {@code outputData} 
  348.      * 缓冲区中从 {@code outputOffset}(包含)开始的位置。 
  349.      * <p /> 
  350.      * 如果 {@code outputData} 缓冲区太小无法保存该结果,则返回 0。 
  351.      *  
  352.      * @param inputData 要解密的数据。 
  353.      * @param inputOffset {@code inputData} 中输入开始位置的偏移量。 
  354.      * @param inputLen 输入长度。 
  355.      * @param outputData 保存结果的缓冲区。 
  356.      * @param outputOffset {@code outputData} 中存储结果的位置的偏移量。 
  357.      * @return {@code outputData} 中存储的字节数。 
  358.      */ 
  359.     public int decrypt(byte[] inputData, int inputOffset, int inputLen, byte[] outputData, int outputOffset) { 
  360.         try { 
  361.             return dec.doFinal(inputData, inputOffset, inputLen, outputData, outputOffset); 
  362.         } catch (Exception ex) { 
  363.             writeDecryptLogger(ex); 
  364.         } 
  365.         return 0; 
  366.     } 
  367.  
  368.     /** 
  369.      * 加密给定的数据,并返回密文转换成16进制的字符串。如果加密失败,则返回 {@code null}。 
  370.      *  
  371.      * @param data 要加密的数据。 
  372.      * @return 返回加密密文转换成16进制的字符串。 
  373.      */ 
  374.     public String encryptToHex(byte[] data) { 
  375.         byte[] bytes = encrypt(data); 
  376.         if (bytes.length == 0) { 
  377.             return null; 
  378.         } 
  379.         return Hex.encodeHexString(bytes); 
  380.     } 
  381.  
  382.     /** 
  383.      * 解密给定的16进制字符串,返回明文数据。如果解密失败则返回空的{@code byte}数组。 
  384.      * <p /> 
  385.      * 该方法用于解密 {@link #encryptToHex(byte[])} 方法加密后的16进制字符串。 
  386.      *  
  387.      * @param hexStr 16进制字符串表示的密文。 
  388.      * @return 返回明文数据。 
  389.      */ 
  390.     public byte[] decryptHex(String hexStr) { 
  391.         if (StringUtils.isBlank(hexStr)) { 
  392.             return ArrayUtils.EMPTY_BYTE_ARRAY; 
  393.         } 
  394.         byte[] bytes; 
  395.         try { 
  396.             bytes = Hex.decodeHex(hexStr.toCharArray()); 
  397.         } catch (DecoderException ex) { 
  398.             writeDecryptLogger(ex); 
  399.             return ArrayUtils.EMPTY_BYTE_ARRAY; 
  400.         } 
  401.         return decrypt(bytes); 
  402.     } 
  403.  
  404.     /** 
  405.      * 使用指定的字符编码,加密给定的字符串,返回密文数据。如果加密失败则返回空的 {@code byte} 数组。 
  406.      *  
  407.      * @param input 要加密的字符串。 
  408.      * @param encoding 字符编码。 
  409.      * @return 返回密文数据。 
  410.      */ 
  411.     public byte[] encryptString(String input, String encoding) { 
  412.         if (StringUtils.isBlank(input)) { 
  413.             return ArrayUtils.EMPTY_BYTE_ARRAY; 
  414.         } 
  415.         if (StringUtils.isBlank(encoding)) { 
  416.             encoding = CharEncoding.ISO_8859_1; 
  417.         } 
  418.         byte[] data; 
  419.         try { 
  420.             data = input.getBytes(encoding); 
  421.         } catch (UnsupportedEncodingException ex) { 
  422.             writeEncryptLogger(ex); 
  423.             return ArrayUtils.EMPTY_BYTE_ARRAY; 
  424.         } 
  425.         return encrypt(data); 
  426.     } 
  427.  
  428.     /** 
  429.      * 使用指定的字符编码对给定的数据进行解密,还原成原字符串。 
  430.      * 如果 {@code encoding == null || "".equals(encoding)},则字符编码默认为 {@code ISO-889-1} 
  431.      * <p /> 
  432.      * 如果 {@code data} 为{@code null} 或空数组,或者解密失败,则返回 {@code null}。 该方法主要用于解密由 
  433.      * {@link #encryptString(String, String)} 加密后的数据。 
  434.      *  
  435.      * @param data 要解密的数据。 
  436.      * @param encoding 字符编码。 
  437.      * @return 解密后的原文字符串。 
  438.      */ 
  439.     public String decryptToString(byte[] data, String encoding) { 
  440.         if (ArrayUtils.isEmpty(data)) { 
  441.             return null; 
  442.         } 
  443.         if (StringUtils.isBlank(encoding)) { 
  444.             encoding = CharEncoding.ISO_8859_1; 
  445.         } 
  446.         byte[] result = decrypt(data); 
  447.         if (result.length == 0) { 
  448.             return null; 
  449.         } 
  450.         try { 
  451.             return new String(result, encoding); 
  452.         } catch (UnsupportedEncodingException ex) { 
  453.             return null; 
  454.         } 
  455.     } 
  456.  
  457.     /** 
  458.      * 使用指定的字符编码,加密给定的字符串,并返回密文转换成16进制的字符串。如果加密失败,则返回 {@code null}。 
  459.      * <p /> 
  460.      * 如果 {@code encoding == null || "".equals(encoding)},则字符编码为 {@code ISO-8859-1}。 
  461.      *  
  462.      * @param input 要加密的字符串。 
  463.      * @param encoding 字符编码。 
  464.      * @return 返回加密后的密文16进制字符串。 
  465.      */ 
  466.     public String encryptStringToHex(String input, String encoding) { 
  467.         byte[] bytes = encryptString(input, encoding); 
  468.         if (bytes.length == 0) { 
  469.             return null; 
  470.         } 
  471.         return Hex.encodeHexString(bytes); 
  472.     } 
  473.  
  474.     /** 
  475.      * 解密给定的16进制字符串,返回明文字符串。如果解密失败则返回 {@code null}。 
  476.      * <p /> 
  477.      * 该方法用于解密 {@link #encryptStringToHex(String, String)} 方法加密后的16进制字符串密文。 
  478.      *  
  479.      * @param hexStr 16进制字符串表示的密文。 
  480.      * @param encoding 字符编码。 
  481.      * @return 返回明文字符串。 
  482.      */ 
  483.     public String decryptHexToString(String hexStr, String encoding) { 
  484.         byte[] bytes = decryptHex(hexStr); 
  485.         if (bytes.length == 0) { 
  486.             return null; 
  487.         } 
  488.         if (StringUtils.isBlank(encoding)) { 
  489.             encoding = CharEncoding.ISO_8859_1; 
  490.         } 
  491.         try { 
  492.             return new String(bytes, encoding); 
  493.         } catch (UnsupportedEncodingException ex) { 
  494.             return null; 
  495.         } 
  496.     } 
  497.  
  498.     /** 
  499.      * 加密给定的数据,将密文数据进行 {@code base64} 编码。如果给定的数据为空或加密失败,则返回 {@code null}。 
  500.      *  
  501.      * @param data 要加密的数据。 
  502.      * @return 返回AES加密后的密文的 {@code base64} 编码。 
  503.      */ 
  504.     public String encryptToBase64(byte[] data) { 
  505.         byte[] bytes = encrypt(data); 
  506.         if (bytes.length == 0) { 
  507.             return null; 
  508.         } 
  509.         return Base64.encodeBase64String(bytes); 
  510.     } 
  511.  
  512.     /** 
  513.      * 将给定的 {@code base64} 编码格式字符串还原成 {@code byte} 数组, 
  514.      * 然后对该数据进行 {@code AES} 解密。如果解密失败,则返回空的{@code byte}数组。 
  515.      * <p /> 
  516.      * 该方法用于解密 {@link #encryptToBase64(byte[])} 方法加密后的字符串。 
  517.      *  
  518.      * @param base64Str base64格式字符串。 
  519.      * @return 返回解密后的数据。 
  520.      */ 
  521.     public byte[] decryptBase64(String base64Str) { 
  522.         byte[] base64Bytes = Base64.decodeBase64(base64Str); 
  523.         if (ArrayUtils.isEmpty(base64Bytes)) { 
  524.             return ArrayUtils.EMPTY_BYTE_ARRAY; 
  525.         } 
  526.         return decrypt(base64Bytes); 
  527.     } 
  528.  
  529.     /** 
  530.      * 使用指定的字符编码加密给定的字符串。 
  531.      * <p /> 
  532.      * 该方法先将明文字符串根据指定字符编码转换成 {@code byte[]},然后调用 {@link #encryptToBase64(byte[])} 进行数据加密。 
  533.      * 如果 {@code encoding == null || "".equals(encoding)},则字符编码默认为 {@code ISO-8859-1}。 
  534.      *  
  535.      * @param input 要加密的字符串。 
  536.      * @param encoding 字符编码。 
  537.      * @return 返回加密后的密文字符串。 
  538.      */ 
  539.     public String encryptStringToBase64(String input, String encoding) { 
  540.         byte[] bytes = encryptString(input, encoding); 
  541.         if (bytes.length == 0) { 
  542.             return null; 
  543.         } 
  544.         return Base64.encodeBase64String(bytes); 
  545.     } 
  546.  
  547.     /** 
  548.      * 将给定的 {@code base64} 编码格式字符串还原成 {@code byte} 数组, 
  549.      * 然后对该数据进行 {@code AES} 解密,返回明文字符串。如果解密失败,则返回 {@code null}。 
  550.      * <p /> 
  551.      * 该方法是对 {@link #decryptBase64(String)} 的補充。用于对 
  552.      * {@link #encryptStringToBase64(String, String)} 方法加密后的 字符串解密。 
  553.      *  
  554.      * <pre> 
  555.      * String plain = "I am a good boy."
  556.      * String encoding = CharEncoding.UTF_8; 
  557.      * String enc_plain = encryptToBase64(plain, encoding); 
  558.      * String dec_plain = decryptToBase64(enc_plain, encoding); 
  559.      * dec_plain = "I am a good boy." 
  560.      * </pre> 
  561.      *  
  562.      * @param base64Str 要解密的经过 {@code base64} 编码的密文。 
  563.      * @param encoding 字符编码。 
  564.      * @return 返回解密后的字符串。 
  565.      */ 
  566.     public String decryptBase64ToString(String base64Str, String encoding) { 
  567.         byte[] bytes = decryptBase64(base64Str); 
  568.         if (bytes.length == 0) { 
  569.             return null; 
  570.         } 
  571.         if (StringUtils.isBlank(encoding)) { 
  572.             encoding = CharEncoding.ISO_8859_1; 
  573.         } 
  574.         try { 
  575.             return new String(bytes, encoding); 
  576.         } catch (UnsupportedEncodingException ex) { 
  577.             return null; 
  578.         } 
  579.     } 
  580.  
  581.     private void writeEncryptLogger(Throwable cause) { 
  582.         LOGGER.error(String.format("AES decrypt failed. Cause: %s", cause.getMessage())); 
  583.     } 
  584.  
  585.     private void writeDecryptLogger(Throwable cause) { 
  586.         LOGGER.error(String.format("AES decrypt failed. Cause: %s", cause.getMessage())); 
  587.     } 
  588.  
  589.     private byte[] padding(byte[] bytes) { 
  590.         int len = bytes.length; 
  591.         if (len == 0) 
  592.             return bytes; 
  593.         int pad = 0
  594.         if (len < 16) { 
  595.             pad = 16 - len; 
  596.             byte[] pads = createSequence((byte) 0, pad, (byte) 0); 
  597.             return ArrayUtils.addAll(bytes, pads); 
  598.         } else { 
  599.             pad = len % 16; 
  600.             if (pad != 0) { 
  601.                 byte[] pads = createSequence((byte) 0, 16 - pad, (byte) 0); 
  602.                 return ArrayUtils.addAll(bytes, pads); 
  603.             } 
  604.             return bytes; 
  605.         } 
  606.     } 
  607.  
  608.     private void initEncryptionCipher() { 
  609.         if (enc == null) { 
  610.             try { 
  611.                 enc = Cipher.getInstance(mode.getName()); 
  612.                 if (ivSpec == null) { 
  613.                     enc.init(Cipher.ENCRYPT_MODE, keySpec); 
  614.                 } else { 
  615.                     enc.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); 
  616.                 } 
  617.             } catch (NoSuchAlgorithmException ex) { 
  618.                 LOGGER.error(String.format("The current platform no such algorithm - %s, Cause: %s", 
  619.                         ALGORITHM, ex.getMessage())); 
  620.             } catch (NoSuchPaddingException ex) { 
  621.                 LOGGER.error(String.format("The current platform no such padding - %s, Cause: %s", 
  622.                         mode.getName(), ex.getMessage())); 
  623.             } catch (InvalidKeyException ex) { 
  624.                 LOGGER.error(StringUtils.join(new Object[] { 
  625.                         "Invalid key - ", (keySpec != null ? keySpec.toString() : "encrypt key. "), 
  626.                         " Cause: ", ex.getMessage() 
  627.                 })); 
  628.             } catch (InvalidAlgorithmParameterException ex) { 
  629.                 LOGGER.error(StringUtils.join(new Object[] { 
  630.                         "Invalid algorithm parameter - ", 
  631.                         (ivSpec != null ? ivSpec.toString() : "encrypt iv parameter. "), "Cause: ", 
  632.                         ex.getMessage() 
  633.                 })); 
  634.             } 
  635.         } 
  636.     } 
  637.  
  638.     private void initDecryptionCipher() { 
  639.         if (dec == null) { 
  640.             try { 
  641.                 dec = Cipher.getInstance(mode.getName()); 
  642.                 if (ivSpec == null) { 
  643.                     dec.init(Cipher.DECRYPT_MODE, keySpec); 
  644.                 } else { 
  645.                     dec.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); 
  646.                 } 
  647.             } catch (NoSuchAlgorithmException ex) { 
  648.                 LOGGER.error(String.format("The current platform no such algorithm - %s, Cause: %s", 
  649.                         ALGORITHM, ex.getMessage())); 
  650.             } catch (NoSuchPaddingException ex) { 
  651.                 LOGGER.error(String.format("The current platform no such padding - %s, Cause: %s", 
  652.                         mode.getName(), ex.getMessage())); 
  653.             } catch (InvalidKeyException ex) { 
  654.                 LOGGER.error(StringUtils.join(new Object[] { 
  655.                         "Invalid key - ", (keySpec != null ? keySpec.toString() : "decrypt key. "), 
  656.                         " Cause: ", ex.getMessage() 
  657.                 })); 
  658.             } catch (InvalidAlgorithmParameterException ex) { 
  659.                 LOGGER.error(StringUtils.join(new Object[] { 
  660.                         "Invalid algorithm parameter - ", 
  661.                         (ivSpec != null ? ivSpec.toString() : "decrypt iv parameter. "), "Cause: ", 
  662.                         ex.getMessage() 
  663.                 })); 
  664.             } 
  665.         } 
  666.     } 
  667.      
  668.     private static byte[] createSequence(byte start, int length, byte step) { 
  669.         byte[] result = new byte[length]; 
  670.         if(step == 0) { 
  671.             for(int i = 0; i < length; i++) { 
  672.                 result[i] = start; 
  673.             } 
  674.             return result; 
  675.         } 
  676.         for(int i = 0; i < length; i++) { 
  677.             result[i] = start; 
  678.             int next = (int)start + (int)step; 
  679.             if(next < Byte.MIN_VALUE || next > Byte.MAX_VALUE) { 
  680.                 // 正序 
  681.                 if(step > 0) { 
  682.                     start = Byte.MAX_VALUE; 
  683.                     step = 0
  684.                 } else { 
  685.                     start = Byte.MIN_VALUE; 
  686.                     step = 0
  687.                 } 
  688.             } else { 
  689.                 start = Integer.valueOf(next).byteValue(); 
  690.             } 
  691.         } 
  692.         return result; 
  693.     } 
  694.  
  695.     /** 
  696.      * JCE支持的AES模式和填充方式枚举。 
  697.      */ 
  698.     public static enum AESMode { 
  699.  
  700.         /** AES/CFB/NoPadding。 */ 
  701.         CFB_NO("AES/CFB/NoPadding"), 
  702.  
  703.         /** AES/CFB/PKCS5Padding。 */ 
  704.         CFB_PKCS5("AES/CFB/PKCS5Padding"), 
  705.  
  706.         /** AES/CFB/ISO10126Padding。 */ 
  707.         CFB_ISO10126("AES/CFB/ISO10126Padding"), 
  708.  
  709.         /** AES/CBC/NoPadding。 */ 
  710.         CBC_NO("AES/CBC/NoPadding"), 
  711.  
  712.         /** AES/CBC/PKCS5Padding。 */ 
  713.         CBC_PKCS5("AES/CBC/PKCS5Padding"), 
  714.  
  715.         /** AES/CBC/ISO10126Padding。 */ 
  716.         CBC_ISO10126("AES/CBC/ISO10126Padding"), 
  717.  
  718.         /** AES/ECB/NoPadding。 */ 
  719.         ECB_NO("AES/ECB/NoPadding"), 
  720.  
  721.         /** AES/ECB/PKCS5Padding。 */ 
  722.         ECB_PKCS5("AES/ECB/PKCS5Padding"), 
  723.  
  724.         /** AES/ECB/ISO10126Padding。 */ 
  725.         ECB_ISO10126("AES/ECB/ISO10126Padding"); 
  726.  
  727.         final String name; 
  728.  
  729.         private AESMode(String name) { 
  730.             this.name = name; 
  731.         } 
  732.  
  733.         /** 返回AES算法模式和填充方式。 */ 
  734.         public String getName() { 
  735.             return name; 
  736.         } 
  737.     } 
  738.  
  739.     public static void main(String[] args) throws Exception { 
  740.         final String encoding = "UTF-8"
  741.         final String plain = "`1234567890~!@#$%^&*()_+|{}:\"<>?[];',./'\\\n\r\t中国人"; 
  742.         final byte[] plainplainBytes = plain.getBytes(encoding); 
  743.         System.out.println(String.format("原文字节数组长度:%s", plainBytes.length)); 
  744.         final byte[] key = "0123456789ABCDEF".getBytes(); 
  745.         final byte[] iv = "FEDCBA9876543210".getBytes(); 
  746.         Rijndael ecb_aes = new Rijndael(key); 
  747.         System.out 
  748.                 .println("ECB+++++++++++++++++++++++++++++++++ Base64 ++++++++++++++++++++++++++++++++++++"); 
  749.         String b64Str = ecb_aes.encryptStringToBase64(plain, encoding); 
  750.         String b64Plain = ecb_aes.decryptBase64ToString(b64Str, encoding); 
  751.         System.out.println(String.format("原文:%s", plain)); 
  752.         System.out.println(String.format("密文:%s", b64Str)); 
  753.         System.out.println(String.format("解密:%s", b64Plain)); 
  754.         System.out.println(""); 
  755.         System.out 
  756.                 .println("ECB+++++++++++++++++++++++++++++++++ Hex(16) +++++++++++++++++++++++++++++++++++"); 
  757.         String hexStr = ecb_aes.encryptStringToHex(plain, encoding); 
  758.         String hexPlain = ecb_aes.decryptHexToString(hexStr, encoding); 
  759.         System.out.println(String.format("原文:%s", plain)); 
  760.         System.out.println(String.format("密文:%s", hexStr)); 
  761.         System.out.println(String.format("解密:%s", hexPlain)); 
  762.         System.out.println(""); 
  763.         Rijndael cbc_aes = new Rijndael(key, iv, AESMode.CBC_NO); 
  764.         System.out 
  765.                 .println("CBC+++++++++++++++++++++++++++++++++ Base64 ++++++++++++++++++++++++++++++++++++"); 
  766.         String b64Str2 = cbc_aes.encryptStringToBase64(plain, encoding); 
  767.         String b64Plain2 = cbc_aes.decryptBase64ToString(b64Str2, encoding); 
  768.         System.out.println(String.format("原文:%s", plain)); 
  769.         System.out.println(String.format("密文:%s", b64Str2)); 
  770.         System.out.println(String.format("解密:%s", b64Plain2)); 
  771.         System.out.println(""); 
  772.         System.out 
  773.                 .println("CBC+++++++++++++++++++++++++++++++++ Hex(16) +++++++++++++++++++++++++++++++++++"); 
  774.         String hexStr2 = cbc_aes.encryptStringToHex(plain, encoding); 
  775.         String hexPlain2 = cbc_aes.decryptHexToString(hexStr2, encoding); 
  776.         System.out.println(String.format("原文:%s", plain)); 
  777.         System.out.println(String.format("密文:%s", hexStr2)); 
  778.         System.out.println(String.format("解密:%s", hexPlain2)); 
  779.         System.out.println(""); 
  780.  
  781.         Rijndael cbc_aes_pkcs5 = new Rijndael(key, iv, AESMode.CBC_PKCS5); 
  782.         System.out 
  783.                 .println("CBC+CBC_PKCS5+++++++++++++++++++++++ Base64 ++++++++++++++++++++++++++++++++++++"); 
  784.         String b64Str3 = cbc_aes_pkcs5.encryptStringToBase64(plain, encoding); 
  785.         String b64Plain3 = cbc_aes_pkcs5.decryptBase64ToString(b64Str3, encoding); 
  786.         System.out.println(String.format("原文:%s", plain)); 
  787.         System.out.println(String.format("密文:%s", b64Str3)); 
  788.         System.out.println(String.format("解密:%s", b64Plain3)); 
  789.         System.out.println(""); 
  790.         System.out 
  791.                 .println("CBC+CBC_PKCS5+++++++++++++++++++++++ Hex(16) +++++++++++++++++++++++++++++++++++"); 
  792.         String hexStr3 = cbc_aes_pkcs5.encryptStringToHex(plain, encoding); 
  793.         String hexPlain3 = cbc_aes_pkcs5.decryptHexToString(hexStr3, encoding); 
  794.         System.out.println(String.format("原文:%s", plain)); 
  795.         System.out.println(String.format("密文:%s", hexStr3)); 
  796.         System.out.println(String.format("解密:%s", hexPlain3)); 
  797.         System.out.println(""); 
  798.     } 

 

热门文章推荐

请稍候...

保利威视云平台-轻松实现点播直播视频应用

酷播云数据统计分析跨平台播放器