NetBurner 3.5.6
PDF Version
PEM Conversion Utilities

Privacy-Enhanced Mail (PEM) format conversion and endianness utilities. More...

Topics

 PEM Data Type Identifiers
 Return values indicating the type of PEM data that was converted.
 
 PEM Format Footers
 Standard PEM footer markers for different data types.
 
 PEM Format Headers
 Standard PEM header markers for different data types.
 

Macros

#define CONVERT_BUFFER_LENGTH_MAX   ((4 * 1024) - 1)
 Maximum data buffer length in bytes for PEM conversion.
 

Functions

int ConvertPEMFormattedData (puint8_t dataPtr, const char *pemEncodedData, uint32_t dataSize, puint32_t convertedDataLength, char **nextPtr=NULL)
 Convert data from Privacy-Enhanced Mail (PEM) format to binary DER format.
 
uint16_t convertLittleEndianWord (uint16_t hData)
 Convert 16-bit data between host byte order and little-endian format.
 
uint32_t convertLittleEndianDword (uint32_t hData)
 Convert 32-bit data between host byte order and little-endian format.
 

Detailed Description

Privacy-Enhanced Mail (PEM) format conversion and endianness utilities.

#include< convert.h>


This module provides functions for converting between PEM-encoded cryptographic data and binary formats, as well as byte-order conversion utilities. PEM format is commonly used for storing and transmitting cryptographic keys and certificates in a text-based, Base64-encoded format.

Supported PEM Types

Typical Use Cases

Note
  • All PEM data must be NULL-terminated strings.
  • Buffer sizes should be at least CONVERT_BUFFER_LENGTH_MAX bytes.

Macro Definition Documentation

◆ CONVERT_BUFFER_LENGTH_MAX

#define CONVERT_BUFFER_LENGTH_MAX   ((4 * 1024) - 1)

#include <convert.h>

Maximum data buffer length in bytes for PEM conversion.

This defines the maximum size of the output buffer needed for PEM conversion operations. The buffer must be at least this size to safely convert PEM data.

Value: 4095 bytes (4KB - 1)

Note
This is a practical limit based on typical certificate and key sizes. Most X.509 certificates and private keys are well under 4KB.
See also
ConvertPEMFormattedData()

Function Documentation

◆ convertLittleEndianDword()

uint32_t convertLittleEndianDword ( uint32_t hData)

#include <convert.h>

Convert 32-bit data between host byte order and little-endian format.

Converts a 32-bit value to or from little-endian byte order. This function is bidirectional - it performs the same operation regardless of conversion direction. On little-endian systems (x86, ARM in little-endian mode), this is a no-op. On big-endian systems (ColdFire, PowerPC), it swaps the byte order.

Byte Order Formats

  • Little-Endian: Least significant byte first (e.g., 0x12345678 -> [0x78, 0x56, 0x34, 0x12])
  • Big-Endian: Most significant byte first (e.g., 0x12345678 -> [0x12, 0x34, 0x56, 0x78])
Parameters
hData32-bit value to convert. Can be in either host or little-endian format.
Returns
32-bit value in the opposite byte order from input:
  • If input is host order: returns little-endian
  • If input is little-endian: returns host order
Note
This function is its own inverse: calling it twice returns the original value.
On little-endian platforms, this function may be optimized to a no-op.
Commonly used for reading/writing file formats that specify little-endian encoding.
See also
convertLittleEndianWord() for 16-bit conversion

Expand for Example Usage

Examples

