几番折磨终有结果,现将Demo整理出来。。。

[java] view plain copy  
  1. package com.king.zjc;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.RandomAccessFile;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.FileChannel;
  7. import java.security.InvalidAlgorithmParameterException;
  8. import java.security.InvalidKeyException;
  9. import java.security.NoSuchAlgorithmException;
  10. import java.security.SecureRandom;
  11. import javax.crypto.BadPaddingException;
  12. import javax.crypto.Cipher;
  13. import javax.crypto.IllegalBlockSizeException;
  14. import javax.crypto.KeyGenerator;
  15. import javax.crypto.NoSuchPaddingException;
  16. import javax.crypto.SecretKey;
  17. import javax.crypto.spec.IvParameterSpec;
  18. import javax.crypto.spec.SecretKeySpec;
  19. import android.util.Log;
  20. public class AESHelper {
  21. public static final String TAG = AESHelper.class.getSimpleName();
  22. Runtime mRuntime = Runtime.getRuntime();
  23. @SuppressWarnings("resource")
  24. public boolean <span style="color:#FF0000;">AESCipher</span>(int cipherMode, String sourceFilePath,
  25. String targetFilePath, String seed) {
  26. boolean result = false;
  27. FileChannel sourceFC = null;
  28. FileChannel targetFC = null;
  29. try {
  30. if (cipherMode != Cipher.ENCRYPT_MODE
  31. && cipherMode != Cipher.DECRYPT_MODE) {
  32. Log.d(TAG,
  33. "Operation mode error, should be encrypt or decrypt!");
  34. return false;
  35. }
  36. Cipher mCipher = Cipher.getInstance("AES/CFB/NoPadding");
  37. byte[] rawkey = getRawKey(seed.getBytes());
  38. File sourceFile = new File(sourceFilePath);
  39. File targetFile = new File(targetFilePath);
  40. sourceFC = new RandomAccessFile(sourceFile, "r").getChannel();
  41. targetFC = new RandomAccessFile(targetFile, "rw").getChannel();
  42. SecretKeySpec secretKey = new SecretKeySpec(rawkey, "AES");
  43. mCipher.init(cipherMode, secretKey, new IvParameterSpec(
  44. new byte[mCipher.getBlockSize()]));
  45. ByteBuffer byteData = ByteBuffer.allocate(1024);
  46. while (sourceFC.read(byteData) != -1) {
  47. // 通过通道读写交叉进行。
  48. // 将缓冲区准备为数据传出状态
  49. byteData.flip();
  50. byte[] byteList = new byte[byteData.remaining()];
  51. byteData.get(byteList, 0, byteList.length);
  52. //此处,若不使用数组加密解密会失败,因为当byteData达不到1024个时,加密方式不同对空白字节的处理也不相同,从而导致成功与失败。
  53. byte[] bytes = mCipher.doFinal(byteList);
  54. targetFC.write(ByteBuffer.wrap(bytes));
  55. byteData.clear();
  56. }
  57. result = true;
  58. } catch (IOException | NoSuchAlgorithmException | InvalidKeyException
  59. | InvalidAlgorithmParameterException
  60. | IllegalBlockSizeException | BadPaddingException
  61. | NoSuchPaddingException e) {
  62. Log.d(TAG, e.getMessage());
  63. } finally {
  64. try {
  65. if (sourceFC != null) {
  66. sourceFC.close();
  67. }
  68. if (targetFC != null) {
  69. targetFC.close();
  70. }
  71. } catch (IOException e) {
  72. Log.d(TAG, e.getMessage());
  73. }
  74. }
  75. return result;
  76. }
  77. /**
  78. * 加密后的字符串
  79. *
  80. * @param seed
  81. * @param clearText
  82. * @return
  83. */
  84. public String encrypt(String seed, String source) {
  85. // Log.d(TAG, "加密前的seed=" + seed + ",内容为:" + clearText);
  86. byte[] result = null;
  87. try {
  88. byte[] rawkey = getRawKey(seed.getBytes());
  89. result = encrypt(rawkey, source.getBytes());
  90. } catch (Exception e) {
  91. e.printStackTrace();
  92. }
  93. String content = toHex(result);
  94. return content;
  95. }
  96. /**
  97. * 解密后的字符串
  98. *
  99. * @param seed
  100. * @param encrypted
  101. * @return
  102. */
  103. public String decrypt(String seed, String encrypted) {
  104. byte[] rawKey;
  105. try {
  106. rawKey = getRawKey(seed.getBytes());
  107. byte[] enc = toByte(encrypted);
  108. byte[] result = decrypt(rawKey, enc);
  109. String coentn = new String(result);
  110. return coentn;
  111. } catch (Exception e) {
  112. e.printStackTrace();
  113. return null;
  114. }
  115. }
  116. /**
  117. * 使用一个安全的随机数来产生一个密匙,密匙加密使用的
  118. *
  119. * @param seed
  120. * @return
  121. * @throws NoSuchAlgorithmException
  122. */
  123. private byte[] <span style="color:#FF0000;">getRawKey</span>(byte[] seed) throws NoSuchAlgorithmException {
  124. // 获得一个随机数,传入的参数为默认方式。
  125. SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
  126. // 设置一个种子,一般是用户设定的密码
  127. sr.setSeed(seed);
  128. // 获得一个key生成器(AES加密模式)
  129. KeyGenerator keyGen = KeyGenerator.getInstance("AES");
  130. // 设置密匙长度128位
  131. keyGen.init(128, sr);
  132. // 获得密匙
  133. SecretKey key = keyGen.generateKey();
  134. // 返回密匙的byte数组供加解密使用
  135. byte[] raw = key.getEncoded();
  136. return raw;
  137. }
  138. /**
  139. * 结合密钥生成加密后的密文
  140. *
  141. * @param raw
  142. * @param input
  143. * @return
  144. * @throws Exception
  145. */
  146. private byte[] encrypt(byte[] raw, byte[] input) throws Exception {
  147. // 根据上一步生成的密匙指定一个密匙
  148. SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
  149. // Cipher cipher = Cipher.getInstance("AES");
  150. // 加密算法,加密模式和填充方式三部分或指定加密算
  151. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  152. // 初始化模式为加密模式,并指定密匙
  153. cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
  154. new byte[cipher.getBlockSize()]));
  155. byte[] encrypted = cipher.doFinal(input);
  156. return encrypted;
  157. }
  158. /**
  159. * 根据密钥解密已经加密的数据
  160. *
  161. * @param raw
  162. * @param encrypted
  163. * @return
  164. * @throws Exception
  165. */
  166. private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
  167. SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
  168. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  169. cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(
  170. new byte[cipher.getBlockSize()]));
  171. byte[] decrypted = cipher.doFinal(encrypted);
  172. return decrypted;
  173. }
  174. public String toHex(String txt) {
  175. return toHex(txt.getBytes());
  176. }
  177. public String fromHex(String hex) {
  178. return new String(toByte(hex));
  179. }
  180. public byte[] toByte(String hexString) {
  181. int len = hexString.length() / 2;
  182. byte[] result = new byte[len];
  183. for (int i = 0; i < len; i++)
  184. result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
  185. 16).byteValue();
  186. return result;
  187. }
  188. public String toHex(byte[] buf) {
  189. if (buf == null || buf.length <= 0)
  190. return "";
  191. StringBuffer result = new StringBuffer(2 * buf.length);
  192. for (int i = 0; i < buf.length; i++) {
  193. appendHex(result, buf[i]);
  194. }
  195. return result.toString();
  196. }
  197. private void appendHex(StringBuffer sb, byte b) {
  198. final String HEX = "0123456789ABCDEF";
  199. sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
  200. }
  201. }

