Skip to content

Latest commit

 

History

History
345 lines (238 loc) · 9.51 KB

File metadata and controls

345 lines (238 loc) · 9.51 KB

✨ Tiny Cert Crypto

A lightweight 🔐 utility for managing, generating, and handling X.509 certificates and RSA key pairs.
Built with flexibility in mind — runs seamlessly in both Node.js and browser environments! 🌍


📦 Features

  • 🛠️ RSA key pair generation (Node.js only)
  • 🧾 Self-signed X.509 certificate creation
  • 🧬 Support for PEM-based 🔑 public/private keys and certificates
  • 🧊 JSON encryption & decryption using Base64 encoding
  • 🕵️ Metadata extraction from certificates (issuer, subject, validity, etc.)
  • 📁 Flexible key loading: from memory, local files (Node.js), or URLs (browser)

🚀 Getting Started

📚 Constructor

const instance = new TinyCertCrypto({
  publicCertPath: 'cert.pem',          // Path to public cert (Node.js)
  privateKeyPath: 'key.pem',           // Path to private key (Node.js)
  publicCertBuffer: null,              // String or Buffer in memory (Node.js/browser)
  privateKeyBuffer: null,              // String or Buffer in memory (Node.js/browser)
  cryptoType: 'RSA-OAEP',              // Encryption algorithm (default: 'RSA-OAEP')
});

🔍 In browser environments, at least publicCertPath or publicCertBuffer must be provided.


🧪 Core Methods

🔧 async init()

Initializes the certificate and key system from files, memory buffers, or URLs.

  • Loads the public certificate/key.
  • Optionally loads the private key.
  • Detects whether you’re running in Node.js or the browser and adjusts behavior accordingly.

🔥 startCrypto(tinyCrypto?)

Starts the internal TinyCrypto instance.

This method initializes the TinyCrypto module. If no instance is provided, it will automatically create a new one.
If an instance is already set, it will throw an error to prevent overwriting the existing module.

instance.startCrypto();
// or
instance.startCrypto(myCustomTinyCrypto);

Parameters:

  • tinyCrypto (TinyCrypto) (Optional): An external TinyCrypto instance to initialize. If omitted, a new instance will be created automatically.

Throws:

  • Error: If the TinyCrypto instance has already been set.

Example:

try {
  instance.startCrypto();
  console.log("TinyCrypto started successfully!");
} catch (error) {
  console.error(error.message);
}

This method ensures that the cryptographic operations have a properly initialized environment before they are used.


📦 getCrypto()

Returns the previously loaded TinyCrypto instance.

This method retrieves the internal TinyCrypto module after it has been started using startCrypto().
If the module has not been started yet, it will throw an error.

const cryptoModule = instance.getCrypto();

Returns:

  • TinyCrypto: The initialized TinyCrypto module instance.

Throws:

  • Error: If the TinyCrypto instance is undefined or null, indicating it has not been properly started.

Example:

try {
  const crypto = instance.getCrypto();
  console.log("TinyCrypto is ready to use!", crypto);
} catch (error) {
  console.error(error.message);
}

This method is essential for safely accessing the TinyCrypto instance after it has been initialized.


🔐 existsCrypto()

Checks if the TinyCrypto instance has been set.

This method returns true if the TinyCrypto module has been assigned and is not null, otherwise it returns false.

const cryptoExists = instance.existsCrypto();

Returns:

  • true: If the TinyCrypto module exists and has been properly set.
  • false: If the TinyCrypto module is not set or is null.

Example:

if (instance.existsCrypto()) {
  console.log("TinyCrypto instance is available.");
} else {
  console.log("TinyCrypto instance is not set.");
}

This method is useful for checking the availability of the TinyCrypto instance before performing cryptographic operations.


📑 extractCertMetadata()

Returns parsed metadata from the loaded certificate.

{
  subject: { names: {}, shortNames: {}, raw: "CN=example.com,O=MyOrg" },
  issuer: { names: {}, shortNames: {}, raw: "CN=example.com,O=MyOrg" },
  serialNumber: '...',
  validFrom: Date,
  validTo: Date
}

🛡️ encryptJson(jsonObject)

Encrypts a JavaScript object using the loaded public key, returning a Base64-encoded string.

const encrypted = instance.encryptJson({ hello: "world" });

🔓 decryptToJson(base64String)

Decrypts a Base64 string using the private key, returning the original JSON object.

const json = instance.decryptToJson(encrypted);

🛡️ encrypt(data)