Example 1: File header with little-endian fields
struct FileHeader {
uint32_t signature; // Little-endian
uint32_t fileSize; // Little-endian
uint32_t dataOffset; // Little-endian
};
void WriteFileHeader(FILE *fp, uint32_t size, uint32_t offset) {
FileHeader header;
// Convert to little-endian for file storage
header.signature = convertLittleEndianDword(0x12345678);
header.fileSize = convertLittleEndianDword(size);
header.dataOffset = convertLittleEndianDword(offset);
fwrite(&header, sizeof(header), 1, fp);
iprintf("Wrote header: size=%lu, offset=%lu\r\n", size, offset);
}
bool ReadFileHeader(FILE *fp, FileHeader *header) {
if (fread(header, sizeof(FileHeader), 1, fp) != 1) {
return false;
}
// Convert from little-endian to host
header->signature = convertLittleEndianDword(header->signature);
header->fileSize = convertLittleEndianDword(header->fileSize);
header->dataOffset = convertLittleEndianDword(header->dataOffset);
return true;
}
uint32_t convertLittleEndianDword(uint32_t hData)
Convert 32-bit data between host byte order and little-endian format.
Example 2: Cross-platform data exchange
// Write timestamp in little-endian format
void SaveTimestamp(FILE *fp) {
uint32_t timestamp = (uint32_t)time(NULL);
uint32_t leTimestamp = convertLittleEndianDword(timestamp);
fwrite(&leTimestamp, sizeof(leTimestamp), 1, fp);
}
// Read timestamp from little-endian format
time_t LoadTimestamp(FILE *fp) {
uint32_t leTimestamp;
fread(&leTimestamp, sizeof(leTimestamp), 1, fp);
uint32_t timestamp = convertLittleEndianDword(leTimestamp);
return (time_t)timestamp;
}
time_t time(time_t *pt)
Gets the current system GMT time.
Example 3: Binary data structure conversion
struct SensorData {
uint32_t timestamp;
uint32_t sensorId;
uint16_t temperature;
uint16_t humidity;
};
// Convert structure to little-endian for storage/transmission
void ConvertToLittleEndian(SensorData *data) {
data->timestamp = convertLittleEndianDword(data->timestamp);
data->sensorId = convertLittleEndianDword(data->sensorId);
data->temperature = convertLittleEndianWord(data->temperature);
data->humidity = convertLittleEndianWord(data->humidity);
}
// Convert structure from little-endian to host order
void ConvertFromLittleEndian(SensorData *data) {
data->timestamp = convertLittleEndianDword(data->timestamp);
data->sensorId = convertLittleEndianDword(data->sensorId);
data->temperature = convertLittleEndianWord(data->temperature);
data->humidity = convertLittleEndianWord(data->humidity);
}
uint16_t convertLittleEndianWord(uint16_t hData)
Convert 16-bit data between host byte order and little-endian format.

◆ convertLittleEndianWord()

uint16_t convertLittleEndianWord ( uint16_t hData)

#include <convert.h>

Convert 16-bit data between host byte order and little-endian format.

Converts a 16-bit value to or from little-endian byte order. This function is bidirectional - it performs the same operation regardless of conversion direction. On little-endian systems (x86, ARM in little-endian mode), this is a no-op. On big-endian systems (ColdFire, PowerPC), it swaps the byte order.

Byte Order Formats

  • Little-Endian: Least significant byte first (e.g., 0x1234 -> [0x34, 0x12])
  • Big-Endian: Most significant byte first (e.g., 0x1234 -> [0x12, 0x34])
Parameters
hData16-bit value to convert. Can be in either host or little-endian format.
Returns
16-bit value in the opposite byte order from input:
  • If input is host order: returns little-endian
  • If input is little-endian: returns host order
Note
This function is its own inverse: calling it twice returns the original value.
On little-endian platforms, this function may be optimized to a no-op.
Commonly used for reading/writing file formats that specify little-endian encoding.
See also
convertLittleEndianDword() for 32-bit conversion

Expand for Example Usage

Examples

Example 1: Converting data for file I/O
// Writing data in little-endian format to file
uint16_t hostValue = 0x1234;
uint16_t fileValue = convertLittleEndianWord(hostValue);
fwrite(&fileValue, sizeof(fileValue), 1, fp);
// Reading data from little-endian file
uint16_t readValue;
fread(&readValue, sizeof(readValue), 1, fp);
uint16_t hostValue2 = convertLittleEndianWord(readValue);
iprintf("Original: 0x%04X, Converted: 0x%04X, Read back: 0x%04X\r\n",
hostValue, fileValue, hostValue2);
Example 2: Network protocol with mixed endianness
struct LittleEndianPacket {
uint16_t length; // Little-endian
uint16_t checksum; // Little-endian
uint8_t data[256];
};
void SendPacket(const uint8_t *data, uint16_t len) {
LittleEndianPacket packet;
// Convert to little-endian for transmission
packet.length = convertLittleEndianWord(len);
memcpy(packet.data, data, len);
uint16_t chk = CalculateChecksum(data, len);
packet.checksum = convertLittleEndianWord(chk);
send(&packet, sizeof(packet));
}

◆ ConvertPEMFormattedData()

int ConvertPEMFormattedData ( puint8_t dataPtr,
const char * pemEncodedData,
uint32_t dataSize,
puint32_t convertedDataLength,
char ** nextPtr = NULL )

#include <convert.h>

Convert data from Privacy-Enhanced Mail (PEM) format to binary DER format.

This function converts PEM-encoded cryptographic data (certificates or private keys) from Base64-encoded text format to binary DER (Distinguished Encoding Rules) format. It automatically detects the type of PEM data based on the header/footer markers.

The function performs:

  1. PEM header/footer validation
  2. Base64 decoding of the content between header and footer
  3. Binary DER format output
  4. Type identification

PEM Format Structure

