Security
OTPHop moves a code from your phone to your browser through a relay server. This page states what the product does, what the relay can and cannot see, and what the design does not cover.
How a code travels
- The browser creates a random channel id and a key pair: a private key and a public key. The private key stays in the browser's own storage.
- The extension shows the channel id and the public key in a QR code. You scan it with the phone app. The QR code holds no secret key.
- When an SMS with an OTP word arrives, the phone finds the code. It encrypts the code to the browser's public key and posts the encrypted message to the relay. Only the browser's private key can decrypt it.
- While an empty code field has focus, the browser asks the relay for new messages every 2 seconds, for at most 3 minutes. It does not poll in the background.
- The browser decrypts the message, checks it, and fills the field.
The security model
- The phone sends only the code itself. It never sends the SMS text, the sender or contacts.
- The app asks for four permissions. RECEIVE_SMS lets it see each new SMS as it arrives. INTERNET lets it send codes to the relay. REQUEST_IGNORE_BATTERY_OPTIMIZATIONS lets it show the system prompt that allows it to run in the background. ACCESS_NETWORK_STATE comes from Google's QR scanner library and only checks whether the phone is online. No camera permission. It cannot read the SMS inbox history.
- The browser creates a random channel id and a P-256 key pair. The QR code shows only the public key. The private key never leaves the browser.
- Each browser has its own channel and key. The phone encrypts each code once per paired browser.
- Codes are AES-256-GCM encrypted. The plain text holds the code and the send time. The extension rejects a code older than 3 minutes. It also rejects a code used before and any message that fails decryption.
- The relay keeps a ciphertext until the browser confirms it received the code or for 3 minutes, whichever is first. It logs no content.
- No accounts and no email sign-up. The server holds only these identifiers: a salted hash of the phone's Android ID (for the trial), a hashed device token, channel ids and the license key.
- The phone keeps a local log of forwarded codes, with a pause switch and an unpair button for each browser.
- The APK is signed with an offline key. Its SHA-256 and signing certificate fingerprint are on the download section.
- No analytics, telemetry, crash reporting or usage counters in the app, the extension or the relay. OTPHop does not count your codes.
Encryption details
- Key exchange: ECDH on P-256 with a new phone key pair for each message. HKDF-SHA256 derives the message key.
- Cipher: AES-256-GCM, with a random 12-byte IV and a 128-bit tag for each message.
- The channel id is bound to each message as additional authenticated data.
- The plain text is a small JSON object with the code and the send time in unix seconds.
- The browser also rejects a code that is not 4 to 10 letters or digits, or that is dated more than 60 seconds in the future.
- The phone skips an SMS unless its text has an OTP word, such as otp, code, verify, password, passcode, pin or one-time.
What the relay holds
| Item | Held by the relay |
|---|---|
| Code | Only as ciphertext, until the browser confirms it received the code or for 3 minutes, whichever is first. |
| Private key | Never. It stays in your browser. |
| SMS text, sender, contacts | Never. The phone does not send them. |
| Identifiers | A salted hash of the phone's Android ID (for the trial), a hashed device token, channel ids and the license key. There are no accounts and no email sign-up. |
What this does not cover
- A person who photographs the QR code cannot decrypt your codes. The QR code does hold the channel id, so that person can unpair the browser. Resetting the browser pairing creates a new channel and a new key pair.
- Like any server, the relay sees the network address of each request, and it sees when messages arrive and how large they are. It cannot read their content.
- A phone or a browser that carries malware can read the code before OTPHop does. OTPHop does not protect against that.
- A code that the extension fills is a code on your screen. Treat it as you would a code you typed.
What you can check
- The source code is not public. Trust rests on the design above and on the checks below.
- Each APK release lists its SHA-256 hash and signing certificate fingerprint in the download section. Compare them with the file you downloaded before you install it.
- The phone app has a local log of every forwarded code, a pause switch, and an unpair button for each browser.
Report a problem
Email support@otphop.com with the details of a security problem. We review each report sent to that address.