写在前面

今天在做一个Android app时遇到了一个问题:Android端采用ASE对称加密的数据在JavaWeb(jre1.8.0_7)后台解密时,居然解密失败了!经过测试后发现,对相同的数据,采用相同的密钥加密时,得到的密文是不同的,而加密的代码是完全一样的,只是在加密最后,对加密结果进行Base64编码时,API的调用略有不同。

Android上,ASE加密是这样写的:

public static String aesEncrypt(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(encryptKey.getBytes()));
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
byte[] bs = cipher.doFinal(content.getBytes("utf-8"));
return Base64.encodeToString(bs, Base64.DEFAULT);
}

在普通JavaWeb上,ASE加密是这样写的:

public static String aesEncrypt(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(encryptKey.getBytes()));
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
return Base64.getEncoder().encodeToString(cipher.doFinal(content.getBytes("utf-8")));
}

最开始以为是二者Base64编码标准不同造成的,于是去了解了一下Base64编码的原理,但最终发现其实二者加密得到的byte数组就不同,估计是标准不同吧。

下面是对Base64编码的学习记录,以及用Java实现Base64编码,主要参考了程晓晖的博客。

什么是Base64编码

首先,我们知道,编码的目的一般是为了数据的压缩,再就是数据传输的需要。Base64编码的产生就是因为后者:有些网络传送渠道并不支持所有的字节的传输。Base64编码就是一种将二进制数据映射成一些可打印字符(或逆过来)的映射规则,具体的说是映射到[A-Za-z0-9+/]上。比如将字符"中国"映射成5Lit5Zu9,当然也可将图片或其他文件编码成类似上述的字符。

Base64编码的原理

其次,我们需要知道的是,在计算机的世界里,一切都是由01011...这样的二进制数组成的,包括一个字符串,一张图片或一些其他类型的文件。比如对于一个字符串"中",在Java里,我们可以调用"中".getBytes()来得到"中"对应的字节数组:[-28, -72, -83],再将字节数组中的每个数转换为二进制,连接起来便是其二进制表示了:1110 0100_1011 1000_1010 1101(为了便于阅读,用下滑线将每个字节分开。当然,采用不同的编码形式,得到的字节数组可能不同,此处采用的是utf-8编码)。对于文件,可以从其输入流读中取到。

因为字符集合[A-Za-z0-9+/]长度是64,可以与所有6位长的二进制数一一对应 ,于是Base64编码的做法就是,将待编码的所有二进制位每6位分为一组,然后将每组二进制数映射到字符集合中的一个字符,最后将这些映射的字符依次排列起来便得到了编码结果。当然,待编码的二进制位可能不能被6整除,即最终可能会剩余2个或4个二进制位不能构成一组,这时我们可以在其后添加4或2个0来凑成一组。

比如对于上述的字符串"中",其二进制为:1110 0100_1011 1000_1010 1101,我们每6位组成一组,得到:111001_001011_100010_101101,每组转换为十进制就是:57_11_34_45,在按顺序映射到字符集合[A-Za-z0-9+/]上,便得到其Base64编码为:5Lit。如果最后一组填充了0,则还需在编码后的字符串后加上=符号。

解码的过程就是编码过程的逆过程,这里不再赘述。

Base64编码的实现

下面给出Base64编码的实现(末尾未加=):

public static String base64Encode(String text) {
if (text == null) {
return null;
}
final String table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
byte[] textBytes = text.getBytes();
byte[] keyBytes = key.getBytes();
int remain = 0, remainBitCount = 0;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < textBytes.length; i++) {
int b = textBytes[i] & 0xFF;
// 获取b的高(6 - remainBitCount)位
int hight = b >>> (2 + remainBitCount) & 0xFF;
// 与上一轮的余留组合成一个字节
int curr = remain << (6 - remainBitCount) | hight;
// builder.append(table.charAt(curr));
builder.append(table.charAt(curr));
// 剩余b的低(2 + remainBitCount)位
remain = hight << (2 + remainBitCount) ^ b;
remainBitCount += 2;
// 若剩余的位刚好为6位,则进行编码
if (remainBitCount == 6) {
builder.append(table.charAt(remain));
remainBitCount = 0;
remain = 0;
}
}
if (remainBitCount != 0) {
// 多出的位到末尾补0凑够6位
builder.append(table.charAt(remain << (6 - remainBitCount)));
}
return builder.toString();
}
public static String base64Decode(String text) {
if (text == null) {
return text;
}
byte[] bs = new byte[text.length() * 6 / 8];
int pos = 0, remain = 0, remainBitCount = 0;
final String table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
for (int i = 0; i < text.length(); i++) {
int code = table.indexOf(text.charAt(i));
if (remainBitCount + 6 < 8) {
// 不足一个字节
remain = remain << 6 | code;
remainBitCount += 6;
} else {
// 足够一个字节,取code的高(8 - remainBitCount)位
int hight = code >>> (remainBitCount - 2) & 0xFF;
bs[pos] = (byte) (remain << (8 - remainBitCount) | hight);
pos++;
remainBitCount -= 2;
// 保留剩余的位
remain = hight << remainBitCount ^ code;
}
}
return new String(bs);
}

