I am trying to decode the response from Google Play Integrity in Android client. I followed the steps from here. Decoding from server works however decoding locally results in this exception:
stackTrace = {StackTraceElement[18]@28628}
0 = {StackTraceElement@28631} "org.jose4j.jwe.SimpleAeadCipher.decrypt(SimpleAeadCipher.java:109)"
1 = {StackTraceElement@28632} "org.jose4j.jwe.AesGcmContentEncryptionAlgorithm.decrypt(AesGcmContentEncryptionAlgorithm.java:79)"
2 = {StackTraceElement@28633} "org.jose4j.jwe.JsonWebEncryption.decrypt(JsonWebEncryption.java:211)"
3 = {StackTraceElement@28634} "org.jose4j.jwe.JsonWebEncryption.getPlaintextBytes(JsonWebEncryption.java:79)"
4 = {StackTraceElement@28635} "org.jose4j.jwe.JsonWebEncryption.getPlaintextString(JsonWebEncryption.java:72)"
5 = {StackTraceElement@28636} "org.jose4j.jwe.JsonWebEncryption.getPayload(JsonWebEncryption.java:87)"
...
8 = {StackTraceElement@28639} "java.lang.reflect.Method.invoke(Native Method)"
12 = {StackTraceElement@28643} "android.os.AsyncTask$3.call(AsyncTask.java:394)"
13 = {StackTraceElement@28644} "java.util.concurrent.FutureTask.run(FutureTask.java:264)"
14 = {StackTraceElement@28645} "android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)"
15 = {StackTraceElement@28646} "java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)"
16 = {StackTraceElement@28647} "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)"
17 = {StackTraceElement@28648} "java.lang.Thread.run(Thread.java:1012)"
Code:
val integrityManager = IntegrityManagerFactory.create(context)
val integrityTokenResponse: Task<IntegrityTokenResponse> =
integrityManager.requestIntegrityToken(
IntegrityTokenRequest.builder()
.setCloudProjectNumber(GOOGLE_CLOUD_PROJECT_NUMBER)
.setNonce(nonce)
.build())
val playIntegrityResponse = Tasks.await(integrityTokenResponse)
val integrityToken = playIntegrityResponse.token()
val base64OfEncodedDecryptionKey = "..."
val base64OfEncodedVerificationKey = "..."
// base64OfEncodedDecryptionKey is provided through Play Console.
val decryptionKeyBytes: ByteArray = Base64.decode(base64OfEncodedDecryptionKey, Base64.DEFAULT)
// Deserialized encryption (symmetric) key.
val decryptionKey: SecretKey = SecretKeySpec(
decryptionKeyBytes,
0,
decryptionKeyBytes.size, //AES_KEY_SIZE_BYTES,
"AES" //AES_KEY_TYPE
)
// base64OfEncodedVerificationKey is provided through Play Console.
val encodedVerificationKey: ByteArray =
Base64.decode(base64OfEncodedVerificationKey, Base64.DEFAULT)
// Deserialized verification (public) key.
val verificationKey: PublicKey = KeyFactory.getInstance("EC")
.generatePublic(X509EncodedKeySpec(encodedVerificationKey))
val jwe: JsonWebEncryption =
JsonWebStructure.fromCompactSerialization(integrityToken) as JsonWebEncryption
jwe.key = decryptionKey
// This also decrypts the JWE token.
val compactJws: String = jwe.payload
val jws: JsonWebSignature =
JsonWebStructure.fromCompactSerialization(compactJws) as JsonWebSignature
jws.key = verificationKey
// This also verifies the signature.
val payload: String = jws.payload <!-- "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT"
Any idea what could cause this?
I ran into this problem a few days ago. And then I read Google's Integrity API setup documentation. Since you're using manual decryption. It is important to notice that your application should be on Google Play if you're to manually decrypt your token, the documentation says:
I think your application is not currently on Google Play. In that case, you can let Google manage your response encryption, which is default and suggested.
Hope this helps :)