Ktor 3.0.1 Help

RSA Keys Generation

RSA (Rivest–Shamir–Adleman) is a widely used public-key crypto-system that enables secure data transmission, digital signatures, and key exchange.

RS256, part of the RSA encryption algorithm, utilizes SHA-256 for hashing and a key (usually 2048-bit, 4096-bit or higher) to secure digital communications.

In the realm of JSON Web Token authentication, RS256 plays a crucial role since the integrity and authenticity of JWTs can be verified through signature mechanisms, such as RS256, where a public/private key pair is employed. This ensures that the information contained within the token remains tamper-proof and trustworthy.

In this section you will learn how such keys are generated and used alongside the Authentication JWT plugin provided by Ktor.

Generating an RSA private key

To generate a private key, you can use OpenSSL, ssh-keygen or another tool of your choice for creating authentication key pairs. For demonstration purposes, OpenSSL will be used.

In a new terminal window, run the following command:

openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 > ktor.pk8

The openssl genpkey command generates a private 2048-bit key using the RSA algorithm and stores it in the specified file, here ktor.pk8. The content of the file is Base64 encoded and thus, needs to be decoded before the public key can be derived.

Deriving the public key

In order to derive the public key from your previously generated private key, you will need to perform the following steps:

  1. Decode the private key.

  2. Extract the public key.

  3. Save the public key in PEM format.

To do this with OpenSSL, run the following command:

openssl rsa -in ktor.pk8 -pubout | tee ktor.spki
  • openssl rsa: This is the OpenSSL command for working with RSA keys. In this context, it is used to perform operations related to RSA keys.

  • -in ktor.pk8: This option specifies the input file (ktor.pk8) from which OpenSSL should read the RSA private key.

  • -pubout: This option instructs OpenSSL to output the public key corresponding to the private key provided in the input file.

  • |: The pipe (|) symbol is used to redirect the output of the previous command (the public key generated by openssl rsa) to the tee command.

  • tee ktor.spki: tee is a command-line utility that reads from standard input and writes to both standard output and one or more files. This part of the command instructs tee to write the received input to a file named ktor.spki. So, the public key will be both displayed on the terminal and saved in the ktor.spki file.

With the public key at hand, you can now derive its exponent and modulus values.

Extracting the modulus & exponent attributes

Now that you have your key-pair, you need to extract the e (exponent) and n (modulus) attributes of your public key, in order to use them in your jwks.json file. This requires the following steps:

  1. Read the public key from the .spki file you created.

  2. Display information about the key in a human-readable format.

To do this using OpenSSL, run the following command:

openssl pkey -in ktor.spki -pubin -noout -text
  • pkey: This is the OpenSSL command-line utility for processing private and public keys.

  • -in ktor.spki: Specifies the input file containing the public key in PEM format. In this case, the input file is ktor.spki.

  • -pubin: Indicates that the input file contains a public key. Without this option, OpenSSL would assume that the input file contains a private key.

  • -noout: This option prevents OpenSSL from outputting the encoded public key. The command will only display information about the public key, and the actual key won't be printed to the console.

  • -text: Requests that OpenSSL display the textual representation of the key. This includes details such as the key type, size, and the actual key data in human-readable form.

The expected output looks like this:

$ openssl pkey -in ktor.spki -pubin -noout -text RSA Public-Key: (512 bit) Modulus: 00:b5:f2:5a:2e:bc:d7:20:b5:20:d5:4d:cd:d4:a5: 7c:c8:9a:fd:d8:61:e7:e4:eb:58:65:1e:ea:5a:4d: 4c:73:87:32:e0:91:a3:92:56:2e:a7:bc:1e:32:30: 43:f5:fd:db:05:5a:08:b2:25:15:5f:ac:4d:71:82: 2b:d0:87:b4:01 Exponent: 65537 (0x10001)

Converting and encoding the modulus and exponent attributes

In the previous step you extracted the n and e attributes needed for your jwks.json file. However, they are in hexadecimal format. You now need to convert the hexadecimal representation of the exponent and modulus to their respective Base64URL encodings.

Exponent

The exponent attribute has a HEX value of 0x10001. To convert the value to Base64URL, use the following command:

