Android Keystore 对称-非对称加密

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

1 private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
2 private static final String AES_MODE = "AES/GCM/NoPadding";
3 private static final String RSA_MODE = "RSA/ECB/PKCS1Padding";
4
5 private static final String KEYSTORE_ALIAS = "KEYSTORE_DEMO";
6
7 KeyStore mKeyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
8 mKeyStore.load(null);

(1)产生随机的RSA Key

产生RSA Key会使用到KeyPairGenerator

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

Api level 23以上改使用KeyGenParameterSpec

1 private void genKeyStoreKey(Context context) throws Exception {
2         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
3             generateRSAKey_AboveApi23();
4         } else {
5             generateRSAKey_BelowApi23(context);
6         }
7     }

api23 以上使用 KeyGenParameterSpec

 1 @RequiresApi(api = Build.VERSION_CODES.M)
 2     private void generateRSAKey_AboveApi23() throws Exception {
 3         KeyPairGenerator keyPairGenerator = KeyPairGenerator
 4                 .getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEYSTORE_PROVIDER);
 5
 6
 7         KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec
 8                 .Builder(KEYSTORE_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
 9                 .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
10                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
11                 .build();
12
13         keyPairGenerator.initialize(keyGenParameterSpec);
14         keyPairGenerator.generateKeyPair();
15
16     }

api23 以下使用 KeyPairGeneratorSpec

 1 private void generateRSAKey_BelowApi23(Context context) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
 2         Calendar start = Calendar.getInstance();
 3         Calendar end = Calendar.getInstance();
 4         end.add(Calendar.YEAR, 30);
 5
 6         KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
 7                 .setAlias(KEYSTORE_ALIAS)
 8                 .setSubject(new X500Principal("CN=" + KEYSTORE_ALIAS))
 9                 .setSerialNumber(BigInteger.TEN)
10                 .setStartDate(start.getTime())
11                 .setEndDate(end.getTime())
12                 .build();
13
14         KeyPairGenerator keyPairGenerator = KeyPairGenerator
15                 .getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEYSTORE_PROVIDER);
16
17         keyPairGenerator.initialize(spec);
18         keyPairGenerator.generateKeyPair();
19     }

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

 1 private void genAESKey() throws Exception {
 2         // Generate AES-Key
 3         byte[] aesKey = new byte[16];
 4         SecureRandom secureRandom = new SecureRandom();
 5         secureRandom.nextBytes(aesKey);
 6
 7         // Generate 12 bytes iv then save to SharedPrefs
 8         byte[] generated = secureRandom.generateSeed(12);
 9         String iv = Base64.encodeToString(generated, Base64.DEFAULT);
10         prefsHelper.setIV(iv);
12
13         // Encrypt AES-Key with RSA Public Key then save to SharedPrefs
14         String encryptAESKey = encryptRSA(aesKey);
15         prefsHelper.setAESKey(encryptAESKey);
16     }

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

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

 1 private String encryptRSA(byte[] plainText) throws Exception {
 2         PublicKey publicKey = keyStore.getCertificate(KEYSTORE_ALIAS).getPublicKey();
 3
 4         Cipher cipher = Cipher.getInstance(RSA_MODE);
 5         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 6
 7         byte[] encryptedByte = cipher.doFinal(plainText);
 8         return Base64.encodeToString(encryptedByte, Base64.DEFAULT);
 9    }
11
12     private byte[] decryptRSA(String encryptedText) throws Exception {
13         PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEYSTORE_ALIAS, null);
14
15         Cipher cipher = Cipher.getInstance(RSA_MODE);
16         cipher.init(Cipher.DECRYPT_MODE, privateKey);
17
18         byte[] encryptedBytes = Base64.decode(encryptedText, Base64.DEFAULT);
19         byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
20
21         return decryptedBytes;
22     }

获取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 初始化

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

具体使用:

 1 /**
 2      * AES Encryption
 3      * @param plainText: A string which needs to be encrypted.
 4      * @return A base64‘s string after encrypting.
 5      */
 6     private String encryptAES(String plainText) throws Exception {
 7         Cipher cipher = Cipher.getInstance(AES_MODE);
 8         cipher.init(Cipher.ENCRYPT_MODE, getAESKey(), new IvParameterSpec(getIV()));
 9
10         // 加密過後的byte
11         byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
12
13         // 將byte轉為base64的string編碼
14         return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
15     }
17
18     private String decryptAES(String encryptedText) throws Exception {
19         // 將加密過後的Base64編碼格式 解碼成 byte
20         byte[] decodedBytes = Base64.decode(encryptedText.getBytes(), Base64.DEFAULT);
21
22         // 將解碼過後的byte 使用AES解密
23         Cipher cipher = Cipher.getInstance(AES_MODE);
24         cipher.init(Cipher.DECRYPT_MODE, getAESKey(), new IvParameterSpec(getIV()));
25
26         return new String(cipher.doFinal(decodedBytes));
27     }

iv 初始化向量

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

关于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越大,加解密时速度就越慢。

