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

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

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

  1. public class CryptoHandler {
  2. private static CryptoHandler instance = null;
  3. public static CryptoHandler getInstance() {
  4. if (instance == null) {
  5. instance = new CryptoHandler();
  6. }
  7. return instance;
  8. }
  9. public String encrypt(String message, String key, String IV) throws NoSuchAlgorithmException,
  10. NoSuchPaddingException, IllegalBlockSizeException,
  11. BadPaddingException, InvalidKeyException,
  12. UnsupportedEncodingException, InvalidAlgorithmParameterException {
  13. byte[] srcBuff = message.getBytes("UTF8");
  14. //here using substring because AES takes only 16 or 24 or 32 byte of key
  15. SecretKeySpec skeySpec = new
  16. SecretKeySpec(key.substring(0,32).getBytes(), "AES");
  17. IvParameterSpec ivSpec = new
  18. IvParameterSpec(IV.substring(0,16).getBytes());
  19. Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
  20. ecipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
  21. byte[] dstBuff = ecipher.doFinal(srcBuff);
  22. String base64 = Base64.encodeToString(dstBuff, Base64.DEFAULT);
  23. return base64;
  24. }
  25. public String decrypt(String encrypted, String key, String IV) throws NoSuchAlgorithmException,
  26. NoSuchPaddingException, InvalidKeyException,
  27. InvalidAlgorithmParameterException, IllegalBlockSizeException,
  28. BadPaddingException, UnsupportedEncodingException {
  29. SecretKeySpec skeySpec = new
  30. SecretKeySpec(key.substring(0,32).getBytes(), "AES");
  31. IvParameterSpec ivSpec = new
  32. IvParameterSpec(IV.substring(0,16).getBytes());
  33. Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
  34. ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
  35. byte[] raw = Base64.decode(encrypted.getBytes(), 0, 16, Base64.DEFAULT);
  36. byte[] originalBytes = ecipher.doFinal(raw);
  37. String original = new String(originalBytes, "UTF8");
  38. return original;
  39. }
  40. }

API响应数据示例:

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

oyt4ldly1#

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

  1. const val AES_KEY = "AES_KEY"
  2. const val AES_IV = "AES_IV"

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

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

然后只需要encode:

  1. fun encrypt(message: String): String? {
  2. try {
  3. val srcBuff = message.toByteArray(charset("UTF8"))
  4. val skeySpec = SecretKeySpec(Base64.decode(pref.getString(Constraints.AES_KEY, null)!!, Base64.DEFAULT), "AES")
  5. val ivSpec = IvParameterSpec(Base64.decode(pref.getString(Constraints.AES_IV, null)!!, Base64.DEFAULT))
  6. val ecipher: Cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
  7. ecipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec)
  8. val dstBuff: ByteArray = ecipher.doFinal(srcBuff)
  9. return Base64.encodeToString(dstBuff, Base64.DEFAULT)
  10. } catch (ex: Exception) {
  11. context.longToast(ex.localizedMessage)
  12. }
  13. return null
  14. }

或解码:

  1. fun decrypt(encrypted: String): String? {
  2. try {
  3. val skeySpec = SecretKeySpec(Base64.decode(pref.getString(Constraints.AES_KEY, null)!!, Base64.DEFAULT), "AES")
  4. val ivSpec = IvParameterSpec(Base64.decode(pref.getString(Constraints.AES_IV, null)!!, Base64.DEFAULT))
  5. val ecipher: Cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
  6. ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec)
  7. val raw: ByteArray = Base64.decode(encrypted, Base64.DEFAULT)
  8. val originalBytes: ByteArray = ecipher.doFinal(raw)
  9. return String(originalBytes, Charset.forName("UTF-8"))
  10. } catch (ex: Exception) {
  11. context.longToast(ex.localizedMessage)
  12. }
  13. return null
  14. }
展开查看全部
rjee0c15

rjee0c152#

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

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

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

xwbd5t1u

xwbd5t1u3#

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

  1. private fun get16CharIv(): String {
  2. return UUID.randomUUID().toString().replace("-", "").substring(0, 16)
  3. }
  4. fun encryptTextWith16CharIv(textToEncrypt: String, key: String): String? {
  5. return try {
  6. val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
  7. val secretKeyByte = key.toByteArray(Charsets.UTF_8)
  8. val keySpec = SecretKeySpec(secretKeyByte, "AES")
  9. val ivSpec = IvParameterSpec(get16CharIv().toByteArray(Charsets.UTF_8))
  10. cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
  11. val encoder = BASE64Encoder()
  12. encoder.encode(cipher.doFinal(textToEncrypt.toByteArray(Charsets.UTF_8)))
  13. } catch (e: Exception) {
  14. null
  15. }
  16. }
  17. fun decryptTextWith16CharIv(encodedTextToDecrypt: String, key: String): String? {
  18. return try {
  19. val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
  20. val secretKeyByte = key.toByteArray(Charsets.UTF_8)
  21. val keySpec = SecretKeySpec(secretKeyByte, "AES")
  22. val ivSpec = IvParameterSpec(get16CharIv().toByteArray(Charsets.UTF_8))
  23. cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
  24. val decodedText = Base64.decode(
  25. encodedTextToDecrypt.toByteArray(Charsets.UTF_8), Base64.DEFAULT
  26. )
  27. String(cipher.doFinal(decodedText))
  28. } catch (e: Exception) {
  29. null
  30. }
  31. }
  32. //Another way to get IV
  33. fun getIv(): ByteArray {
  34. if (IV == null) {
  35. val IV = ByteArray(32)
  36. val random: SecureRandom = SecureRandom()
  37. random.nextBytes(IV)
  38. }
  39. return IV!!
  40. }

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

展开查看全部

相关问题