Encrypts a value and returns a Base64-encoded string.

const result = instance.encrypt('Hello!');

🔓 decrypt(data, expectedType?)

Decrypts a previously encrypted value and returns the original data. You can optionally pass an expectedType to validate it.

const plain = instance.decrypt(result, 'string');

🛡️ encryptWithoutKey(data)

Encrypts a value and returns a Base64-encoded string.

const result = instance.encryptWithoutKey('Hello!');

Behavior:

  • The data is encrypted without the AES key.
  • The returned result is a Base64-encoded string, similar to the regular encrypt() function.
  • This method is suitable when you wish to use a different encryption method.

🔓 decryptWithoutKey(data, expectedType?)

Decrypts a previously encrypted value and returns the original data. You can optionally pass an expectedType to validate it.

const plain = instance.decryptWithoutKey(result, 'string');

Behavior:

  • The data is decrypted using the internal AES key.
  • You can pass an optional expectedType to ensure the decrypted value matches the expected type, similar to the regular decrypt() function.
  • This method is suitable when you wish to use a different encryption method.

🔧 setDeepMode(value)

Sets the behavior for deep serialization and deserialization in the TinyCrypto instance.


🔍 hasKeys()

Returns true if both publicKey and privateKey are loaded.


📜 hasCert()

Returns true if a certificate (publicCert) is loaded.


♻️ reset()

Resets the internal state, clearing:

  • publicKey
  • privateKey
  • publicCert
  • metadata
  • source

📦 fetchNodeForge() & getNodeForge()

Handles lazy-loading and reuse of the node-forge module.

Use if you want to access Forge directly without importing it yourself:

const forge = await instance.fetchNodeForge();

🧠 Internals & Design

  • 🔍 Uses regular expressions to detect PEM types (CERTIFICATE, PUBLIC KEY, PRIVATE KEY)
  • 🧪 Automatically parses PEM buffers and files depending on the runtime
  • 🔐 Encrypts data with the selected algorithm (RSA-OAEP, etc.)
  • 🧬 X.509 certificate metadata extraction is done via node-forge

🧰 Requirements

Environment Requirement
Node.js node-forge
Browser Works with native fetch() and TextDecoder

😺 Example Use Case

const crypto = new TinyCertCrypto({ publicCertPath: 'cert.pem', privateKeyPath: 'key.pem' });
await crypto.init();

const data = { secret: 'I love ponies' };
const encrypted = crypto.encryptJson(data);
const decrypted = crypto.decryptToJson(encrypted);

console.log(decrypted); // { secret: 'I love ponies' }

🧾 async generateX509Cert(subjectFields, options = {})

Generates a new RSA key pair and a self-signed X.509 certificate using the provided subject information.

🔐 This is ideal for internal services, development environments, or cryptographic testing tools where a trusted CA is not required.


🧬 Parameters:

  • subjectFields (Object) – Describes the identity fields that will be embedded into the certificate's subject and issuer:

    • Common fields include:
      • CN: Common Name (e.g. domain or hostname)
      • O: Organization Name
      • OU: Organizational Unit
      • L: Locality (City)
      • ST: State or Province
      • C: Country (2-letter code)
      • emailAddress: Optional email field
  • options (Object) – Optional configuration:

    • keySize (number) – RSA key size in bits (default: 2048)
    • validityInYears (number) – Certificate validity period (default: 1)
    • randomBytesLength (number) – Length of the serial number (default: 16)
    • digestAlgorithm (string) – Digest algorithm used to sign the certificate (default: 'sha256')
    • forgeInstance (object) – Optionally inject a specific instance of node-forge
    • cryptoType (string) – Encryption scheme used for later operations (e.g., 'RSA-OAEP', 'RSAES-PKCS1-V1_5')

✅ Returns:

An object containing all the generated artifacts:

{
  publicKey: '-----BEGIN PUBLIC KEY-----...',
  privateKey: '-----BEGIN PRIVATE KEY-----...',
  cert: '-----BEGIN CERTIFICATE-----...'
}
  • publicKey: The newly generated PEM-encoded RSA public key
  • privateKey: The corresponding PEM-encoded RSA private key
  • cert: A PEM-encoded X.509 certificate that is self-signed with the private key and matches the provided subject

📌 Notes:

  • 🔄 The subject and issuer of the certificate are the same (self-signed).
  • ⏳ The certificate validFrom is set to the current date, and validTo is based on the validityInYears option.
  • 🔢 A secure random serialNumber is generated using node-forge.