Hashing and Encrypting PII data
This guide explains how to properly implement hashing and encryption for PII data before it reaches Meiro CDP, ensuring compliance with privacy requirements while maintaining functionality for identity resolution and activation.
Overview
To fulfill CDP requirements while limiting PII data exposure, implement a dual approach:
- Hashing - For identity resolution and advertising platform activation
- Encryption - For secure transmission to destination systems
Prerequisites
- Access to Meiro Events Web SDK
- Understanding of JavaScript hashing and encryption
- Public/private key pair for RSA encryption
Hashing Implementation
Requirements
- Send Client ID from all sources when possible
- Hash PII data using consistent sanitization and algorithms across all sources
- Follow advertising platform requirements (Meta, Google, etc.)
Standardized Process
Use the following sanitization and hashing approach for all sources:
- Email sanitization: lowercase + trim whitespace
- Phone sanitization: remove symbols, leading zeros, spaces, include country code
- Hashing algorithm: SHA256
Implementation Example
// Email hashing
const email = "Kurka.Vojtech@gmail.com";
const sanitizedEmail = email.toLowerCase().trim();
const emailHash = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(sanitizedEmail)
);
// Phone hashing
const phone = "+420 606 199 831";
const sanitizedPhone = "420606199831"; // Remove symbols, spaces, leading zeros
const phoneHash = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(sanitizedPhone)
);
Common Mistakes to Avoid
❌ Inconsistent sanitization:
- Source A:
Kurka.Vojtech@gmail.com
→ Different hash - Source B:
kurka.vojtech@gmail.com
→ Different hash
❌ Different algorithms:
- Source A: SHA256
- Source B: MD5
✅ Correct approach: Same sanitization + same algorithm = consistent hashes
Encryption Implementation
RSA Encryption Setup
For scenarios requiring raw PII in destination systems while maintaining CDP security:
- Public key: Distributed to data sources for encryption
- Private key: Available only in destination system for decryption
JavaScript Implementation
// RSA encryption using Web Crypto API
async function encryptWithRSA(data, publicKey) {
const encrypted = await crypto.subtle.encrypt(
{
name: "RSA-OAEP",
hash: "SHA-256"
},
publicKey,
new TextEncoder().encode(data)
);
return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}
Complete Payload Example
For a contact form with email and phone:
User Input:
- Email:
Kurka.Vojtech@gmail.com
- Phone:
+420 606 199 831
ME SDK Payload:
{
"email_hash": "1AF6402BFF01BF4C9C59760A1AD70C0F9AC6581E1F1BC6F0E42CFD0E5507F849",
"phone_hash": "1252E4992ABDDA7AFEC3BD5243C5DA5426A051AAA4B9CE879A2A0DA063C8AD58",
"email_rsa": "kebusJ6sLtgiN0n0l1ZtBk/V+sJAMg4DgBQO6UVSeOZt...",
"phone_rsa": "mOfcZlyzJ9av00kVJK10cqoTTV3VnPLXr8LBZLCs..."
}
Data Flow
In CDP
- Hashed values: Used for identity resolution and advertising platform uploads
- Encrypted values: Stored securely, passed through to destination systems
In Destination Systems
- Private key decryption: Convert encrypted values back to raw PII
- Activation: Use raw PII for personalization and communication
Security Benefits
- CDP isolation: No raw PII stored in CDP
- Advertising compliance: Proper hashing for Meta, Google uploads
- Destination access: Secure decryption in authorized systems only
- Key management: Private keys never leave destination systems
Implementation Steps
- Generate key pair: Create RSA public/private key pair
- Distribute public key: Share with all data collection points
- Implement hashing: Add consistent sanitization and SHA256 hashing
- Implement encryption: Add RSA encryption for sensitive fields
- Update ME SDK: Send both hashed and encrypted values
- Configure destinations: Set up private key decryption
Testing and Validation
Hash Consistency Check
Verify identical inputs produce identical hashes across all sources:
// Test with same input from different sources
const testEmail = "test@example.com";
const hash1 = await hashEmail(testEmail); // Source A
const hash2 = await hashEmail(testEmail); // Source B
console.assert(hash1 === hash2, "Hash mismatch detected");
Encryption/Decryption Test
Validate the encryption-decryption cycle:
// Encrypt with public key
const encrypted = await encryptWithRSA(originalData, publicKey);
// Decrypt with private key (in destination system)
const decrypted = decryptWithPrivateKey(encrypted, privateKey);
console.assert(originalData === decrypted, "Decryption failed");
References
Support
For implementation assistance or questions about hashing and encryption setup, contact the Meiro support team.
No Comments