感谢CSDN博主Mr_甘 的博客android imageloader加密解密图片(地址:http://blog.csdn.net/gan303/article/details/50266569)
当使用网络图片缓存到本地时,基于安全考虑需要加密缓存到本地的数据,加上使用UIL已经很久了,并且很好用,所以决定扩展UIL支持加密本地缓存。开始干活了!!!
在ImageLoaderConfiguration中找到imageDecoder和diskCache,imageDecoder用于提供读取数据生成Bitmap的接口,diskCache提供磁盘缓存的接口;就在这两个方面下功夫了。加密技术我选择javax下面CipherInputStream,提高效率,如果不满足你的需求可以自定义InputStream,重写read函数在(read函数里面进行加解密操作)就可以。这些前提就是你已经成功配置UniversalImageLoader库(包含需要的权限之类的)
1(加密):继承UnlimitedDiskCache并重写save函数,save函数的功能就是将需要缓存到本地的数据保存在本地,当然我们只加密网络缓存图片,加密操作就是将原来的InputStream转化成加密的CipherInputStream。
package com.common.cipher; import android.util.Log; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator; import com.nostra13.universalimageloader.utils.IoUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; import javax.crypto.CipherInputStream; /** * 作者:徐仕海 on 2016/7/25 0025 14:47 * <p> 加密图片磁盘缓存 * 邮箱:1056483075@qq.com */ public class CipherUnlimitedDiskCache extends UnlimitedDiskCache { public CipherUnlimitedDiskCache(File cacheDir) { super(cacheDir); } public CipherUnlimitedDiskCache(File cacheDir, File reserveCacheDir) { super(cacheDir, reserveCacheDir); } public CipherUnlimitedDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) { super(cacheDir, reserveCacheDir, fileNameGenerator); } @Override public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException { Log.e("TAG", "保存到本地"); InputStream inputStream; /** * 本地文件的缓存就不加密了 */ if (imageUri.startsWith("http")) { try { inputStream = new CipherInputStream(imageStream, CipherImage.getInstance().getEncryptCipher()); } catch (Exception e) { imageStream.close(); e.printStackTrace(); return false; } } else { inputStream = imageStream; } return super.save(imageUri, inputStream, listener); } }
2(解密):加密了图片接下来就是解密加密过后的数据,继承BaseImageDecoder,并重写getImageStream函数,当然我们也只解密网络图片,解密操作就是将InputStream转化成解密的CipherInputStream。
package com.common.cipher; import com.nostra13.universalimageloader.core.decode.BaseImageDecoder; import com.nostra13.universalimageloader.core.decode.ImageDecodingInfo; import java.io.IOException; import java.io.InputStream; import javax.crypto.CipherInputStream; /** * 作者:徐仕海 on 2016/7/25 0025 11:20 * <p> 解密图片解码器 * 邮箱:1056483075@qq.com */ public class CipherImageDecoder extends BaseImageDecoder { public CipherImageDecoder(boolean loggingEnabled) { super(loggingEnabled); } @Override protected InputStream getImageStream(ImageDecodingInfo decodingInfo) throws IOException { InputStream imageStream = super.getImageStream(decodingInfo); /** * 只解密网络下载的图片,其他的途径的图片不用加密所以就不用解密,加解密手段用的是Java的加解密输入流 */ if (decodingInfo.getOriginalImageUri().startsWith("http")) { CipherInputStream in = null; try { in = new CipherInputStream(imageStream, CipherImage.getInstance().getDecryptCipher()); } catch (Exception e) { e.printStackTrace(); imageStream.close(); } return in; } return imageStream; } }
3(加解密Cipher对象):为了方便使用且方便修改密钥和加解密算法新建一个CipherImage类,他主要用来配置密钥和算法,生成加解密的Cipher对象供创建CipherInputStream类使用
package com.common.cipher; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; /** * 作者:徐仕海 on 2016/7/26 0026 10:18 * <p>主要提供加密密钥,加解密算法,加密Cipher对象,解密Cipher对象 * 邮箱:1056483075@qq.com */ public class CipherImage { private static CipherImage ourInstance = new Builder().build(); public static CipherImage getInstance() { return ourInstance; } private CipherImage() {} /** * 加解密图片的密钥 */ private String key; /** * 加解密算法 */ private String algorithm; /** * 获取解密Cipher * * @return * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws InvalidKeyException */ public Cipher getDecryptCipher() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { byte[] str = key.getBytes(); Key key = new SecretKeySpec(str, 0, str.length, algorithm); Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE, key); return cipher; } /** * 获取加密Cipher * * @return * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws InvalidKeyException */ public Cipher getEncryptCipher() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { byte[] str = key.getBytes(); Key key = new SecretKeySpec(str, 0, str.length, algorithm); Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key); return cipher; } /** * 构造器 */ public static class Builder { private String key, algorithm; public Builder() { key = "123456";//默认密钥 algorithm = "RC4";//默认加解密算法 } public Builder cipherKey(String key) { this.key = key; return this; } public Builder cipherAlgorithm(String algorithm) { this.algorithm = algorithm; return this; } public CipherImage build() { if (ourInstance == null) { ourInstance = new CipherImage(); } ourInstance.algorithm = algorithm; ourInstance.key = key; return ourInstance; } } }
功能实现完毕,接下来该试试如何使用了。首先必须启用缓存到磁盘,在设置图片解码器和磁盘缓存,这样每张网络图片缓存在磁盘上的数据都是加密的都是安全的。
DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheOnDisk(true).cacheInMemory(true).build(); ImageLoaderConfiguration configuration = null; configuration = new ImageLoaderConfiguration.Builder(this) .imageDecoder(new CipherImageDecoder(true)) .diskCache(new CipherUnlimitedDiskCache(getExternalCacheDir())) .defaultDisplayImageOptions(displayImageOptions) .build(); ImageLoader.getInstance().init(configuration); final ImageView imageView = (ImageView) findViewById(R.id.imageView); ImageLoader.getInstance().displayImage("http://desk.fd.zol-img.com.cn/t_s1920x1080c5/g5/M00/0D/0D/ChMkJ1eV_E2IMTEQABERSEVD0poAAT0hAID5McAERFg559.jpg", imageView);
当然如果你不喜欢默认的密钥123456或者默认的加解密算法RC4,可以更新密钥和算法,只要在图片保存之前都会有效
new CipherImage.Builder() .cipherAlgorithm("RC4") .cipherKey("dhghd") .build();
本文示例工程的地址https://files.cnblogs.com/files/xushihai/CipherUIL.rar