javax.crypto.AEADBadTagException:GCM中的mac签入失败
我正在开发Android客户端。我们所拥有的:javax.crypto.AEADBadTagException:GCM中的mac签入失败,java,android,kotlin,encryption,aes-gcm,Java,Android,Kotlin,Encryption,Aes Gcm,我正在开发Android客户端。我们所拥有的: 服务器ecnrypts数据通过AES算法和GCM 服务器通过RESTAPI发送给客户端 客户端必须解密数据并显示它 我坚持走3步。我的问题是如何解密到达的数据。这是我已经尝试过的: class PrivateInfoDecrypter { companion object { const val SECRET_KEY = "secret_key" } private val bytes
class PrivateInfoDecrypter {
companion object {
const val SECRET_KEY = "secret_key"
}
private val bytes = ByteArray(16)
private val gcmParameterSpec: GCMParameterSpec = GCMParameterSpec(128, bytes)
fun decrypt(input: String, smsCode: String): String {
val keySpec = generateKey(smsCode)
val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec)
val original = cipher.doFinal(input.toByteArray())
return String(original)
}
private fun generateKey(smsCode: String): SecretKeySpec {
val spec: KeySpec = PBEKeySpec(smsCode.toCharArray(), SECRET_KEY.encodeToByteArray(), 65536, 256)
val f: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
val key: SecretKey = f.generateSecret(spec)
return SecretKeySpec(key.encoded, "AES")
}
}
我在logcat中得到这个错误:
E/Whoops: javax.crypto.AEADBadTagException: mac check in GCM failed
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(BaseBlockCipher.java:1367)
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:1100)
at javax.crypto.Cipher.doFinal(Cipher.java:2056)
加密端:(服务器端代码)
目前,如果没有看到加密方面,您的问题是无法回答的,即使它应该使用不同的语言。原因很简单-GCM模式通过添加HMAC值提供了额外的安全性,但不同语言和实现如何传输该值(“GCM标记”)是不同的。第二:在GCMParameterSpec中,值始终为16个零字节-这对于完整加密的安全性来说是可怕的。请将加密代码添加到您的问题中。@MichaelFehr editedDecryption缺少密文的十六进制解码,除此之外,解密可以在我的机器上工作(如果加密和解密中使用一致的数据,并且省略了未发布的
getPseudoSaltedValue()
)@Topaco这意味着服务器必须向客户端发送带有编码数据的IV?在代码中,用于加密(第1条注释)的IV(实际上是GCM的12个字节)和用于密钥派生的salt(这里称为secretKey
)都是静态的(通常都是为每次加密随机生成的,并与密文一起发送,例如连接). 对于AES/GCM,出于安全原因,密钥/IV对只能使用一次至关重要。为了使用静态IV实现这一点,每次加密都必须更改密钥(或者同样使用静态salt,密码,这里称为optCode
/smsCode
)。
private static final byte[] bytes = new byte[16];
static final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, bytes);
String encrypt(String input) throws Exception {
KeySpec spec = new PBEKeySpec(otpCode.toCharArray(), secretKey.getEncoded(), 65536, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] key = f.generateSecret(spec).getEncoded();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
var salted = getPseudoSaltedValue(val);
return new String(Hex.encode(cipher.doFinal(salted.getBytes())));
}