dvsekhvalnov / jose-jwt

Ultimate Javascript Object Signing and Encryption (JOSE), JSON Web Token (JWT) and Json Web Keys (JWK) Implementation for .NET and .NET Core
MIT License
921 stars 183 forks source link

AesKeyWrap integrity check failed for A256KW for alg #202

Open cupatil opened 1 year ago

cupatil commented 1 year ago

Hi @dvsekhvalnov,

I am trying to decrypt the play integrity token using this lib. The JWE uses A256KW for [alg] and A256GCM for [enc]

below are the code I am trying to execute and it throws the AesKeyWrap integrity check failed error

  var publicKey = new Jose.Jwk();

  publicKey.Kty = "oct";
  publicKey.K = DECRYPTION_KEY;

  var jweToken=Jose.JWE.Decrypt(tokenString, publicKey);
  log.LogInformation(jweToken.Plaintext);

Please let me know if I am doing something wrong here.

dvsekhvalnov commented 1 year ago

Hi @cupatil

are you facing any error? :) Nothing mentioned in a ticket.

And typically you want Jose.JWT.Decode(), not Jose.JWE.Decrypt(), unless you truly working with RFC 7516 (Json serialization).

cupatil commented 1 year ago

Hi @dvsekhvalnov ,

In both ways I am getting AesKeyWrap integrity check failed error.

I am trying to write equivalent code in c# using this lib. Below are the java code

JsonWebEncryption jwe =
    (JsonWebEncryption)JsonWebStructure
        .fromCompactSerialization(integrityToken);
jwe.setKey(decryptionKey);

// This also decrypts the JWE token.
String compactJws = jwe.getPayload();

JsonWebSignature jws =
    (JsonWebSignature) JsonWebStructure.fromCompactSerialization(compactJws);
jws.setKey(verificationKey);

// This also verifies the signature.
String payload = jws.getPayload();

Can you please suggest? Above code was written with Jose4J.

dvsekhvalnov commented 1 year ago

Looks like you only need compact serialization, not json, so this should make it:

var decrypted = Jose.JWT.Decode(integrityToken, decryptionKey)
var payload = Jose.JWT.Decode(decrypted, verificationKey)

AesKeyWrap integrity check failed - usually means you messed up keys. If you have example token and key, feel free to share, i can try to run myself. (Please don't share real keys).

cupatil commented 1 year ago

Hi @dvsekhvalnov, Thanks for the quick help, 1 line of code works for me. and In second decrypted text (JWS uses ES256.) It gives me error "EcdsaUsingSha algorithm expects key to be of CngKey, ECDsa or Jwk types with kty='EC'."

Now I am trying to convert base64 encoded verification key to EC (ES256) public key using JWK can you please suggest how this is possible through this lib. Please suggest.

In java below code works to generate the key:

var encodedVerificationKey: ByteArray =
    Base64.decode(base64OfEncodedVerificationKey, Base64.DEFAULT)

// Deserialized verification (public) key.
var verificationKey: PublicKey = KeyFactory.getInstance(EC_KEY_TYPE)
    .generatePublic(X509EncodedKeySpec(encodedVerificationKey))

Thanks in advance.

dvsekhvalnov commented 1 year ago

@cupatil, what's inside your base64 encoded key? Is it just PEM key? or JWK?

If you can post base64 url string - will help greatly to understand issue :)

cupatil commented 1 year ago

@dvsekhvalnov The key is provided from the play console Its base64OfEncodedVerificationKey

Here is the sample key: MFkwEwYHKoZIzj0CAQYIKo..........................................................................................uwsnZtn8ow==

I need to generate ECC key from this. I have tried some manual approach mentioned below.

  var verifyKey = Convert.FromBase64String(verificationKey); 
  var pubKeyX = verifyKey.Skip(27).Take(32).ToArray();
  var pubKeyY = verifyKey.Skip(59).Take(32).ToArray();
  var eccKey= EccKey.New(pubKeyX, pubKeyY);
  var payload = Jose.JWT.Decode(jweToken, eccKey);

It works for me. Can you please suggest is it the write way to do?

dvsekhvalnov commented 1 year ago

Can you post full base64 string? can't decode and check what's inside.

EccKey.New(pubKeyX, pubKeyY) - you can use it to construct Elliptic CngKey if you are sure pubX and pubY are correct key material.

dvsekhvalnov commented 1 year ago

Is your verification key string after Base64 decode starts with -----BEGIN EC PRIVATE KEY----- ?

Jitendran commented 1 year ago

Hi @dvsekhvalnov , I am facing same type of issue when I implement Play Integrity in my Android app. I am facing "org.jose4j.lang.IntegrityException: A256KW key unwrap/decrypt failed." exception In try catch block that exception get. var jwe = JsonWebStructure.fromCompactSerialization(integrityToken) as JsonWebEncryption jwe.key = decryptionKey var compactJws: String? = null try { compactJws = jwe.payload } catch (e: JoseException) { Log.d(TAG, e.message!!) } Please help me....

dvsekhvalnov commented 1 year ago

Hey @Jitendran , i need some details to help with those kind of issues: your code that producing or verifying tokens with jose-jwt library and ideally keys if not secret.

Would suggest to open separate issue and add details.

Jitendran commented 1 year ago

Hi @dvsekhvalnov Thanks for your reply ... As you suggested I have created 1 new separate issue , please open this below link

https://github.com/dvsekhvalnov/jose-jwt/issues/226

Jitendran commented 1 year ago

Hi @cupatil , Can you help me on this issue ? https://github.com/dvsekhvalnov/jose-jwt/issues/226

I think you are also tried Play-Integrity in Android Kotlin.

Please help me on this, because I am stuck and not getting any solution from any where.

dishanphilips commented 1 year ago

Hi :)

You can decode the Google Attestation Statement in the following way in C#

var decryptionKey = Convert.FromBase64String("<DECRYPTION KEY>");
var verificationKey = Convert.FromBase64String("<VERIFICATION KEY>");
var signedAttestationStatement = "<ATTESTATION STATEMENT>";

var ecDsa = ECDsa.Create();
ecDsa.ImportSubjectPublicKeyInfo(new ReadOnlySpan<byte>(verificationKey), out _);

var decrypted = Jose.JWT.Decode(signedAttestationStatement, decryptionKey);
var payload = Jose.JWT.Decode(decrypted, ecDsa);
Jitendran commented 1 year ago

Hi @dishanphilips Thanks for your reply, we are testing the on the app which was not live in PlayStore, but we upload the app on PlayStore after that we are not facing this issue now. Thanks to @cupatil as well he help us via phone communication.

Jitendran commented 1 year ago

Hi :)

You can decode the Google Attestation Statement in the following way in C#

var decryptionKey = Convert.FromBase64String("<DECRYPTION KEY>");
var verificationKey = Convert.FromBase64String("<VERIFICATION KEY>");
var signedAttestationStatement = "<ATTESTATION STATEMENT>";

var ecDsa = ECDsa.Create();
ecDsa.ImportSubjectPublicKeyInfo(new ReadOnlySpan<byte>(verificationKey), out _);

var decrypted = Jose.JWT.Decode(signedAttestationStatement, decryptionKey);
var payload = Jose.JWT.Decode(decrypted, ecDsa);

What will be used in place of ATTESTATION STATEMENT ?

dishanphilips commented 1 year ago

The attestation statement that you received from the google play integrity api. Looking at you code above that would be : integrityToken