Android移动开发-Android数据加密与解密的实现

来源:互联网 发布:看板设计软件 编辑:程序博客网 时间:2024/05/29 09:24

数据的安全是非常重要的,现在无论干什么都要账号和密码,一旦账号与密码泄露出去必将造成财产的损失,所以做好数据保密是非常重要的。
Android加密算法有多种多样,常见的有MD5、RSA、AES、3DES四种。

  • MD5加密:

MD5是不可逆的加密算法,也就是无法解密,主要用于客户端的用户密码加密。MD5算法加密代码如下:

  • 定义工具类MD5Util.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;public class MD5Util {    //首先初始化一个MessageDigest对象,该对象通过update方法获取原始数据,    //并调用digest方法完成哈希计算,然后把字节数组逐位转换为十六进制数,最后拼装加密字符串    public static String encrypBy(String raw) {        String md5Str = raw;        try {            MessageDigest md = MessageDigest.getInstance("MD5");            md.update(raw.getBytes());            byte[] encryContext = md.digest();            int i;            StringBuffer buf = new StringBuffer("");            for (int offset = 0; offset < encryContext.length; offset++) {                i = encryContext[offset];                if (i < 0) {                    i += 256;                }                if (i < 16) {                    buf.append("0");                }                buf.append(Integer.toHexString(i));            }            md5Str = buf.toString();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        }        return md5Str;    }}

无论原始字符串是什么,MD5算法的加密串都是32位的十六进制字符串。

  • RSA加密:

RSA算法在客户端使用公钥加密,在服务端使用私钥解密。这样一来,即使加密的公钥被泄露,没有私钥仍然无法解密。(注意:使用RSA加密之前必须在AndroidStudio的libs目录下导入bcprov-jdk的jar包)RSA算法的加密代码如下:

  • 定义工具类RSAUtil.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;import com.fukaimei.encryptiontest.util.tool.ConvertBytesToBase64;import java.io.ByteArrayOutputStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.math.BigInteger;import java.net.URLDecoder;import java.net.URLEncoder;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.SecureRandom;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.InvalidKeySpecException;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.RSAPrivateKeySpec;import java.security.spec.RSAPublicKeySpec;import java.security.spec.X509EncodedKeySpec;import javax.crypto.Cipher;//RSA 工具类。提供加密,解密,生成密钥对等方法。public class RSAUtil {    private static final String TAG = "RSAUtil";    private static final String Algorithm = "RSA";//  private static String RSAKeyStore = "E:/RSAKey.txt";////  //生成密钥对//  private static KeyPair generateKeyPair() throws Exception {//      try {//          KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(Algorithm,//                  new org.bouncycastle.jce.provider.BouncyCastleProvider());//          // 这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会降低//          final int KEY_SIZE = 1024;//          keyPairGen.initialize(KEY_SIZE, new SecureRandom());//          KeyPair keyPair = keyPairGen.generateKeyPair();//          saveKeyPair(keyPair);//          return keyPair;//      } catch (Exception e) {//          throw new Exception(e.getMessage());//      }//  }////  private static KeyPair getKeyPair() throws Exception {//      FileInputStream fis = new FileInputStream(RSAKeyStore);//      ObjectInputStream oos = new ObjectInputStream(fis);//      KeyPair kp = (KeyPair) oos.readObject();//      oos.close();//      fis.close();//      return kp;//  }////  private static void saveKeyPair(KeyPair kp) throws Exception {//      FileOutputStream fos = new FileOutputStream(RSAKeyStore);//      ObjectOutputStream oos = new ObjectOutputStream(fos);//      oos.writeObject(kp);//      oos.close();//      fos.close();//  }////  //生成公钥//  private static RSAPublicKey generateRSAPublicKey(byte[] modulus,//          byte[] publicExponent) throws Exception {//      KeyFactory keyFac = null;//      try {//          keyFac = KeyFactory.getInstance(Algorithm,//                  new org.bouncycastle.jce.provider.BouncyCastleProvider());//      } catch (NoSuchAlgorithmException ex) {//          throw new Exception(ex.getMessage());//      }////      RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(//              modulus), new BigInteger(publicExponent));//      try {//          return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);//      } catch (InvalidKeySpecException ex) {//          throw new Exception(ex.getMessage());//      }//  }////  //生成私钥//  private static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,//          byte[] privateExponent) throws Exception {//      KeyFactory keyFac = null;//      try {//          keyFac = KeyFactory.getInstance(Algorithm,//                  new org.bouncycastle.jce.provider.BouncyCastleProvider());//      } catch (NoSuchAlgorithmException ex) {//          throw new Exception(ex.getMessage());//      }////      RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(//              modulus), new BigInteger(privateExponent));//      try {//          return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);//      } catch (InvalidKeySpecException ex) {//          throw new Exception(ex.getMessage());//      }//  }////  // 通过公钥byte[]将公钥还原,适用于RSA算法//  private static PublicKey getPublicKey(byte[] keyBytes)//          throws NoSuchAlgorithmException, InvalidKeySpecException {//      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);//      KeyFactory keyFactory = KeyFactory.getInstance(Algorithm);//      PublicKey publicKey = keyFactory.generatePublic(keySpec);//      return publicKey;//  }////  // 通过私钥byte[]将公钥还原,适用于RSA算法//  private static PrivateKey getPrivateKey(byte[] keyBytes)//          throws NoSuchAlgorithmException, InvalidKeySpecException {//      PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);//      KeyFactory keyFactory = KeyFactory.getInstance(Algorithm);//      PrivateKey privateKey = keyFactory.generatePrivate(keySpec);//      return privateKey;//  }    //加密    private static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {        try {            Cipher cipher = Cipher.getInstance(Algorithm,                    new org.bouncycastle.jce.provider.BouncyCastleProvider());            cipher.init(Cipher.ENCRYPT_MODE, pk);            int blockSize = cipher.getBlockSize();            int outputSize = cipher.getOutputSize(data.length);            int leavedSize = data.length % blockSize;            int blocksSize = leavedSize != 0 ? data.length / blockSize + 1                    : data.length / blockSize;            byte[] raw = new byte[outputSize * blocksSize];            int i = 0;            while (data.length - i * blockSize > 0) {                if (data.length - i * blockSize > blockSize) {                    cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);                } else {                    cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);                }                i++;            }            return raw;        } catch (Exception e) {            throw new Exception(e.getMessage());        }    }    //解密    private static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {        try {            Cipher cipher = Cipher.getInstance(Algorithm,                    new org.bouncycastle.jce.provider.BouncyCastleProvider());            cipher.init(cipher.DECRYPT_MODE, pk);            int blockSize = cipher.getBlockSize();            ByteArrayOutputStream bout = new ByteArrayOutputStream(64);            int j = 0;            while (raw.length - j * blockSize > 0) {                bout.write(cipher.doFinal(raw, j * blockSize, blockSize));                j++;            }            return bout.toByteArray();        } catch (Exception e) {            throw new Exception(e.getMessage());        }    }    // 使用N、e值还原公钥    private static PublicKey getPublicKey(String modulus, String publicExponent, int radix)            throws NoSuchAlgorithmException, InvalidKeySpecException {        BigInteger bigIntModulus = new BigInteger(modulus, radix);        BigInteger bigIntPrivateExponent = new BigInteger(publicExponent, radix);        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus,                bigIntPrivateExponent);        KeyFactory keyFactory = KeyFactory.getInstance("RSA");        PublicKey publicKey = keyFactory.generatePublic(keySpec);        return publicKey;    }    // 使用N、d值还原私钥    private static PrivateKey getPrivateKey(String modulus, String privateExponent, int radix)            throws NoSuchAlgorithmException, InvalidKeySpecException {        BigInteger bigIntModulus = new BigInteger(modulus, radix);        BigInteger bigIntPrivateExponent = new BigInteger(privateExponent, radix);        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(bigIntModulus,                bigIntPrivateExponent);        KeyFactory keyFactory = KeyFactory.getInstance("RSA");        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);        return privateKey;    }    //加密函数    public static String encodeRSA(RSAKeyData key_data, String src) {        if (key_data == null) {            //默认的密钥对            key_data = new RSAKeyData();            key_data.public_key = "10001";            key_data.private_key = "";            key_data.modulus = "c7f668eccc579bb75527424c21be31c104bb44c921b4788ebc82cddab5042909eaea2dd706431531392d79890f9091e13714285a7e79e9d1836397f847046ef2519c9b65022b48bf157fe409f8a42155734e65467d04ac844dfa0c2ae512517102986ba9b62d67d4c920eae40b2f11c363b218a703467d342faa81719f57e2c3";            key_data.radix = 16;        }        try {            PublicKey key = getPublicKey(key_data.modulus, key_data.public_key, key_data.radix);            String rev = encodeURL(new StringBuilder(src).reverse().toString());            byte[] en_byte = encrypt(key, rev.getBytes());            String base64 = encodeURL(ConvertBytesToBase64.BytesToBase64String(en_byte));            return base64;        } catch (Exception e) {            e.printStackTrace();            return "RSA加密失败";        }    }    //URL编码    private static String encodeURL(String str) {        String encode_str = str;        try {            encode_str = URLEncoder.encode(str, "utf-8");        } catch (Exception e) {            e.printStackTrace();        }        return encode_str;    }    //URL解码    private static String decodeURL(String str) {        String decode_str = str;        try {            decode_str = URLDecoder.decode(str, "utf-8");        } catch (Exception e) {            e.printStackTrace();        }        return decode_str;    }    public static class RSAKeyData {        public String modulus;        public String public_key;        public String private_key;        public int radix;        public RSAKeyData() {            modulus = "";            public_key = "";            private_key = "";            radix = 0;        }    }}

RSA算法加密结果是经过URL编码的字符串。

  • AES加密:

AES是设计用来替换DES的高级加密算法。下面是AES算法加密和解密的代码:

  • 定义工具类AesUtil.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;import java.security.SecureRandom;import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;public class AesUtil {    private static final String Algorithm = "AES";    private final static String HEX = "0123456789ABCDEF";    //加密函数,key为密钥    public static String encrypt(String key, String src) throws Exception {        byte[] rawKey = getRawKey(key.getBytes());        byte[] result = encrypt(rawKey, src.getBytes());        return toHex(result);    }    //解密函数。key值必须和加密时的key一致    public static String decrypt(String key, String encrypted) throws Exception {        byte[] rawKey = getRawKey(key.getBytes());        byte[] enc = toByte(encrypted);        byte[] result = decrypt(rawKey, enc);        return new String(result);    }    private static void appendHex(StringBuffer sb, byte b) {        sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));    }    private static byte[] getRawKey(byte[] seed) throws Exception {        KeyGenerator kgen = KeyGenerator.getInstance(Algorithm);        // SHA1PRNG 强随机种子算法, 要区别Android 4.2.2以上版本的调用方法        SecureRandom sr = null;        if (android.os.Build.VERSION.SDK_INT >= 17) {            sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");        } else {            sr = SecureRandom.getInstance("SHA1PRNG");        }        sr.setSeed(seed);        kgen.init(256, sr); // 256位或128位或192位        SecretKey skey = kgen.generateKey();        byte[] raw = skey.getEncoded();        return raw;    }    private static byte[] encrypt(byte[] key, byte[] src) throws Exception {        SecretKeySpec skeySpec = new SecretKeySpec(key, Algorithm);        Cipher cipher = Cipher.getInstance(Algorithm);        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);        byte[] encrypted = cipher.doFinal(src);        return encrypted;    }    private static byte[] decrypt(byte[] key, byte[] encrypted) throws Exception {        SecretKeySpec skeySpec = new SecretKeySpec(key, Algorithm);        Cipher cipher = Cipher.getInstance(Algorithm);        cipher.init(Cipher.DECRYPT_MODE, skeySpec);        byte[] decrypted = cipher.doFinal(encrypted);        return decrypted;    }    private static byte[] toByte(String hexString) {        int len = hexString.length() / 2;        byte[] result = new byte[len];        for (int i = 0; i < len; i++) {            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();        }        return result;    }    private static String toHex(byte[] buf) {        if (buf == null) {            return "";        }        StringBuffer result = new StringBuffer(2 * buf.length);        for (int i = 0; i < buf.length; i++) {            appendHex(result, buf[i]);        }        return result.toString();    }}

AES算法是可逆算法,支持对加密字符串进行解密,前提是解密时密钥必须与加密时一致。

  • 3DES加密:

3DES(Triple DES)是三重数据加密算法,相当于对每个数据块应用3次DES加密算法。因为原先DES算法的密钥长度过短,容易遭到暴力破解,所以3DES算法通过增加密钥的长度防范加密数据被破解。该算法的加密和解密代码如下:

  • 定义工具类Des3Util.java逻辑代码如下:
package com.fukaimei.encryptiontest.util;import com.fukaimei.encryptiontest.util.base64.BASE64Decoder;import com.fukaimei.encryptiontest.util.base64.BASE64Encoder;import java.io.IOException;import java.io.UnsupportedEncodingException;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;public class Des3Util {    // 定义加密算法,DESede即3DES      private static final String Algorithm = "DESede";    //加密函数。key为密钥    public static String encrypt(String key, String raw) {        byte[] enBytes = encryptMode(key, raw.getBytes());        BASE64Encoder encoder = new BASE64Encoder();        return encoder.encode(enBytes);    }    //解密函数。key值必须和加密时的key一致    public static String decrypt(String key, String enc) {        try {            BASE64Decoder decoder = new BASE64Decoder();            byte[] enBytes = decoder.decodeBuffer(enc);            byte[] deBytes = decryptMode(key, enBytes);            return new String(deBytes);        } catch (IOException e) {            e.printStackTrace();            return enc;        }    }    private static byte[] encryptMode(String key, byte[] src) {        try {            SecretKey deskey = new SecretKeySpec(build3DesKey(key), Algorithm);            Cipher cipher = Cipher.getInstance(Algorithm);            cipher.init(Cipher.ENCRYPT_MODE, deskey);            return cipher.doFinal(src);        } catch (Exception e) {            e.printStackTrace();            return null;        }    }    private static byte[] decryptMode(String key, byte[] src) {        try {            SecretKey deskey = new SecretKeySpec(build3DesKey(key), Algorithm);            Cipher cipher = Cipher.getInstance(Algorithm);            cipher.init(Cipher.DECRYPT_MODE, deskey);            return cipher.doFinal(src);        } catch (Exception e) {            e.printStackTrace();            return null;        }    }    //根据字符串生成密钥24位的字节数组    private static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {        byte[] key = new byte[24];        byte[] temp = keyStr.getBytes("UTF-8");        if (key.length > temp.length) {            System.arraycopy(temp, 0, key, 0, temp.length);        } else {            System.arraycopy(temp, 0, key, 0, key.length);        }        return key;    }}

3DES算法与AES一样是可逆算法,支持对加密字符串进行解密,前提是解密时密钥必须与加密时一致。

  • layout/activity_main.xml界面布局代码如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:focusable="true"    android:focusableInTouchMode="true"    android:orientation="vertical"    android:padding="5dp">    <ScrollView        android:layout_width="match_parent"        android:layout_height="wrap_content">        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical">            <LinearLayout                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:orientation="horizontal">                <TextView                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_weight="2"                    android:gravity="right"                    android:text="加密字符串:"                    android:textColor="#000000"                    android:textSize="16sp" />                <EditText                    android:id="@+id/et_raw"                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_weight="3"                    android:hint="请输入要加密的字符串"                    android:text=""                    android:textColor="#000000"                    android:textSize="16sp" />            </LinearLayout>            <LinearLayout                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:orientation="horizontal">                <Button                    android:id="@+id/btn_md5"                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_weight="1"                    android:gravity="center"                    android:text="MD5加密"                    android:textColor="#000000"                    android:textSize="14sp" />                <Button                    android:id="@+id/btn_rsa"                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_weight="1"                    android:gravity="center"                    android:text="RSA加密"                    android:textColor="#000000"                    android:textSize="14sp" />                <Button                    android:id="@+id/btn_aes"                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_weight="1"                    android:gravity="center"                    android:text="AES加密"                    android:textColor="#000000"                    android:textSize="14sp" />                <Button                    android:id="@+id/btn_3des"                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_weight="1"                    android:gravity="center"                    android:text="3DES加密"                    android:textColor="#000000"                    android:textSize="14sp" />            </LinearLayout>            <TextView                android:id="@+id/tv_des"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:gravity="left"                android:text=""                android:textColor="#000000"                android:textSize="18sp" />        </LinearLayout>    </ScrollView></LinearLayout>
  • MainActivity.java逻辑代码如下:
package com.fukaimei.encryptiontest;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.view.View.OnClickListener;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import com.fukaimei.encryptiontest.util.AesUtil;import com.fukaimei.encryptiontest.util.Des3Util;import com.fukaimei.encryptiontest.util.MD5Util;import com.fukaimei.encryptiontest.util.RSAUtil;public class MainActivity extends AppCompatActivity implements OnClickListener {    private final static String TAG = "MainActivity";    private EditText et_raw;    private TextView tv_des;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        et_raw = (EditText) findViewById(R.id.et_raw);        tv_des = (TextView) findViewById(R.id.tv_des);        findViewById(R.id.btn_md5).setOnClickListener(this);        findViewById(R.id.btn_rsa).setOnClickListener(this);        findViewById(R.id.btn_aes).setOnClickListener(this);        findViewById(R.id.btn_3des).setOnClickListener(this);    }    @Override    public void onClick(View v) {        String raw = et_raw.getText().toString();        if (raw == null || raw.length() <= 0) {            Toast.makeText(this, "请输入待加密字符串", Toast.LENGTH_LONG).show();            return;        }        if (v.getId() == R.id.btn_md5) {            String enStr = MD5Util.encrypBy(raw);            tv_des.setText("MD5的加密结果是:" + enStr);        } else if (v.getId() == R.id.btn_rsa) {            String enStr = RSAUtil.encodeRSA(null, raw);            tv_des.setText("RSA加密结果是:" + enStr);        } else if (v.getId() == R.id.btn_aes) {            try {                String seed = "a";                String enStr = AesUtil.encrypt(seed, raw);                String deStr = AesUtil.decrypt(seed, enStr);                String desc = String.format("AES加密结果是:%s\nAES解密结果是:%s", enStr, deStr);                tv_des.setText(desc);            } catch (Exception e) {                e.printStackTrace();                tv_des.setText("AES加密/解密失败");            }        } else if (v.getId() == R.id.btn_3des) {            String key = "a";            String enStr = Des3Util.encrypt(key, raw);            String deStr = Des3Util.decrypt(key, enStr);            String desc = String.format("3DES加密结果是:%s\n3DES解密结果是:%s", enStr, new String(deStr));            tv_des.setText(desc);        }    }}
  • Demo程序运行效果界面截图如下:

MD5加密截图RSA加密截图AES加密/解密截图3DES加密/解密截图


Demo程序源码下载地址一(GitHub)
Demo程序源码下载地址二(Gitee)

原创粉丝点击