解決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解密,這樣就能保證接受數據的正確性而且不會缺失。java

Base64Utils加密工具android

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;  
    } 
    
}

TestWebServiceweb

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位密鑰長度19二、32位密鑰長度256(在delphi中對應kb12八、kb19二、快播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("服務已啓動~~~~");
    }
    
}
相關文章
相關標籤/搜索