Android数据加密:

Anroid数据加密方式

Android 提供了 KeyStore 等可以长期存储和检索加密密钥的机制,Android KeyStore 系统特别适合于存储加密密钥。

“AndroidKeyStore” 是 KeyStore 的一个子集,存进 AndroidKeyStore 的 key 将受到签名保护,并且这些 key 是存在系统里的,而不是在 App 的 data 目录下,依托于硬件的 KeyChain 存储,可以做到 private key 一旦存入就无法取出,

每个 App 自己创建的 key,别的应用是访问不到的。

它提供了限制何时以何种方式使用密钥的方法,比如使用密钥时需要用户认证或限制密钥只能在加密模式下使用。

一个应用程式只能编辑、保存、取出自己的密钥。

App可以生成或者接收一个公私密钥对,并存储在Android的Keystore系统中。公钥可以用于在应用数据放置到特定文件夹前对数据进行加密,私钥可以在需要的时候解密相应的数据。

作用:

KeyStore 适用于生成和存储密钥,这些密钥可以用来加密运行时获取到的数据,比如运行时,用户输入的密码,或者服务端传下来的 token。

操作方式

建议做法

1. 使用对称式加解密,但只能在Api Level 23+使用

对称式加解密(AES)速度较快,但是对称式的Key若要存在KeyStore裡,Api level一定要在23以上才支持,23以下是无法存入KeyStore的,非对称式的Key則不在此限。

2. 想兼容各Api版本(23以下也能用)

  • 若要存取的東西不多、字串長度也不長:直接使用非对称式加解密即可
  • 若要存取的東西很多或字串長度很長:由於非对称式加解密速度较慢,使用非对称式+对称式加解密可以解決此問題。

考慮到加解密效能、版本兼容,下面會介紹用非对称式+对称式來加解密。

KeyStore非对称+对称式加解密流程

  1. 使用KeyStore产生随机的RSA Key;
  2. 产生AES Key,并用RSA Public Key加密后存入SharedPrefs;
  3. 从SharedPrefs取出AES Key,並用RSA Private Key解密,用這把AES Key來加解密信息;

主流的加密方式有:(对称加密)AES、DES        (非对称加密)RSA、DSA

工作模式:

DES一共有:

电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)、输出反馈模式(OFB);

AES一共有:

电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)、输出反馈模式(OFB)、计数器模式(CTR),伽罗瓦计数器模式(GCM

PKCS5Padding是填充模式,还有其它的填充模式;

对于初始化向量iv: 初始化向量参数,AES 为16bytes. DES 为8bytes

 private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
private static final String AES_MODE = "AES/GCM/NoPadding";
private static final String RSA_MODE = "RSA/ECB/PKCS1Padding"; private static final String KEYSTORE_ALIAS = "KEYSTORE_DEMO"; KeyStore mKeyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
mKeyStore.load(null);

(1)产生随机的RSA Key

产生RSA Key会使用到KeyPairGenerator

其中KeyPairGeneratorSpec在Api 23以上已經Deprecated了;

Api level 23以上改使用KeyGenParameterSpec

 private void genKeyStoreKey(Context context) throws Exception {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
generateRSAKey_AboveApi23();
} else {
generateRSAKey_BelowApi23(context);
}
}

api23 以上使用 KeyGenParameterSpec

 @RequiresApi(api = Build.VERSION_CODES.M)
private void generateRSAKey_AboveApi23() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEYSTORE_PROVIDER); KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec
.Builder(KEYSTORE_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build(); keyPairGenerator.initialize(keyGenParameterSpec);
keyPairGenerator.generateKeyPair(); }

api23 以下使用 KeyPairGeneratorSpec

 private void generateRSAKey_BelowApi23(Context context) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 30); KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias(KEYSTORE_ALIAS)
.setSubject(new X500Principal("CN=" + KEYSTORE_ALIAS))
.setSerialNumber(BigInteger.TEN)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build(); KeyPairGenerator keyPairGenerator = KeyPairGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEYSTORE_PROVIDER); keyPairGenerator.initialize(spec);
keyPairGenerator.generateKeyPair();
}