1. 其实我的Demo中只用到了AESCipher和getRawKey两个方法。若要返回字符串,一定要注意编码,如

[html] view plain copy  
  1. public static String encrypt(String data, String key) throws Exception {
  2. try {
  3. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  4. SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
  5. cipher.init(Cipher.ENCRYPT_MODE, keyspec);
  6. byte[] encrypted = cipher.doFinal(data.getBytes());
  7. return Base64.encodeToString(encrypted, Base64.DEFAULT);
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. return null;
  11. }
  12. }
  13. public static String desEncrypt(String data, String key) throws Exception {
  14. try {
  15. byte[] encrypted1 = Base64.decode(data.getBytes(), Base64.DEFAULT);
  16. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  17. SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
  18. cipher.init(Cipher.DECRYPT_MODE, keyspec);
  19. byte[] original = cipher.doFinal(encrypted1);
  20. return new String(original, "UTF-8");
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. return null;
  24. }
  25. }

2. 如果先把一个文件转换成字节数组,然后再加密,最后生成文件,这样很大机率很会产生OOM,所以这里利用了FileChannel,一次读取一定的字节数,而后再进行加密解密,最后再通过Channel生成新文件。

3. 先前一直失败,其重点是对“填充模式”的应用,我最终使用了AES/CFB/NoPadding,当不满16字节时,加密后数据长度不变。

