PKCS#8

#cryptxdevquotes: The allocation for this structure needs more space than exists on the calculator. How is this even working? - Anthony Cagliano

Module Functionality
Provides functions for the import of PKCS#8-encoded public and private keys that can be used with the RSA and EC modules of this library.

PKCS stands for Public Key Cryptography Standards and specification #8 provides general key encoding guidelines for various forms of public and private keys. Because the API of this library tends to work on raw data (rather than on key structures like other libraries do), this module provides a way to deserialize PKCS#8 keyfiles such that you can access components of the key. You can also pass these public and private key structures directly to the TLS implementation (coming soon).

PKCS#8 typically encodes keydata using the following workflow:

  1. The components of the key are encoded using ASN.1/DER. Click here for more details.

  2. The ASN.1 structure is then encoded using Base64/PEM.

  3. The key data is wrapped in a header/footer banner indicating the type of key. These banners may be:

-----BEGIN PUBLIC KEY-----
base64-encoded public key
-----END PUBLIC KEY-----

-----BEGIN PRIVATE KEY-----
base64-encoded private key
-----END PRIVATE KEY-----

-----BEGIN ENCRYPTED PRIVATE KEY-----
base64-encoded encrypted private key
-----END ENCRYPTED PRIVATE KEY-----

Enumerations

enum _pkcs8_pubkey_rsa_fields

Values:

enumerator PKCS8_PUBLIC_RSA_MODULUS = 0

reference to public modulus in cryptx_pkcs8_pubkey

enumerator PKCS8_PUBLIC_RSA_EXPONENT

reference to public exponent in cryptx_pkcs8_pubkey

enumerator PKCS8_PUBLIC_RSA_FIELDS

number of RSA fields in structure (for enumeration)

enum _pkcs8_pubkey_ec_fields

Values:

enumerator PKCS8_PUBLIC_EC_CURVEID = 0

reference to EC Curve ID in cryptx_pkcs8_pubkey

enumerator PKCS8_PUBLIC_EC_PUBKEY

reference to ECPoint public key in cryptx_pkcs8_pubkey

enumerator PKCS8_PUBLIC_EC_FIELDS

number of EC fields in structure (for enumeration)

enum _pkcs8_privkey_rsa_fields

Values:

enumerator PKCS8_PRIVATE_RSA_VERSION = 0

reference to RSA version in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_MODULUS

reference to private modulus in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_PUBEXPONENT

reference to public exponent in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_EXPONENT

reference to private exponent in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_P

reference to P in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_Q

reference to Q in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_EXP1

reference to Exp1 in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_EXP2

reference to Exp2 in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_COEFF

reference to Coefficient in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_RSA_FIELDS

number of RSA fields in structure (for enumeration)

enum _pkcs8_privkey_ec_fields

Values:

enumerator PKCS8_PRIVATE_EC_CURVEID = 0

reference to EC Curve ID in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_EC_VERSION

reference to EC version in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_EC_PRIVKEY

reference to private key in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_EC_PUBKEY

reference to public key in cryptx_pkcs8_privkey

enumerator PKCS8_PRIVATE_EC_FIELDS

number of EC fields in structure (for enumeration)

Structures

struct cryptx_pkcs8_pubkey

Defines a structure for holding imported RSA or ECC public key data.

Public Members

bool error

deserialization status, False if no error, True if failed.

struct cryptx_asn1_object objectid

reference to primary object ID of object.

union cryptx_pkcs8_pubkey::_publickey publickey

expresses EC or RSA key data.

size_t len

length of raw data portion of structure.

uint8_t raw[]

contains dump of raw data from deserialized key.

union _publickey

Public Members

struct cryptx_asn1_object ec_fields[PKCS8_PUBLIC_EC_FIELDS]

reserve EC fields

struct cryptx_asn1_object rsa_fields[PKCS8_PUBLIC_RSA_FIELDS]

reserve RSA fields

