Android keyStore系统存储的RSA密钥,加解密处理

Android keyStore系统存储的RSA密钥,加解密处理

Android有keysrore可以存储密钥,RSA密钥对中,公钥可以取出,私钥不能取出只能使用。本文只看23就是6.0及以上。

生产密钥对

生成密钥的参数。

spec = new KeyGenParameterSpec.Builder(mAlias, KeyProperties.PURPOSE_SIGN
                    | KeyProperties.PURPOSE_ENCRYPT
                    | KeyProperties.PURPOSE_DECRYPT)
                    .setKeySize(DEFAULT_KEY_SIZE)
                    .setUserAuthenticationRequired(false)
                    .setCertificateSubject(new X500Principal("CN=" + mAlias))
                    //, KeyProperties.DIGEST_NONE, KeyProperties.DIGEST_SHA224, KeyProperties.DIGEST_SHA384,
                    // KeyProperties.DIGEST_SHA512, KeyProperties.DIGEST_MD5)
                    .setDigests(KeyProperties.DIGEST_SHA512,KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_MD5)
                    .setCertificateNotBefore(start.getTime())
                    .setCertificateNotAfter(end.getTime())
                    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
                    .build();
使用参数

KeyProperties.PURPOSE_SIGN
| KeyProperties.PURPOSE_ENCRYPT
| KeyProperties.PURPOSE_DECRYP
这三个是声明密钥是可以用来干啥的:加密,解密和签名。
注意:私钥不能用来加密,取私钥加密的时候会报key操作失败。可能是我用的不对,但是目前是这样。因为公钥是明文,私钥加密无法对数据进行保护。

签名算法

setDigests(KeyProperties.DIGEST_SHA512,KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_MD5)
如果没有申明使用,会报操作失败。

加解密填充

setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
里面虽然有PKCS7,但是不是给给RSA使用的。这个pkcs1也不是对称密钥的那种填充规则。啰嗦一下。
同样,这里如果不申明,后续填充是无法使用的。

Android支持的RSA操作官方文档描述如下:

RSA/ECB/NoPadding	18+	
RSA/ECB/PKCS1Padding	18+	
RSA/ECB/OAEPWithSHA-1AndMGF1Padding	23+	
RSA/ECB/OAEPWithSHA-224AndMGF1Padding	23+	
RSA/ECB/OAEPWithSHA-256AndMGF1Padding	23+	
RSA/ECB/OAEPWithSHA-384AndMGF1Padding	23+	
RSA/ECB/OAEPWithSHA-512AndMGF1Padding	23+	
RSA/ECB/OAEPPadding	23+

加解密开始

加密

keyStore里面的生成的密钥长度可以是K:1024,2048。目前常用是这两个其他的不考虑。那么rsa加密最长数据段为:K/8.就是1024/8或者2048/8.
以2048为例最大数据长度为256.
如果我们的数据长度超过256,就需要进行分段加密。比较非对称密钥计算时间太长,一般也不会使用太长数据。

然后就是填充:

  1. 如果是无填充,那么数据长度就是256.
  2. 如果是pcks1,那么最大数据长度是256-11=245
  3. 如果是OAEPWithSHA-**AndMGF1Padding 代表哈希数,那么明文最大长度是:256-2(/8)-2
  4. OAEPPadding 这个好像默认是使用sha-1。有待研究。

所以根据上面的填充规则,我们数据段切割的时候,就需要注意长度。

 ByteArrayOutputStream out = new ByteArrayOutputStream();
               int offSet = 0;
               int inputLen = needEncryptWord.length();
               byte[] inputData = needEncryptWord.getBytes();
               for (int i = 0; inputLen - offSet > 0; offSet = i * blockSize) {//最大长度245(256-11)PKCS1
                   byte[] cache;
                   if (inputLen - offSet > rsaEncryptBlock) {
                       cache = inCipher.doFinal(inputData, offSet, blockSize);
                   } else {
                       cache = inCipher.doFinal(inputData, offSet, inputLen - offSet);
                   }
                   out.write(cache, 0, cache.length);
                   ++i;
               }
               byte[] encryptedData = out.toByteArray();
               out.close();

填充完毕,数据合并,一次加密完成。

解密

解密就比较简单了。同样是分段解密,注意数据长度:就是类似:2048/8。具体的看自己的密钥长度。

 for (int i = 0; inputLen - offSet > 0; offSet = i * rsaDecryptBlock) {//rsaDecryptBlock=2048/8
                    byte[] cache;
                    if (inputLen - offSet > rsaDecryptBlock) {
                        cache = outCipher.doFinal(encryptedData, offSet, rsaDecryptBlock);
                    } else {
                        cache = outCipher.doFinal(encryptedData, offSet, inputLen - offSet);
                    }
                    out.write(cache, 0, cache.length);
                    ++i;
                }

分段解密,合并数据。

签名

签名部分直接贴代码:

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
        Signature s = Signature.getInstance("SHA1withRSA");
        s.initSign(privateKeyEntry.getPrivateKey());
        s.update(data.getBytes());
        return Base64.encodeToString(s.sign(),0);
验签
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);

        Signature s = Signature.getInstance("SHA1withRSA");
        s.initVerify(privateKeyEntry.getCertificate());
        s.update(srcData.getBytes());

        return s.verify(Base64.decode(sign.getBytes(), 0));

关于签名部分的填充,暂时没看明白,希望得到大佬们的指点。

以上,完成。谢谢。希望大佬们留言讨论。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
当将密钥存储Android Keystore中时,以下是一些示例代码: 1. 生成AES密钥: ```java KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); keyGenerator.init(new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .setUserAuthenticationRequired(true) // 需要用户验证 .build()); SecretKey secretKey = keyGenerator.generateKey(); ``` 2. 加载KeyStore: ```java KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); ``` 3. 生成并存储密钥对: ```java KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); keyPairGenerator.initialize(new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) .setUserAuthenticationRequired(true) // 需要用户验证 .build()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); ``` 4. 使用密钥: ```java PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, null); PublicKey publicKey = keyStore.getCertificate(keyAlias).getPublicKey(); // 使用私钥进行加密 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] encryptedData = cipher.doFinal(data); // 使用公钥进行解密 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] decryptedData = cipher.doFinal(encryptedData); ``` 请注意,以上代码仅为示例,您需要根据自己的需求进行修改和适配。确保密钥别名(keyAlias)是唯一且安全的,并在必要时处理异常。此外,代码中的用户验证(User Authentication)部分可以根据您的需求进行调整。 希望这些代码能够帮助您在Android应用程序中将密钥存储Android Keystore中。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值