echo 010001 | xxd -p -r | base64
  • echo 010001: This part of the command uses the echo command to output the string "010001", which represents the public exponent (e) of the RSA key, to the standard output.

  • |: The | character is a pipe that takes the output from the preceding command and passes it as input to the following command.

  • xxd -p -r: This command is used to convert hexadecimal to binary. It takes the hexadecimal input and produces the corresponding binary output.

  • | base64: This part of the command takes the binary output from the previous step and encodes it in Base64 format using the base64 command.

This is the expected output for the aforementioned exponent value:

$ echo 010001 | xxd -p -r | base64 AQAB

The Base64URL encoded value of the exponent is AQAB and does not require further processing for this case. In other cases, you may need to use the tr command as shown in the next step.

Modulus

For the n attribute, you will use the tr utility to further process the hexadecimal representation of the modulus.

echo "b5:f2:5a:2e:bc:d7:20:b5:20:d5:4d:cd:d4:a5: 7c:c8:9a:fd:d8:61:e7:e4:eb:58:65:1e:ea:5a:4d: 4c:73:87:32:e0:91:a3:92:56:2e:a7:bc:1e:32:30: 43:f5:fd:db:05:5a:08:b2:25:15:5f:ac:4d:71:82: 2b:d0:87:b4:01" | tr -d ": \n" | xxd -p -r | base64 | tr +/ -_ | tr -d "=\n"
  • echo "b5:f2:5a:2e:bc:d7:20:b5:20:d5:4d:cd:d4:a5: \ ... ": This part of the command echoes a multi-line hexadecimal string, representing a series of bytes. The backslashes at the end of each line indicate line continuation.

  • tr -d ": \n": The tr command is used to delete characters specified in the argument list. Here, it removes colons, spaces, and newline characters from the hexadecimal string, making it a continuous string of hex digits.

  • xxd -p -r: xxd is a utility for creating a hex dump of a binary file or converting a hex dump back to binary. The -p option specifies plain hexdump without line number or ASCII character columns. The -r option reverses the operation, converting hex back to binary.

  • base64: Encodes the binary output from the previous step into Base64 format.

  • tr +/ -_: Translates the + and / characters in the Base64 output to - and _, respectively. This is a common modification for URL-safe Base64 encoding.

  • tr -d "=\n": Removes any equal signs (=) and newline characters from the final Base64-encoded string.

The output of the above command is:

$ echo "b5:f2:5a:2e:bc:d7:20:b5:20:d5:4d:cd:d4:a5: 7c:c8:9a:fd:d8:61:e7:e4:eb:58:65:1e:ea:5a:4d: 4c:73:87:32:e0:91:a3:92:56:2e:a7:bc:1e:32:30: 43:f5:fd:db:05:5a:08:b2:25:15:5f:ac:4d:71:82: 2b:d0:87:b4:01" | tr -d ": \n" | xxd -p -r | base64 | tr +/ -_ | tr -d "=\n" tfJaLrzXILUg1U3N1KV8yJr92GHn5OtYZR7qWk1Mc4cy4JGjklYup7weMjBD9f3bBVoIsiUVX6xNcYIr0Ie0AQ

By leveraging the tr command properly, the modulus field has been encoded into a Base64URL string that you can use in your jwks.json file.

Populating the jwks.json file

In the previous steps, you gathered the following necessary information:

  1. An RSA key-pair.

  2. The modulus of the RSA public key in Base64URL format.

  3. The exponent of the RSA public key in Base64URL format.

With these at hand, you can now populate the jwks.json file of your Ktor project with the following attributes:

  • The e and n values with the Base64URL encoded values you produced in the previous steps.

  • A key id (in this case, the kid is derived from the sample project).

  • The kty attribute as RSA.

{ "keys": [ { "kty": "RSA", "e": "AQAB", "kid": "6f8856ed-9189-488f-9011-0ff4b6c08edc", "n":"tfJaLrzXILUg1U3N1KV8yJr92GHn5OtYZR7qWk1Mc4cy4JGjklYup7weMjBD9f3bBVoIsiUVX6xNcYIr0Ie0AQ" } ] }

The only remaining step is to specify your private key so that your Ktor project can use it for authentication.

Defining the private key

With your public key information set up, the last step is to provide your Ktor project with access to your private key.

Assuming that you have extracted your private key (which you generated at the beginning in your .pk8 file) into an environment variable on your system, called jwt_pk in this case, your resources/application.conf file's jwt section should look similar to:

jwt { privateKey = ${jwt_pk} issuer = "http://0.0.0.0:8080/" audience = "http://0.0.0.0:8080/login" realm = "MyProject" }
Last modified: 02 April 2024