Sova Nanny

Baby monitor

How Sova is secured

Technical note · Android app com.iwelautomatyka.sova · Privacy policy

PIN never sentPairing proves it instead
Two keysWe only ever get the weaker one
Relay stays blindForwarded, never readable

In one paragraph

Your phones share a secret that no server of ours ever receives, and each parent phone also holds a key of its own. Pairing hands them over without the PIN ever crossing the network. At home, the phones talk directly, encrypted end to end. Away from home, their alerts, sound and video pass through our server, encrypted with keys worked out from that secret, which is why we can forward them and cannot read them. Because every parent phone signs with its own key, the nursery can disconnect one phone without touching the others.

This page is the detail behind one sentence in the privacy policy: that we cannot hear or see what passes through our server. It is written for people who want to check that claim rather than take it. Nothing here is a promise about what we collect; that is the policy's job.

Pairing, without ever sending the PIN

The nursery phone shows a four-digit PIN and a QR code. A parent phone joins by scanning the code, or by typing the PIN. The QR code carries only the PIN and a short tag that names the nursery; it does not carry the room key. Scanning and typing then take exactly the same road.

Pairing works only on the home Wi-Fi, and only while the nursery phone is showing its code; with the code card closed, or the nursery screen asleep for the night, it refuses every pairing attempt. Every attempt runs a password-authenticated key exchange (SRP-6a, RFC 5054, 2048-bit group, SHA-256). The PIN never travels, in any form: a device listening on your Wi-Fi learns nothing it could guess from later, and each guess costs the attacker one whole attempt against the nursery. The nursery counts those attempts, started ones included. Five wrong PINs from one address lock pairing for a minute; keep going and the PIN is thrown away and replaced, which ends the attack for good.

A correct PIN is still not enough. The nursery phone shows who is asking and waits for the person holding it to tap Let in; nothing is handed over before that, and no answer within a minute is a refusal. Only then does the parent receive the room key: 128 random bits generated on the nursery, handed over inside the encrypted exchange. On its first connection after that, inside the encrypted session, the nursery also gives that phone its own parent key, another 128 random bits that only the nursery and that one phone know. Everything below is built on these two.

A nursery without Sova Pro accepts one parent phone. The check happens after the PIN has been proven and before anyone is asked to let the phone in.

Signing keys, one way

The room key and the parent keys stay on your phones. Our server never receives them. What it receives are signing keys, one for the nursery and one for each parent phone, sent by the nursery itself:

nursery signing key = HMAC-SHA-256(room key, "sova-alert-auth")
parent signing key  = HMAC-SHA-256(parent key, "sova-alert-auth")

HMAC runs one way. A signing key is enough for the server to verify that a heartbeat, an event, a status request or a socket really comes from one of your phones, and it cannot be turned back into the key it came from. Since every key that encrypts alerts, sound and video is derived from the room key, the server cannot compute any of them.

Disconnecting one phone. The nursery keeps the list of parent signing keys on our server. Remove a phone on the nursery, and its key leaves the list: from then on the server refuses that phone's requests and sockets, drops its notification address, and closes its open connections, while the other parent phones go on as before. Once every parent phone in a room has its own key, the nursery switches the room to parent keys only: the room key alone, including a copy kept on an old phone, then opens nothing on our server or on your Wi-Fi.

Your room is named by the hash of the signing key, so that registering a key under someone else's room name is rejected. The name identifies nothing about you: not your phone, not your network, not you.

At home: the two phones talk directly

The parent phone finds the nursery over mDNS and a UDP beacon, then opens a direct TCP connection. The broadcast carries a tag that changes every hour, never the PIN and never the nursery's name, so a listener on the same network cannot tell which room is which, nor link one hour to the next. The name, and a fixed tag that the QR code points to, appear only while the pairing card is open on the nursery.

tag = HMAC-SHA-256(room key, "sova-rr|" + hour)

Each connection starts with an ephemeral ECDH key agreement on P-256, authenticated by HMAC tags computed from that phone's own parent key (from the room key for a phone that has none yet), with separate labels for the two ends. Both sides then derive separate keys per direction with HKDF, and every frame after that, sound, video, status and commands alike, is sealed with AES-256-GCM under a counter nonce. A device on your Wi-Fi can see that two phones are talking and nothing more. It cannot read a frame, replay one, or inject one.

Away from home: through us, but closed to us

When your phone is not on the nursery's Wi-Fi, both phones open a WebSocket to our server, each request signed with that phone's own signing key. The server's whole job is to copy bytes from one socket to the others in the same room. It holds each message in memory for the instant that takes and writes none of them anywhere.

Every relayed message carries its own header: a 16-byte sender nonce, an 8-byte counter, then the ciphertext. The key is derived per sender and per direction:

key = HKDF(room key, nonce, "sova-relay-n2c")  nursery to parent
key = HKDF(room key, nonce, "sova-relay-c2n")  your voice back

AES-256-GCM again, a fresh key per session, and the receiver derives it from the header of the message in front of it, so two nursery sockets overlapping for a moment cannot confuse one another. The server has no room key, so it has no key here at all. Audio is AAC-LC at 32 kbit/s, video is H.264; both are encrypted before they reach the socket and decrypted only on your phone.

Alert traffic uses TLS on top of all this, and every request carries a timestamp inside the signature, so a captured request cannot be replayed later.

Alerts: sealed for your phones

What the nursery reports, whether it is crying, overheating, the end of crying, or its battery, temperature, signal and the crying of the last four hours, is sealed on the nursery before it leaves:

key = HKDF(room key, "sova-state-v1")
AES-256-GCM, 12-byte random nonce, associated data = room name | "hb" or "ev"

The server stores the sealed status as it is and passes sealed events on to Google, who deliver them to your phones. Neither can read them. What they do see is that the nursery checked in or sent something, and when: without that the server could not wake you when the nursery goes silent, and the notification could not be delivered. A sealed event also carries the nursery's own time inside, and your phone throws away one that is far from the time it was delivered, so an old event cannot be replayed as a new one.

For as long as some parent phone in a room still runs an older version of the app, the server tells the nursery so, and the nursery adds a readable copy for that phone only. When the last old phone is updated or removed, the readable copies stop.

What this does not protect you from

An honest list is worth more than a long one.

Found a problem?

Write to contact@forgelabs.systems. Security reports are welcome and answered, and nothing here is a trap: the protocol is described above precisely so that it can be checked.