UPDATING: I made my own solution using other examples along the way. Below we have 3 use cases and the specific Phps codes for whom you want to use:
- Create public and private RSA keys to sign JWT using the openssl library
- Create a JWT token and subscribe using RSA private keys
- Validate the signed JWT token using public RSA keys
- If you want to reverse the encryption order: Private Key Encryption => Public Key Decryption for Public Key Encryption => Private Key Decryption.
1 - Create RSA public and private keys to sign JWT using the openssl library:
// ====================== OPENSSL KEY CREATE METHOD ==================
// URL of the source: https://8gwifi.org/docs/php-asym.jsp
// I tried all 3 types of keys, but only RSA type works.
$password = "password"; // Change it for what value you want
$config = array(
"digest_alg" => "sha512",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
// Create the keypair
$res = openssl_pkey_new($config);
// Get private key
openssl_pkey_export($res, $privkey);
// Get public key
$pubkey = openssl_pkey_get_details($res);
$pubkey = $pubkey["key"];
echo "====PKCS1 RSA Key in Non Encrypted Format ====\n";
var_dump($privkey);
echo "====PKCS1 RSA Key in Encrypted Format====\n ";
// Get private key in Encrypted Format
openssl_pkey_export($res, $privkey,$password);
// Get public key
$pubkey = openssl_pkey_get_details($res);
$pubkey = $pubkey["key"];
var_dump($privkey);
echo "RSA Public Key \n ";
var_dump($pubkey);
2 - Create JWT token and sign using RSA and 3 private keys - Validate signed JWT token using RSA public keys:
// ====================== JWT WITH ENCRYPT AND DECRYPT ==================
// ===== Variables definition
$keyPrivatePassword = 'password';
$keyPrivatePath = "private.key";
$keyPublicPath = "public.key";
$cryptMaxCharsValue = 245; // There are char limitations on openssl_private_encrypt() and in the url below are explained how define this value based on openssl key format: https://www.php.net/manual/en/function.openssl-private-encrypt.php#119810
$debug = Array(
'print-msgs' => true,
'print-openssl-errors' => false,
'print-openssl-crypt' => false,
'print-key-details' => false,
);
// ##################### START DEFINITION OF JWT
// ===== Definition of header
$header = [
'alg' => 'RSA',
'typ' => 'JWT'
];
$header = json_encode($header);
$header = base64_encode($header);
// ===== Definition of payload
$payload = [
'iss' => 'localhost', // The issuer of the token
'sub' => 'test', // The subject of the token
'aud' => 'private', // The audience of the token
'exp' => '1300819380', // This will define the expiration in NumericDate value. The expiration MUST be after the current date/time.
'data' => [ // Change it with use case data
'name' => 'User',
'email' => 'user@mail'
]
];
$payload = json_encode($payload);
$payload = base64_encode($payload);
// ===== START ENCRYPT SIGN JWT
$data = $header.".".$payload;
// ===== Print example header
if($debug['print-msgs']){
echo "JWT CRYPT / DECRYPT EXAMPLE\n\n";
echo "Value of header . payload: ".$data."\n";
}
// ===== Open private path and return this in string format
$fp = fopen($keyPrivatePath,"r");
$keyPrivateString = fread($fp,8192);
fclose($fp);
// ===== Open private key string and return 'resourse'
if(isset($keyPrivatePassword)){
$resPrivateKey = openssl_get_privatekey($keyPrivateString,$keyPrivatePassword);
} else {
$resPrivateKey = openssl_get_privatekey($keyPrivateString);
}
// ===== If any openssl error occurs, print it
$openSSLError = false;
if($debug['print-openssl-errors']){
while($msg = openssl_error_string()){
echo $msg . "\n";
$openSSLError = true;
}
}
// ===== See details of a private key
if($debug['print-key-details']){
$keyPrivateDetails = openssl_pkey_get_details($resPrivateKey);
echo "Private Key Details:\n";
echo print_r($keyPrivateDetails,true)."\n";
}
// ===== Crypt data in parts if necessary. When char limit of data is upper than 'cryptMaxCharsValue'.
$rawDataSource = $data;
$countCrypt = 0;
$partialData = '';
$encodedData = '';
$split = str_split($rawDataSource , $cryptMaxCharsValue);
foreach($split as $part){
openssl_private_encrypt($part, $partialData, $resPrivateKey);
if($debug['print-openssl-crypt']){
$countCrypt++;
echo "CRYPT PART ".$countCrypt.": ".$partialData."\n";
}
$encodedData .= (strlen($encodedData) > 0 ? '.':'') . base64_encode($partialData);
}
// ===== If any openssl error occurs, print it
$openSSLError = false;
if($debug['print-openssl-errors']){
while($msg = openssl_error_string()){
echo $msg . "\n";
$openSSLError = true;
}
}
// ===== Print data encrypted
if($debug['print-msgs']){
if($openSSLError) echo "\n";
echo "Encrypted signature: ".$encodedData."\n";
}
// ===== Encode base64 again to remove dots (Dots are used in JWT syntaxe)
$encodedData = base64_encode($encodedData);
if($debug['print-msgs']){
echo "Encrypted signature Base64: ".$encodedData."\n";
}
$signature = $encodedData;
// ===== FINISH JWT
$JWTToken = $header.".".$payload.".".$signature;
if($debug['print-msgs']){
echo "\nJWT Token: ".$JWTToken."\n\n";
echo "FINISH CREATE JWT!\n\n";
}
// ##################### START VALIDATE JWT
$token = $JWTToken;
$part = explode(".",$token);
$header = $part[0];
$payload = $part[1];
$signature = $part[2];
$encodedData = $signature;
// ===== Open public path and return this in string format
$fp = fopen($keyPublicPath,"r");
$chavePublicaString = fread($fp,8192);
fclose($fp);
// ===== Open public key string and return 'resourse'
$resPublicKey = openssl_get_publickey($chavePublicaString);
// ===== If any openssl error occurs, print it
$openSSLError = false;
if($debug['print-openssl-errors']){
while($msg = openssl_error_string()){
echo $msg . "\n";
$openSSLError = true;
}
}
// ===== See details of a public key
if($debug['print-key-details']){
$keyPublicDetails = openssl_pkey_get_details($resPublicKey);
echo "Public Key Details:\n";
echo print_r($keyPublicDetails,true)."\n";
}
// ===== Decode base64 to reaveal dots (Dots are used in JWT syntaxe)
$encodedData = base64_decode($encodedData);
if($debug['print-msgs']){
echo "Encrypted signature: ".$encodedData."\n";
}
// ===== Decrypt data in parts if necessary. Using dots as split separator.
$rawEncodedData = $encodedData;
$countCrypt = 0;
$partialDecodedData = '';
$decodedData = '';
$split2 = explode('.',$rawEncodedData);
foreach($split2 as $part2){
$part2 = base64_decode($part2);
if($debug['print-openssl-crypt']){
$countCrypt++;
echo "CRYPT PART ".$countCrypt.": ".$part2."\n";
}
openssl_public_decrypt($part2, $partialDecodedData, $resPublicKey);
$decodedData .= $partialDecodedData;
}
// ===== Print data decrypted
if($debug['print-msgs']){
echo "Decrypted signature: ".$decodedData."\n";
}
// ===== If any openssl error occurs, print it
$openSSLError = false;
if($debug['print-openssl-errors']){
while($msg = openssl_error_string()){
echo $msg . "\n";
$openSSLError = true;
}
}
// ===== Validate JWT
if($debug['print-msgs']){
echo "\nFINISH VALIDATE JWT!\n\n";
}
if($header.".".$payload === $decodedData){
echo "VALID JWT!\n\n";
$payload = base64_decode($payload);
$payload = json_decode($payload,true);
echo "Payload:\n";
echo print_r($payload,true);
} else {
echo "INVALID JWT!";
}
4 - If you want to reverse the encryption order: Private Key Encryption => Public Key Decryption for Public Key Encryption => Private Key Decryption:
// ====================== ENCRYPTATION INVERSE ==================
// If want to change Private Key Encryptation -> Public Key Decryptation to Public Key Encryptation -> Private Key Decryptation this example can help.
$keyPrivatePassword = 'password';
$keyPrivatePath = "private.key";
$keyPublicPath = "public.key";
// ===== Open private path and return this in string format
$fp = fopen($keyPrivatePath,"r");
$keyPrivateString = fread($fp,8192);
fclose($fp);
// ===== Open public path and return this in string format
$fp = fopen($keyPublicPath,"r");
$keyPublicString = fread($fp,8192);
fclose($fp);
// ===== Test of encryptation
$data = 'O que vou encriptar';
$resPrivateKey = openssl_get_privatekey($keyPrivateString,$keyPrivatePassword);
$resPublicKey = openssl_get_publickey($keyPublicString);
echo 'Data: '.$data."\n";
openssl_public_encrypt($data, $encData, $resPublicKey);
echo 'encData: '.$encData."\n";
openssl_private_decrypt($encData, $decData, $resPrivateKey);
echo 'decData: '.$decData."\n";
Welcome to the Stack Overflow in Portuguese. As the name suggests, the official language used here is Portuguese. So, could you please translate your question? If you prefer, you can also ask the same question on Stack Overflow English Website.
– Leticia Rosa
@Leticiarosa did not know this differentiation, always accessed in English. But I will do what you said.
– Otávio C A Serra