Android DES加密解密

网上的demo一搜一大堆,但是,基本上都是一知半解(包括我)。为什么呢?我在尝试分别在两个平台加密的时候,竟然发现Android DES 加密和java DES加密的程序不能互通。就是加密的结果不一样,更不要说Android平台的加密输入作为java DES的解密输出了。这样的话,客户端和服务器端就不能进行通信了。我网上之前也发帖子问了不少人,但是回答都不满意。

今天部门的另外一个同事跟我说了一下,才解决了这个不能互通的问题。

调用DES加密算法包最精要的就是下面两句话:

Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);

CBC是工作模式,DES一共有电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB)四种模式,

PKCS5Padding是填充模式,还有其它的填充模式:

然后,cipher.init()一共有三个参数:Cipher.ENCRYPT_MODE, key, zeroIv,zeroIv就是初始化向量,一个8为字符数组。

工作模式、填充模式、初始化向量这三种因素一个都不能少。否则,如果你不指定的话,那么就要程序就要调用默认实现。问题就来了,这就与平台有关了。难怪网上一搜"DES加密结果不一致“,出现n多网页结果。(之前我并没有指定IV,被折磨了2周)

源程序如下(从java平台到android平台,我根本没有更改一行代码):

另外,一般情况下,加密后的结果都会用base64编码进行传输。

java平台:

主程序

public class testDES {

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		String key = "12345678";
		String text = "12345678";
		String result1 = DES.encryptDES(text,key);
		String result2 = DES.decryptDES(result1, key);
		System.out.println(result1);
		System.out.println(result2);
	}
}

用到的DES加密类
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DES {
	private static byte[] iv = {1,2,3,4,5,6,7,8};
	public static String encryptDES(String encryptString, String encryptKey) throws Exception {
//		IvParameterSpec zeroIv = new IvParameterSpec(new byte[8]);
		IvParameterSpec zeroIv = new IvParameterSpec(iv);
		SecretKeySpec key = new SecretKeySpec(encryptKey.getBytes(), "DES");
		Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
		byte[] encryptedData = cipher.doFinal(encryptString.getBytes());
	 
		return Base64.encode(encryptedData);
	}
	public static String decryptDES(String decryptString, String decryptKey) throws Exception {
		byte[] byteMi = new Base64().decode(decryptString);
		IvParameterSpec zeroIv = new IvParameterSpec(iv);
//		IvParameterSpec zeroIv = new IvParameterSpec(new byte[8]);
		SecretKeySpec key = new SecretKeySpec(decryptKey.getBytes(), "DES");
		Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
		cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
		byte decryptedData[] = cipher.doFinal(byteMi);
	 
		return new String(decryptedData);
	}
}

用到的BASE64工具类:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;



public class Base64 {
	private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
	/**
	 * data[]进行编码
	 * @param data
	 * @return
	 */
	    public static String encode(byte[] data) {
	        int start = 0;
	        int len = data.length;
	        StringBuffer buf = new StringBuffer(data.length * 3 / 2);

	        int end = len - 3;
	        int i = start;
	        int n = 0;

	        while (i <= end) {
	            int d = ((((int) data[i]) & 0x0ff) << 16)
	                    | ((((int) data[i + 1]) & 0x0ff) << 8)
	                    | (((int) data[i + 2]) & 0x0ff);

	            buf.append(legalChars[(d >> 18) & 63]);
	            buf.append(legalChars[(d >> 12) & 63]);
	            buf.append(legalChars[(d >> 6) & 63]);
	            buf.append(legalChars[d & 63]);

	            i += 3;

	            if (n++ >= 14) {
	                n = 0;
	                buf.append(" ");
	            }
	        }

	        if (i == start + len - 2) {
	            int d = ((((int) data[i]) & 0x0ff) << 16)
	                    | ((((int) data[i + 1]) & 255) << 8);

	            buf.append(legalChars[(d >> 18) & 63]);
	            buf.append(legalChars[(d >> 12) & 63]);
	            buf.append(legalChars[(d >> 6) & 63]);
	            buf.append("=");
	        } else if (i == start + len - 1) {
	            int d = (((int) data[i]) & 0x0ff) << 16;

	            buf.append(legalChars[(d >> 18) & 63]);
	            buf.append(legalChars[(d >> 12) & 63]);
	            buf.append("==");
	        }

	        return buf.toString();
	    }

