0

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?

rysv
  • 2,416
  • 7
  • 30
  • 48

1 Answers1

0

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:

To manage and download your response encryption keys, you must use the Play Console, and your app must be available on Google Play.

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 :)

  • App released to internal testing (not public) nevertheless downloaded from Google Play so I believe this will be considered as "available on Google Play". – rysv Jul 18 '23 at 04:29