(2)产生AES Key后, 并用RSA Public Key加密后存入SharedPrefs

 private void genAESKey() throws Exception {
// Generate AES-Key
byte[] aesKey = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(aesKey); // Generate 12 bytes iv then save to SharedPrefs
byte[] generated = secureRandom.generateSeed(12);
String iv = Base64.encodeToString(generated, Base64.DEFAULT);
prefsHelper.setIV(iv); // Encrypt AES-Key with RSA Public Key then save to SharedPrefs
String encryptAESKey = encryptRSA(aesKey);
prefsHelper.setAESKey(encryptAESKey);
}

  1] 加密存储:使用RSA Public Key 加密 AES Key,存入缓存中。

  2]  解密使用:使用RSA Private Key 解密 得到 AES Key。

 private String encryptRSA(byte[] plainText) throws Exception {
PublicKey publicKey = keyStore.getCertificate(KEYSTORE_ALIAS).getPublicKey(); Cipher cipher = Cipher.getInstance(RSA_MODE);
cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedByte = cipher.doFinal(plainText);
return Base64.encodeToString(encryptedByte, Base64.DEFAULT);
} private byte[] decryptRSA(String encryptedText) throws Exception {
PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEYSTORE_ALIAS, null); Cipher cipher = Cipher.getInstance(RSA_MODE);
cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] encryptedBytes = Base64.decode(encryptedText, Base64.DEFAULT);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes); return decryptedBytes;
}

获取AES :

1 private SecretKeySpec getAESKey() throws Exception {
2 String encryptedKey = prefsHelper.getAESKey();
3 byte[] aesKey = decryptRSA(encryptedKey);
4
5 return new SecretKeySpec(aesKey, AES_MODE);
6 }

再使用AES 加解密内容:

对于:Cipher 初始化

 //实例化加密类,参数为加密方式,要写全
Cipher cipher = Cipher.getIntance("AES/CBC/PKCS5Padding"); //初始化,此方法可以采用三种方式,按服务器要求来添加。
//(1)无第三个参数
//(2)第三个参数为SecureRandom random = new SecureRandom();
// 中random对象,随机数。(AES不可采用这种方法)
//(3)第三个参数:IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec/random);

具体使用:

 /**
* AES Encryption
* @param plainText: A string which needs to be encrypted.
* @return A base64's string after encrypting.
*/
private String encryptAES(String plainText) throws Exception {
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.ENCRYPT_MODE, getAESKey(), new IvParameterSpec(getIV())); // 加密過後的byte
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes()); // 將byte轉為base64的string編碼
return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
} private String decryptAES(String encryptedText) throws Exception {
// 將加密過後的Base64編碼格式 解碼成 byte
byte[] decodedBytes = Base64.decode(encryptedText.getBytes(), Base64.DEFAULT); // 將解碼過後的byte 使用AES解密
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.DECRYPT_MODE, getAESKey(), new IvParameterSpec(getIV())); return new String(cipher.doFinal(decodedBytes));
}

iv 初始化向量

 private byte[] getIV() {
String prefIV = prefsHelper.getIV();
return Base64.decode(prefIV, Base64.DEFAULT);
}

关于RSA:

使用RSA加解密时,在较低版本的手机上可能无法选择OAEP(最优非对称加密填充,RSA的加密解密是基于OAEP的)這個模式;

因此可以改使用RSA_PKCS1_PADDING模式,使用这个模式的話,输入必须比RSA的Key至少11個字节,如果需要被加密的字串过长的话,可以在产生Key时指定Key Size长度,或是将字串分段加密。

以预设Key Size = 2048bit(256byte)來说,输入最长只能到256–11=245byte,我們可以透过setKeySize(int keySize)指定Key的长度,但是Key Size越大,加解密时速度就越慢。

 KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec
