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
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------此外,还有另外一个写法-----------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- import java.security.SecureRandom;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- import javax.crypto.spec.SecretKeySpec;
- public class AESHelper {
- public static String encrypt(String content, String pwd,String charSet) {
- try {
- byte[] byteContent = content.getBytes(charSet);
- KeyGenerator kgen = KeyGenerator.getInstance("AES");
- kgen.init(128, new SecureRandom(pwd.getBytes()));
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
- byte[] buf = cipher.doFinal(byteContent);
- //byte[]转16进制
- 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();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- /***
- *
- * @param content 16进制的字符串
- * @param pwd
- * @param charSet
- * @return
- */
- public static String decrypt(String content, String pwd,String charSet) {
- try {
- byte[] byteContent = new byte[content.length() / 2];
- if (content.length() < 1){
- return null;
- }
- //将16进制转换为二进制
- for (int i = 0; i < content.length() / 2; i++) {
- int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
- int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
- byteContent[i] = (byte) (high * 16 + low);
- }
- KeyGenerator kgen = KeyGenerator.getInstance("AES");
- kgen.init(128, new SecureRandom(pwd.getBytes()));
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
- byte[] buf = cipher.doFinal(byteContent);
- return new String(buf,charSet);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- public static void main(String[] args) {
- String layer = AESHelper.encrypt("编程ABCDefgh~!@#$%^&*()|'?>.<;", "123","utf-8");
- System.out.println(layer);
- String plain = AESHelper.decrypt(layer,"123","utf-8");
- System.out.println(plain);
- }
- }
据说要加上要两句话,不然,跨操作系统加解密可能有问题:
SecureRandom secureRandom=SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(pwd.getBytes());
最终写法:
- import java.security.Key;
- import java.security.SecureRandom;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- public class AESHelper {
- public static String encrypt(String content) {
- return encrypt(content, null, "utf-8");
- }
- /***
- * 加密
- *
- * @param plain
- * @param keySeed
- * @param charSet
- * @return 输出密文 16进制
- */
- public static String encrypt(String plain, String keySeed, String charSet) {
- try {
- byte[] byteContent = plain.getBytes(charSet);
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.ENCRYPT_MODE, getKey(keySeed));
- byte[] buf = cipher.doFinal(byteContent);
- // byte[]转16进制
- 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();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- public static String decrypt(String content) {
- return decrypt(content, null, "utf-8");
- }
- /***
- * 解密 输入16进制的字符串
- *
- * @param layer
- * @param keySeed
- * @param charSet
- * @return 原文
- */
- public static String decrypt(String layer, String keySeed, String charSet) {
- try {
- byte[] byteContent = new byte[layer.length() / 2];
- if (layer.length() < 1) {
- return null;
- }
- // 将16进制转换为二进制
- for (int i = 0; i < layer.length() / 2; i++) {
- int high = Integer.parseInt(layer.substring(i * 2, i * 2 + 1), 16);
- int low = Integer.parseInt(layer.substring(i * 2 + 1, i * 2 + 2), 16);
- byteContent[i] = (byte) (high * 16 + low);
- }
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.DECRYPT_MODE, getKey(keySeed));
- byte[] buf = cipher.doFinal(byteContent);
- return new String(buf, charSet);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- public static Key getKey(String keySeed) {
- if (keySeed == null) {
- keySeed = System.getenv("AES_SYS_KEY");
- }
- if (keySeed == null) {
- keySeed = System.getProperty("AES_SYS_KEY");
- }
- if (keySeed == null || keySeed.trim().length() == 0) {
- keySeed = "abcd1234!@#$";// 默认种子
- }
- try {
- SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
- secureRandom.setSeed(keySeed.getBytes());
- KeyGenerator generator = KeyGenerator.getInstance("AES");
- generator.init(secureRandom);
- return generator.generateKey();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- public static void main(String[] args) {
- if(null==args||args.length==0){
- args=new String[1];
- args[0]="编程ABCDefgh~!@#$%^&*()|'?>.<;1234567823401";
- }
- String layer = AESHelper.encrypt(args[0]);
- System.out.println("密文:"+layer);
- String plain = AESHelper.decrypt(layer);
- System.out.println("原文:"+plain);
- }
- }
linux 运行该方法:
[zhangbin@WEB01 test]$ java AESHelper "jwe223489430214aefhasduf3423"
密文:49336565BD95CB2E70297F4F89DEE2D37EA6A7C14A320194848CF17E930B1DB5
原文:jwe223489430214aefhasduf3423
java加密算法之AES小记的更多相关文章
- JAVA加密算法系列-AES
package ***; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; ...
- Atitit.加密算法 des aes 各个语言不同的原理与解决方案java php c#
Atitit.加密算法 des aes 各个语言不同的原理与解决方案java php c# 1. 加密算法的参数::算法/模式/填充 1 2. 标准加密api使用流程1 2.1. Md5——16bi ...
- Atitit.加密算法ati Aes的框架设计
Atitit.加密算法ati Aes的框架设计 版本进化 c:\1t\aesC47.java c:\1t\aes.java 增加了public static byte[] encrypt(byte[] ...
- Atitit.加密算法ati Aes的框架设计v2.2
Atitit.加密算法ati Aes的框架设计v2.2 版本进化1 V2.2 add def decode key api1 v1版本1 Aes的历史2 Atitit.加密算法 des aes ...
- java加密算法入门(二)-对称加密详解
1.简单介绍 什么是对称加密算法? 对称加密算法即,加密和解密使用相同密钥的算法. 优缺点: 优点:算法公开.计算量小.加密速度快.加密效率高. 缺点: (1)交易双方都使用同样钥匙,安全性得不到保证 ...
- Java加密算法
密码的常用术语: 1.密码体制:由明文空间.密文空间.密钥空间.加密算法和解密算法5部分组成. 2.密码协议:也称为安全协议,是指以密码学为基础的消息交换的通信协议,目的是在网络环境中提供安全的服务. ...
- java C# objective-c AES对称加解密
/** * AES加解密 */ public class AESHelper { final static String AES_KEY = "43hr8fhu34b58123"; ...
- Java中的AES加解密工具类:AESUtils
本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.constants.SysConsta ...
- Java加密算法 RSA
Java加密算法 RSA 2015-06-06 08:44 511人阅读 评论(0) 收藏 举报 分类: JAVA(57) 公钥加密也称为非对称加密.速度慢.加密和解密的钥匙不相同,某一个人持有私 ...
随机推荐
- yii 初步安装
第一步: window下点击>开始 >运行CMD命令. 第二步:进入Yiic文件的目录 (例如在D盘里面 D:/yii/framework) 第三步:D:\yii\framework& ...
- 【转】JavaScript获取节点类型、节点名称和节点值
DOM节点信息包括节点类型(nodeType).节点名称(nodeName)和节点值(nodeValue). 节点类型 DOM节点中,每个节点都拥有不同的类型.W3C规范中常用的 DOM节点类型有以下 ...
- jquery+ajax跨域请求webservice
最近几天在学习webservice...在学习的时候便想到用ajax的方式去请求webservice.. 一直在测试..如果这个被请求的webservice和自己使用的是同一个端口号.则不用考虑那aj ...
- GitLab服务器搭建及配置
一.服务器环境 操作系统:CentOS release 6.5 (Final) GitLab版本: GitLab-shell:2.0.1 Ruby version: ruby 2.1.2p95 (20 ...
- URL Scheme APP跳转safari以及跳回APP
上图 : 在plist文件里面设置. URL identifier 一般为反域名+项目名称 (尽可能保证少重复) URL Schemes是一个数组.一个APP可以添加多个.该参数为跳转时使用的标识. ...
- java_SE(Day15)_集合1
一.集合类概述: 1.为什么出现集合类? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类. 2.数组和集合类同是容器,有何不同? 数组虽然也可以存储对象 ...
- 简谈ashx
是一般处理程序, 是asp.net web 组件的一种,ashx是其扩展名. 实现IHttpHandler接口,接收并处理http请求.这个接口有一个IsReusable成员,一个待实现的方法Proc ...
- ADB命令详解
一.adb介绍 ADB的全称为Android Debug Bridge,字面意思就是安卓调试桥接,简单点说,它是Android系统提供的一套工具,通过它,我们可以在电脑上建立一个连接到手机的通道,然后 ...
- js中十进制数转换为16进制
使用 Number类的 toString()方法: var num = 255; console.log(num.toString(16));//输出FF
- firefox兼容性问题
//innertext 火狐不同版本不兼容 document.getElementById("user-content").textContent=content; 博主使用的是最 ...