aes算法填充方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了aes算法填充方式相关的知识,希望对你有一定的参考价值。

参考技术A NoPadding,PKCS5Padding,ISO10126Padding,PaddingMode.Zeros,PaddingMode.PKCS7。
aes算法基本介绍
AES技术是一种对称的分组加密技术,使用128位分组加密数据,提供比WEP/TKIPS的RC4算法更高的加密强度。AES的加密码表和解密码表是分开的,并且支持子密钥加密,这种做法优于以前用一个特殊的密钥解密的做法。AES算法支持任意分组大小,初始时间快。特别是它具有的并行性可以有效地利用处理器资源。
    官方服务
      官方网站官方网站

java加密算法之AES小记

jce中提供了加解密的api:

1、首先应该明白AES是基于数据块的加密方式,也就是说,每次处理的数据是一块(16字节),当数据不是16字节的倍数时填充,这就是所谓的分组密码(区别于基于比特位的流密码),16字节是分组长度

AES支持五种模式:CBC,CFB,ECB,OFB,PCBC,

jce中实现了三种补码方式:NoPadding,PKCS5Padding,ISO10126Padding;不支持SSL3Padding,不支持“NONE”模式。

ECB:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
CBC:是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度。
CFB/OFB实际上是一种反馈模式,目的也是增强破解的难度。
ECB和CBC的加密结果是不一样的,两者的模式不同,而且CBC会在第一个密码块运算时加入一个初始化向量。

算法/模式/填充                    16字节加密后数据长度         不满16字节加密后长度

AES/CBC/NoPadding                  16                         不支持
AES/CBC/PKCS5Padding             32                         16
AES/CBC/ISO10126Padding        32                          16
AES/CFB/NoPadding                    16                          原始数据长度
AES/CFB/PKCS5Padding              32                          16
AES/CFB/ISO10126Padding         32                          16
AES/ECB/NoPadding                    16                          不支持
AES/ECB/PKCS5Padding              32                          16
AES/ECB/ISO10126Padding         32                          16
AES/OFB/NoPadding                     16                          原始数据长度
AES/OFB/PKCS5Padding               32                          16
AES/OFB/ISO10126Padding          32                          16
AES/PCBC/NoPadding                   16                          不支持
AES/PCBC/PKCS5Padding             32                          16
AES/PCBC/ISO10126Padding        32                          16
可 以看到,在原始数据长度为16的整数倍时,假如原始数据长度等于16*n,则使用NoPadding时加密后数据长度等于16*n,其它情况下加密数据长 度等于16*(n+1)。在不足16的整数倍的情况下,假如原始数据长度等于16*n+m[其中m小于16],除了NoPadding填充之外的任何方 式,加密数据长度都等于16*(n+1);NoPadding填充情况下,CBC、ECB和PCBC三种模式是不支持的,CFB、OFB两种模式下则加密 数据长度等于原始数据长度。 

 

Demo:

技术分享

 

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AESCoder {
    
    private static final Logger log=LoggerFactory.getLogger(AESCoder.class);
    
    /**
     * 加密
     * hexStr和hexKey都须为16进制表示的字符串
     * 加密后返回16进制表示的字符串*/
    public static String ecbEnc(String hexStr, String hexKey){
        String rs=null;
        try {
            byte[] inBytes = HexUtil.hexToBytes(hexStr);            
            byte[] keyBytes = HexUtil.hexToBytes(hexKey);
            SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");// "算法/模式/补码方式"
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            byte[] encrypted = cipher.doFinal(inBytes);            
            rs=HexUtil.bytesToHex(encrypted);
        } catch (Exception e) {
            log.error("加密异常",e);
            log.error("输入参数为hexStr:{},hexKey:{}",hexStr,hexKey);
        }
        return rs;
    }
    
    /**
     * 解密
     * hexStr和hexKey都须为16进制
     * 加密后返回16进制的字符串*/
    public static String ecbDec(String hexStr,String hexKey){
        String rs=null;
        try {
            byte[] outBytes = HexUtil.hexToBytes(hexStr);
            byte[] keyBytes = HexUtil.hexToBytes(hexKey);
            SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");// "算法/模式/补码方式"
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] decBytes = cipher.doFinal(outBytes);
            rs=HexUtil.bytesToHex(decBytes);
        } catch (Exception e) {
            log.error("解密异常",e);
            log.error("输入参数为hexStr:{},hexKey:{}",hexStr,hexKey);
        }
        return rs;
    }

}

 

