一个用于Android AES加密解密的工具类,记录一下。。。

import android.os.Build
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import androidx.annotation.RequiresApi
import java.io.*
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec@RequiresApi(Build.VERSION_CODES.M)
class CryptoManager {companion object {private const val IV_BLOCK_SIZE = 16private const val ALGORITHM = KeyProperties.KEY_ALGORITHM_AESprivate const val BLOCK_MODE = KeyProperties.BLOCK_MODE_CBCprivate const val PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7private const val TRANSFORMATION = "$ALGORITHM/$BLOCK_MODE/$PADDING"private const val KeyStoreType = "AndroidKeyStore"private const val KEY_ALIAS = "SecretKeyAlias"private val cipher = Cipher.getInstance(TRANSFORMATION) //创建密码器fun encrypt(encryptBytes: ByteArray): ByteArray?{try {cipher.init(Cipher.ENCRYPT_MODE, getKey()) //用密钥初始化Cipher对象val final = cipher.doFinal(encryptBytes)return cipher.iv + final  // iv占前16位,加密后的数据占后面} catch (e: Exception) {e.printStackTrace()}return null}fun decrypt(decryptBytes: ByteArray): ByteArray? {try {val iv = decryptBytes.copyOfRange(0, IV_BLOCK_SIZE) // 先取出IVval decryptData = decryptBytes.copyOfRange(IV_BLOCK_SIZE, decryptBytes.size) // 取出加密后的数据cipher.init(Cipher.DECRYPT_MODE, getKey(), IvParameterSpec(iv))return cipher.doFinal(decryptData)} catch (e: Exception) {e.printStackTrace()}return null}// type设为"AndroidKeyStore"使用Android专门提供的密钥存储系统,可以根据别名获取key, 类似于spprivate val keyStore = KeyStore.getInstance(KeyStoreType).apply { load(null) }private fun getKey(): SecretKey {val existingKey = keyStore.getEntry(KEY_ALIAS, null) as? KeyStore.SecretKeyEntryreturn existingKey?.secretKey ?: generateKey()}private fun generateKey(): SecretKey {return KeyGenerator.getInstance(ALGORITHM, KeyStoreType).apply {init(KeyGenParameterSpec.Builder(KEY_ALIAS,KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT).setBlockModes(BLOCK_MODE).setEncryptionPaddings(PADDING).setUserAuthenticationRequired(false).setRandomizedEncryptionRequired(true).build())}.generateKey()}/*** 将 text 加密*/fun encrypt(text: String): String? {val encryptedBytes = encrypt(text.toByteArray())return encryptedBytes?.let {// NO_WRAP is important as was getting \n at the endBase64.encodeToString(it, Base64.NO_WRAP)}}/*** 将 text 解密*/fun decrypt(base64EncodedText: String): String? {val decodedCipherBytes = Base64.decode(base64EncodedText, Base64.NO_WRAP)val decryptedBytes = decrypt(decodedCipherBytes)return decryptedBytes?.let { String(it) }}}
}

(注意:上面代码使用了一些API要求在 Android 6.0 以上)

以下 Cipher 类支持设置的加密算法:

上面代码中 Cipher 使用的就是 AES/CBC/PKCS7Padding 这一种加密算法。

这里关键的一点是加密解密用的 key 是使用 KeyStore 来存储,它是 Android 的密钥库系统,使用 KeyStore 存储的密钥只能使用但是不能从设备中导出,安全性更好。详情可以参考:Android 密钥库系统。

使用方式:

// 加密结果
val textEncrypted = CryptoManager.encrypt("hello world") ?: ""
// 解密结果
val textDecrypted = CryptoManager.decrypt(textEncrypted) ?: ""

这种使用方式是将文本加密后以Base64的字符串形式返回,解密时再传回这段Base64字符串。

还可以直接加密成 byte 数组来保存,但解密时同样需要传回 byte 数组:

// 加密结果
var encryptedBytes: ByteArray? = CryptoManager.encrypt(text.toByteArray())
// 如需将加密结果转换成文本,可以这样做
val textEncrypted = encryptedBytes?.let { String(it) } ?: ""// 解密结果
var decryptedBytes: ByteArray? = encryptedBytes?.let { CryptoManager.decrypt(it) }
// 如需将解密结果转换成文本,可以这样做
val textDecrypted = decryptedBytes?.let { String(it) }  ?: ""

示例 demo:

import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.fly.mycompose.application.ui.theme.MyComposeApplicationTheme@RequiresApi(Build.VERSION_CODES.M)
class EncryptActivity : ComponentActivity() {var encryptedBytes: ByteArray? = nullvar decryptedBytes: ByteArray? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) setContent {MyComposeApplicationTheme {var text by remember { mutableStateOf("") }var textEncrypted by remember { mutableStateOf("") }var textDecrypted by remember { mutableStateOf("") }Column(modifier = Modifier.fillMaxSize().padding(32.dp).verticalScroll(rememberScrollState())) {TextField(value = text,onValueChange = { text = it },modifier = Modifier.fillMaxWidth(),placeholder = { Text(text = "请输入加密内容") })Spacer(modifier = Modifier.height(8.dp))Row {Button(onClick = { textEncrypted = CryptoManager.encrypt(text) ?: "" // encryptedBytes = CryptoManager.encrypt(text.toByteArray())// textEncrypted = encryptedBytes?.let { String(it) } ?: ""}) {Text(text = "加密")}Spacer(modifier = Modifier.width(16.dp))Button(onClick = { textDecrypted = CryptoManager.decrypt(textEncrypted) ?: "" // decryptedBytes = encryptedBytes?.let { CryptoManager.decrypt(it) }// textDecrypted = decryptedBytes?.let { String(it) }  ?: ""}) {Text(text = "解密")}}Text(text = "加密后的内容:$textEncrypted")Text(text = "解密后的内容:$textDecrypted")}}}}
}

下面是另一个工具类,在其他地方看到的,实现方式也是类似,这个没有API在 Android 6.0 以上的限制,但是它没有使用 KeyStore 来存储 key,在加密/解密时还需要显示的指定一个密码。

import android.util.Base64
import android.util.Base64.*
import java.io.UnsupportedEncodingException
import java.security.GeneralSecurityException
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpecobject AESCryptUtil {private const val AES_MODE = "AES/CBC/PKCS7Padding"private const val CHARSET = "UTF-8"private const val CIPHER = "AES"private const val HASH_ALGORITHM = "SHA-256"private val IV_BYTES = byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)/*** Generates SHA256 hash of the password which is used as key** @param password used to generated key* @return SHA256 of the password*/private fun generateKey(password: String): SecretKeySpec {val digest = MessageDigest.getInstance(HASH_ALGORITHM)val bytes = password.toByteArray(charset(CHARSET))digest.update(bytes, 0, bytes.size)val key = digest.digest()return SecretKeySpec(key, CIPHER)}/*** Encrypt and encode message using 256-bit AES with key generated from password.** @param password used to generated key* @param message  the thing you want to encrypt assumed String UTF-8* @return Base64 encoded CipherText* @throws GeneralSecurityException if problems occur during encryption*/fun encrypt(password: String, message: String): String {try {val key = generateKey(password)val cipherText = encrypt(key, IV_BYTES, message.toByteArray(charset(CHARSET)))//NO_WRAP is important as was getting \n at the endreturn Base64.encodeToString(cipherText, Base64.NO_WRAP)} catch (e: UnsupportedEncodingException) {throw GeneralSecurityException(e)}}/*** More flexible AES encrypt that doesn't encode** @param key     AES key typically 128, 192 or 256 bit* @param iv      Initiation Vector* @param message in bytes (assumed it's already been decoded)* @return Encrypted cipher text (not encoded)* @throws GeneralSecurityException if something goes wrong during encryption*/@Throws(GeneralSecurityException::class)fun encrypt(key: SecretKeySpec, iv: ByteArray, message: ByteArray): ByteArray {val cipher = Cipher.getInstance(AES_MODE)val ivSpec = IvParameterSpec(iv)cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec)return cipher.doFinal(message)}/*** Decrypt and decode ciphertext using 256-bit AES with key generated from password** @param password                used to generated key* @param base64EncodedCipherText the encrpyted message encoded with base64* @return message in Plain text (String UTF-8)* @throws GeneralSecurityException if there's an issue decrypting*/@Throws(GeneralSecurityException::class)fun decrypt(password: String, base64EncodedCipherText: String): String {try {val key = generateKey(password)val decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP)val decryptedBytes = decrypt(key, IV_BYTES, decodedCipherText)return String(decryptedBytes, charset(CHARSET))} catch (e: UnsupportedEncodingException) {throw GeneralSecurityException(e)}}/*** More flexible AES decrypt that doesn't encode** @param key               AES key typically 128, 192 or 256 bit* @param iv                Initiation Vector* @param decodedCipherText in bytes (assumed it's already been decoded)* @return Decrypted message cipher text (not encoded)* @throws GeneralSecurityException if something goes wrong during encryption*/@Throws(GeneralSecurityException::class)fun decrypt(key: SecretKeySpec, iv: ByteArray, decodedCipherText: ByteArray): ByteArray {val cipher = Cipher.getInstance(AES_MODE)val ivSpec = IvParameterSpec(iv)cipher.init(Cipher.DECRYPT_MODE, key, ivSpec)return cipher.doFinal(decodedCipherText)}
}

使用方式:

// 加密结果
val textEncrypted = AESCryptUtil.encrypt("123456", "hello world")
// 解密结果
val textDecrypted = AESCryptUtil.decrypt("123456", textEncrypted)

Android AES加密解密工具类相关推荐

  1. Java AES 加密解密工具类

    maven 引入一个依赖 <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <depen ...

  2. java aes 工具类_AESUtil Java AES 加密解密工具类

    package com.singlee.util; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; impo ...

  3. JAVA AES加密解密工具类

    import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.spec. ...

  4. java aes 工具类_Java中的AES加解密工具类:AESUtils

    本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.constants.SysConsta ...

  5. java des加密解密_Java实现的DES加密解密工具类实例

    本文实例讲述了Java实现的DES加密解密工具类.分享给大家供大家参考,具体如下: 一个工具类,很常用,不做深入研究了,那来可直接用 DesUtil.java package lsy; import ...

  6. java des 加密工具的使用,Java中DES加密解密工具类的实现实例

    这篇文章主要介绍了Java实现的DES加密解密工具类,结合具体实例形式分析了Java实现的DES加密解密工具类定义与使用方法,需要的朋友可以参考下 本文实例讲述了Java实现的DES加密解密工具类.分 ...

  7. jwt加密解密工具类

    jwt 加密&解密工具类 引入依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId ...

  8. 在线AES加密/解密工具

    在线AES加密/解密工具 在线AES加密/解密工具 使用工具测试加密结果 http://lzltool.com/AES 使用工具测试解密结果 http://lzltool.com/AES

  9. java字符串加密解密工具类

    /*** 字符串加密解密工具类** @author guyuqiang* @date 2021-06-07*/ public class StringEncryptUtil {/*** 字符串默认键值 ...

最新文章

  1. Spring IoC 学习(3)
  2. linux遭入侵挖矿进程被隐藏案例分析
  3. apache评分表的意义_APACHE评分系统及评分表
  4. C++_标准模板库STL概念介绍5-其他库与总结
  5. jq修改导航栏样式(选中、使用两张图片替代的是否选中效果)
  6. 基于嵌入式webserver的服务器状态监控
  7. map怎么转化dto_使用MapStruct进行Dto到实体的转换时出错
  8. 光线如何从宇宙黑暗时代逃逸:黑洞让宇宙变光明
  9. c语言习题集(含答案)
  10. 传奇修改map地图教程_传奇地图MAP编辑器
  11. c语言单片机当型编程,手把手教你学单片机的C语言程序设计(十四).pdf
  12. Python基础+数据科学入门(四)程序控制结构
  13. pygame画圆练习赤橙黄绿青蓝紫
  14. [Err] 1146 [Err] 1682
  15. 【数据分析】京东平台用户画像分析
  16. PHP如何启动scrapy,python,_新手Scrapy爬虫运行问题,python - phpStudy
  17. 怎样和控制欲很强的家人相处-不受他人影响
  18. python文件的两种类型是什么意思_Python文件处理里encoding和encode有事区别,bytes类型是什么意思?...
  19. 希捷ST9500325AS本盘0容量数据恢复
  20. 将txt文件数据转成bin文件.

热门文章

  1. 请问一个神经网络的问题
  2. 2022年全球与中国配电自动化系统市场现状及未来发展趋势
  3. 维特比算法的java实现_原创:维特比算法
  4. B站微博吾爱破解知乎热榜软件
  5. 一个顾客买了价值x元的商品,并将y元的钱交给售货员。售货员希望用张数最少的钱币找给顾客。 无论买商品的价值x是多大,找给他的钱最多需要以下六种币值:50,20,10,5,2,1
  6. 掩膜区域内像素值_掩膜(mask)
  7. 小程序如何指定按钮分享指定内容
  8. 【ZZULIOJ】1103: 平均学分绩点(函数专题)
  9. C++ 判断是否存在Emjoi表情
  10. 16进制转带符号的10进制,16进制转负数10进制