解决IllegalBlockSizeException:last block incomplete in decryption异常
分类: webkit android
最近做个加解密的实现,虽然实现了,但是发现还有如下的异常出现:
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711)
at javax.crypto.Cipher.doFinal(Cipher.java:1090)

问题原因:
可能是因为直接将一个string的byte []字符串直接加密成密文,在传输过程中,由于默认的编码方式的问题可能会造成数据的丢失。(如果有更好的解释,欢迎指出)
解决方法:
将加密后的密文再进行整体的base64加密,解码时先对其进行base64解密再进DES/AES解密,这样就能保证接受数据的正确性并且不会缺失。

Base64Utils加密工具

package test;
import it.sauronsoftware.base64.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
/** *//**
* <p>
* BASE64编码解码工具包
* </p>
* <p>
* 依赖javabase64-1.3.1.jar
* </p>
*
* @author IceWee
* @date 2012-5-19
* @version 1.0
*/
public class Base64Utils {
private static String SF_DF_BASE64= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";//自定义时解码使用
/** *//**
* 文件读取缓冲区大小
*/
private static final int CACHE_SIZE = 1024; /** *//**
* <p>
* BASE64字符串解码为二进制数据
* </p>
*
* @param base64
* @return
* @throws Exception
*/
public static byte[] decode(String base64) throws Exception {
return Base64.decode(base64.getBytes());
}
/**
* 自定义的解码实现
* @param base64
* @return
* @throws Exception
*/
public static byte[] selfDecode1(String base64)throws Exception {
int n,i,j,pad;
byte [] dst;
char [] src;
int len = 0;
pad=0;
n = base64.length();
src = new char [n];
for(i=0;i<n;i++){//复制到src中
src[i] = base64.charAt(i);
}
while(n>0&&src[n-1]=='=') {
src[n-1]=0;
pad++;
n--;
} for(i=0;i<n;i++) { //map base64 ASCII character to 6 bit value
int iTt = SF_DF_BASE64.indexOf(src[i]);
if(iTt<0)
break;
src[i] = (char)iTt;
}
dst = new byte[n*3/4+1];
for(i=0,j=0;i<n;i+=4,j+=3) {
dst[j] = (byte)((src[i]<<2) + ((src[i+1]&0x30)>>4));
dst[j+1] = (byte)(((src[i+1]&0x0F)<<4) + ((src[i+2]&0x3C)>>2));
dst[j+2] = (byte)(((src[i+2]&0x03)<<6) + src[i+3]);
len+=3;
}
len-=pad;
return dst;
}
/** *//**
* <p>
* 二进制数据编码为BASE64字符串
* </p>
*
* @param bytes
* @return
* @throws Exception
*/
public static String encode(byte[] bytes) throws Exception {
return new String(Base64.encode(bytes));
} /** *//**
* <p>
* 二进制数据编码为BASE64字符串
* </p>
*
* @param buf
* @return
* @throws Exception
*/
public static String selfEncode1(byte[] buf) throws Exception {
int n,buflen,i,j;
byte []dst = null;
//CString buf = src;
buflen=n=buf.length;
dst = new byte[buflen/3*4+3];
for(i=0,j=0;i<=buflen-3;i+=3,j+=4) {
dst[j] = (byte)((buf[i]&0xFC)>>2);
dst[j+1] = (byte)(((buf[i]&0x03)<<4) + ((buf[i+1]&0xF0)>>4));
dst[j+2] = (byte)(((buf[i+1]&0x0F)<<2) + ((buf[i+2]&0xC0)>>6));
dst[j+3] = (byte)(buf[i+2]&0x3F);
}
if(n%3==1) {
dst[j] = (byte)((buf[i]&0xFC)>>2);
dst[j+1] = (byte)(((buf[i]&0x03)<<4));
dst[j+2]=64;
dst[j+3]=64;
j+=4;
}
else if(n%3==2) {
dst[j] = (byte)((buf[i]&0xFC)>>2);
dst[j+1] = (byte)(((buf[i]&0x03)<<4)+((buf[i+1]&0xF0)>>4));
dst[j+2] = (byte)(((buf[i+1]&0x0F)<<2));
dst[j+3]=64;
j+=4;
}
for(i=0;i<j;i++) /* map 6 bit value to base64 ASCII character */
dst[i] = (byte)SF_DF_BASE64.charAt((int)dst[i]);
dst[j]=0;
return new String(dst);
} /** *//**
* <p>
* 将文件编码为BASE64字符串
* </p>
* <p>
* 大文件慎用,可能会导致内存溢出
* </p>
*
* @param filePath 文件绝对路径
* @return
* @throws Exception
*/
public static String encodeFile(String filePath) throws Exception {
byte[] bytes = fileToByte(filePath);
return encode(bytes);
} /** *//**
* <p>
* BASE64字符串转回文件
* </p>
*
* @param filePath 文件绝对路径
* @param base64 编码字符串
* @throws Exception
*/
public static void decodeToFile(String filePath, String base64) throws Exception {
byte[] bytes = decode(base64);
byteArrayToFile(bytes, filePath);
} /** *//**
* <p>
* 文件转换为二进制数组
* </p>
*
* @param filePath 文件路径
* @return
* @throws Exception
*/
public static byte[] fileToByte(String filePath) throws Exception {
byte[] data = new byte[0];
File file = new File(filePath);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
data = out.toByteArray();
}
return data;
} /** *//**
* <p>
* 二进制数据写文件
* </p>
*
* @param bytes 二进制数据
* @param filePath 文件生成目录
*/
public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
InputStream in = new ByteArrayInputStream(bytes);
File destFile = new File(filePath);
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
destFile.createNewFile();
OutputStream out = new FileOutputStream(destFile);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
} // 加密
public static String getBase64(String str) {
byte[] b = null;
String s = null;
try {
b = str.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (b != null) {
s = new BASE64Encoder().encode(b);
}
return s;
} // 解密
public static String getFromBase64(String s) {
byte[] b = null;
String result = null;
if (s != null) {
BASE64Decoder decoder = new BASE64Decoder();
try {
b = decoder.decodeBuffer(s);
result = new String(b, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
} }

TestWebService

package test;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; 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;
import javax.jws.WebService;
import javax.xml.ws.Endpoint; @WebService
public class TestWebService { //解密
public String executeDe(String content){ String password = "1234567890123456";
byte[] decryptResult;
String decrypt;
try {
//base64解密(后加!!)
String decodeBase64 = Base64Utils.getFromBase64(content); decryptResult = Base64Utils.decode(decodeBase64);
decrypt = new String(decrypt(decryptResult,password,16));
return decrypt;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
} return null;
} //加密
public String executeEn(String content){ System.out.println(System.getProperty("file.encoding"));
//加密内容
//String content = "密码学中的高级加密标准(AdvancedEncryptionStandard,AES)";
//String content = "rowvin";
//String content = "test123456";
//为与Delphi编码统一,将字符转为UTF8编码(其他语言也相同)
//String ss=new String(content.getBytes(),"UTF-8");
//密钥
String password = "1234567890123456";
System.out.println("加密前:" + content);
byte[] encryptResult;
String encrypt;
try {
encryptResult = encrypt(content, password,16);//16位密钥长度128位、24位密钥长度192、32位密钥长度256(在delphi中对应kb128、kb192、快播56)
//System.out.println("加密后:" + parseByte2HexStr(encryptResult));//将加密后编码二进制转为16进制编码
System.out.println(Base64Utils.encode(encryptResult));//二进制转Hbase64
encrypt = Base64Utils.encode(encryptResult);
//base64加密(后加!)
String encodeAfterBase64 = Base64Utils.getBase64(encrypt);
StringBuffer AesBuff = new StringBuffer(); /*decrypt = new String(decrypt(encryptResult,password,16));
System.out.println("解密后:" + decrypt);*/
AesBuff.append("{");
AesBuff.append("\"encrypt\":" + "\"" + encrypt + "\",");
AesBuff.append("\"encodeAfterBase64\":" + "\"" + encodeAfterBase64 + "\"}");
//System.out.println(json.toString());
return AesBuff.toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
} return null;
} /**
* 加密
*
* @param content 需要加密的内容
* @param password 加密密码
* @param keySize 密钥长度16,24,32
* @return
* @throws UnsupportedEncodingException
* @throws InvalidAlgorithmParameterException
*/ public byte[] encrypt(String content, String password, int keySize) throws UnsupportedEncodingException, InvalidAlgorithmParameterException {
try {
//密钥长度不够用0补齐。
SecretKeySpec key = new SecretKeySpec(ZeroPadding(password.getBytes(), keySize), "AES");
//定义加密算法AES、算法模式ECB、补码方式PKCS5Padding
//Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//定义加密算法AES 算法模式CBC、补码方式PKCS5Padding
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//CBC模式模式下初始向量 不足16位用0补齐
IvParameterSpec iv = new IvParameterSpec(ZeroPadding("1234567890123456".getBytes(),16));
byte[] byteContent = content.getBytes();
//初始化加密
//ECB
//cipher.init(Cipher.ENCRYPT_MODE, key);
//CBC
cipher.init(Cipher.ENCRYPT_MODE, key,iv);
byte[] result = cipher.doFinal(byteContent);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
} /**解密
* @param content 待解密内容
* @param password 解密密钥
* @param keySize 密钥长度16,24,32
* @return
* @throws InvalidAlgorithmParameterException
*/
public byte[] decrypt(byte[] content, String password, int keySize) throws InvalidAlgorithmParameterException {
try {
//密钥长度不够用0补齐。
SecretKeySpec key = new SecretKeySpec(ZeroPadding(password.getBytes(), keySize), "AES");
//定义加密算法AES、算法模式ECB、补码方式PKCS5Padding
//Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//定义加密算法AES 算法模式CBC、补码方式PKCS5Padding
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//CBC模式模式下初始向量 不足16位用0补齐
IvParameterSpec iv = new IvParameterSpec(ZeroPadding("1234567890123456".getBytes(),16));
// 初始化解密
//ECB
//cipher.init(Cipher.DECRYPT_MODE, key);
//CBC
cipher.init(Cipher.DECRYPT_MODE, key,iv); byte[] result = cipher.doFinal(content);
return result; } catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
} /**将二进制转换成16进制
* @param buf
* @return
*/
public 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
*/
public 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;
} public byte[] ZeroPadding(byte[] in,Integer blockSize){
Integer copyLen = in.length;
if (copyLen > blockSize) {
copyLen = blockSize;
}
byte[] out = new byte[blockSize];
System.arraycopy(in, 0, out, 0, copyLen);
return out;
} public static void main(String[] args) {
Endpoint.publish("http://10.80.3.51:9999/Service/TestWebService", new TestWebService());
System.out.println("服务已启动~~~~");
} }

解决IllegalBlockSizeException:last block incomplete in decryption异常的更多相关文章

  1. 如何解决结果由block返回情况下的同步问题(转)

    开发中经常会遇到一种简单的同步问题: 系统在获取资源时,采用了block写法,外部逻辑需要的结果是在block回调中返回的 举个例子: 请求获取通讯录权限的系统弹窗 调用系统方法请求通讯录权限: AB ...

  2. CSS开发技巧(四):解决flex多行布局的行间距异常、子元素高度拉伸问题

    在使用flex布局时,若出现换行,有两种较为特殊的现象是值得我们研究的: 子元素高度被拉伸,其实际高度大于它的内容高度. 各行子元素之间的行间距过大,甚至我们根本没有给子元素设置margin. 现在我 ...

  3. .NET WebAPI 自定义 NullableConverter 解决请求入参 “”空字符触发转换异常问题

    最近在项目中启用了Nullable 可为空的类型,这个特性确实很好用,在 WebAPI 的入参上可以直接采用 ? 来标记一个字段是否允许为空,但是使用过程中遇到了如下一个问题,比如创建部门接口 我们定 ...

  4. 使用AFNetworking时, 控制器点击返回销毁了, 但还是会执行请求成功或失败的block, 导致野指针异常

    原本我以为是我程序框架有问题...后来才知道, 无知真可怕... __unsafe_unretained __block typeof(self) weakSelf = self; AFHTTPSes ...

  5. 解决Entity Framework中DateTime类型字段异常

    从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值 具体的错误原因是:C#中的DateTime类型比SqlServer中的datetime范围大.SqlServe ...

  6. 解决eclipse报PermGen space内存溢出异常的问题

    异常问题如下所示: 1.点击Eclipse->Window->Preferences,如下所示: 2.点击Server->Runtime Environments,选择Apache ...

  7. hadoop异常: 到目前为止解决的最牛逼的一个异常(java.io.IOException: Incompatible clusterIDs)

    (注意: 本人用的版本为hadoop2.2.0, 旧的版本和此版本的解决方法不同) 异常为: 9 (storage id DS-2102177634-172.16.102.203-50010-1384 ...

  8. 解决Kubelet Pod启动CreatePodSandbox或RunPodSandbox异常方法

    新装Kubernetes,创建一个新Pod,启动Pod遇到CreatePodSandbox或RunPodSandbox异常.查看日志 # journalctl --since :: -u kubele ...

  9. 【手记】解决“未能创建 SSL/TLS 安全通道”异常

    之前写了一个桌面程序,程序会间歇性访问某个https接口,一直用的好好的,今天突然报错了,异常就发生在访问接口的地方,曰“请求被中止,未能创建 SSL/TLS 安全通道.”,另外有台电脑也有跑该程序, ...

随机推荐

  1. hoj2188 WordStack

    WordStack My Tags   (Edit)   Source : Mid-Atlantic 2005   Time limit : 5 sec   Memory limit : 32 M S ...

  2. Ruby对象模型总结

    参考<Ruby元编程>,元编程,即 用来编写代码的代码 . 对象由一组实例变量和一个类的引用组成 对象的方法存在与对象所属的类中,类似js中的prototype,在ruby中准确的说,应该 ...

  3. iOS集成支付宝支付

    本文由本人原创发表于博客园,转载请注明出处 http://www.cnblogs.com/wangqw/p/5074907.html 一. 开发前准备 iOS 支付宝SDK下载地址:(内含iOS An ...

  4. 51 Nod 1640 天气晴朗的魔法( Kruskall )

    #include <bits/stdc++.h> typedef long long LL; using namespace std; ; struct node{ LL u,v,w; n ...

  5. NET4.5中的Task.Run及Task.Delay方法

  6. VLAN-3-VLAN Trunk:ISL和802.1Q

      (1)ISL和802.1Q概念       通过使用VLAN Trunk链路,设备可以通过一条链路发送去往多个vlan的流量.为了知道数据帧属于哪个vlan,发送方会添加原始以太网数据帧的头部,这 ...

  7. Python及bs4、lxml、numpy模块包的安装

    http://blog.csdn.net/tiantiancsdn/article/details/51046490(转载) Python及bs4.lxml.numpy模块包的安装 Python 的安 ...

  8. [題解]51nod_1515_明辨是非

    好久沒有話多了,是覺得有點浪費時間,今天考試和一中用的一樣的題,結果反而考得不好,不過Jackpei一句知恥而後勇點醒夢中人偷偷@Jackpei 就是這樣吧 還有我極度懷疑我的鍵帽打油了......我 ...

  9. DRF教程6-分页

    rest框架提供自定义分页样式,让你修改再每个页面上显示多少条数据, pagination API 可以: 分页链接作为响应内容的一部分 分页链接包含在响应头里,比如Content-Range or  ...

  10. Django quick tutorial

    --第一部分,快速开始-- 01. Django简介