zoukankan      html  css  js  c++  java
  • 使用java实现AES加密

       公司最近做agent项目,需要对一些远程重要的请求参数进行加密。加密之前选型,选择了AES,而DES算法加密,容易被破解。网上有很多关于加密的算法的Demo案列,我发现这些Demo在Window平台运行正常,然后再MAC下就一直报错,现在选择网上常见的AES加密算法如下:

    一·AES加密

     1 /**
     2      * AES加密字符串
     3      * 
     4      * @param content
     5      *            需要被加密的字符串
     6      * @param password
     7      *            加密需要的密码
     8      * @return 密文
     9      */
    10     public static byte[] encrypt(String content, String password) {
    11         try {
    12             KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
    13 
    14             kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
    15                                                                     // 128位的key生产者
    16             //加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行
    17 
    18             SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
    19 
    20             byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
    21                                                             // null。
    22 
    23             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
    24 
    25             Cipher cipher = Cipher.getInstance("AES");// 创建密码器
    26 
    27             byte[] byteContent = content.getBytes("utf-8");
    28 
    29             cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
    30 
    31             byte[] result = cipher.doFinal(byteContent);// 加密
    32 
    33             return result;
    34 
    35         } catch (NoSuchPaddingException e) {
    36             e.printStackTrace();
    37         } catch (NoSuchAlgorithmException e) {
    38             e.printStackTrace();
    39         } catch (UnsupportedEncodingException e) {
    40             e.printStackTrace();
    41         } catch (InvalidKeyException e) {
    42             e.printStackTrace();
    43         } catch (IllegalBlockSizeException e) {
    44             e.printStackTrace();
    45         } catch (BadPaddingException e) {
    46             e.printStackTrace();
    47         }
    48         return null;
    49     }

    二.AES解密

     1  /**
     2      * 解密AES加密过的字符串
     3      * 
     4      * @param content
     5      *            AES加密过过的内容
     6      * @param password
     7      *            加密时的密码
     8      * @return 明文
     9      */
    10     public static byte[] decrypt(byte[] content, String password) {
    11         try {
    12             KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
    13             kgen.init(128, new SecureRandom(password.getBytes()));
    14             SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
    15             byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
    16             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
    17             Cipher cipher = Cipher.getInstance("AES");// 创建密码器
    18             cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
    19             byte[] result = cipher.doFinal(content);  
    20             return result; // 明文   
    21             
    22         } catch (NoSuchAlgorithmException e) {
    23             e.printStackTrace();
    24         } catch (NoSuchPaddingException e) {
    25             e.printStackTrace();
    26         } catch (InvalidKeyException e) {
    27             e.printStackTrace();
    28         } catch (IllegalBlockSizeException e) {
    29             e.printStackTrace();
    30         } catch (BadPaddingException e) {
    31             e.printStackTrace();
    32         }
    33         return null;
    34     }

    三.测试

     1  public static void main(String[] args) {
     2         String content = "对面的楼上的男生,你们有女朋友吗?";
     3         String password = "123456789";
     4         System.out.println("加密之前:" + content);
     5 
     6         // 加密
     7         byte[] encrypt = AesTest.encrypt(content, password);
     8         System.out.println("加密后的内容:" + new String(encrypt));
     9         
    10         // 解密
    11         byte[] decrypt = AesTest.decrypt(encrypt, password);
    12         System.out.println("解密后的内容:" + new String(decrypt));        
    13     }

    以上代码在Window平台上运行正常,但是在MAC下运行加密正常,解密一直以下报 Given final block not properly padded的错!!!

    网上查了很多资料,最后分析了下错误原因:

    SecureRandom 实现完全随操作系统本身的内部状态,除非调用方在调用 getInstance 方法之后又调用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 MAC 或部分 linux 系统上则不同。两次加密,解密产生的密钥都不相同,所以解密就报错。为了规避这个错误,采用了另一种AES加密的方法,而且需要添加2个依赖jar包。两个依赖的maven坐标是:

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.4</version>
    </dependency>
    <dependency>
        <groupId>org.apache.directory.studio</groupId>
        <artifactId>org.apache.commons.codec</artifactId>
        <version>1.8</version>
    </dependency>

    下面是改进后的代码:

      1 package com.corearchi.utils;
      2 
      3 import javax.crypto.Cipher;
      4 import javax.crypto.KeyGenerator;
      5 import javax.crypto.spec.SecretKeySpec;
      6 import org.apache.commons.codec.binary.Base64;
      7 import org.apache.commons.lang3.StringUtils;
      8 
      9 import sun.misc.BASE64Decoder;
     10 
     11 /**
     12  * AES算法进行加密
     13  *
     14  * @author CodeGeek
     15  * @create 2018-01-23 上午11:00
     16  **/
     17 public class EncryptUtils {
     18 
     19     /**
     20      * 密钥
     21      */
     22     private static final String KEY = "1234567887654321";// AES加密要求key必须要128个比特位(这里需要长度为16,否则会报错)
     23 
     24     /**
     25      * 算法
     26      */
     27     private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
     28 
     29     public static void main(String[] args) throws Exception {
     30         String content = "url:findNames.action";
     31         System.out.println("加密前:" + content);
     32 
     33         System.out.println("加密密钥和解密密钥:" + KEY);
     34 
     35         String encrypt = aesEncrypt(content, KEY);
     36         System.out.println("加密后:" + encrypt);
     37 
     38         String decrypt = aesDecrypt(encrypt, KEY);
     39 
     40         System.out.println("解密后:" + decrypt);
     41     }
     42 
     43     /**
     44      * base 64 encode
     45      * @param bytes 待编码的byte[]
     46      * @return 编码后的base 64 code
     47      */
     48       private static String base64Encode(byte[] bytes){
     49         return Base64.encodeBase64String(bytes);
     50     }
     51 
     52     /**
     53      * base 64 decode
     54      * @param base64Code 待解码的base 64 code
     55      * @return 解码后的byte[]
     56      * @throws Exception 抛出异常
     57      */
     58     private static byte[] base64Decode(String base64Code) throws Exception{
     59         return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
     60     }
     61 
     62 
     63     /**
     64      * AES加密
     65      * @param content 待加密的内容
     66      * @param encryptKey 加密密钥
     67      * @return 加密后的byte[]
     68      */
     69     private static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
     70         KeyGenerator kgen = KeyGenerator.getInstance("AES");
     71         kgen.init(128);
     72         Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
     73         cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
     74 
     75         return cipher.doFinal(content.getBytes("utf-8"));
     76     }
     77 
     78 
     79     /**
     80      * AES加密为base 64 code
     81      *
     82      * @param content 待加密的内容
     83      * @param encryptKey 加密密钥
     84      * @return 加密后的base 64 code
     85      */
     86     private static String aesEncrypt(String content, String encryptKey) throws Exception {
     87         return base64Encode(aesEncryptToBytes(content, encryptKey));
     88     }
     89 
     90     /**
     91      * AES解密
     92      *
     93      * @param encryptBytes 待解密的byte[]
     94      * @param decryptKey 解密密钥
     95      * @return 解密后的String
     96      */
     97     private static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
     98         KeyGenerator kgen = KeyGenerator.getInstance("AES");
     99         kgen.init(128);
    100 
    101         Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
    102         cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
    103         byte[] decryptBytes = cipher.doFinal(encryptBytes);
    104 
    105         return new String(decryptBytes);
    106     }
    107 
    108 
    109     /**
    110      * 将base 64 code AES解密
    111      *
    112      * @param encryptStr 待解密的base 64 code
    113      * @param decryptKey 解密密钥
    114      * @return 解密后的string
    115      */
    116     private static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
    117         return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    118     }
    119 
    120 }

    这个时候在MAC下就可以正常运行了,在Window以及Linux上都可以正常运行。


    作者:撩琼不止
    出处:https://www.cnblogs.com/codegeekgao/
    github:https://github.com/codegeekgao
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

     
  • 相关阅读:
    python解压缩rar,zip文件的正确姿势
    tensorflow1.x及tensorflow2.x不同版本实现验证码识别
    qt5.6.3下使用firebird
    Python3.6下的Requests登录及利用Cookies登录
    c++实现全密码生成
    android中利用HttpURLConnection进行Get、Post和Session读取页面。
    Freebsd10.3 Nginx多版本PHP
    Freebsd10.3(FreeBSD11 Beta1)使用手记
    Eclipse导入的User Libarary
    MySQL zip版本安装
  • 原文地址:https://www.cnblogs.com/codegeekgao/p/8336118.html
Copyright © 2011-2022 走看看