Privacy Tools Guide

Standard push notifications expose sender information and message metadata to Google (FCM) and Apple (APNs), who can read this data during delivery. Signal solves this problem by sending encrypted payloads through FCM/APNs that contain only minimal unencrypted wake-up signals, keeping message content and sender identity hidden from platform operators. This architecture provides end-to-end privacy while maintaining the real-time notification experience users expect.

The Privacy Problem With Traditional Push Notifications

When you receive a traditional push notification, your device sends a device token to the messaging server. When a message arrives, the server sends a payload through FCM or APNs containing the sender ID, notification title, and message body. The push service then delivers this to your device.

This architecture means Google and Apple can see:

For most users, this might seem acceptable. However, for users requiring strong privacy guarantees—journalists, activists, or anyone discussing sensitive matters—this metadata exposure represents a meaningful attack surface.

Signal’s Solution: Sealed Sender and Encrypted Payloads

Signal implements two complementary mechanisms to protect push notification content: Sealed Sender and encrypted payload delivery.

Sealed Sender: Removing Sender Information

Traditional push notifications include the sender’s identifier in the payload. Signal’s Sealed Sender removes this information, allowing the server to deliver a notification without knowing who sent it.

Here’s how the flow works conceptually:

# Simplified conceptual flow for Sealed Sender
def create_sealed_notification(sender_public_key, recipient_device_token, message):
    # Generate one-time use keypair for this notification
    ephemeral_keypair = generate_ecdh_keypair()

    # Create encrypted envelope
    envelope = {
        "sender": encrypt(sender_public_key, ephemeral_keypair.private),
        "recipient": recipient_device_token,
        "timestamp": current_unix_timestamp()
    }

    # Server can deliver to recipient but cannot identify sender
    return push_service.deliver(envelope)

The key insight is that the push server acts as an opaque transport layer—it knows where to deliver the notification but not who sent it or potentially what it contains.

Encrypted Payload Delivery

Sealed Sender alone doesn’t protect the notification content. To solve this, Signal encrypts the notification payload itself. The device receives an opaque blob that only the Signal app can decrypt.

Implementation Details: How Signal Encrypts Push Content

The actual implementation uses a multi-layer encryption approach:

// Conceptual encrypted notification payload structure
const encryptedNotification = {
  // Layer 1: Encryption for push service transport
  encrypted_payload: base64(encrypt_aes_gcm(
    plaintext: JSON.stringify({
      message_preview: "...",  // Already encrypted
      sender_identity: "...",   // Blinded identifier
      timestamp: 1234567890
    }),
    key: push_service_key
  )),

  // Layer 2: Signal-specific encryption (device-to-device)
  signal_encrypted: base64(sealed_sender_encrypt(
    recipient_device: device_public_key,
    message: message_content
  ))
};

When your device receives this notification, the Signal app:

  1. Decrypts the outer layer using keys stored only on your device
  2. Processes the inner Signal-encrypted content
  3. Displays a generic notification or the decrypted message preview (depending on your settings)

Practical Implications for Developers

If you’re building privacy-focused applications, Signal’s approach offers several architectural lessons:

Key Management

Signal uses a combination of identity keys and one-time ephemeral keys. The identity key provides consistent sender verification, while ephemeral keys prevent traffic analysis:

# Pseudocode for notification encryption key derivation
def derive_notification_keys(identity_key, ephemeral_key, recipient_prekey):
    # ECDH key agreement
    shared_secret = ecdh(identity_key, ephemeral_key)

    # Derive separate keys for different purposes
    message_key = hkdf(shared_secret, "message-encryption")
    metadata_key = hkdf(shared_secret, "metadata-hiding")

    return {"message_key": message_key, "metadata_key": metadata_key}

Blind Identifiers

To prevent the push service from correlating notifications with specific users, Signal uses cryptographic blinding:

# Blinding the sender identifier from push service
def blind_sender_identifier(sender_identity_key, server_public_key):
    # The push server can verify the recipient exists
    # but cannot identify the specific sender
    blinded = sha256(ecdh(sender_identity_key, server_public_key))
    return blinded

Notification Content Options

Signal provides users with granular control over notification content:

Limitations and Considerations

While Signal’s approach significantly improves privacy, some limitations exist:

  1. Metadata still flows: While content is encrypted, connection metadata (timing, device identifiers) remains visible to platform operators
  2. Device token correlation: If a device receives many notifications, pattern analysis could potentially identify users
  3. Fallback mechanisms: When Sealed Sender isn’t available (first message from new contact, offline devices), traditional notifications are used
  4. Battery and latency: Additional encryption processing adds slight overhead

Enabling Signal’s Privacy Features

For Signal users wanting maximum protection:

  1. Open Signal Settings → Notifications
  2. Enable “Sealed Sender” (may show as “Allow from contacts” or “Always”)
  3. Choose notification display preference under “Show”

Note that both sender and recipient must have Sealed Sender enabled for full protection.

Alternative Messaging Apps and Their Notification Approaches

Understanding how other applications handle push notifications helps evaluate comparative privacy.

Telegram’s Notification Model

Telegram sends notifications through its own infrastructure for paid premium users ($ 4.99/month). Standard users receive notifications through FCM/APNs, exposing metadata similarly to standard push services. Telegram Cloud Chat technology stores messages on servers, creating different privacy trade-offs than Signal’s server-minimal approach.

Wire’s Multi-Layer Approach

Wire encrypts notification content server-side and uses its own infrastructure for notification delivery when possible. The application defaults to encrypted notifications, though users can adjust settings. However, Wire’s paid model ($5/month for premium features) creates complexity in comparing free services.

Session’s Push Notification Strategy

Session uses Loki Service Node network for push notifications, avoiding centralized platforms like FCM/APNs entirely. The trade-off involves slower notification delivery and higher power consumption from polling the decentralized network.

WhatsApp’s Silent Notification Strategy

WhatsApp relies on silent push notifications—the app doesn’t display message previews in notifications at all, only a generic notification that messages arrived. The app itself fetches message content upon waking. This approach avoids exposing message content to platform operators at the cost of slightly longer perceived notification latency.

Developing Encrypted Push Infrastructure

For developers building applications requiring privacy-focused notifications, several architectural approaches exist.

Self-Hosted Push Solution

Running your own push infrastructure eliminates dependency on FCM/APNs:

# Example: Setting up UnifiedPush with Nextpush
# UnifiedPush is an open standard for decentralized push notifications

# Install Nextpush on your server
docker run -d \
  -e "NEXTPUSH_APP_NAME=MyApp" \
  -p 8080:8000 \
  -v nextpush_data:/data \
  nextcloud/nextpush

UnifiedPush allows applications to send encrypted notifications through your own infrastructure without relying on Google or Apple. Applications supporting UnifiedPush include K-9 Mail, Telegram, and others.

Hybrid Approach: Fallback Notifications

Most privacy-conscious applications use this strategy:

  1. Send encrypted “silent” notification through FCM/APNs (minimal data)
  2. Device receives notification and wakes the app
  3. App fetches encrypted message content from application server using standard encryption

This keeps the notification payload minimal while ensuring timely delivery. Signal implements exactly this approach.

Per-Message Notification Keys

Some applications generate unique encryption keys for each notification:

# Pseudocode for per-message notification key generation
def create_notification_key(recipient_id, message_id, server_secret):
    # Derive unique key for this specific notification
    combined = f"{recipient_id}:{message_id}:{server_secret}"
    notification_key = sha256(combined)

    # Send notification encrypted with this key
    encrypted_payload = aes_encrypt(
        plaintext=notification_content,
        key=notification_key
    )

    # Send encrypted payload and key to device through separate mechanism
    return (encrypted_payload, notification_key)

This approach ensures each notification uses different encryption, making pattern analysis more difficult.

Metadata Protection Beyond Message Content

Even encrypted notifications expose metadata that can reveal patterns.

Timing Patterns

When notifications arrive can reveal active users and conversation partners:

Mitigations include batching notifications (delay delivery by random interval) or uniform notification patterns (fake notifications at regular intervals).

Device Fingerprinting Through Notifications

The apps installed on your device affect how you interact with notifications. Platform operators can infer:

notification privacy requires reducing what information is exposed beyond message content.

Regulatory and Compliance Considerations

For organizations deploying encrypted messaging with privacy-conscious notifications, regulatory considerations matter.

GDPR Implications

GDPR’s data minimization principle suggests storing minimal notification-related data. Some interpretations require deletion of notification metadata after delivery, which some platforms struggle to implement.

Enterprise Deployment Constraints

Corporate environments often require different notification models:

Building enterprise applications often requires accepting some privacy trade-offs for compliance and auditing capabilities.

Testing Your Notification Privacy

For Signal users wanting to verify notification privacy:

  1. Enable Sealed Sender in Settings
  2. Ask a contact to send you a message
  3. Check Settings → Privacy to review who can message you
  4. Look at the notification that arrives—verify minimal information appears
  5. Compare with unencrypted notifications from other apps

More technical testing involves intercepting network traffic:

# Capture and decrypt Signal notification traffic (requires certificate pinning bypass)
mitmproxy -m transparent --mode reverse --modify-body /pattern/replacement "https://push.signal.org"

Formal security audits by third parties (like those performed by Open Whisper Systems) provide more verification than individual testing.

Built by theluckystrike — More at zovo.one