Android Studio Android,AES算法加密和解密与密钥和IV?

vcudknz3  于 2023-10-23  发布在  Android
关注(0)|答案(3)|浏览(194)

我想用AES算法加密和解密明文。我得到的密钥和iv来自API。我尝试了很多方法,但都不管用。怎么了?
https://github.com/simbiose/Encryption
https://github.com/scottyab/AESCrypt-Android

public class CryptoHandler {

    private static CryptoHandler instance = null;

    public static CryptoHandler getInstance() {

        if (instance == null) {
            instance = new CryptoHandler();
        }
        return instance;
    }

    public String encrypt(String message, String key, String IV) throws NoSuchAlgorithmException,
            NoSuchPaddingException, IllegalBlockSizeException,
            BadPaddingException, InvalidKeyException,
            UnsupportedEncodingException, InvalidAlgorithmParameterException {

        byte[] srcBuff = message.getBytes("UTF8");
        //here using substring because AES takes only 16 or 24 or 32 byte of key
        SecretKeySpec skeySpec = new
                SecretKeySpec(key.substring(0,32).getBytes(), "AES");
        IvParameterSpec ivSpec = new
                IvParameterSpec(IV.substring(0,16).getBytes());
        Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        ecipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
        byte[] dstBuff = ecipher.doFinal(srcBuff);
        String base64 = Base64.encodeToString(dstBuff, Base64.DEFAULT);
        return base64;
    }

    public String decrypt(String encrypted, String key, String IV) throws NoSuchAlgorithmException,
            NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException,
            BadPaddingException, UnsupportedEncodingException {

        SecretKeySpec skeySpec = new
                SecretKeySpec(key.substring(0,32).getBytes(), "AES");
        IvParameterSpec ivSpec = new
                IvParameterSpec(IV.substring(0,16).getBytes());
        Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
        byte[] raw = Base64.decode(encrypted.getBytes(), 0, 16, Base64.DEFAULT);
        byte[] originalBytes = ecipher.doFinal(raw);
        String original = new String(originalBytes, "UTF8");
        return original;
    }

}

API响应数据示例:

{
  "key": "QaDtfPpeMW0VgMMd4XF88K6KkIPe5ZG0sitpyhuJf/E=",
  "iv": "ccp2YePjewVL9X+vCms5BQ==",
  "string": "5c2c82a6-66da-41f9-b20d-5d4ffd0c505a",
}
oyt4ldly

oyt4ldly1#

尤努斯,我也面临同样的问题,晚了,但如果其他人再次面临,我分享我的解决方案。Key和IVkey已经转换为base64并准备解码,因此不需要substr过程。当你做substr的时候,你会失去整个键的一部分。
下面的键是从共享的首选项中读取的。

const val AES_KEY = "AES_KEY"
    const val AES_IV = "AES_IV"

sharedprefs返回与您的键相同的键(编码为base64并且作为字符串-而不是bytearray-)

{
  "key": "QaDtfPpeMW0VgMMd4XF88K6KkIPe5ZG0sitpyhuJf/E=",
  "iv": "ccp2YePjewVL9X+vCms5BQ==",
  "string": "5c2c82a6-66da-41f9-b20d-5d4ffd0c505a",
}

然后只需要encode:

fun encrypt(message: String): String? {
    try {
        val srcBuff = message.toByteArray(charset("UTF8"))
        val skeySpec = SecretKeySpec(Base64.decode(pref.getString(Constraints.AES_KEY, null)!!, Base64.DEFAULT), "AES")
        val ivSpec = IvParameterSpec(Base64.decode(pref.getString(Constraints.AES_IV, null)!!, Base64.DEFAULT))
        val ecipher: Cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
        ecipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec)
        val dstBuff: ByteArray = ecipher.doFinal(srcBuff)
        return Base64.encodeToString(dstBuff, Base64.DEFAULT)
    } catch (ex: Exception) {
        context.longToast(ex.localizedMessage)
    }
    return null
}

或解码:

fun decrypt(encrypted: String): String? {
        try {
            val skeySpec = SecretKeySpec(Base64.decode(pref.getString(Constraints.AES_KEY, null)!!, Base64.DEFAULT), "AES")
            val ivSpec = IvParameterSpec(Base64.decode(pref.getString(Constraints.AES_IV, null)!!, Base64.DEFAULT))
            val ecipher: Cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
            ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec)
            val raw: ByteArray = Base64.decode(encrypted, Base64.DEFAULT)
            val originalBytes: ByteArray = ecipher.doFinal(raw)
            return String(originalBytes, Charset.forName("UTF-8"))
        } catch (ex: Exception) {
            context.longToast(ex.localizedMessage)
        }
        return null
    }
rjee0c15

rjee0c152#

除了字符串化不正确(键和IV应该包含随机字节值,包括那些不属于可打印ASCII字符集的值)之外,我没有看到太多错误。
然而,最有可能的罪魁祸首是这一行:

byte[] raw = Base64.decode(encrypted.getBytes(), 0, 16, Base64.DEFAULT);

由于PKCS#7总是取消填充,因此使用单个块可能意味着如果它出现在以下块之一中,则取消填充失败。只要解码整个基64,而不仅仅是16个字符。
CryptoHandler绝对没有理由只有一个示例。您当前的getInstace方法也不是线程安全的,因此无论如何都可能出现多个处理程序。只要使用普通的类,并考虑它们应该包含什么。
这主要是一个所谓的“ Package 器类”。它没有任何用处。我建议编写特定于特定用例的加密相关类。相信我,当我说你可能最终重写一切以后,如果你不-我已经在那里。

xwbd5t1u

xwbd5t1u3#

不需要任何第三方图书馆。

private fun get16CharIv(): String {
    return UUID.randomUUID().toString().replace("-", "").substring(0, 16)
}

fun encryptTextWith16CharIv(textToEncrypt: String, key: String): String? {
    return try {
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        val secretKeyByte = key.toByteArray(Charsets.UTF_8)
        val keySpec = SecretKeySpec(secretKeyByte, "AES")
        val ivSpec = IvParameterSpec(get16CharIv().toByteArray(Charsets.UTF_8))
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
        val encoder = BASE64Encoder()
        encoder.encode(cipher.doFinal(textToEncrypt.toByteArray(Charsets.UTF_8)))
    } catch (e: Exception) {
        null
    }
}

fun decryptTextWith16CharIv(encodedTextToDecrypt: String, key: String): String? {
    return try {
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        val secretKeyByte = key.toByteArray(Charsets.UTF_8)
        val keySpec = SecretKeySpec(secretKeyByte, "AES")
        val ivSpec = IvParameterSpec(get16CharIv().toByteArray(Charsets.UTF_8))
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
        val decodedText = Base64.decode(
            encodedTextToDecrypt.toByteArray(Charsets.UTF_8), Base64.DEFAULT
        )
        String(cipher.doFinal(decodedText))
    } catch (e: Exception) {
        null
    }
}

//Another way to get IV
fun getIv(): ByteArray {
    if (IV == null) {
        val IV = ByteArray(32)
        val random: SecureRandom = SecureRandom()
        random.nextBytes(IV)
    }
    return IV!!
}

还有一种填充格式称为无填充。我们必须使用“AES/CBC/NoPadding”

相关问题