zoukankan      html  css  js  c++  java
  • 解决IllegalBlockSizeException:last block incomplete in decryption异常

    解决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("服务已启动~~~~");
        }
        
    }
  • 相关阅读:
    react 全局监听报错,监听白屏
    【Python】(八)Python中的set集合(每个人都是唯一的个体)
    【Python】(六)Python数据类型-列表和元组,九浅一深,用得到
    mybatis-spring多数据源配置
    自己动手实现springboot运行时新增/更新外部接口
    自己动手实现springboot运行时执行java源码(运行时编译、加载、注册bean、调用)
    自己动手实现java断点/单步调试(一)
    自己动手实现java断点/单步调试(二)
    Swift 模式下面LLDB 输出对象
    Understanding Swift’s value type thread safety
  • 原文地址:https://www.cnblogs.com/yaomajor/p/6292758.html
Copyright © 2011-2022 走看看