1 KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec
2         .Builder(KEYSTORE_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
3         .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
4         .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
5         .setKeySize(4096)
6         .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

區塊加密法工作模式

原文地址:https://www.cnblogs.com/CharlesGrant/p/8378854.html

时间: 2024-10-08 17:47:19

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

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

在非对称加密中使用的主要算法有:RSA.Elgamal.背包算法.Rabin.D-H.ECC(椭圆曲线加密算法)等. 优点: 非对称加密与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解.而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥 比如: 做登陆功能的时候为了数据安全,需要对密码进行加密,这时候可以使用非对称加密, 首先通过后台提供的接口获取公钥,

Android安全加密:对称加密与非对称加密

凯撒密码 1. 介绍 凯撒密码作为一种最为古老的对称加密体制,在古罗马的时候都已经很流行,他的基本思想是:通过把字母移动一定的位数来实现加密和解密.明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文.例如,当偏移量是3 的时候,所有的字母A 将被替换成D,B 变成E,由此可见,位数就是凯撒密码加密和解密的密钥. 例如:字符串"ABC"的每个字符都右移3 位则变成"DEF",解密的时候"DEF"的每个字符左移3 位即能

概念解释:对称加密、非对称加密、公钥、私钥、签名、证书

楔子 现在网络的安全性已经变得越来越重要,各位程序员在开发过程中或多或少都会遇到公钥.私钥.加密.签名等一些相关名词.这些概念比较杂乱,容易混淆,下面就来梳理一下这部分的内容. 对称加密 在重要的信息的传递过程中,人们总是希望信息不会被偷看.不会被篡改,伪造等.为了达到这个要求人们一直在不断努力着. 电报加密使用的密码本,就是初代网络安全所使用的加密方式,用法为:发信时将内容翻译为密文发出,收到电报的一方,使用相同的密码本才能解密出正确的信息,否则看到的就是一堆乱码. 这种传统的加密方式就叫做对

https 结合使用 对称加密和非对称加密

(一)对称加密(Symmetric Cryptography) ---共享密钥加密 对称加密是最快速.最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key),这种方法在密码学中叫做对称加密算法.对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中.对称加密通常使用的是相对较小的密钥,一般小于256 bit.因为密钥越大,加密越强,但加密与解密的过程越慢.如果你只用1 bit来做这个密钥,那黑客们可以先试着用

对称与非对称加密;SSL;HTTPS;AJP

1.对称加密就是加密与解密的时候都是用一个密码 2.非对称加密,有一对密码A,B:用A加密就得用B解密,相对的用B加密就得用A解密 3.公钥与私钥,这一对密码,随便拿一个公布出去,那个就是公钥,剩下一个是私钥. 4.应用1:我想给一个人发信息,我就去拿他公布出来的公钥加密,加密后就只能用私钥来解密,由于私钥在他手中,就能很好在传输中保密. 5.应用2:我收到一个信息,说是银行发来的账单,银行为了不被别人冒牌货发假信息给客户,事先给客户说好,我给你发信息是我的私钥加密了的,所以客户到了信息就要去拿

对称加密与非对称加密

(一)对称加密(Symmetric Cryptography) 对称加密是最快速.最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key).对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中. 对称加密通常使用的是相对较小的密钥,一般小于256 bit.因为密钥越大,加密越强,但加密与解密的过程越慢.如果你只用1 bit来做这个密钥,那黑客们可以先试着用0来解密,不行的话就再用1解:但如果你的密钥有1 MB

对称加密,非对称加密

对称加密: DES(Data Encryption Standard), 1976, 容易被破解,不安全 AES(Advanced Encryption Standard or Rijndael), around 2001,目前最流行 aes-128|192|256 非对称加密(public-key cryptography) RSA: Rivest-Shamir-Adleman 对称加密,非对称加密,布布扣,bubuko.com

第10章 网络安全(1)_对称加密和非对称加密

1 网络安全概述 1.1 计算机网络面临的安全威协 (1)截获:攻击者从网络上窃听他人的通信内容,通常把这类攻击称为"截获".在被动攻击中,攻击者只是观察和分析某一个协议数据单元(PDU)而不干扰信息流. (2)篡改:攻击者篡改网络上传递的报文.这里包括彻底中断传递的报文,甚至把完全伪造的报文传送给接收方,这种攻击也有时也称为"更改报文流".如DNS劫持(域名劫持),安装黑客软件Cain可以进行验证. (3)恶意程序:是一种特殊的主动攻击形式.如计算机病毒.蠕虫.木

单向加密 对称加密 非对称加密

单向加密: 单向加密又称为不可逆加密算法,在加密过程中不使用密钥,明文由系统加密处理成密文,密文无法解密.一般适合于验证,在验证过程中,重新输入明文,并经过同样的加密算法处理,得到相同的密文并被系统重新认证.广泛使用于口令加密. 一:base64 常见于邮件.http加密,截取http信息,你就会发现登录操作的用户名.密码字段通过BASE64加密的. 主要就是BASE64Encoder.BASE64Decoder两个类 BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充 二:md5