1 分组加密
首先了解下什么是分组加密:分组密码是将明文消息编码表示后的数字(简称明文数字)序列,划分成长度为n的组(可看成长度为n的矢量),每组分别在密钥的控制下变换成等长的输出数字(简称密文数字)序列。


3 ECB的加密方式

http://zh.wikipedia.org/wiki/%E5%9D%97%E5%AF%86%E7%A0%81%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F电码本模式:这种模式是将整个明文分成若干段相同的小段,然后对每一小段进行加密


将明文的各个分组独立的使用相同的密钥进行加密,这种方式加密时各分组的加密独立进行互不干涉,因而可并行进行。同样因为各分组独立加密的缘故,相同的明文分组加密之后具有相同的密文。该模式容易暴露明文分组的统计规律和结构特征。不能防范替换攻击。

优点:

1.简单;

2.有利于并行计算;

3.误差不会被传送;

缺点:

1.不能隐藏明文的模式;

2.可能对明文进行主动攻击;

2 CBC加密模式

密码分组链接模式:这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密;


优点:

1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。

缺点:

1.不利于并行计算;

2.误差传递;

3.需要初始化向量IV

3 编程实现

package com.zhy.concurrency.cyclic;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AesEncryption {



    // 使用CBC加密需要使用添加一个向量

    // 此处不符合安全规范:分组密码算法使用到的IV值,必须不可预测;推荐使用安全的随机数



    public static void main(String[] args) {

              // TODO Auto-generated method stub

              String aes_key = "0123456789abcdef";

              // 此处密钥硬编码

              String strSrc = "0123456789abcdefadmin";

              // 数据明文,敏感信息泄露

              System.out.println(strSrc);

              String encrypt_code = AesEncrypt_test(strSrc, aes_key);

              System.out.println(encrypt_code);

              String decrypt_code = AesDncrypt_test(encrypt_code, aes_key);

              System.out.println(decrypt_code);

              // log打印,敏感信息泄露

    }



    // 使用CBC的加密算法,要求密钥为16byte

    public static String AesEncrypt_test(String content, String aes_key) {

              try {

                       byte[] raw = aes_key.getBytes();

                       SecretKeySpec secretkey = new SecretKeySpec(raw, "AES");

                       Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");



                       SecureRandom random = new SecureRandom();

                       byte ivParameter[] = new byte[16];

                       random.nextBytes(ivParameter);



                       System.out.println(parseByte2HexStr(ivParameter));



                       IvParameterSpec ivparam = new IvParameterSpec(ivParameter);

                       cipher.init(Cipher.ENCRYPT_MODE, secretkey, ivparam);

                       byte[] encrypted = cipher.doFinal(content.getBytes());

                       return parseByte2HexStr(ivParameter) + parseByte2HexStr(encrypted);

                       //将IV生成的结果附在加密数据前16bytes,每次都使用不同的iv



              } catch (InvalidKeyException | NoSuchAlgorithmException

                                | NoSuchPaddingException | InvalidAlgorithmParameterException

                                | IllegalBlockSizeException | BadPaddingException e) {

                       // TODO Auto-generated catch block

                       e.printStackTrace();

              }

              return null;

    }



    public static String AesDncrypt_test(String content, String aes_key) {

              try {

                       byte[] raw = aes_key.getBytes();

                       SecretKeySpec secretkey = new SecretKeySpec(raw, "AES");

                       Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");





                       String ivParameter = content.substring(0,32);

                  //取前16byte作为cbc解密的iv向量

                       System.out.println(ivParameter);



                       IvParameterSpec ivparam = new IvParameterSpec(

                                          parseHexStr2Byte(ivParameter));

                       cipher.init(Cipher.DECRYPT_MODE, secretkey, ivparam);

                       byte[] decrypted = cipher.doFinal(parseHexStr2Byte(content.substring(32)));

                       return new String(decrypted);

              } catch (InvalidKeyException | NoSuchAlgorithmException

                                | NoSuchPaddingException | InvalidAlgorithmParameterException

                                | IllegalBlockSizeException | BadPaddingException e) {

                       // TODO Auto-generated catch block

                       e.printStackTrace();

              }

              return null;

    }

    /**

     * 将2进制转换为16进制

     * 

     * @param hexStr

     * @return

     */

    private static String parseByte2HexStr(byte buf[]) {

              StringBuffer sb = new StringBuffer();

              for (int i = 0; i < buf.length; i++) {

                       String hex = Integer.toHexString(buf[i] & 0xFF);

                       if (hex.length() == 1) {

                                hex = '0' + hex;

                       }

                       sb.append(hex.toUpperCase());

              }

              return sb.toString();

    }

    /**

     * 将16进制转换为二进制

     * 

     * @param hexStr

     * @return

     */

    private static byte[] parseHexStr2Byte(String hexStr) {

              if (hexStr.length() < 1)

                       return null;

              byte[] result = new byte[hexStr.length() / 2];

              for (int i = 0; i < hexStr.length() / 2; i++) {

                       int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);

                       int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);

                       result[i] = (byte) (high * 16 + low);

              }

              return result;

}
}