struct cryptx_pkcs8_privkey

Defines a structure for holding imported RSA or ECC private key data.

Public Members

bool error

deserialization status, False if no error, True if failed.

struct cryptx_asn1_object objectid

reference to primary object ID of object.

union cryptx_pkcs8_privkey::_privatekey privatekey

expresses EC or RSA key data.

size_t len

length of raw data portion of structure.

uint8_t raw[]

contains dump of raw data from deserialized key.

union _privatekey

Public Members

struct cryptx_asn1_object rsa_fields[PKCS8_PRIVATE_RSA_FIELDS]

reserve RSA fields

struct cryptx_asn1_object ec_fields[PKCS8_PRIVATE_EC_FIELDS]

reserve EC fields

Note

These structures, particularly cryptx_pkcs8_privkey, take up a lot of memory. This module uses dynamic allocation to optimize storage requirements for these structures to the best extent possible. Each structure contains a static portion which contains references to a dump of the raw data of the key and the dump section is of variable size depending on the size of the key.

Note

Passphrase-encrypted private keys are not currently supported by this library and will return an error if used for now. This may change in the future, check in or poke us on the discord.

Functions

struct cryptx_pkcs8_pubkey *cryptx_pkcs8_import_publickey(void *data, size_t len, void *(*malloc)(size_t))

Attempts to import a PKCS#8-encoded public key for RSA or ECC.

Parameters
  • data – Pointer to PKCS#8-encoded key data.

  • len – Length of key data to import.

  • malloc – Pointer to toolchain malloc function.

Returns

A malloc’d cryptx_pkcs8_pubkey structure populated with key metadata.

Returns

NULL if arguments invalid or allocation failure.

Returns

The error field of the structure set to True if a deserialization error occurred.

struct cryptx_pkcs8_privkey *cryptx_pkcs8_import_privatekey(void *data, size_t len, void *(*malloc)(size_t))

Attempts to import a PKCS#8-encoded private key for RSA or ECC.

Parameters
  • data – Pointer to PKCS#8-encoded key data.

  • len – Length of key data to import.

  • malloc – Pointer to toolchain malloc function.

Returns

A malloc’d cryptx_pkcs8_privkey structure populated with key metadata.

Returns

NULL if arguments invalid or allocation failure.

Returns

The error field of the structure set to True if a deserialization error occurred.

void cryptx_pkcs8_free_publickey(struct cryptx_pkcs8_pubkey *pk, void (*free)(void*))

Erases a PKCS#8 public key structure returned by cryptx_pkcs8_import_publickey and then frees the allocated memory.

Parameters
  • pk – Pointer to a PKCS#8 public key structure.

  • free – Pointer to toolchain free function.

void cryptx_pkcs8_free_privatekey(struct cryptx_pkcs8_privkey *pk, void (*free)(void*))

Erases a PKCS#8 private key structure returned by cryptx_pkcs8_import_privatekey and then frees the allocated memory.

Parameters
  • pk – Pointer to a PKCS#8 private key structure.

  • free – Pointer to toolchain free function.

Note

Remember to call the corresponding free method for any structure allocated with the module or you may wind up with memory leaks.


You can import your keyfiles like so:

// assume that you have generated a keypair using openssl or some similar software
// then converted to appvars 'MyPub' and 'MyPriv' using convbin,
// then transferred both to your calculator
char *pubkey_fname = "MyPub";
char *privkey_fname = "MyPriv";
uint8_t fp;
uint8_t *key_data;
size_t key_len;

// load pubkey from file (requires FILEIOC library)
if(!(fp = ti_Open(pubkey_fname, "r"))) {
  printf("File IO Error");
  exit(1);
}
key_data = ti_GetDataPtr(fp);
key_len = ti_GetSize(fp);
ti_Close(fp);
cryptx_pkcs8_pubkey *pub = cryptx_pkcs8_import_publickey(key_data, key_len, malloc);
if(!pub){
  printf("Alloc error!");
  exit(2);
}
if(pub->error) {
  printf("Deserialization error!");
  exit(3);
}

