Decrypting Dart AES encrypted data in Kotlin results in BadPaddingException
Dart加密代码
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:encrypt/encrypt.dart';
class CryptoService {
static String encryptString(String input) {
const keyString = "ABCdefg1234!!";
final keyBytes = sha256.convert(utf8.encode(keyString)).bytes;
final key = Key(Uint8List.fromList(keyBytes));
final iv = IV.fromSecureRandom(16);
final encrypter = Encrypter(AES(key));
final encrypted = encrypter.encrypt(input, iv: iv);
final combined = iv.bytes + encrypted.bytes;
return base64Url.encode(combined);
}
static String decryptString(String encoded) {
const keyString = "ABCdefg1234!!";
final keyBytes = sha256.convert(utf8.encode(keyString)).bytes;
final key = Key(Uint8List.fromList(keyBytes));
final encrypter = Encrypter(AES(key));
final combinedBytes = base64Url.decode(encoded);
final ivBytes = combinedBytes.sublist(0, 16);
final encryptedBytes = combinedBytes.sublist(16);
final iv = IV(Uint8List.fromList(ivBytes));
final encrypted = Encrypted(encryptedBytes);
final decrypted = encrypter.decrypt(encrypted, iv: iv);
return decrypted;
}
}
void main() {
print(CryptoService.encryptString("abcdef"));
}
Kotlin解密代码
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.util.*
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import java.security.SecureRandom
object CryptoService {
private const val keyString = "ABCdefg1234!!"
private fun generateKey(): SecretKey {
val keyBytes = MessageDigest.getInstance("SHA-256").digest(keyString.toByteArray(StandardCharsets.UTF_8))
return SecretKeySpec(keyBytes, "AES")
}
fun encryptString(input: String): String {
val key = generateKey()
val iv = ByteArray(16).apply { SecureRandom().nextBytes(this) }
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding").apply {
init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
}
val encryptedBytes = cipher.doFinal(input.toByteArray(StandardCharsets.UTF_8))
val combined = iv + encryptedBytes
return Base64.getUrlEncoder().encodeToString(combined)
}
fun decryptString(encoded: String): String {
val key = generateKey()
val combinedBytes = Base64.getUrlDecoder().decode(encoded)
val iv = combinedBytes.sliceArray(0 until 16)
val encryptedBytes = combinedBytes.sliceArray(16 until combinedBytes.size)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding").apply {
init(Cipher.DECRYPT_MODE, key, IvParameterSpec(iv))
}
val decryptedBytes = cipher.doFinal(encryptedBytes)
return String(decryptedBytes, StandardCharsets.UTF_8)
}
}
fun main() {
println(CryptoService.decryptString("FzaO3XI3ZVtUDAdM1So357dhQwg37fh0vzVr6jkPDaY="))
println("end")
}
报错如下:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.unpad (:-1)
at com.sun.crypto.provider.CipherCore.fillOutputBuffer (:-1)
at com.sun.crypto.provider.CipherCore.doFinal (:-1)
解决:
kotlin解密部分改为如下代码:
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.util.*
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import java.security.SecureRandom
import org.bouncycastle.jce.provider.BouncyCastleProvider
import javax.crypto.SecretKey
object CryptoService {
private const val keyString = "ABCdefg1234!!"
init {
Security.addProvider(BouncyCastleProvider())
}
// 此处是关键代码
private fun generateKey(): SecretKey {
val keyBytes = MessageDigest.getInstance("SHA-256").digest(keyString.toByteArray(StandardCharsets.UTF_8))
return SecretKeySpec(keyBytes, "AES")
}
fun encryptString(input: String): String {
val key = generateKey()
val iv = ByteArray(16).apply { SecureRandom().nextBytes(this) }
val cipher = Cipher.getInstance("AES/CTR/PKCS5Padding", "BC").apply {
init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
}
val encryptedBytes = cipher.doFinal(input.toByteArray(StandardCharsets.UTF_8))
val combined = iv + encryptedBytes
return Base64.getUrlEncoder().encodeToString(combined)
}
fun decryptString(encoded: String): String {
val key = generateKey()
val combinedBytes = Base64.getUrlDecoder().decode(encoded)
val iv = combinedBytes.sliceArray(0 until 16)
val encryptedBytes = combinedBytes.sliceArray(16 until combinedBytes.size)
val cipher = Cipher.getInstance("AES/CTR/PKCS5Padding", "BC").apply {
init(Cipher.DECRYPT_MODE, key, IvParameterSpec(iv))
}
val decryptedBytes = cipher.doFinal(encryptedBytes)
return String(decryptedBytes, StandardCharsets.UTF_8)
}
}
fun main() {
println(CryptoService.decryptString("FzaO3XI3ZVtUDAdM1So357dhQwg37fh0vzVr6jkPDaY="))
println("end")
}