SMS Forward is a secure Android application designed to forward SMS messages from one device (Sender) to another (Receiver) using Firebase Realtime Database as a relay. Security and privacy are at the core of this application, ensuring that your messages remain private even while passing through the cloud.
The application implements End-to-End Encryption (E2EE) for all forwarded messages.
When you pair two devices, they share a Pairing Code (a 12-character alphanumeric string). This code acts as the shared secret and never leaves the devices.
- Encryption Key: The app uses
SHA-256(PairingCode)to generate a 256-bit AES Secret Key. - Routing ID: The app uses a different hash
SHA-256("routing_" + PairingCode)to generate a Routing ID. This ID is used as the database path in Firebase.
By using two different hashes, the "Routing ID" seen by the server cannot be used to reverse-engineer the "Encryption Key". Even if someone knows the database path, they don't have the key to decrypt the data.
We use AES-GCM (Advanced Encryption Standard - Galois/Counter Mode) with NoPadding.
- Confidentiality: AES ensures that only those with the key can read the message.
- Integrity & Authenticity: GCM is an "Authenticated Encryption" mode. It includes a 128-bit authentication tag that ensures the message hasn't been tampered with during transit.
For every single message:
- A random 12-byte IV is generated.
- This ensures that even if you receive the exact same SMS twice, the encrypted data stored on the server will be completely different.
- The IV is prepended to the encrypted message bytes before being encoded.
The combined IV and ciphertext are encoded into a Base64 string for safe transmission and storage in the database.
The application uses Firebase Realtime Database to relay messages. To maximize security, messages are treated as ephemeral data (Burn-After-Reading):
- Relay Logic: The Receiver device deletes each message from the server immediately after successful decryption and local storage.
- No Persistence: No historical messages are stored on the server. If the Receiver is offline, the server acts as a queue; as soon as the Receiver comes online and syncs, the messages are wiped from the cloud.
The data is briefly stored under the following structure:
messages/
└── {ROUTING_ID}/
└── {MESSAGE_ID}/
├── id: "{MESSAGE_ID}"
├── body: "Encrypted_Base64_String"
├── sender: "Encrypted_Base64_String"
└── timestamp: 1712345678901
- Routing ID: A SHA-256 hash of the pairing code. It serves as a "mailbox address". The server knows where to put the messages, but doesn't know the key to open them.
- Encrypted Body: The content of the SMS, encrypted using AES-GCM.
- Encrypted Sender: The phone number of the original sender, encrypted using AES-GCM.
- Timestamp: The time the message was received (stored in plain text to allow sorting).
- Zero-Knowledge Architecture: The Firebase server only sees the Routing ID and encrypted blobs. It never sees the original Pairing Code or the Encryption Key derived from it.
- Burn-After-Reading: Once the message is synced to your Receiver device, it is deleted from the server, leaving no trace in the cloud.
- No Plaintext Leaks: Both the message body and the sender's phone number are encrypted before they ever leave your device.
- End-to-End Security: Decryption only happens locally on your Receiver device using the Pairing Code stored in its private shared preferences.
- Authenticated Encryption: By using AES-GCM, the app automatically detects if an attacker (or the server) tries to modify the encrypted data. If the data is tampered with, the 128-bit authentication tag will fail, and the app will refuse to decrypt it.
-
Brute-Force Resistance: A 12-character alphanumeric pairing code provides over
$36^{12}$ combinations, making it extremely difficult to guess.