Skip to content

Sentinel Core API

The identity-sentinel-core.js module provides the cryptographic foundation for SAP identity management. It handles sealing (encryption) and unsealing (decryption) of identity data.

No installation required—uses Node.js built-in crypto module.

const { sealIdentity, unsealIdentity } = require('./src/identity-sentinel-core.js');

Encrypts identity data into a sealed backup artifact.

ParameterTypeRequiredDescription
keystring | BufferYesMaster passphrase or key material
dataobject | string | BufferYesData to encrypt

SealedBackup object:

interface SealedBackup {
header: {
format: "IdentitySentinel/SealedBackup";
formatVersion: number;
createdAt: string; // ISO 8601 timestamp
cipher: { name: "aes-256-gcm" };
kdf: {
name: "scrypt";
N: number; // CPU/memory cost (default: 32768)
r: number; // Block size (default: 8)
p: number; // Parallelization (default: 1)
keyLen: number; // Key length (default: 32)
};
saltB64: string; // Base64-encoded 16-byte salt
ivB64: string; // Base64-encoded 12-byte IV
contentType: string; // MIME type of original data
};
ciphertextB64: string; // Base64-encoded encrypted data
authTagB64: string; // Base64-encoded 16-byte auth tag
}
Input TypeDetected contentType
Bufferapplication/octet-stream
stringtext/plain; charset=utf-8
objectapplication/json; charset=utf-8
const { sealIdentity } = require('./src/identity-sentinel-core.js');
// Seal JSON data
const identityData = {
name: "my-agent",
keys: { operational: "..." },
created: "2026-02-06"
};
const sealed = sealIdentity("my-master-passphrase", identityData);
console.log(sealed.header.format);
// "IdentitySentinel/SealedBackup"
console.log(sealed.header.contentType);
// "application/json; charset=utf-8"
// Save to file
const fs = require('fs');
fs.writeFileSync('backup.json', JSON.stringify(sealed, null, 2));

Decrypts a sealed backup and returns the original data.

ParameterTypeRequiredDescription
keystring | BufferYesSame key used for sealing
sealedBackupSealedBackup | stringYesSealed backup object or JSON string

UnsealResult object:

interface UnsealResult {
header: SealedBackup['header']; // Original header
raw: Buffer; // Raw decrypted bytes
data: object | string | Buffer; // Parsed data based on contentType
}
contentTypedata Type
application/json*Parsed JSON object
text/*UTF-8 string
OtherRaw Buffer
const { unsealIdentity } = require('./src/identity-sentinel-core.js');
const fs = require('fs');
// Read sealed backup
const sealedJson = fs.readFileSync('backup.json', 'utf8');
// Unseal
const { data, header, raw } = unsealIdentity("my-master-passphrase", sealedJson);
console.log(data);
// { name: "my-agent", keys: {...}, created: "2026-02-06" }
console.log(header.createdAt);
// "2026-02-06T12:00:00.000Z"
console.log(raw.length);
// 123 (bytes)
try {
const result = unsealIdentity(wrongKey, sealed);
} catch (e) {
// Common errors:
// - "Bad format" - Not a valid sealed backup
// - "Unsupported formatVersion" - Version mismatch
// - "Unsupported cipher" - Unknown encryption algorithm
// - [Node.js crypto error] - Wrong key or corrupted data
console.error('Unseal failed:', e.message);
}

Encrypt data from file or stdin.

Terminal window
node src/identity-sentinel-core.js seal \
--key <passphrase> \
[--in <input-file>] \
[--out <output-file>]
OptionRequiredDefaultDescription
--keyYes*$IDENTITY_KEYMaster passphrase
--inNostdinInput file path
--outNostdoutOutput file path

Examples:

Terminal window
# From file to file
node src/identity-sentinel-core.js seal \
--key "passphrase" \
--in identity.json \
--out sealed.json
# From stdin to stdout
echo '{"name":"agent"}' | node src/identity-sentinel-core.js seal --key "pass"
# Using environment variable
export IDENTITY_KEY="passphrase"
node src/identity-sentinel-core.js seal --in identity.json --out sealed.json

Decrypt a sealed backup and output plaintext.

Terminal window
node src/identity-sentinel-core.js unseal \
--key <passphrase> \
--in <sealed-file>
OptionRequiredDefaultDescription
--keyYes*$IDENTITY_KEYMaster passphrase
--inYes-Sealed backup file

Output:

  • JSON data: Pretty-printed JSON
  • Text data: UTF-8 string
  • Binary data: Base64-encoded

Examples:

Terminal window
# Unseal to stdout
node src/identity-sentinel-core.js unseal --key "pass" --in sealed.json
# Unseal to file
node src/identity-sentinel-core.js unseal --key "pass" --in sealed.json > recovered.json
# Pipe to jq
node src/identity-sentinel-core.js unseal --key "pass" --in sealed.json | jq '.name'

Verify a sealed backup is valid without extracting content.

Terminal window
node src/identity-sentinel-core.js verify \
--key <passphrase> \
--in <sealed-file>
OptionRequiredDefaultDescription
--keyYes*$IDENTITY_KEYMaster passphrase
--inYes-Sealed backup file

Output:

  • Success: OK formatVersion=1 createdAt=2026-02-06T... (exit 0)
  • Failure: VERIFY_FAILED: <reason> (exit 1)

Examples:

Terminal window
# Verify backup
node src/identity-sentinel-core.js verify --key "pass" --in sealed.json
# OK formatVersion=1 createdAt=2026-02-06T12:00:00.000Z
# Use in scripts
if node src/identity-sentinel-core.js verify --key "$KEY" --in backup.json; then
echo "Backup is valid"
else
echo "Backup is corrupted or key is wrong"
fi

Master Key (passphrase)
┌─────────┐
│ Scrypt │ ◄── Salt (16 random bytes)
│ │
│ N=32768 │ Cost parameter (2^15)
│ r=8 │ Block size
│ p=1 │ Parallelization
└────┬────┘
Derived Key (32 bytes / 256 bits)
Derived Key ──────────────────┐
IV (12 random bytes) ─────────┤
┌─────────┐
Plaintext ─────────────►│AES-256 │────► Ciphertext
│ GCM │
Header (AAD) ──────────►│ │────► Auth Tag (16 bytes)
└─────────┘
PropertyGuarantee
ConfidentialityAES-256 encryption
IntegrityGCM authentication tag
AuthenticityAEAD binds header to ciphertext
Key stretchingScrypt resists brute force
RandomnessFresh salt + IV per seal operation

ErrorCauseSolution
Missing --keyNo key providedAdd --key or set $IDENTITY_KEY
Bad formatInput isn’t sealed backupCheck file is valid sealed backup JSON
Unsupported formatVersionVersion mismatchUse compatible library version
Unsupported cipherUnknown algorithmUse compatible library version
Unsupported kdfUnknown KDFUse compatible library version
Crypto errorWrong key or corruptionVerify key; check file integrity

// ✅ Use strong passphrases
sealIdentity("correct-horse-battery-staple-quantum", data);
// ✅ Handle errors
try {
const result = unsealIdentity(key, backup);
} catch (e) {
console.error('Failed to unseal:', e.message);
process.exit(1);
}
// ✅ Verify before trusting
const { header } = unsealIdentity(key, backup);
if (header.formatVersion !== 1) {
throw new Error('Unsupported version');
}
// ❌ Weak passphrase
sealIdentity("password", data);
// ❌ Ignoring errors
const result = unsealIdentity(key, backup); // May throw!
// ❌ Storing passphrase with backup
fs.writeFileSync('backup.json', JSON.stringify({ key, sealed })); // NO!