The PKCS#7 Padding (Public Key Cryptography Standards #7) is a padding scheme that adds additional bytes to the end of the data to make it a multiple of a specific size.
This scheme is widely used in cryptography, as many cryptographic algorithms require data to have a length that is a multiple of the block size.
So let’s look at what PKCS#7 Padding is, how it works, and how to implement it on an ESP32.
What is PKCS#7 Padding
PKCS#7 Padding is a padding method used to adjust the length of the data to a specified size required by another algorithm.
Basically, block cryptographic algorithms (like AES) require data to have a length that is a multiple of the block size (for example, 16 bytes).
If the data does not meet this requirement, we need to add padding to adjust its length (up to this point it seems easy, right?).
But of course, to later be able to remove this padding and retain the original data, we must be able to distinguish the padding bytes we added.
There are several algorithms to solve this. PKCS#7 Padding is an efficient and simple solution to this problem.
The PKCS#7 Padding scheme adds additional bytes to the end of the data, where each added byte has the value of the number of bytes added. This allows the receiver to identify and remove the padding accordingly.
Example of PKCS#7 Padding
Suppose we have a cryptographic algorithm that operates with blocks of 16 bytes and we want to encrypt a message of 25 bytes.
01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19
In this case, we need to add 7 bytes of padding so that the total length is 32 bytes (multiple of 16).
PKCS#7 Padding will add 7 bytes, each with the value 0x07 (7 in hexadecimal).
01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 07 07 07 07 07 07 07
Upon receiving the encrypted message, the receiver can check the value of the last byte (0x07) to determine how many padding bytes need to be removed.
How to Use PKCS#7 Padding on an ESP32
To use PKCS#7 Padding on an ESP32, we can implement our own padding and unpadding functions.
Here’s an example of how to do it, which includes the pkcs7_padding
and pkcs7_unpadding
functions, along with a demonstration of their use.
#include <vector>
#include <cstdint>
// Function to print a block of data in hexadecimal format
void printBlockAsHex(std::vector<uint8_t> data) {
for (int i = 0; i < data.size(); i++) {
Serial.printf("%02X ", data[i]);
}
Serial.println();
}
// Function to apply PKCS#7 Padding
std::vector<uint8_t> pkcs7_padding(std::vector<uint8_t>& input) {
std::vector<uint8_t> output(input);
// Calculate the necessary length to be a multiple of 16
size_t padded_length = (input.size() / 16 + 1) * 16;
size_t padToAdd = padded_length - input.size();
// Add the padding bytes
for (auto i = 0; i < padToAdd; i++) {
output.push_back(padToAdd);
}
return output;
}
// Function to remove PKCS#7 Padding
std::vector<uint8_t> pkcs7_unpadding(std::vector<uint8_t>& input) {
std::vector<uint8_t> output(input);
// Get the number of padding bytes
size_t padToRemove = input[input.size() - 1];
// Remove the padding bytes
for (auto i = 0; i < padToRemove; i++) {
output.pop_back();
}
return output;
}
void setup() {
Serial.begin(115200);
delay(2000);
// Sample data
std::vector<uint8_t> data;
for (size_t i = 0; i < 14; i++) {
data.push_back(i);
}
Serial.println("Original data:");
printBlockAsHex(data);
// Apply PKCS#7 Padding
auto padded = pkcs7_padding(data);
Serial.println("Data with PKCS#7 Padding:");
printBlockAsHex(padded);
// Remove PKCS#7 Padding
auto unpadded = pkcs7_unpadding(padded);
Serial.println("Data without PKCS#7 Padding:");
printBlockAsHex(unpadded);
}
void loop() {
delay(1000);
}
- We create a data vector with 14 bytes.
- We apply PKCS#7 Padding and display the result.
- We remove the padding and verify that the original data has been successfully recovered.