tiny-crypto-suite
Version:
Tiny tools, big crypto β seamless encryption and certificate handling for modern web and Node apps.
346 lines (238 loc) β’ 9.73 kB
Markdown
# β¨ 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
```js
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.
```js
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:
```js
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.
```js
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:
```js
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`.
```js
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:
```js
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.
```js
{
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**.
```js
const encrypted = instance.encryptJson({ hello: "world" });
```
### π `decryptToJson(base64String)`
Decrypts a Base64 string using the **private key**, returning the original JSON object.
```js
const json = instance.decryptToJson(encrypted);
```
### π‘οΈ `encrypt(data)`
Encrypts a value and returns a **Base64-encoded string**.
```js
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.
```js
const plain = instance.decrypt(result, 'string');
```
### π‘οΈ `encryptWithoutKey(data)`
Encrypts a value and returns a **Base64-encoded string**.
```js
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.
```js
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:
```js
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
```js
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:
```js
{
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`.