【问题标题】:Android, AES algorithm encrypt and decrypt with key and IV?Android,AES算法用密钥和IV加密和解密?
【发布时间】:2021-04-10 10:43:11
【问题描述】:

我想将明文加密和解密为 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",
}

【问题讨论】:

  • API 使用什么加密方法,采用什么编码?
  • 它带有用于 key 和 iv 的 base64 代码。它采用密钥和 IV 大小的 AES256。加解密采用PKCS7填充类型的ECB/CBC块加密。
  • 嗯,ECB 和 CBC 是不同的操作模式,哪一种?一旦缺少IV,就可以区分ECB和CBC。 AES 的标准 IV 大小始终为 128 位——即块大小。
  • 我不知道。我有一个文档,它正在写你应该使用来自 API 的密钥和 iv 来加密字符串,使用密钥和 iv 使用 AES 算法。
  • 那个键和 IV 看起来是 base 64 编码的,我没有看到你解码任何东西。您可能必须实际学习这些东西,而不仅仅是尝试。

标签: android android-studio aes


【解决方案1】:

我没有看到太多错误,除了它被错误地字符串化(键和 IV 应该包含随机字节值,包括那些不属于可打印 ASCII 字符集的那些)。

然而,最有可能的罪魁祸首是这行:

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

由于 PKCS#7 总是取消填充,使用单个块可能意味着如果它出现在以下块之一中,则取消填充会失败。只需解码整个 base 64,而不仅仅是 16 个字符。

绝对没有任何理由为什么CryptoHandler 应该只有一个实例。您当前的 getInstace 方法也不是线程安全的,因此无论如何您都可能出现多个处理程序。只需使用普通类,并考虑其中应该包含哪些内容。

这主要是所谓的“包装类”。它没有任何用处。我建议编写特定于特定用例的加密相关类。相信我,如果你不这样做,你可能会在以后重写所有内容 - 我去过那里。

【讨论】:

  • 我该如何解决这个问题?
  • 更新答案,只需解码整个base 64编码的密文。
  • 我收到错误“javax.crypto.IllegalBlockSizeException: error:1e00007b:Cipher functions:OPENSSL_internal:WRONG_FINAL_BLOCK_LENGTH”行“byte[] originalBytes = ecipher.doFinal(raw);”
  • 删除 .getBytes() 并使用 the String version of decode 只是为了确定。比较加密的 base 64 输出和解密的输出。
  • 同样的错误我试过byte[] raw = Base64.decode(encrypted, Base64.DEFAULT);byte[] raw = encrypted.getBytes("UTF8");
【解决方案2】:

尤努斯,我遇到了同样的问题,迟到了,但如果其他人再次面临,我正在分享我的解决方案。 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",
}

然后编码:

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
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-21
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    相关资源
    最近更新 更多