.Builder(KEYSTORE_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.setKeySize(4096)
.build();

引言:

RSA Supported sizes: 512, 768, 1024, 2048, 3072, 4096

RSA PKCS1 填充方式

Where is the best place to store a password in your Android app?

Securely Storing Secrets in an Android Application

區塊加密法工作模式

Android Keystore 对称-非对称加密的更多相关文章

  1. [svc]openssl对称非对称加密实战

    OpenSSL进行aes加密解密-对称加密(symmetry) 建立文件test.txt, 特意写入中英文 # cd /tmp # echo "test测试" > test. ...

  2. 常见的哈希Hash算法 & MD5 & 对称非对称加密 & 海明码

    参考 Link 另外,这篇文章也提到了利用Hash碰撞而产生DOS攻击的案例: http://www.cnblogs.com/charlesblc/p/5990475.html DJB的算法实现核心是 ...

  3. 聊聊对称/非对称加密在HTTPS中的使用

    目前常用的加密算法主要分成三类: 对称加密算法 非对称加密算法 消息摘要算法 在互联网中,信息防护主要涉及两个方面:信息窃取和信息篡改.对称/非对称加密算法能够避免信息窃取,而消息摘要算法能够避免信息 ...

  4. 十二张图:从0开始理解对称/非对称加密、CA认证、以及K8S各组件颁发证书原由

    目录 一.对称加密 二.对称加密-不安全 三.非对称加密 四.非对称加密-不安全 五.对称加密和非对称加密结合 六.对称加密和非对称加密结合-不安全 七.Https的做法-引入CA机构 八.乘胜追击理 ...

  5. android 对称加密,非对称加密 android 常见的加密

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha android 常见的加密 ======== 不可逆加密:md5,sha1 可逆的加密中 ...

  6. Android 中 非对称(RSA)加密和对称(AES)加密

    在非对称加密中使用的主要算法有:RSA.Elgamal.背包算法.Rabin.D-H.ECC(椭圆曲线加密算法)等. 优点: 非对称加密与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥, ...

  7. 非对称加解密 Asymmetric encryption 对称加密和非对称加密的区别

    考虑这样一个问题:一切的装备文件都存储在 Git 长途库房,RAR密码破解装备文件中的一些信息又是比较灵敏的.所以,我们需求对这些灵敏信息进行加密处理.首要的加密方法分为两种:一种是同享密钥加 密(对 ...

  8. 个人理解c#对称加密 非对称加密 散列算法的应用场景

    c#类库默认实现了一系列加密算法在System.Security.Cryptography; 命名空间下 对称加密 通过同一密匙进行加密和解密.往往应用在内部数据传输情况下.比如公司a程序 和B程序 ...

  9. ssl原理,非对称加密握手,对称加密传输

    SSL的基本思想是用非对称加密来建立链接(握手阶段),用对称加密来传输数据(传输阶段).这样既保证了密钥分发的安全,也保证了通信的效率. SSL握手,单方服务器认证(一般的浏览器上网) SSL握手,双 ...

随机推荐

  1. R-----shiny包的部分解释和控件介绍

    R-----shiny包的部分解释和控件介绍 作者:周彦通.贾慧 shinyApp( ui = fixedPage( fixedPanel( top = 50, right=50, width=200 ...

  2. Python的安装及小程序练习

    Python 1.Python的安装教程 (1)进入Python官网 (2)双击Python-3.6.4.exe安装程序,勾选Add Python 3.6 to PATH (3)选择自定义安装. (4 ...

  3. docker安装redis

    查询镜像 docker search redis 拉取镜像 docker pull redis 启动容器 docker run --name redis -p 6379:6379 -d --resta ...

  4. Scrapy+Scrapy-redis+Scrapyd+Gerapy 分布式爬虫框架整合

    简介:给正在学习的小伙伴们分享一下自己的感悟,如有理解不正确的地方,望指出,感谢~ 首先介绍一下这个标题吧~ 1. Scrapy:是一个基于Twisted的异步IO框架,有了这个框架,我们就不需要等待 ...

  5. codeforces 1151 D

    SM的水题. codeforces 1151D 当时写对了,因为第一题卡了,,然后这题就没细想,原来是没开longlong. 题意:n个位置每个位置有a和b,让sum=(每个点的左面的点的数量*a+右 ...

  6. Triplet Loss(转)

    参考:https://blog.csdn.net/u013082989/article/details/83537370 作用:用于对差异较小的类别进行区分

  7. CentOs7.5安装PostgreSQL11

    前言 本章介绍在CentOs上安装一个PostgreSQL数据库 下一篇可能是安装 Redis 本篇使用的服务器是已经安装过Python/Nginx等常用软件的环境,因此在安装过程中可能会遇到按照本章 ...

  8. gradle.properties使用

    设置属性 COMPILE_SDK_VERSION = 26 BUILD_TOOLS_VERSION = 26.0.0 MIN_SDK_VERSION = 19 TARGET_SDK_VERSION = ...

  9. Linux从入门到入门

    一. 前言 首先,在你的Windows系统上要想有linux系统,那就必须先安装一款软件,这里提供的是14.15的,还有ISO镜像:VMware-workstation 安装VMware:略 新建虚拟 ...

  10. Java数据类型与运算符

    Java 基本数据类型 Java 的两大数据类型: 内置数据类型 引用数据类型 内置数据类型 Java语言提供了八种基本类型.六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型. b ...