public class HexUtil {
    
    /**
     * 将普通字符串用16进制描述
     * 如"WAZX-B55SY6-S6DT5" 描述为:"57415a582d4235355359362d5336445435"
     * */
    public static String strToHex(String str){
         byte[] bytes = str.getBytes(); 
         return bytesToHex(bytes);
    }
    
    /**将16进制描述的字符串还原为普通字符串
     * 如"57415a582d4235355359362d5336445435" 还原为:"WAZX-B55SY6-S6DT5"
     * */
    public static String hexToStr(String hex){
        byte[] bytes=hexToBytes(hex);
        return new String(bytes);
    }
    
    
    /**16进制转byte[]*/
    public static byte[] hexToBytes(String hex){
        int length = hex.length() / 2;
        byte[] bytes=new byte[length];
        for(int i=0;i<length;i++){
            String tempStr=hex.substring(2*i, 2*i+2);//byte:8bit=4bit+4bit=十六进制位+十六进制位
            bytes[i]=(byte) Integer.parseInt(tempStr, 16);
        }
        return bytes;
    }
    
    /**byte[]转16进制*/
    public static String bytesToHex(byte[] bytes){
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<bytes.length;i++){
            int tempI=bytes[i] & 0xFF;//byte:8bit,int:32bit;高位相与.
            String str = Integer.toHexString(tempI);
            if(str.length()<2){
                sb.append(0).append(str);//长度不足两位,补齐:如16进制的d,用0d表示。
            }else{
                sb.append(str);
            }
        }
        return sb.toString();
    }

}

 

public class AESTest {
    
    private static String key="2b7e151628aed2a6abf7158809cf4f3c";
    
    @Test
    public void test_all(){
        String enOri="000000000000000WAZX-B55SY6-S6DT5";
        String enHex=HexUtil.strToHex(enOri);
        String enRS=AESCoder.ecbEnc(enHex,key);
        System.out.println("加密结果为:"+enRS);
        
        String deHex="7312560ccb30ad9b445ee94b426c8a2bdf75d11ded50f053568ec08bf3f9be04";
        String deRS=AESCoder.ecbDec(deHex,key);
        String deOri=HexUtil.hexToStr(deRS);
        System.out.println("解密结果为:"+deOri);
    }
    
    
    @Test
    public void test_enc(){
        String enStr ="6bc1bee22e409f96e93d7e117393172a";        
        String enRS=AESCoder.ecbEnc(enStr,key);        
        System.out.println(enRS);
    }
    
    @Test
    public void test_dec(){
        String deStr ="3ad77bb40d7a3660a89ecaf32466ef97";        
        String enRS=AESCoder.ecbDec(deStr,key);        
        System.out.println(enRS);

    }
    
    
    
    /**
     * 和后台联调时使用
     * 该函数用于讲16进制数组转成String
     * 如密钥key为
     * uint8_t key[] = 
     *         {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 
     *          0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
     * 则格式化之后为"2b7e151628aed2a6abf7158809cf4f3c"
     * */
    public static String convertStr(String hexStr) {
        String[] kStrs = hexStr.split(",");
        String[] keyStrs = new String[kStrs.length];
        for (int i = 0; i < kStrs.length; i++) {
            String str = kStrs[i].trim().substring(2);
            keyStrs[i] = str;
        }
        StringBuffer sb = new StringBuffer();
        for (String str : keyStrs) {
            sb.append(str);
        }
        return sb.toString().toUpperCase();
    }

}

AESTest运行结果:

加密结果为:7312560ccb30ad9b445ee94b426c8a2bdf75d11ded50f053568ec08bf3f9be04
解密结果为:000000000000000WAZX-B55SY6-S6DT5

 

以上是关于aes算法填充方式的主要内容,如果未能解决你的问题,请参考以下文章

java aes CBC的填充方式发现

pkcs1padding怎么填充

Java Cipher - AES 填充问题

python Crypto AES-256-ECB 与PHP之间完成加解密

AES算法特点简述

AES补位填充的一个问题