How to convert some information to JWE token using a public key?

Hi All,

I need to convert some information to JWE token using a public key. Currently I am considering Jose GitHub - potatosalad/erlang-jose: JSON Object Signing and Encryption (JOSE) for Erlang and Elixir. I am getting the signed output in a map. But I am not sure how to convert it to JWE token. If I decrypt it in jwt.io, not getting the proper layload what I have supplied.

Please help.

Thanks

Can you show us what the error is? and also what did you try so far maybe then we can help you. Error log will be helpful here

I tried to decode the encrypted token in jwt.io, it says invalid signature and garbled output. There is no error while generating the token. I am also trying Joken to generate the JWT token

Can you provide some code?

In your initial post you talk only about encryption. In your second post, you say the signature is invalid. What operations are you applying?

One usual secure scheme is to sign then encrypt the payload, which must contain the issuer and the audience of the token. Are you implementing a standard or are you rolling out your own crypto?

Also, encryption is exclusively done with symmetric encryption. Asymmetric keys can be used to generate such symmetric keys (ECDH-ES alg for instance). This is why in JWEs you have both the "alg" and "enc" fields. Which algorithms do you use exactly?

Also to have the compact representation you have to call the JOSE.JWE.compact/1 function at some point. You have many examples here: https://hexdocs.pm/jose/JOSE.JWE.html#module-a128gcmkw-a192gcmkw-and-a256gcmkw

I use “alg” => “RSA-OAEP-256”, “enc” => “A256GCM”
I need to sign using self signed private key and encrypt using public key.

Please let me know, if there is any way

Thanks

Well the usual way is to first create a signed JWS and get the compact representation, and then to encrypt this payload as a JWE.

First create the keys:

signing_key = JOSE.JWK.generate_key({:ec, :secp256r1})
encryption_key_private = JOSE.JWK.generate_key({:rsa, 4096})
encryption_key_public = JOSE.JWK.to_public(encryption_key_private)

Of course, when encrypting, you won’t have the encryption private key.

Sign the payload and then encrypt it:

signed_payload = JOSE.JWS.sign(signing_key, "some message", %{ "alg" => "ES256" }) |> JOSE.JWS.compact |> elem(1)
encrypted_payload = JOSE.JWE.block_encrypt(encryption_key_public, signed_payload, %{ "alg" => "RSA-OAEP", "enc" => "A256GCM" }) |> JOSE.JWE.compact |> elem(1)

Finally you can decrypt and check the signature:

decrypted_payload = JOSE.JWE.block_decrypt(encryption_key_private, encrypted_payload) |> elem(0)
JOSE.JWS.verify(signing_key, decrypted_payload) |> elem(0)

Verification usually involves checking the recipient and the sender of the token, otherwise you can have some subtle but problematic security issues. See https://crypto.stackexchange.com/questions/5458/should-we-sign-then-encrypt-or-encrypt-then-sign and the first link of the first response. Again, rolling out your own crypto is dangerous if this is what you intend to do.

2 Likes

Thanks for the response.

Hi @tangui , can you please let me know how to pass the claim set in this?

Thanks

To passe the claim set where? What does “this” refers to? When encrypting or decrypting?

I need to add the claimset, which has issuer while generating the encrypted token.

I am currently generating the JWE token in this way,

def generate_jwe_token(user) do

    private_key = Application.get_env(:app, :private_key)

    public_key = Application.get_env(:app, :public_key)

    encryption_key_private = JOSE.JWK.from_pem(private_key)

    encryption_key_public = JOSE.JWK.from_pem(public_key)

    {:ok, user} = Poison.encode(user)

    signed_payload =

      JOSE.JWS.sign(encryption_key_private, user, %{

        "alg" => "RS256"

      })

      |> JOSE.JWS.compact()

      |> elem(1)

    encrypted_payload =

      JOSE.JWE.block_encrypt(

        encryption_key_public,

        signed_payload,

        %{"alg" => "RSA-OAEP", "enc" => "A256GCM"}

      )

      |> JOSE.JWE.compact()

      |> elem(1)

    encrypted_payload

  end

end

Is this approach for sending transparent parameters instead of an encrypted token by URL? In case I want an opaque token by URL, could I use only the encryption part without singing? Any contra-indication?

Tks!

Definitely not a good idea unless you know all the details of the crypto you are using. One of the neat example given is that, in some cases (depends on the encryption algorithm chosen, IV, etc.) an attacker could change the ID in your encrypted token.

Feel free to tell more about what you’re trying to achieve. But the rule of thumb is: stick to the standard, that is sign-then-encrypt.

Very useful information, thanks!

Hi @tangui,

I am trying to do a similar case where I only have the public key and I would like to verify the JWT before using it.

I am stuck at the verifying stage, I have created a post for help How to verify RS256 JWT with Joken.Signer.verify/2 - 2022