// load pubkey from file (requires FILEIOC library)
if(!(fp = ti_Open(privkey_fname, "r"))) {
  printf("File IO Error");
  exit(1);
}
key_data = ti_GetDataPtr(fp);
key_len = ti_GetSize(fp);
ti_Close(fp);
cryptx_pkcs8_privkey *priv = cryptx_pkcs8_import_privatekey(key_data, key_len, malloc);
if(!priv){
  printf("Alloc error!");
  exit(2);
}
if(priv->error) {
  printf("Deserialization error!");
  exit(3);
}

// these structs can be passed directly to the TLS implementation (coming soon)
// or the members can be accessed directly for advanced usage.

Additional Info

PKCS#8 Specification

This section details the PKCS#8 encoding format for public and private key files.

PublicKeyInfo ::= SEQUENCE {
  algorithm ::= SEQUENCE {
    algorithm   OBJECT IDENTIFIER,
    parameters  ANY DEFINED BY algorithm OPTIONAL
  }
  PublicKey   BIT STRING
}

PrivateKeyInfo ::= SEQUENCE {
  version Version,
  algorithm ::= SEQUENCE {
    algorithm   OBJECT IDENTIFIER,
    parameters  ANY DEFINED BY algorithm OPTIONAL
  }
  PrivateKey  BIT STRING
}

EncryptedPrivateKeyInfo ::= SEQUENCE {
  encryptionAlgorithm ::= SEQUENCE {
    algorithm   OBJECT IDENTIFIER,
    parameters  ANY DEFINED BY algorithm OPTIONAL
  }
  encryptedData ::= OCTET STRING (encrypts PrivateKeyInfo)
}

For some key formats the PublicKey field further encodes a structure from a different standard. This is true for all CryptX use cases of these keys.

-- from PKCS#1, src: rfc3447 A.1.1
RSAPublicKey ::= SEQUENCE {
  modulus         INTEGER,    -- n
  publicExponent  INTEGER,    -- e
}

-- from PKCS#1, src: rfc3447 A.1.2
RSAPrivateKey ::= SEQUENCE {
  version           Version,
  modulus           INTEGER,  -- n
  publicExponent    INTEGER,  -- e
  privateExponent   INTEGER,  -- d
  prime1            INTEGER,  -- p
  prime2            INTEGER,  -- q
  exponent1         INTEGER,  -- d mod (p-1)
  exponent2         INTEGER,  -- d mod (q-1)
  coefficient       INTEGER,  -- (inverse of q) mod p
  otherPrimeInfos   OtherPrimeInfos OPTIONAL
}

-- from SECG1, src: rfc5915 1.3
ECPrivateKey ::= SEQUENCE {
  version     INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  privateKey  OCTET STRING,
  parameters  [0] ECParameters {{ NamedCurve }} OPTIONAL,
  publicKey   [1] BIT STRING OPTIONAL
}

-- from SECG1, src: rfc5915 2.2
ECPublicKey ::= ECPoint ::= OCTET STRING
-- first octet of key is 0x04 for uncompressed or 0x03 or 0x02 for compressed

Object Identifier Reference

This section lists object identifiers for algorithms supported by this library. Developers should generally never need to use these as the library should handle it internally, but if you need them for other projects or even for custom implementations, here they are.

Bear in mind that while this module can successfully import objects for most algorithm types, only the ones listed below can actually be USED by the library.

static const uint8_t cryptx_pkcs8_objectid_rsa[]

Encoded Object Identifier for RSA.

static const uint8_t cryptx_pkcs8_objectid_ec[]

Encoded Object Identifier for ECC.

static const uint8_t cryptx_pkcs8_curveid_sect233k1[]

Encoded Object Identifier for SECT233k1.