How do initial the IV correctly?

Viewed 84

When Google refered me to this issue, I added to IvParameterSpec the first 16 bytes of hash of provided key. This ensures to me that for each encryption/decryption the same IV is used:

fun encipher(value: String, key: String): String {
    val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
    cipher.init(
        Cipher.ENCRYPT_MODE,
        SecretKeySpec(hash(key, 32), "AES"),
        IvParameterSpec(hash(key, 16)) 
    )
    return Base64.encodeToString(cipher.doFinal(value.toByteArray()), Base64.DEFAULT)
}

fun decipher(value: String?, key: String = CRYPT_PASS): String {
    val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
    cipher.init(
        Cipher.DECRYPT_MODE,
        SecretKeySpec(hash(key, 32), "AES"),
        IvParameterSpec(hash(key, 16))
    )
    return String(cipher.doFinal(Base64.decode(value?.toByteArray(), Base64.DEFAULT)))
}

The problem is, the decryption does not give the original text back. Let's say I encrypt this text

Arctium is a genus of biennial plants commonly known as burdock, family Asteraceae.

but, after decryption I get

w@[GL^FQAURQ[us of biennial plants commonly known as burdock, family Asteraceae.

Why does it happen? Did I do something wrong?

EDIT: Here is the missing part:

// This one is called while encrypting and decrypting
private fun hash(key: String?, length: Int): ByteArray {
    return hash(hash(key).substring(0, length)).substring(
        0,
        length
    ).toByteArray()
}

private fun hash(data: String?): String {
    val md = MessageDigest.getInstance("SHA-256")
    data?.toByteArray()?.let { md.update(it) }
    val result = StringBuffer()
    for (bt in md.digest())
        result.append(((bt and 0xFF.toByte()) + 0x100).toString(16).substring(1))
    return result.toString()
}

Test data:

    val newData = arrayListOf(
    Data("First test string...", "FirstKey"),
    Data("Second test string...", "SecondKey"),
    Data("First test string...", "FirstKey"))
    
    newData.forEach {
       roomDb.addData(encipher(it.text, it.pass))
    }
    
    ....
    
    roomData.forEachIndexed { s, i ->
       decData.add(decipher(s), newData[i]))
    }
0 Answers
Related