Base64编码的更多相关文章

  1. URL安全的Base64编码

    Base64编码可用于在HTTP环境下传递较长的标识信息.在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式.此时,采用Base64编码不仅比较简短,同时也具有不可 ...

  2. Android数据加密之Base64编码算法

    前言: 前面学习总结了平时开发中遇见的各种数据加密方式,最终都会对加密后的二进制数据进行Base64编码,起到一种二次加密的效果,其实呢Base64从严格意义上来说的话不是一种加密算法,而是一种编码算 ...

  3. 网络安全——Base64编码、MD5、SHA1-SHA512、HMAC(SHA1-SHA512)哈希

    据说今天520是个好日子,为什么我想起的是502.500.404这些?还好服务器没事! 一.Base64编码 Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之 ...

  4. Base64编码【转】

    转http://www.cnblogs.com/luguo3000/p/3940197.html 开发者对Base64编码肯定很熟悉,是否对它有很清晰的认识就不一定了.实际上Base64已经简单到不能 ...

  5. 【前端攻略】:玩转图片Base64编码

    引言 图片处理在前端工作中可谓占据了很重要的一壁江山.而图片的 base64 编码可能相对一些人而言比较陌生,本文不是从纯技术的角度去讨论图片的 base64 编码.标题略大,不过只是希望通过一些浅显 ...

  6. 为什么要用base64编码

    1.需求 了解为什么要使用base64对数据编码 2.理由 因为传输二进制数据的时候,网络中间的有些路由会把ascii码中的不可见字符删了,导致数据不一致.一般也会对url进行base64编码 Whe ...

  7. 图片Base64编码

    我们经常在做Jquery插件的时候需要插入一些自定义的控件,比如说按钮,而我们自己又觉着button标签很丑,而且不同浏览器显示的效果还不一样,这个时候我们需要用到图片,当然,我们可以通过img标签添 ...

  8. 浅析用Base64编码的图片优化网页加载速度

    想必大家都知道网页加载的过程,从开始请求,到加载页面,开始解析和显示网页,遇到图片就再次向服务器发送请求,加载图片.如果图片很多的话,就会产生大量的http请求,从而影响页面的加载速度.所以现在有一种 ...

  9. Base64编码原理分析

    Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,在了解Base64编码之前,先了解几个基本概念:位.字节. 位:"位(bit)"是计算机中最小的数据单位.每一位 ...

随机推荐

  1. ABP入门系列(1)——学习Abp框架之实操演练

    作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...

  2. ASP.NET Aries 入门开发教程9:业务表单的开发

    前言: 经过前面那么多篇的列表的介绍,终于到了大伙期待的表单开发了. 也是本系列的最后一篇文章了! 1:表单页面的权限设置与继承 对于表单页面,权限的设置有两种: 1:你可以选择添加菜单(设置为不显示 ...

  3. SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...

  4. spark处理大规模语料库统计词汇

    最近迷上了spark,写一个专门处理语料库生成词库的项目拿来练练手, github地址:https://github.com/LiuRoy/spark_splitter.代码实现参考wordmaker ...

  5. Twproject Gantt开源甘特图功能扩展

    1.Twproject Gantt甘特图介绍 Twproject Gantt 是一款基于 jQuery 开发的甘特图组件,也可以创建其它图表,例如任务树(Task Trees).内置编辑.缩放和 CS ...

  6. Asp.Net Core + Dapper + Repository 模式 + TDD 学习笔记

    0x00 前言 之前一直使用的是 EF ,做了一个简单的小项目后发现 EF 的表现并不是很好,就比如联表查询,因为现在的 EF Core 也没有啥好用的分析工具,所以也不知道该怎么写 Linq 生成出 ...

  7. 移动应用App测试与质量管理一

    测试工程师 基于Html的WebApp测试, 现在一些移动App混Html5 HTML5性能测试 兼容性 整理后的脑图 测试招聘 弱化大量技术考察 看重看问题的高度 看重潜力 测试经验 质量管理 专项 ...

  8. IOS开发基础知识--碎片51

    1:https关闭证书跟域名的验证 AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy]; securityPolic ...

  9. 【一起学OpenFoam】02 软件准备

    "工欲善其事必先利其器",在利用OpenFoam解决我们的工程问题之前,首先要做的事情是搭建一个OpenFoam运行环境.很遗憾的是,OpenFoam的原生开发系统是Linux,因 ...

  10. Hadoop

    Hadoop应用场景 Hadoop是专为离线处理和大规模数据分析而设计的,它并不适合那种对几个记录随机读写的在线事务处理模式. 大数据存储:Hadoop最适合一次写入.多次读取的数据存储需求,如数据仓 ...