[html] view plain copy  
  1. 算法/模式/填充                16字节加密后数据长度        不满16字节加密后长度
  2. AES/CBC/NoPadding             16                          不支持
  3. AES/CBC/PKCS5Padding          32                          16
  4. AES/CBC/ISO10126Padding       32                          16
  5. AES/CFB/NoPadding             16                          原始数据长度
  6. AES/CFB/PKCS5Padding          32                          16
  7. AES/CFB/ISO10126Padding       32                          16
  8. AES/ECB/NoPadding             16                          不支持
  9. AES/ECB/PKCS5Padding          32                          16
  10. AES/ECB/ISO10126Padding       32                          16
  11. AES/OFB/NoPadding             16                          原始数据长度
  12. AES/OFB/PKCS5Padding          32                          16
  13. AES/OFB/ISO10126Padding       32                          16
  14. AES/PCBC/NoPadding            16                          不支持
  15. AES/PCBC/PKCS5Padding         32                          16
  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

[java] view plain copy  
  1. package com.king.zjc;
  2. import javax.crypto.Cipher;
  3. import com.hisense.ad.encryption.AESHelper;
  4. import com.hisense.ad.encryption.R;
  5. import android.annotation.SuppressLint;
  6. import android.app.Activity;
  7. import android.os.AsyncTask;
  8. import android.os.Bundle;
  9. import android.view.View;
  10. import android.view.View.OnClickListener;
  11. import android.widget.Button;
  12. import android.widget.EditText;
  13. import android.widget.TextView;
  14. @SuppressLint("SdCardPath")
  15. public class MainActivity extends Activity {
  16. private final String SDcardPath = "/mnt/sdcard/encry/";
  17. private Button mEncryptButton;
  18. private Button mDecryptButton;
  19. private TextView mShowMessage;
  20. private EditText mFileName;
  21. private EditText mNewFileName;
  22. private AESHelper mAESHelper;
  23. private EncryptionOrDecryptionTask mTask = null;
  24. @Override
  25. protected void onCreate(Bundle savedInstanceState) {
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.main);
  28. mAESHelper = new AESHelper();
  29. mFileName = (EditText) findViewById(R.id.file_name);
  30. mNewFileName = (EditText) findViewById(R.id.new_file_name);
  31. mShowMessage = (TextView) findViewById(R.id.message);
  32. mEncryptButton = (Button) findViewById(R.id.encrypt);
  33. mDecryptButton = (Button) findViewById(R.id.decrypt);
  34. mEncryptButton.setOnClickListener(new OnClickListener() {
  35. @Override
  36. public void onClick(View v) {
  37. mShowMessage.setText("开始加密,请稍等...");
  38. if (mTask != null) {
  39. mTask.cancel(true);
  40. }
  41. mTask = new EncryptionOrDecryptionTask(true, SDcardPath
  42. + mFileName.getText(), SDcardPath, mNewFileName
  43. .getText().toString(), "zjc");
  44. mTask.execute();
  45. }
  46. });
  47. mDecryptButton.setOnClickListener(new OnClickListener() {
  48. @Override
  49. public void onClick(View v) {
  50. mShowMessage.setText("开始解密,请稍等...");
  51. if (mTask != null) {
  52. mTask.cancel(true);
  53. }
  54. mTask = new EncryptionOrDecryptionTask(false, SDcardPath
  55. + mFileName.getText(), SDcardPath, mNewFileName
  56. .getText().toString(), "zjc");
  57. mTask.execute();
  58. }
  59. });
  60. }
  61. // #######################
  62. /**
  63. * 加密解密
  64. */
  65. private class EncryptionOrDecryptionTask extends
  66. AsyncTask<Void, Void, Boolean> {
  67. private String mSourceFile = "";
  68. private String mNewFilePath = "";
  69. private String mNewFileName = "";
  70. private String mSeed = "";
  71. private boolean mIsEncrypt = false;
  72. public EncryptionOrDecryptionTask(boolean isEncrypt, String sourceFile,
  73. String newFilePath, String newFileName, String seed) {
  74. this.mSourceFile = sourceFile;
  75. this.mNewFilePath = newFilePath;
  76. this.mNewFileName = newFileName;
  77. this.mSeed = seed;
  78. this.mIsEncrypt = isEncrypt;
  79. }
  80. @Override
  81. protected Boolean doInBackground(Void... params) {
  82. boolean result = false;
  83. if (mIsEncrypt) {
  84. result = mAESHelper.AESCipher(Cipher.ENCRYPT_MODE, mSourceFile,
  85. mNewFilePath + mNewFileName, mSeed);
  86. } else {
  87. result = mAESHelper.AESCipher(Cipher.DECRYPT_MODE, mSourceFile,
  88. mNewFilePath + mNewFileName, mSeed);
  89. }
  90. return result;
  91. }
  92. @Override
  93. protected void onPostExecute(Boolean result) {
  94. super.onPostExecute(result);
  95. String showMessage = "";
  96. if (mIsEncrypt) {
  97. showMessage = result ? "加密已完成" : "加密失败!";
  98. } else {
  99. showMessage = result ? "解密完成" : "解密失败!";
  100. }
  101. mShowMessage.setText(showMessage);
  102. }
  103. }
  104. }

