Android AES 文件加密解密
几番折磨终有结果,现将Demo整理出来。。。
![](https://code.csdn.net/assets/CODE_ico.png)
- package com.king.zjc;
- import java.io.File;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import java.nio.ByteBuffer;
- import java.nio.channels.FileChannel;
- import java.security.InvalidAlgorithmParameterException;
- import java.security.InvalidKeyException;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import javax.crypto.BadPaddingException;
- import javax.crypto.Cipher;
- import javax.crypto.IllegalBlockSizeException;
- import javax.crypto.KeyGenerator;
- import javax.crypto.NoSuchPaddingException;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.IvParameterSpec;
- import javax.crypto.spec.SecretKeySpec;
- import android.util.Log;
- public class AESHelper {
- public static final String TAG = AESHelper.class.getSimpleName();
- Runtime mRuntime = Runtime.getRuntime();
- @SuppressWarnings("resource")
- public boolean <span style="color:#FF0000;">AESCipher</span>(int cipherMode, String sourceFilePath,
- String targetFilePath, String seed) {
- boolean result = false;
- FileChannel sourceFC = null;
- FileChannel targetFC = null;
- try {
- if (cipherMode != Cipher.ENCRYPT_MODE
- && cipherMode != Cipher.DECRYPT_MODE) {
- Log.d(TAG,
- "Operation mode error, should be encrypt or decrypt!");
- return false;
- }
- Cipher mCipher = Cipher.getInstance("AES/CFB/NoPadding");
- byte[] rawkey = getRawKey(seed.getBytes());
- File sourceFile = new File(sourceFilePath);
- File targetFile = new File(targetFilePath);
- sourceFC = new RandomAccessFile(sourceFile, "r").getChannel();
- targetFC = new RandomAccessFile(targetFile, "rw").getChannel();
- SecretKeySpec secretKey = new SecretKeySpec(rawkey, "AES");
- mCipher.init(cipherMode, secretKey, new IvParameterSpec(
- new byte[mCipher.getBlockSize()]));
- ByteBuffer byteData = ByteBuffer.allocate(1024);
- while (sourceFC.read(byteData) != -1) {
- // 通过通道读写交叉进行。
- // 将缓冲区准备为数据传出状态
- byteData.flip();
- byte[] byteList = new byte[byteData.remaining()];
- byteData.get(byteList, 0, byteList.length);
- //此处,若不使用数组加密解密会失败,因为当byteData达不到1024个时,加密方式不同对空白字节的处理也不相同,从而导致成功与失败。
- byte[] bytes = mCipher.doFinal(byteList);
- targetFC.write(ByteBuffer.wrap(bytes));
- byteData.clear();
- }
- result = true;
- } catch (IOException | NoSuchAlgorithmException | InvalidKeyException
- | InvalidAlgorithmParameterException
- | IllegalBlockSizeException | BadPaddingException
- | NoSuchPaddingException e) {
- Log.d(TAG, e.getMessage());
- } finally {
- try {
- if (sourceFC != null) {
- sourceFC.close();
- }
- if (targetFC != null) {
- targetFC.close();
- }
- } catch (IOException e) {
- Log.d(TAG, e.getMessage());
- }
- }
- return result;
- }
- /**
- * 加密后的字符串
- *
- * @param seed
- * @param clearText
- * @return
- */
- public String encrypt(String seed, String source) {
- // Log.d(TAG, "加密前的seed=" + seed + ",内容为:" + clearText);
- byte[] result = null;
- try {
- byte[] rawkey = getRawKey(seed.getBytes());
- result = encrypt(rawkey, source.getBytes());
- } catch (Exception e) {
- e.printStackTrace();
- }
- String content = toHex(result);
- return content;
- }
- /**
- * 解密后的字符串
- *
- * @param seed
- * @param encrypted
- * @return
- */
- public String decrypt(String seed, String encrypted) {
- byte[] rawKey;
- try {
- rawKey = getRawKey(seed.getBytes());
- byte[] enc = toByte(encrypted);
- byte[] result = decrypt(rawKey, enc);
- String coentn = new String(result);
- return coentn;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 使用一个安全的随机数来产生一个密匙,密匙加密使用的
- *
- * @param seed
- * @return
- * @throws NoSuchAlgorithmException
- */
- private byte[] <span style="color:#FF0000;">getRawKey</span>(byte[] seed) throws NoSuchAlgorithmException {
- // 获得一个随机数,传入的参数为默认方式。
- SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
- // 设置一个种子,一般是用户设定的密码
- sr.setSeed(seed);
- // 获得一个key生成器(AES加密模式)
- KeyGenerator keyGen = KeyGenerator.getInstance("AES");
- // 设置密匙长度128位
- keyGen.init(128, sr);
- // 获得密匙
- SecretKey key = keyGen.generateKey();
- // 返回密匙的byte数组供加解密使用
- byte[] raw = key.getEncoded();
- return raw;
- }
- /**
- * 结合密钥生成加密后的密文
- *
- * @param raw
- * @param input
- * @return
- * @throws Exception
- */
- private byte[] encrypt(byte[] raw, byte[] input) throws Exception {
- // 根据上一步生成的密匙指定一个密匙
- SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
- // Cipher cipher = Cipher.getInstance("AES");
- // 加密算法,加密模式和填充方式三部分或指定加密算
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- // 初始化模式为加密模式,并指定密匙
- cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
- new byte[cipher.getBlockSize()]));
- byte[] encrypted = cipher.doFinal(input);
- return encrypted;
- }
- /**
- * 根据密钥解密已经加密的数据
- *
- * @param raw
- * @param encrypted
- * @return
- * @throws Exception
- */
- private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
- SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(
- new byte[cipher.getBlockSize()]));
- byte[] decrypted = cipher.doFinal(encrypted);
- return decrypted;
- }
- public String toHex(String txt) {
- return toHex(txt.getBytes());
- }
- public String fromHex(String hex) {
- return new String(toByte(hex));
- }
- public 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;
- }
- public String toHex(byte[] buf) {
- if (buf == null || buf.length <= 0)
- return "";
- StringBuffer result = new StringBuffer(2 * buf.length);
- for (int i = 0; i < buf.length; i++) {
- appendHex(result, buf[i]);
- }
- return result.toString();
- }
- private void appendHex(StringBuffer sb, byte b) {
- final String HEX = "0123456789ABCDEF";
- sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
- }
- }
1. 其实我的Demo中只用到了AESCipher和getRawKey两个方法。若要返回字符串,一定要注意编码,如
![](https://code.csdn.net/assets/CODE_ico.png)
- public static String encrypt(String data, String key) throws Exception {
- try {
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
- SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
- cipher.init(Cipher.ENCRYPT_MODE, keyspec);
- byte[] encrypted = cipher.doFinal(data.getBytes());
- return Base64.encodeToString(encrypted, Base64.DEFAULT);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- public static String desEncrypt(String data, String key) throws Exception {
- try {
- byte[] encrypted1 = Base64.decode(data.getBytes(), Base64.DEFAULT);
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
- SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
- cipher.init(Cipher.DECRYPT_MODE, keyspec);
- byte[] original = cipher.doFinal(encrypted1);
- return new String(original, "UTF-8");
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
2. 如果先把一个文件转换成字节数组,然后再加密,最后生成文件,这样很大机率很会产生OOM,所以这里利用了FileChannel,一次读取一定的字节数,而后再进行加密解密,最后再通过Channel生成新文件。
3. 先前一直失败,其重点是对“填充模式”的应用,我最终使用了AES/CFB/NoPadding,当不满16字节时,加密后数据长度不变。
![](https://code.csdn.net/assets/CODE_ico.png)
- 算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度
- AES/CBC/NoPadding 16 不支持
- AES/CBC/PKCS5Padding 32 16
- AES/CBC/ISO10126Padding 32 16
- AES/CFB/NoPadding 16 原始数据长度
- AES/CFB/PKCS5Padding 32 16
- AES/CFB/ISO10126Padding 32 16
- AES/ECB/NoPadding 16 不支持
- AES/ECB/PKCS5Padding 32 16
- AES/ECB/ISO10126Padding 32 16
- AES/OFB/NoPadding 16 原始数据长度
- AES/OFB/PKCS5Padding 32 16
- AES/OFB/ISO10126Padding 32 16
- AES/PCBC/NoPadding 16 不支持
- AES/PCBC/PKCS5Padding 32 16
- AES/PCBC/ISO10126Padding 32 16
当原始数据长度为16的整数倍时,假如原始数据长度等于16*n,则使用NoPadding时加密后数据长度等于16*n,其它情况下加密数据长度等于16*(n+1)。在不足16的整数倍的情况下,假如原始数据长度等于16*n+m[其中m小于16],除了NoPadding填充之外的任何方 式,加密数据长度都等于16*(n+1);NoPadding填充情况下,CBC、ECB和PCBC三种模式是不支持的,CFB、OFB两种模式下则加密数据长度等于原始数据长度。
4. 文件大小不同,用时不定,所以把加密解密过程放到一个AsyncTask内进行
MainActivity.java
![](https://code.csdn.net/assets/CODE_ico.png)
- package com.king.zjc;
- import javax.crypto.Cipher;
- import com.hisense.ad.encryption.AESHelper;
- import com.hisense.ad.encryption.R;
- import android.annotation.SuppressLint;
- import android.app.Activity;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
- @SuppressLint("SdCardPath")
- public class MainActivity extends Activity {
- private final String SDcardPath = "/mnt/sdcard/encry/";
- private Button mEncryptButton;
- private Button mDecryptButton;
- private TextView mShowMessage;
- private EditText mFileName;
- private EditText mNewFileName;
- private AESHelper mAESHelper;
- private EncryptionOrDecryptionTask mTask = null;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mAESHelper = new AESHelper();
- mFileName = (EditText) findViewById(R.id.file_name);
- mNewFileName = (EditText) findViewById(R.id.new_file_name);
- mShowMessage = (TextView) findViewById(R.id.message);
- mEncryptButton = (Button) findViewById(R.id.encrypt);
- mDecryptButton = (Button) findViewById(R.id.decrypt);
- mEncryptButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mShowMessage.setText("开始加密,请稍等...");
- if (mTask != null) {
- mTask.cancel(true);
- }
- mTask = new EncryptionOrDecryptionTask(true, SDcardPath
- + mFileName.getText(), SDcardPath, mNewFileName
- .getText().toString(), "zjc");
- mTask.execute();
- }
- });
- mDecryptButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mShowMessage.setText("开始解密,请稍等...");
- if (mTask != null) {
- mTask.cancel(true);
- }
- mTask = new EncryptionOrDecryptionTask(false, SDcardPath
- + mFileName.getText(), SDcardPath, mNewFileName
- .getText().toString(), "zjc");
- mTask.execute();
- }
- });
- }
- // #######################
- /**
- * 加密解密
- */
- private class EncryptionOrDecryptionTask extends
- AsyncTask<Void, Void, Boolean> {
- private String mSourceFile = "";
- private String mNewFilePath = "";
- private String mNewFileName = "";
- private String mSeed = "";
- private boolean mIsEncrypt = false;
- public EncryptionOrDecryptionTask(boolean isEncrypt, String sourceFile,
- String newFilePath, String newFileName, String seed) {
- this.mSourceFile = sourceFile;
- this.mNewFilePath = newFilePath;
- this.mNewFileName = newFileName;
- this.mSeed = seed;
- this.mIsEncrypt = isEncrypt;
- }
- @Override
- protected Boolean doInBackground(Void... params) {
- boolean result = false;
- if (mIsEncrypt) {
- result = mAESHelper.AESCipher(Cipher.ENCRYPT_MODE, mSourceFile,
- mNewFilePath + mNewFileName, mSeed);
- } else {
- result = mAESHelper.AESCipher(Cipher.DECRYPT_MODE, mSourceFile,
- mNewFilePath + mNewFileName, mSeed);
- }
- return result;
- }
- @Override
- protected void onPostExecute(Boolean result) {
- super.onPostExecute(result);
- String showMessage = "";
- if (mIsEncrypt) {
- showMessage = result ? "加密已完成" : "加密失败!";
- } else {
- showMessage = result ? "解密完成" : "解密失败!";
- }
- mShowMessage.setText(showMessage);
- }
- }
- }
main.xml
![](https://code.csdn.net/assets/CODE_ico.png)
- <?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:orientation="vertical" >
- <TextView
- android:id="@+id/textView1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="请输入文件名" />
- <EditText
- android:id="@+id/file_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ems="10"
- android:hint="请输入文件名" >
- <requestFocus />
- </EditText>
- <EditText
- android:id="@+id/new_file_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ems="10"
- android:hint="请输入新的文件名" >
- </EditText>
- <Button
- android:id="@+id/encrypt"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="加密" />
- <Button
- android:id="@+id/decrypt"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="解密" />
- <TextView
- android:id="@+id/message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="TextView" />
- </LinearLayout>
注:许多代码来自网络,但已记不清最初来自哪里了。
转载地址:http://blog.csdn.net/zjclugger/article/details/34838447
Android AES 文件加密解密相关推荐
- Android AES文件加密 ECB模式
项目过程中遇到一个新需求,对文件进行AES加密解密,要求用ECB模式,这里记录一下 网上找了很多资料,对字符串进行加密很多,可是我需要的是对文件进行加密,一开始的思路是把文件内容读出来,然后对这些内容 ...
- android aes文件加密,如何在Android中使用AES从SD卡加密文件?
你应该看看: CipherInputStream和CipherOutputStream.它们用于加密和解密字节流. 我有一个名为的文件cleartext.该文件包含: Hi, I'm a clear ...
- android下zip压缩文件加密解密的完美解决方案,Android之zip文件加密解压及进度条的实现...
zip文件的解压可以使用java的zip库,但是没有实现对加密文件的解压功能,这里可以使用zip4j来实现.具体可以参看该文<Android下zip压缩文件加密解密的完美解决方案 http:// ...
- openssl算法 —— 利用openssl进行BASE64编码解码、md5/sha1摘要、AES/DES3加密解密
openssl 加密字符串的方法: 一.利用openssl命令进行BASE64编码解码(base64 encode/decode): 1. BASE64编码命令 对字符串'abc'进行base64编码 ...
- 使用WPF开发文件加密解密软件
应用场景 在很多情况下,我们希望对一些比较私密的文件进行加密,当自己需要查看的时候,再解密出来.因此,今天与大家分享一款自己以前用WPF开发的文件加密解密软件. 准备工作 开发环境:VisualStu ...
- 基于PHP和JS的AES相互加密解密方法详解(CryptoJS)
在最近的项目中,前端后台数据交互需要进行加密之后传输使用,以保证系统数据的安全.有关数据加密解密的问题,有很多种加密的方式,在这里我选择了AES的加密方式.特此写下此篇博文,总结讲述下PHP和JS进行 ...
- 【C 语言】文件操作 ( 文件加密解密 | 解密文件 )
文章目录 一.文件加密解密操作 1.解密整 4096 字节的数据 2.解密小于 4096 字节的数据 二.完整代码示例 1.文件加密操作 main.c 2.DES 加密解密头文件 des.h 3.第三 ...
- 【C 语言】文件操作 ( 文件加密解密 | 加密文件 )
文章目录 一.文件加密解密操作 1.加密整 4096 字节的数据 2.加密小于 4096 字节的数据 二.完整代码示例 1.文件加密操作 2.DES 加密解密头文件 3.第三方 DES 加密解密函数库 ...
- AES在线加密解密-附AES128,192,256,CBC,CFB,ECB,OFB,PCBC各种加密
一.AES在线加密解密:AES 128/192/256位CBC/CFB/ECB/OFB/PCBC在线加密解密|在线工具|在线助手|在线生成|在线制作 http://www.it399.com/aes ...
最新文章
- 用split分割文件和数据(笔记)
- 记于2014-12-9
- 建博客的原因。。。。
- go语言中go+select的理解
- sklearn的认识
- Mysql 多实例multi_mysqld_multi多实例运行
- thinkCMF----导航高亮显示
- infor wms 项目启动_派诺科技数字工厂MES/WMS系统项目正式启动
- java中抛出异常快捷键_idea中处理异常的快捷键
- C#语言-NPOI.dll导入Excel功能的实现
- 网络编程6_multiprocess模块.锁.队列
- 【转】Visio(流程图绘制软件)的免费替代品
- 两个iOS应用之间的跳转
- 程序入口地址的直接定制表【 (1) 清屏(2) 设置前景色 (3) 设置背景色 (4) 向上滚动一行】...
- java正则表达式判断浮点_java正则表达式浮点数
- gtp传输java_一种GTP数据包传输方法、相关装置及存储介质与流程
- mysql查看sa密码_查询mssql 密码
- php获取无限极团队人数,PHP实现无限极菜单
- 原子性 可见性 有序性_极简主义的内容可见性
- Python 局域网即时通讯工具