【问题标题】:AES Encryption in KotlinKotlin 中的 AES 加密
【发布时间】: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。

标签: android android-studio kotlin encryption


【解决方案1】:

javax.crypto.Cipher 是 JCE 的一部分,应该可用。导入javax.crypto.Cipher 不起作用吗?那么你的环境可能有问题。

【讨论】:

    【解决方案2】:

    我不确定是否有必要使用 Cipher,以及我提供的解决方案是否是最好的方法,但我可以使用 AESencryptiondecryption 使用以下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))
    

    解密

    您必须保存 keyinitialisation vectorencrypted 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 和消息存储在同一数据库的不同位置是可以的。但是对于密钥:密钥管理是整本书的主题;将密钥存储在密文旁边显然不是一个好主意;几乎按照定义,密钥应该比密文更难访问(否则:你要保护什么?)。
    猜你喜欢
    • 2021-10-10
    • 1970-01-01
    • 2021-06-24
    • 2021-10-30
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 2010-10-24
    相关资源
    最近更新 更多