AES/ECB/PKCS5Padding/PKCS7Padding 128位密钥(带密钥补位功能)加密解密-程序员宅基地

技术标签: Java  密钥补位  AES加密解密  

今天客户说发解密算法过来,本来以为拿来的是代码直接用,
没想到就直接给了我个网站http://www.seacha.com/tools/aes.html尴尬
和他们用的算法模式+密钥。
以前还真没玩过AES加密解密,下面是今天研究的结果。

实现结果:
算法:AES
模式:ECB
密钥长度:128位
密钥:自己填(代码中带补位功能
补码方式:PKCS5Padding/PKCS7Padding (这两个补码方式出来的结果都一样,好像没区别疑问
加密结果编码方式:十六进制/base64(加密解密的方法里面两种编码方式的代码都有)

AES.java

package com.sun.aes;

import java.math.BigInteger;

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

import org.apache.commons.codec.binary.Base64;  
import org.apache.commons.codec.binary.Hex;
  
public class AES {
	
    /** 
     * 加密
     * @param String src 加密字符串 
     * @param String key 密钥
     * @return 加密后的字符串 
     */  
    public static String Encrypt(String src, String key) throws Exception {
    	// 判断密钥是否为空
        if (key == null) {
            System.out.print("密钥不能为空");
            return null;
        }
        
        // 密钥补位
        int plus= 16-key.length();        
        byte[] data = key.getBytes("utf-8");
        byte[] raw = new byte[16];
        byte[] plusbyte={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
        for(int i=0;i<16;i++)
        {
        	if (data.length > i)
        		raw[i] = data[i];
        	else
        		raw[i] = plusbyte[plus];
        }
        
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");	// 算法/模式/补码方式 
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(src.getBytes("utf-8"));
 
        //return new Base64().encodeToString(encrypted);//base64
        return binary(encrypted, 16); //十六进制
    }

    /** 
     * 解密
     * @param String src 解密字符串 
     * @param String key 密钥
     * @return 解密后的字符串 
     */  
    public static String Decrypt(String src, String key) throws Exception {
        try {
            // 判断Key是否正确
            if (key == null) {
                System.out.print("Key为空null");
                return null;
            }

            // 密钥补位
            int plus= 16-key.length();            
            byte[] data = key.getBytes("utf-8");
            byte[] raw = new byte[16];
            byte[] plusbyte={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
            for(int i=0;i<16;i++)
            {
            	if (data.length > i)
            		raw[i] = data[i];
            	else
            		raw[i] = plusbyte[plus];
            }
            
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            
            //byte[] encrypted1 = new Base64().decode(src);//base64
            byte[] encrypted1 = toByteArray(src);//十六进制
            
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original,"utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }
    
    /** 
     * 将byte[]转为各种进制的字符串 
     * @param bytes byte[] 
     * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制 
     * @return 转换后的字符串 
     */  
    public static String binary(byte[] bytes, int radix){  
        return new BigInteger(1, bytes).toString(radix);	// 这里的1代表正数  
    }
    
    /**
     * 16进制的字符串表示转成字节数组
     *
     * @param hexString 16进制格式的字符串            
     * @return 转换后的字节数组
     **/
    public static byte[] toByteArray(String hexString) {
        if (hexString.isEmpty())
            throw new IllegalArgumentException("this hexString must not be empty");

        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {//因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }
    
    public static void main(String[] args) throws Exception {
    	// 密钥
        String key = "smph20151208shao";
        // 需要加密的字符串
        String src = "出版社";
        
        System.out.println(src);
        
        // 加密
        String enString = Encrypt(src, key);
        System.out.println("加密后的字串是:" + enString);
 
        // 解密
        String DeString = Decrypt(enString, key);
        System.out.println("解密后的字串是:" + DeString);
    }

}  

运行结果:
出版社
加密后的字串是:c4735c066ad590cb11e0fd6084592df2

解密后的字串是:出版社

-------------------------------------------------补充-------------------------------------------------

今天拿到了客户加密后的文件,发觉XML是整个文件加密,且按照每三个字符加密,加密后的字符串带换行,XML开始位置竟然还有乱码。
修改后的解密代码如下:

    /** 
     * 解密
     * @param String src 解密字符串 
     * @param String key 密钥
     * @return 解密后的字符串 
     */  
    public static String decrypt(String src, String key) throws Exception {
        try {
            // 判断Key是否正确
            if (key == null) {
                System.out.print("Key为空null");
                return null;
            }

            // 密钥补位
            int plus= 16-key.length();            
            byte[] data = key.getBytes("utf-8");
            byte[] raw = new byte[16];
            byte[] plusbyte={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
            for(int i=0;i<16;i++)
            {
            	if (data.length > i)
            		raw[i] = data[i];
            	else
            		raw[i] = plusbyte[plus];
            }
            
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            
            //byte[] encrypted1 = new Base64().decode(src);//base64
            byte[] encrypted1 = toByteArray(src);//十六进制
            
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original,"utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }
    
    /** 
     * 将byte[]转为各种进制的字符串 
     * @param bytes byte[] 
     * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制 
     * @return 转换后的字符串 
     */  
    public static String binary(byte[] bytes, int radix){  
        return new BigInteger(1, bytes).toString(radix);	// 这里的1代表正数  
    }
    
    /**
     * 16进制的字符串表示转成字节数组
     *
     * @param hexString 16进制格式的字符串            
     * @return 转换后的字节数组
     **/
    public static byte[] toByteArray(String hexString) {
        if (hexString.isEmpty())
            throw new IllegalArgumentException("this hexString must not be empty");

        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {//因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }
    
    /**
     * 执行解码并生成解码后文件
     *
     * @param sourceFile 加密文件
     * @param targetFile 解密后生成文件
     **/
    public static void decryptFile(String sourceFile, String targetFile) {
    	// 密钥
        String key = "smbk20160101shao";
        
        try{
	        File file = new File(targetFile);
	        if (file.exists())
	        	file.delete();
	        file.createNewFile();
	    	
	        // read net source file to local target file
	    	URL url = new URL(encodeUrlToUTF8(sourceFile));  
	        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));  
	        String s;
	        while ((s = reader.readLine()) != null) {
	        	writeFile(targetFile, decrypt(changeString(s), key));
	        }
	        reader.close();
        }
	catch(Exception e)
	{
            e.printStackTrace();
	}
    }

    /**
     * 
     * Url中的中文转换
     * 
     */
    public static String encodeUrlToUTF8(String url) throws UnsupportedEncodingException{  
    StringBuffer sb = new StringBuffer();  
        for (int i = 0; i < url.length(); i++) {  
            String s = url.substring(i, i + 1);  
            byte[] bytes = s.getBytes("UTF-8"); 
            // 中文字符是2个字节,符号和英文为1个字节  
            if (bytes.length == 1) {
                if (bytes[0] == ' ')  
                    sb.append("%20");  
                else  
                    sb.append(s);  
            } else {  
                sb.append(URLEncoder.encode(s, "UTF-8"));
            }  
        }  
        return sb.toString();
    }  
	

    /**
     * 
     * 除去乱码
     * 
     */
    private static String changeString(String str){
 	String str_Result = "", str_OneStr = "";  
   	for (int z = 0; z < str.length(); z++) {  
	    str_OneStr = str.substring(z, z + 1);  
	    if (!str_OneStr.matches("[\u4e00-\u9fa5]+")) {  
	        if (str_OneStr.matches("[\\x00-\\x7F]+")) {  
	            str_Result = str_Result + str_OneStr;  
	        }  
	    }
	}
        return str_Result;
    }

    /**
     * 
     * 将内容写入输出文件
     * 
     */
    public static void writeFile(String fileName, String content) throws IOException{
        FileWriter fw = new FileWriter(fileName, true);
        fw.write(content);
        //刷新缓冲区
        fw.flush();
        //关闭文件流对象
        fw.close();
    }

调用:

decryptFile("http://localhost:8080/Test/Source/test.xml", "D:/Test/test.xml")


-------------------------------------------------继续补充-------------------------------------------------

如果要在前台用JS加密解密,需要CryptoJS的js包
需要引入3个文件:

<script type="text/javascript" src="${ctxStatic}/modules/smph/js/CryptoJS/rollups/aes.js"></script>
<script type="text/javascript" src="${ctxStatic}/modules/smph/js/CryptoJS/components/mode-ecb-min.js"></script>
<script type="text/javascript" src="${ctxStatic}/modules/smph/js/CryptoJS/components/pad-nopadding-min.js"></script>

JS:
<script type="text/javascript">  
        var key = CryptoJS.enc.Utf8.parse("1234567890123456"); 
        function Encrypt(word){
            srcs = CryptoJS.enc.Utf8.parse(word);
            var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
            return encrypted.ciphertext.toString().toUpperCase();
        }

        function Decrypt(word){
            var encryptedHexStr = CryptoJS.enc.Hex.parse(word);
            var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
            var decrypt = CryptoJS.AES.decrypt(srcs, key, { mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
            var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
            return decryptedStr.toString();
        }

<span style="white-space:pre">	</span>var source = "ABC";
        var target = Encrypt(source);
<span style="white-space:pre">	</span>console.log(target);
<span style="white-space:pre">	</span>console.log(Decrypt(target));
</script>


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sunroyi666/article/details/52300443

智能推荐

计算机基础知识面试题集_计算机基础面试题-程序员宅基地

文章浏览阅读6.3w次,点赞100次,收藏955次。凡是计算机类的面试都少不了计算机基础知识,汇总整理此类知识有助于面试集中复习,说不定什么时候就用上了。1、ICMP 是什么协议?处于哪一层?答:ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议簇的一个子协议,用于在IP主机、路由器之间传递控制消息。属于网络层协议控制消息是指网络通不通、主机..._计算机基础面试题

redhat oracle 12c 安装图解,RedHat 7 静默安装Oracle 12c-程序员宅基地

文章浏览阅读673次。之前在网上看了很多Oracle的静默安装教程,感觉有些乱,经过自己查阅Oracle官网英文手册,结合在虚拟机中安装测试,整理出了这篇RedHat 7 静默安装Oracle 12c。redhat 6静默安装Oracle 11g R2也已基本整理好了,等有时间了再发出来。一、环境要求与准备1、硬件要求(1)磁盘空间EnterpriseEdition : 6.4GBStandardEdition : 6..._oracl12c redhat7 非图形界面安装

shell函数的使用方法,轻松写脚本_shell脚本函数调用怎么写-程序员宅基地

文章浏览阅读2k次。目录shell函数1.函数的作用2.函数的基本格式3.函数注意事项4.函数调用的方法5.函数的返回值6.函数的传参7.在外部调用函数8.函数变量的作用范围9.函数的递归shell函数1.函数的作用语句块定义成函数约等于别名,定义函数,再引用函数封装的可重复利用的具有特定功能的代码2.函数的基本格式法一:[function] 函数名 (){ 命令序列 [return x] #使用return或者exit可以显式的结束函数} 法二:函数名(){ 命令序列}3._shell脚本函数调用怎么写

设计模式之七适配器模式_软件设计模式实验7适配器模式-程序员宅基地

文章浏览阅读157次。概念适配器模式(Adapater Pattern)是指将一个类的接口转换成用户期望的另一个接口,使原本接口不兼容的类可以一起工作,属于结构型设计模式。场景场景一已经存在的类的方法和需求不匹配(方法结果相同或者相似)的情况场景二适配器模式不是软件设计初始阶段考虑的设计模式,是随着软件的发展,由于不同的产品、不同的厂家造成功能类似而接口不同的问题的解决方法,有点亡羊补牢的感觉。生活中电源..._软件设计模式实验7适配器模式

首届《Mr媛杯》程序媛选帅大赛开幕-程序员宅基地

文章浏览阅读180次。点击欧盟IT那些事关注我们公告:因企鹅审核规定,本公众号从《德国IT那些事》更名为《欧盟IT那些事》。你们要的比赛来了。宣传防骗,人人有责,让骗子无人可骗。近期在德国各地华人群中,频繁..._选帅哥大赛开始

WebSocket的那些事(1-概念篇)_qwebsocket的唯一标识-程序员宅基地

文章浏览阅读1.9k次,点赞5次,收藏6次。根据RFC 6455标准,Websocket协议提供了一种标准化的方式在客户端和服务端之间通过TCP连接建立全双工、双向通信渠道。它是一种不同于HTTP的TCP协议,但是被设计为在HTTP基础上运行。Websocket交互始于HTTP请求,该请求会通过HTTPUpgrade请求头去升级请求,进而切换到Websocket协议。我们可以看到在该请求报文中有两个特殊的请求头,一个是Upgrade请求头,代表升级为websocket协议。还有一个是Connection请求头,代表升级连接。_qwebsocket的唯一标识

随便推点

linux0.01源代码分析笔记_linux0.01源码分析-程序员宅基地

文章浏览阅读7.6k次,点赞6次,收藏45次。linux0.01(原始版)源代码分析笔记 1. 整体结构:第一个文件夹boot ,包含boot.s 和head.s 。boot.s 实现计算机加电自检引导扇区,第一次加载扇区和第二次加载操作系统的功能,head.s 主要包括初始设置的代码、时钟中断int 0x08的过程代码、系统调用中断int 0x80的过程代码以及任务A 和任务B 等的代码和数据。 (其中.S为扩展名的文件为汇编文件..._linux0.01源码分析

CAS-KG——知识推理_部分完整性假设-程序员宅基地

文章浏览阅读1.4k次,点赞2次,收藏19次。说明:CAS是国科大的简称,KG是知识图谱的缩写,这个栏目之下是我整理的国科大学习到的知识图谱的相关笔记。课程目标了解以知识图谱为代表的大数据知识工程的基本问题和方法掌握基于知识图谱的语义计算关键技术具备建立小型知识图谱并据此进行数据分析应用的能力教学安排详情请见博客:CAS-KG——课程安排文章目录..._部分完整性假设

Android trace文件分析小技巧-程序员宅基地

文章浏览阅读3.3k次。网上有很多trace文件分析博客,但是都是解释anr发生得原因,没有指导anr文件如何着手分析?本篇文章就是讲trace文件怎么切入?_android trace文件分析

特殊符号组成的图案_用符号拼出来的图案-程序员宅基地

文章浏览阅读6.4w次,点赞29次,收藏61次。在命令行利用特殊符号变成代码图案各位博客们大家好啊,初次与大家会面,我就以图案的形式跟大家见面,接下来我会经常更新我个人的博客,提一些经常用到的技术点,也希望能够帮助大家在工作以及学习中有很好的帮助,也可以偷偷关注我哦,谢谢你们!!!在Linux登录时,你是否也想设置你想要的图案字符显示,他来了是不是心动了,如果你也拥有自己的主机,那赶紧行动起来把修改他的方法来了,修改/etc/motd配置文件可显示你想要的东西复制下面的符号字符,粘贴到/etc/motd配置文件就可以实现哦!1、机器人 _用符号拼出来的图案

BZOJ 3439 Kpm的MC密码 Trie+可持久化线段树-程序员宅基地

文章浏览阅读932次。题目大意:定义一种串,如果一个串是另一个串的后缀,那么这个串称作kpm串。问一个串的标号第k大的kpm串是多少。思路:将所有的串翻转之后变成前缀,全都插进一个Trie树中。每个节点维护一个last指针,表示最后一次更新的可持久化线段树的指针,如果再有串经过这里,就继续更新last指针。最后只需要查询last指针中的东西就可以了。CODE:#include #inc

imagemagick 这个软件很难下载旧的版本_imagemagick7.10版本-程序员宅基地

文章浏览阅读43次。imagemagick 这个软件很难下载旧的版本_imagemagick7.10版本

推荐文章

热门文章

相关标签