main.xml

[html] view plain copy  
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <TextView
  7. android:id="@+id/textView1"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:text="请输入文件名" />
  11. <EditText
  12. android:id="@+id/file_name"
  13. android:layout_width="match_parent"
  14. android:layout_height="wrap_content"
  15. android:ems="10"
  16. android:hint="请输入文件名" >
  17. <requestFocus />
  18. </EditText>
  19. <EditText
  20. android:id="@+id/new_file_name"
  21. android:layout_width="match_parent"
  22. android:layout_height="wrap_content"
  23. android:ems="10"
  24. android:hint="请输入新的文件名" >
  25. </EditText>
  26. <Button
  27. android:id="@+id/encrypt"
  28. android:layout_width="wrap_content"
  29. android:layout_height="wrap_content"
  30. android:text="加密" />
  31. <Button
  32. android:id="@+id/decrypt"
  33. android:layout_width="wrap_content"
  34. android:layout_height="wrap_content"
  35. android:text="解密" />
  36. <TextView
  37. android:id="@+id/message"
  38. android:layout_width="wrap_content"
  39. android:layout_height="wrap_content"
  40. android:text="TextView" />
  41. </LinearLayout>

注:许多代码来自网络,但已记不清最初来自哪里了。

转载地址:http://blog.csdn.net/zjclugger/article/details/34838447