-----BEGIN [TYPE]-----
[Base64 Encoded Data]
-----END [TYPE]-----
Parameters
[out]dataPtrPointer to buffer for converted binary data. Must be at least CONVERT_BUFFER_LENGTH_MAX bytes. The buffer will contain the DER-encoded binary representation of the key or certificate.
[in]pemEncodedDataPointer to NULL-terminated string containing PEM-encoded data. May contain multiple PEM objects; function will process the first valid one found.
[in]dataSizeSize of the output buffer pointed to by dataPtr, in bytes. Should be at least CONVERT_BUFFER_LENGTH_MAX.
[out]convertedDataLengthPointer to uint32_t where the actual length of converted data will be stored. This value will be less than or equal to dataSize.
[out]nextPtrOptional pointer to char pointer. If provided and not NULL, will be set to point to the character immediately following the converted PEM data. Useful for processing multiple PEM objects in a single string. Pass NULL if not needed.
Returns
PEM data type identifier:
Return values
CONVERT_NONEMalformed data, calling parameters invalid, or conversion failed
CONVERT_CERTIFICATESuccessfully converted X.509 certificate
CONVERT_RSA_PRIVATE_KEYSuccessfully converted RSA private key
CONVERT_DSA_PRIVATE_KEYSuccessfully converted DSA private key
CONVERT_ECDSA_PRIVATE_KEYSuccessfully converted ECDSA private key

Notes:

  • The pemEncodedData string must be NULL-terminated.
  • The output buffer (dataPtr) must be large enough to hold the decoded data.
  • The function only processes one PEM object per call; use nextPtr to process multiple objects.
  • The converted data is in binary DER format, suitable for use with SSL/TLS libraries and cryptographic functions.

Warnings:

  • Private keys should be handled securely. Consider:
    • Zeroing buffers after use
    • Limiting key exposure in memory
    • Using secure storage when possible
  • Ensure adequate buffer size to prevent overflow. If dataSize is too small, the function will return CONVERT_NONE.

Expand for Example Usage

Examples

