Zero-PII Cryptography
Marigold Insights operates on a strict, mathematically-provable Zero-Trust boundary. We enforce AES-256-GCM authenticated encryption at the edge. Your PII never touches our processors in plaintext.
The Zero-Knowledge Mandate
State election systems manage Highly Sensitive Personally Identifiable Information (HS-PII). Traditional data brokers ingest these massive datasets via SFTP, placing the liability of SOC 2 / FedRAMP compliance squarely on the cloud provider. We reject this architecture.
Marigold functions exclusively on Encrypted Vaults. We act as an algebraic calculator for your system. We perform standard deviation logic, Fellegi-Sunter log-odds evaluation, and NCOA clustering on pre-encrypted hashes.
AES-256-GCM Specification
aes-256-gcm32 bytes (256 bits)12 bytes (96 bits)16 bytes (128 bits)Preparing the Encrypted Vault
Preparing the Encrypted Vault
Before calling the /modules/anomalies/detect endpoint, you must construct an encrypted vault. The vault is a Base64-encoded string containing three concatenated elements:
- The IV (Nonce): 12 bytes of cryptographically secure random data.
- The Ciphertext: Your JSON-stringified dataset, encrypted with your 32-byte master key.
- The Auth Tag: 16 bytes generated by the GCM cipher validating the integrity of the ciphertext.
Reference Implementation (Node.js)
Below is a production-ready Node 20+ implementation utilizing the native node:crypto module to generate the exact encrypted_vault.payload string expected by the API.
1import crypto from 'node:crypto';23// CAUTION: This key must be securely generated (32 bytes) and stored locally.4// Marigold NEVER receives this key. If you lose it, the anomalies we return5// cannot be decrypted by your system.6const LOCAL_MASTER_KEY = Buffer.from(process.env.MARIGOLD_LOCAL_KEY, 'hex');78function createEncryptedVault(dataArray: string[]): string {9 // 1. Stringify your data (e.g. array of Row IDs)10 const plaintext = JSON.stringify(dataArray);1112 // 2. Generate a 12-byte secure random IV (Nonce)13 const iv = crypto.randomBytes(12);1415 // 3. Instantiate the AES-256-GCM cipher16 const cipher = crypto.createCipheriv('aes-256-gcm', LOCAL_MASTER_KEY, iv);1718 // 4. Encrypt the data19 const ciphertext = Buffer.concat([20 cipher.update(plaintext, 'utf8'),21 cipher.final()22 ]);2324 // 5. Extract the 16-byte Authentication Tag25 const authTag = cipher.getAuthTag();2627 // 6. Concatenate: IV (12) + Ciphertext (N) + AuthTag (16)28 const finalPayload = Buffer.concat([iv, ciphertext, authTag]);2930 // 7. Base64 encode for API transmission31 return finalPayload.toString('base64');32}
Reference Implementation (C# / .NET 8)
For state agencies relying on Microsoft infrastructure, here is the equivalent implementation utilizing the highly optimized AesGcm class in System.Security.Cryptography.
1using System;2using System.Security.Cryptography;3using System.Text;4using System.Text.Json;56public class MarigoldCryptography7{8 private readonly byte[] _masterKey; // Must be exactly 32 bytes910 public MarigoldCryptography(string hexKey)11 {12 _masterKey = Convert.FromHexString(hexKey);13 }1415 public string CreateEncryptedVault(string[] dataArray)16 {17 byte[] plaintext = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(dataArray));1819 byte[] nonce = new byte[12];20 RandomNumberGenerator.Fill(nonce);2122 byte[] ciphertext = new byte[plaintext.Length];23 byte[] authTag = new byte[16];2425 using (AesGcm aesGcm = new AesGcm(_masterKey, 16)) // 16 byte tag size26 {27 aesGcm.Encrypt(nonce, plaintext, ciphertext, authTag);28 }2930 // Concatenate: Nonce (12) + Ciphertext (N) + AuthTag (16)31 byte[] finalPayload = new byte[nonce.Length + ciphertext.Length + authTag.Length];32 Buffer.BlockCopy(nonce, 0, finalPayload, 0, nonce.Length);33 Buffer.BlockCopy(ciphertext, 0, finalPayload, nonce.Length, ciphertext.Length);34 Buffer.BlockCopy(authTag, 0, finalPayload, nonce.Length + ciphertext.Length, authTag.Length);3536 return Convert.ToBase64String(finalPayload);37 }38}
Decrypting the Response
Decrypting the Response
When Marigold processes your algorithm, we encrypt the flagged anomalies (e.g., Row IDs that failed the density check) utilizing the same Nonce architecture. When you receive the response payload, you must reverse the concatenation process (extract the first 12 bytes as the IV, the last 16 bytes as the Auth Tag, and the middle as the Ciphertext) to securely read the flagged rows locally.
ERR_AUTH_TAG_MISMATCH
The most common decryption error occurs when the authTag is incorrectly sliced from the payload. AES-GCM will aggressively throw an exception if the Tag is altered by even a single bit. Ensure you are extracting exactly 16 bytes from the absolute end of the Buffer array before attempting decipher.setAuthTag().