Android AES 文件加密解密相关推荐

  1. Android AES文件加密 ECB模式

    项目过程中遇到一个新需求,对文件进行AES加密解密,要求用ECB模式,这里记录一下 网上找了很多资料,对字符串进行加密很多,可是我需要的是对文件进行加密,一开始的思路是把文件内容读出来,然后对这些内容 ...

  2. android aes文件加密,如何在Android中使用AES从SD卡加密文件?

    你应该看看: CipherInputStream和CipherOutputStream.它们用于加密和解密字节流. 我有一个名为的文件cleartext.该文件包含: Hi, I'm a clear ...

  3. android下zip压缩文件加密解密的完美解决方案,Android之zip文件加密解压及进度条的实现...

    zip文件的解压可以使用java的zip库,但是没有实现对加密文件的解压功能,这里可以使用zip4j来实现.具体可以参看该文<Android下zip压缩文件加密解密的完美解决方案 http:// ...

  4. openssl算法 —— 利用openssl进行BASE64编码解码、md5/sha1摘要、AES/DES3加密解密

    openssl 加密字符串的方法: 一.利用openssl命令进行BASE64编码解码(base64 encode/decode): 1. BASE64编码命令 对字符串'abc'进行base64编码 ...

  5. 使用WPF开发文件加密解密软件

    应用场景 在很多情况下,我们希望对一些比较私密的文件进行加密,当自己需要查看的时候,再解密出来.因此,今天与大家分享一款自己以前用WPF开发的文件加密解密软件. 准备工作 开发环境:VisualStu ...

  6. 基于PHP和JS的AES相互加密解密方法详解(CryptoJS)

    在最近的项目中,前端后台数据交互需要进行加密之后传输使用,以保证系统数据的安全.有关数据加密解密的问题,有很多种加密的方式,在这里我选择了AES的加密方式.特此写下此篇博文,总结讲述下PHP和JS进行 ...

  7. 【C 语言】文件操作 ( 文件加密解密 | 解密文件 )

    文章目录 一.文件加密解密操作 1.解密整 4096 字节的数据 2.解密小于 4096 字节的数据 二.完整代码示例 1.文件加密操作 main.c 2.DES 加密解密头文件 des.h 3.第三 ...

  8. 【C 语言】文件操作 ( 文件加密解密 | 加密文件 )

    文章目录 一.文件加密解密操作 1.加密整 4096 字节的数据 2.加密小于 4096 字节的数据 二.完整代码示例 1.文件加密操作 2.DES 加密解密头文件 3.第三方 DES 加密解密函数库 ...

  9. AES在线加密解密-附AES128,192,256,CBC,CFB,ECB,OFB,PCBC各种加密

    一.AES在线加密解密:AES 128/192/256位CBC/CFB/ECB/OFB/PCBC在线加密解密|在线工具|在线助手|在线生成|在线制作 http://www.it399.com/aes ...

最新文章

  1. 用split分割文件和数据(笔记)
  2. 记于2014-12-9
  3. 建博客的原因。。。。
  4. go语言中go+select的理解
  5. sklearn的认识
  6. Mysql 多实例multi_mysqld_multi多实例运行
  7. thinkCMF----导航高亮显示
  8. infor wms 项目启动_派诺科技数字工厂MES/WMS系统项目正式启动
  9. java中抛出异常快捷键_idea中处理异常的快捷键
  10. C#语言-NPOI.dll导入Excel功能的实现
  11. 网络编程6_multiprocess模块.锁.队列
  12. 【转】Visio(流程图绘制软件)的免费替代品
  13. 两个iOS应用之间的跳转
  14. 程序入口地址的直接定制表【 (1) 清屏(2) 设置前景色 (3) 设置背景色 (4) 向上滚动一行】...
  15. java正则表达式判断浮点_java正则表达式浮点数
  16. gtp传输java_一种GTP数据包传输方法、相关装置及存储介质与流程
  17. mysql查看sa密码_查询mssql 密码
  18. php获取无限极团队人数,PHP实现无限极菜单
  19. 原子性 可见性 有序性_极简主义的内容可见性
  20. Python 局域网即时通讯工具

热门文章

  1. 在Element UI中表格根据数据动态变化显示表格的内容
  2. 微信公众号标题怎么写更吸引人?
  3. 2015广东最新DNS服务器地址
  4. 测度论中的概率空间,可测空间
  5. Mac安装软件时各种异常情况的解决方法
  6. ENSPAC的web配置直接转发
  7. 运用简单的HTML、CSS建立一个音乐网站模板
  8. 深度增强学习:走向通用人工智能之路
  9. 借贷记账法--借贷记账法 (Debit and Credit)
  10. MATLAB泰勒级数展开