	    private static int decode(char c) {
	        if (c >= 'A' && c <= 'Z')
	            return ((int) c) - 65;
	        else if (c >= 'a' && c <= 'z')
	            return ((int) c) - 97 + 26;
	        else if (c >= '0' && c <= '9')
	            return ((int) c) - 48 + 26 + 26;
	        else
	            switch (c) {
	            case '+':
	                return 62;
	            case '/':
	                return 63;
	            case '=':
	                return 0;
	            default:
	                throw new RuntimeException("unexpected code: " + c);
	            }
	    }

	    /**
	     * Decodes the given Base64 encoded String to a new byte array. The byte
	     * array holding the decoded data is returned.
	     */

	    public static byte[] decode(String s) {

	        ByteArrayOutputStream bos = new ByteArrayOutputStream();
	        try {
	            decode(s, bos);
	        } catch (IOException e) {
	            throw new RuntimeException();
	        }
	        byte[] decodedBytes = bos.toByteArray();
	        try {
	            bos.close();
	            bos = null;
	        } catch (IOException ex) {
	            System.err.println("Error while decoding BASE64: " + ex.toString());
	        }
	        return decodedBytes;
	    }

	    private static void decode(String s, OutputStream os) throws IOException {
	        int i = 0;

	        int len = s.length();

	        while (true) {
	            while (i < len && s.charAt(i) <= ' ')
	                i++;

	            if (i == len)
	                break;

	            int tri = (decode(s.charAt(i)) << 18)
	                    + (decode(s.charAt(i + 1)) << 12)
	                    + (decode(s.charAt(i + 2)) << 6)
	                    + (decode(s.charAt(i + 3)));

	            os.write((tri >> 16) & 255);
	            if (s.charAt(i + 2) == '=')
	                break;
	            os.write((tri >> 8) & 255);
	            if (s.charAt(i + 3) == '=')
	                break;
	            os.write(tri & 255);

	            i += 4;
	        }
	    }
	    
}

adnroid平台的主函数:
public class main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        String key = "12345678";
		String text = "12345678";
		
		
		try {
			String result1 = DES.encryptDES(text,key);
			String result2 = DES.decryptDES(result1, key);
			Log.i("DES encode text is ", result1);
			Log.i("DES encode text is ", result2);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}    
    }
}

通过查看log日志就可以看到结果。

两个平台的结果是一样的,都是:

加密结果:X2p9Uo45Tzk6Ntu6W7Ev+Q==
解密结果:12345678

 

 

 

 

 

 

 

最近做项目,需要加密Android客户端的一些sql语句,我当时使用的是DES加密的,结果加密出现了
1.javax.crypto.BadPaddingException: Given final block not properly padded 
这样的错误,要不就是出现乱码的问题,很纠结!当时查了一些资料,就有可能是密钥的问题或者编码的问题,检查了发现,密钥正确的,就是在创建Key 的时候,得到的byte[]数组有一些处理的,具体完整的代码如下:

