android 5.0 AES加密实现
2015-11-26 14:56
645 查看
可以参考的资料:http://blog.csdn.net/zjclugger/article/details/34838447
前几天因需要研究了下android 5.0平台上使用AES加密,但在网上找了相关资料并按照相关代码实现后发现加密可以成功,但解密时会报错失败,
查找一大堆资料后发现 在android 4.2之后SHA1PRNG 强随机种子算法调用方法不同,可用以下方式区别调用
同时 需要注意的是Cipher中的加密模式和填充方式两个参数,因这两个参数不适配的话也会导致解密失败,
android
4.2以后以下方式获取Cipher也不太适用:
// 加密算法,加密模式和填充方式三部分或指定加密算
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
经过验证可以在android4.2以上版本有效使用的代码如下(本人使用的是android 5.0平台):
前几天因需要研究了下android 5.0平台上使用AES加密,但在网上找了相关资料并按照相关代码实现后发现加密可以成功,但解密时会报错失败,
查找一大堆资料后发现 在android 4.2之后SHA1PRNG 强随机种子算法调用方法不同,可用以下方式区别调用
同时 需要注意的是Cipher中的加密模式和填充方式两个参数,因这两个参数不适配的话也会导致解密失败,
android
4.2以后以下方式获取Cipher也不太适用:
// 加密算法,加密模式和填充方式三部分或指定加密算
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
经过验证可以在android4.2以上版本有效使用的代码如下(本人使用的是android 5.0平台):
package com.silead.fp.utils; import android.annotation.SuppressLint; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; /** * AES encryptor * * @author janning_ning * */ public class AESEncryptor { private static final String HEX = "0123456789ABCDEF"; /** * encrypt the clear string * * @param seed * the key for encryptting * @param clearText * the clear string that need to be encryptted * @return * @throws Exception */ public static String encrypt(String seed, String clearText) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, clearText.getBytes()); return toHex(result); } /** * decrypt the encryptted string * * @param seed * the key for decryptting * @param encrypttedText * the encryptted string that need to be decryptted * @return * @throws Exception */ public static String decrypt(String seed, String encrypttedText) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] enc = toByte(encrypttedText); byte[] result = decrypt(rawKey, enc); return new String(result); } @SuppressLint("TrulyRandom") private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); sr.setSeed(seed); kgen.init(128, sr); // 192 and 256 bits may not be available SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clearText) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clearText); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encryptedText) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encryptedText); return decrypted; } public static String toHex(String txt) { return toHex(txt.getBytes()); } public static String fromHex(String hex) { return new String(toByte(hex)); } public 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; } public static String toHex(byte[] buf) { if (buf == null) { return ""; } int len = buf.length; StringBuffer result = new StringBuffer(2 * len); for (int i = 0; i < len; i++) { appendHex(result, buf[i]); } return result.toString(); } private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); } } 以下是网上其他代码供参考: 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 AESCipher(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[] getRawKey(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)); } } MainActivity.java: 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 { 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: <?xml version="1.0" encoding="utf-8"?>
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories