Kotlin 中的 AES 加密
Posted
技术标签:
【中文标题】Kotlin 中的 AES 加密【英文标题】:AES Encryption in Kotlin 【发布时间】:2021-09-28 04:31:27 【问题描述】:android docs 给出以下 sn-p 以了解如何在 AES 中加密消息:
val plaintext: ByteArray = ...
val keygen = KeyGenerator.getInstance("AES")
keygen.init(256)
val key: SecretKey = keygen.generateKey()
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val ciphertext: ByteArray = cipher.doFinal(plaintext)
val iv: ByteArray = cipher.iv
执行此方法时出现此错误:
未解析的引用:密码
所以看起来“密码”对象不是本地的,但是我无法知道如何按照 Android 文档导入它。 如何设置我的项目以使用“密码”?
【问题讨论】:
javax.crypto.Cipher
是 JCE 的一部分,应该可用。 import javax.crypto.Cipher
不起作用吗?那么你的环境可能有问题。
有趣。看起来它会起作用,但是我不确定根据文档我应该如何了解它。另外,我什至不知道上面的代码是如何工作的。为什么将“明文”声明为 ByteArray?密码在哪里?为什么要在最后一步声明iv?最终加密发生在哪里?
我将编辑这个问题,因为我不知道如何使用上面的代码“sn-p”加密字符串
@metamonkey 请检查我的更新答案一次 :)
评论中的问题都可以从文档中得到解答(例如:为什么“明文”声明为ByteArray
? 因为doFinal()
期望@987654328 @) 或者可以用基本的密码学知识来回答(例如:为什么要在最后一步声明iv?因为解密需要它)。关于您问题中的 Edit:如果您想使用密码而不是密钥,则应使用基于密码的密钥派生函数,如 PBKDF2 或 Argon2。
【参考方案1】:
javax.crypto.Cipher
是 JCE 的一部分,应该可用。导入javax.crypto.Cipher
不起作用吗?那么你的环境可能有问题。
【讨论】:
【参考方案2】:我不确定是否有必要使用 Cipher
,以及我提供的解决方案是否是最好的方法,但我可以使用 AES
为 encryption
和 decryption
使用以下text
输入的代码,表示String
:
加密
// text
val aesEncrypt: AESEncrypt = AESEncrypt()
val encryptedByteArray = aesEncrypt.encrypt(text)
val baos_text = ByteArrayOutputStream()
val oosText = ObjectOutputStream(baos_text)
oosText.writeObject(encryptedByteArray)
val encryptedText = String(android.util.Base64.encode(baos_text.toByteArray(), android.util.Base64.DEFAULT))
// key
val key = aesEncrypt.mySecretKey
val baos = ByteArrayOutputStream()
val oos = ObjectOutputStream(baos)
oos.writeObject(key)
val keyAsString = String(android.util.Base64.encode(baos.toByteArray(), android.util.Base64.DEFAULT))
// initialisation vector
val iv = aesEncrypt.myInitializationVector
val baosIV = ByteArrayOutputStream()
val oosIV = ObjectOutputStream(baosIV)
oosIV.writeObject(iv)
val initialisationVector = String(android.util.Base64.encode(baosIV.toByteArray(), android.util.Base64.DEFAULT))
解密
您必须保存 key
、initialisation vector
和 encrypted text
才能将其解密。
val initialisationVector = ... // get from wherever you saved it, local db, firebase...
val bytesIV = android.util.Base64.decode(iv, android.util.Base64.DEFAULT)
val oisIV = ObjectInputStream(ByteArrayInputStream(bytesIV))
val initializationVectorIV = oisIV.readObject() as ByteArray
val encryptedText = ... // get
val bytesText = android.util.Base64.decode(encryptedText, android.util.Base64.DEFAULT)
val oisText = ObjectInputStream(ByteArrayInputStream(bytesText))
val textByteArray = oisText.readObject() as ByteArray
val key = ... // get your key
val bytesKey = android.util.Base64.decode(key, android.util.Base64.DEFAULT)
val oisKey = ObjectInputStream(ByteArrayInputStream(bytesKey))
val secretKeyObj = oisKey.readObject() as SecretKey
val aesDecrypt = AESDecrypt(secretKeyObj,initializationVectorIV)
val decryptedByteArray = aesDecrypt.decrypt(textByteArray)
val textAfterDecryption = decryptedByteArray.toString(charset("UTF-8"))
编辑
AES 帮助类:
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
class AESEncrypt
var mySecretKey: SecretKey? = null
var myInitializationVector: ByteArray? = null
fun encrypt(strToEncrypt: String): ByteArray
val plainText = strToEncrypt.toByteArray(Charsets.UTF_8)
val keygen = KeyGenerator.getInstance("AES")
keygen.init(256)
val key = keygen.generateKey()
mySecretKey = key
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val cipherText = cipher.doFinal(plainText)
myInitializationVector = cipher.iv
return cipherText
AES 解密助手
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
class AESDecrypt(private val mySecretKey: SecretKey?, private val initializationVector: ByteArray?)
fun decrypt(dataToDecrypt: ByteArray): ByteArray
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
val ivSpec = IvParameterSpec(initializationVector)
cipher.init(Cipher.DECRYPT_MODE, mySecretKey, ivSpec)
val cipherText = cipher.doFinal(dataToDecrypt)
return cipherText
如果您还需要任何帮助,请告诉我们:)
【讨论】:
这是什么类型的 AES?即分组密码?什么填充?等等。另外,保存初始化向量? imo这没有意义。 好吧,我的错,这是一个旧代码,我忘记了这个助手类确实是由我创建的,是的,它确实使用了Cipher
。让我更新我的答案
您可以编辑答案以显示密码输入,而不仅仅是生成新密钥吗?
对于 CBC 模式的攻击者来说,IV “just”需要完全不可预测,通常只是直接在密文前面加上 16 个随机字节。
在用于加密的那一刻,它需要让攻击者无法预测。将 iv 和消息存储在同一数据库的不同位置是可以的。但是对于密钥:密钥管理是整本书的主题;将密钥存储在密文旁边显然不是一个好主意;几乎按照定义,密钥应该比密文更难访问(否则:你要保护什么?)。以上是关于Kotlin 中的 AES 加密的主要内容,如果未能解决你的问题,请参考以下文章