1.package com.spring.sky.util;  
2.  
3.import java.io.BufferedReader;  
4.import java.io.BufferedWriter;  
5.import java.io.FileInputStream;  
6.import java.io.FileNotFoundException;  
7.import java.io.FileOutputStream;  
8.import java.io.IOException;  
9.import java.io.InputStream;  
10.import java.io.InputStreamReader;  
11.import java.io.OutputStream;  
12.import java.security.Key;  
13.  
14.import javax.crypto.Cipher;  
15.import javax.crypto.CipherInputStream;  
16.import javax.crypto.spec.SecretKeySpec;  
17.  
18.import org.apache.http.entity.InputStreamEntity;  
19.  
20./*** 
21. * DES文件加密&解密  <br> 
22. * 可以实现android和window的文件互通  
23. * @author spring.sky 
24. * Email:vipa1888@163.com 
25. * QQ:840950105 
26. * 
27. */  
28.public class FileDES {  
29.    /**加密解密的key*/  
30.    private Key mKey;  
31.    /**解密的密码*/  
32.    private Cipher mDecryptCipher;  
33.    /**加密的密码*/  
34.    private Cipher mEncryptCipher;  
35.    public FileDES(String key) throws Exception  
36.    {  
37.        initKey(key);  
38.        initCipher();  
39.    }  
40.      
41.    /** 
42.     * 创建一个加密解密的key 
43.     * @param keyRule  
44.     */  
45.    public void initKey(String keyRule) {  
46.        byte[] keyByte = keyRule.getBytes();  
47.        // 创建一个空的八位数组,默认情况下为0   
48.        byte[] byteTemp = new byte[8];  
49.        // 将用户指定的规则转换成八位数组   
50.        for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {  
51.            byteTemp[i] = keyByte[i];  
52.        }  
53.        mKey = new SecretKeySpec(byteTemp, "DES");  
54.    }  
55.      
56.    /*** 
57.     * 初始化加载密码 
58.     * @throws Exception 
59.     */  
60.    private void initCipher() throws Exception  
61.    {  
62.        mEncryptCipher = Cipher.getInstance("DES");  
63.        mEncryptCipher.init(Cipher.ENCRYPT_MODE, mKey);  
64.          
65.        mDecryptCipher = Cipher.getInstance("DES");  
66.        mDecryptCipher.init(Cipher.DECRYPT_MODE, mKey);  
67.    }  
68.      
69.    /** 
70.     * 加密文件 
71.     * @param in 
72.     * @param savePath 加密后保存的位置 
73.     */  
74.    public void doEncryptFile(InputStream in,String savePath)  
75.    {  
76.        if(in==null)  
77.        {  
78.            System.out.println("inputstream is null");  
79.            return;  
80.        }  
81.        try {  
82.            CipherInputStream cin = new CipherInputStream(in, mEncryptCipher);  
83.            OutputStream os = new FileOutputStream(savePath);  
84.            byte[] bytes = new byte[1024];  
85.            int len = -1;  
86.            while((len=cin.read(bytes))>0)  
87.            {  
88.                os.write(bytes, 0, len);  
89.                os.flush();  
90.            }  
91.            os.close();  
92.            cin.close();  
93.            in.close();  
94.            System.out.println("加密成功");  
95.        } catch (Exception e) {  
96.            System.out.println("加密失败");  
97.            e.printStackTrace();  
98.        }  
99.    }  
100.      
101.    /** 
102.     * 加密文件 
103.     * @param filePath 需要加密的文件路径 
104.     * @param savePath 加密后保存的位置 
105.     * @throws FileNotFoundException  
106.     */  
107.    public void doEncryptFile(String filePath,String savePath) throws FileNotFoundException  
108.    {  
109.        doEncryptFile(new FileInputStream(filePath), savePath);  
110.    }  
111.      
112.      
113.    /** 
114.     * 解密文件 
115.     * @param in 
116.     */  
117.    public void doDecryptFile(InputStream in)  
118.    {  
119.        if(in==null)  
120.        {  
121.            System.out.println("inputstream is null");  
122.            return;  
123.        }  
124.        try {  
125.            CipherInputStream cin = new CipherInputStream(in, mDecryptCipher);  
126.            BufferedReader reader = new BufferedReader(new InputStreamReader(cin)) ;  
127.            String line = null;  
128.            while((line=reader.readLine())!=null)  
129.            {  
130.                System.out.println(line);  
131.            }  
132.            reader.close();  
133.            cin.close();  
134.            in.close();  
135.            System.out.println("解密成功");  
136.        } catch (Exception e) {  
137.            System.out.println("解密失败");  
138.            e.printStackTrace();  
139.        }  
140.    }  
141.    /** 
142.     * 解密文件 
143.     * @param filePath  文件路径 
144.     * @throws Exception 
145.     */  
146.    public void doDecryptFile(String filePath) throws Exception  
147.    {  
148.        doDecryptFile(new FileInputStream(filePath));  
149.    }  
150.      
151.      
152.    public static void main(String[] args)throws Exception {  
153.        FileDES fileDES = new FileDES("spring.sky");  
154.        fileDES.doEncryptFile("d:/a.txt", "d:/b");  //加密   
155.        fileDES.doDecryptFile("d:/b"); //解密   
156.    }  
157.      
158.} 
上面的代码,我分别在android 1.6和java平台上面测试通过了,没任何问题的,只是根据不同的需求做一下封装,希望对大家有帮忙,让大家少走弯路!

本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2012-05/60017.htm

 

 

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值