Example 1: Converting a single certificate
const char *pemCert =
"-----BEGIN CERTIFICATE-----\n"
"MIIDXTCCAkWgAwIBAgIJAKJ9VJN8ER5jMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n"
"BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n"
"aWRnaXRzIFB0eSBMdGQwHhcNMTgwMzEyMTkyODUyWhcNMTkwMzEyMTkyODUyWjBF\n"
"MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n"
"ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
"CgKCAQEAw5TLyD3m...\n"
"-----END CERTIFICATE-----\n";
uint8_t binaryData[CONVERT_BUFFER_LENGTH_MAX];
uint32_t dataLength;
int result = ConvertPEMFormattedData(binaryData, pemCert,
sizeof(binaryData), &dataLength);
if (result == CONVERT_CERTIFICATE) {
printf("Certificate converted successfully\r\n");
printf("Binary data length: %lu bytes\r\n", dataLength);
// Use binaryData with SSL/TLS functions
} else {
printf("Failed to convert certificate\r\n");
}
#define CONVERT_BUFFER_LENGTH_MAX
Maximum data buffer length in bytes for PEM conversion.
Definition convert.h:58
int ConvertPEMFormattedData(puint8_t dataPtr, const char *pemEncodedData, uint32_t dataSize, puint32_t convertedDataLength, char **nextPtr=NULL)
Convert data from Privacy-Enhanced Mail (PEM) format to binary DER format.
#define CONVERT_CERTIFICATE
X.509 Certificate.
Definition convert.h:125
Example 2: Converting an RSA private key
const char *pemKey =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpAIBAAKCAQEAw5TLyD3m8F7xWQKLp6F5xoTUlqVJYALZ+qYQVQM8FnDtqZKr\n"
"...\n"
"-----END RSA PRIVATE KEY-----\n";
uint8_t keyData[CONVERT_BUFFER_LENGTH_MAX];
uint32_t keyLength;
int result = ConvertPEMFormattedData(keyData, pemKey,
sizeof(keyData), &keyLength);
if (result == CONVERT_RSA_PRIVATE_KEY) {
printf("RSA key converted: %lu bytes\r\n", keyLength);
// Use the key with crypto library
// ...
// Security: Zero the key buffer when done
memset(keyData, 0, sizeof(keyData));
} else {
printf("Failed to convert RSA key\r\n");
}
#define CONVERT_RSA_PRIVATE_KEY
RSA Private Key in PKCS#1 format.
Definition convert.h:104
Example 3: Processing multiple PEM objects
const char *multiPEM =
"-----BEGIN CERTIFICATE-----\n"
"...\n"
"-----END CERTIFICATE-----\n"
"-----BEGIN RSA PRIVATE KEY-----\n"
"...\n"
"-----END RSA PRIVATE KEY-----\n";
uint8_t buffer[CONVERT_BUFFER_LENGTH_MAX];
uint32_t length;
char *nextPEM = (char*)multiPEM;
int objectCount = 0;
while (nextPEM && *nextPEM) {
int type = ConvertPEMFormattedData(buffer, nextPEM,
sizeof(buffer), &length, &nextPEM);
if (type == CONVERT_NONE) {
break; // No more valid PEM data
}
objectCount++;
switch (type) {
printf("Object %d: Certificate (%lu bytes)\r\n",
objectCount, length);
break;
printf("Object %d: RSA Key (%lu bytes)\r\n",
objectCount, length);
break;
printf("Object %d: ECDSA Key (%lu bytes)\r\n",
objectCount, length);
break;
}
}
printf("Processed %d PEM objects\r\n", objectCount);
#define CONVERT_NONE
No valid PEM data found or conversion failed.
Definition convert.h:94
#define CONVERT_ECDSA_PRIVATE_KEY
ECDSA (Elliptic Curve) Private Key.
Definition convert.h:136
Example 4: Loading certificate and key for SSL/TLS
bool LoadSSLCredentials(const char *certPEM, const char *keyPEM) {
uint8_t certData[CONVERT_BUFFER_LENGTH_MAX];
uint8_t keyData[CONVERT_BUFFER_LENGTH_MAX];
uint32_t certLen, keyLen;
// Convert certificate
int certType = ConvertPEMFormattedData(certData, certPEM,
sizeof(certData), &certLen);
if (certType != CONVERT_CERTIFICATE) {
printf("Error: Invalid certificate format\r\n");
return false;
}
// Convert private key
int keyType = ConvertPEMFormattedData(keyData, keyPEM,
sizeof(keyData), &keyLen);
if (keyType != CONVERT_RSA_PRIVATE_KEY &&
printf("Error: Invalid private key format\r\n");
return false;
}
// Load into SSL context
if (!SSL_LoadCertificate(certData, certLen)) {
printf("Failed to load certificate\r\n");
memset(keyData, 0, sizeof(keyData)); // Clear sensitive data
return false;
}
if (!SSL_LoadPrivateKey(keyData, keyLen)) {
printf("Failed to load private key\r\n");
memset(keyData, 0, sizeof(keyData));
return false;
}
// Security: Clear sensitive key data
memset(keyData, 0, sizeof(keyData));
printf("SSL credentials loaded successfully\r\n");
return true;
}
Example 5: Error handling and validation
int SafeConvertPEM(const char *pem, uint8_t *output,
uint32_t outputSize, uint32_t *outLen) {
// Validate inputs
if (!pem || !output || !outLen) {
printf("Error: NULL pointer\r\n");
return CONVERT_NONE;
}
if (outputSize < CONVERT_BUFFER_LENGTH_MAX) {
printf("Error: Buffer too small (need %d bytes)\r\n",
return CONVERT_NONE;
}
// Attempt conversion
int result = ConvertPEMFormattedData(output, pem, outputSize, outLen);
if (result == CONVERT_NONE) {
printf("Error: PEM conversion failed\r\n");
printf(" Check PEM format and headers/footers\r\n");
return CONVERT_NONE;
}
// Validate output length
if (*outLen == 0 || *outLen > outputSize) {
printf("Error: Invalid output length: %lu\r\n", *outLen);
return CONVERT_NONE;
}
return result;
}
Example 6: Reading PEM data from file
#include <stdio.h>
bool ConvertPEMFile(const char *filename) {
FILE *fp = fopen(filename, "r");
if (!fp) {
printf("Error: Cannot open %s\r\n", filename);
return false;
}
// Read entire file into buffer
char pemBuffer[8192];
size_t bytesRead = fread(pemBuffer, 1, sizeof(pemBuffer) - 1, fp);
fclose(fp);
if (bytesRead == 0) {
printf("Error: Empty file\r\n");
return false;
}
pemBuffer[bytesRead] = '\0'; // Ensure NULL termination
// Convert PEM data
uint8_t binaryData[CONVERT_BUFFER_LENGTH_MAX];
uint32_t dataLen;
int type = ConvertPEMFormattedData(binaryData, pemBuffer,
sizeof(binaryData), &dataLen);
switch (type) {
printf("Converted certificate from %s\r\n", filename);
break;
printf("Converted RSA key from %s\r\n", filename);
break;
printf("Converted ECDSA key from %s\r\n", filename);
break;
default:
printf("Error: Invalid PEM data in %s\r\n", filename);
return false;
}
return true;
}