How to verify extension design?

January 4, 2021

"On the Internet, nobody knows you're a dog." Cloud services are pretty cloudy. Most famous giant companies did not protect our data as they claimed.

Those giants, who face public pressure, may not protect our data well; what about password managers storing all our passwords? ID Guard Offline extension claims that it uses end-to-end encryption and can prevent employees, not to mention hackers, from accessing our passwords. Is that true?

OK. Let's show you how to verify the security design!

ID Guard Offline might be the only password manager that tells users how to verify its security design.

No worry if you are not a geek! Just with a little patient, you can do this experiment!

Leaning Tower of Pisa by Saffron Blaze

First, our experiment purposes:


Extension architecture:

How does the app send passwords to the browser extension when we select the account to fill on the phone?

  1. The app encrypts the user name and password.
  2. The app launches a mobile browser, which loads a web program to send the encrypted data to the cloud.
  3. The extension receives the encrypted data, decrypts it, and fills in the user name and password.

With ECDH algorithm, the app and extension generate a shared secret to encrypt the transportation of passwords.

by David Göthberg

There are a few steps to generate the shared secret:


Requirements: install and use ID Guard Offline app and extension.

Toggle a breakpoint to capture data in transit. Demonstrate with Edge here.

  1. Click the extension menu to show extensions:

  2. Click the background page of ID Guard Offline extension to open the debug window:

  3. Toggle breakpoint:

    We need 4 clicks:

    1. Sources
    2. Page
    3. background.js
    4. find onServerMessage function and click on the line number on the left.

Carrying out

  1. Open a login page in the browser,, for example. A QR code will appear:


  2. Scan the QR code with ID Guard Offline app on your phone. The app can get the website and extension's public key from the QR code.

    Do not use your real password in the experiment.

  3. The app will launch a mobile browser to fill after selecting the account. Tap the address bar of the browser and copy the URL. Save the URL for analysis later. It looks like this:

    The text string before # is a web page address. Those after # are parameters or data for transportation. Each parameter is separated by & in name=value format.

    • t=1609300964 is the filling time for expiration detection.
    • is the host name of the website.
    • to=15579832-e41c-4b17-8615-b6507a02dd4b is the address of extension, randomly generated for every QR code.
    • And encryption parameters in Base64 encoding:
      • key is the app's public key for deriving shared secret with the extension's private key.
      • iv is the Initial Vector parameter for AES-256-GCM.
      • cipher is the encryption result of user name and passwords, etc.
  4. The debugging window will capture the transported message soon. It looks like this:

  5. Inspect the message by moving your mouse to message. The message looks like this:

    { to: "15579832-e41c-4b17-8615-b6507a02dd4b", from: "a3ae6e09-8b2c-43bf-a61b-08f4022adfc5", ts: "1609300964", id: "83072ef7-11fe-49fe-bac3-787f92881bbf", data: "{ "key":"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAELzVA+9qJXZJShDcwWxo5/WWQTOGi/uaRAi1+HrcLWw6vISQmzusRptXE+CTSVi2HWxQ3BQjCDDd/PqTyATgkeUyv3GbfBBXVw2q8LjVpt1wnlrFG729QsnExYVqgI5WP", "iv":"v6DyQ+mx16mt71Ab", "cipher":"1Ug43zUPuRkQn74m1309FL0J5BNGcqT5FHcwubzYnpBLAscF+n78RfmurjiWIgOP3cbZ1/5Kz/a9sjWyZozdUv1HXmo3u0k3/16KkPGuWaaTsHt8uCV7tQP0MNIs84fxr4REnBY=" }" }

    Save it for analysis later. The order does not matter.


Then we can conduct our analysis after gathering all those data.

Compare data sent from phone and received by the extension:

Data item Sent Received Same?
Time t=1609300964 ts: "1609300964" Y
Extension address to=15579832-...-b6507a02dd4b to: "15579832-...-b6507a02dd4b" Y
ECC public key key=MHY...5WP "key":"MHY...5WP" Y1
AES IV iv=v6DyQ%2Bmx16mt71Ab "iv":"v6DyQ+mx16mt71Ab" Y1
Cipher cipher=1Ug...BY%3D "cipher":"1Ug...BY=" Y1
Host NA N
Message ID NA id: "83072ef7-...-787f92881bbf" N
Sending address NA from: "a3ae6e09-...-08f4022adfc5" N
1 Some special characters such as /, +, = are replaced with %2F %2B %3D when using in URL.

  1. The hostname is not sent to the extension. It only displays in the mobile browser. The cloud side has no idea which website is filling. No worry for privacy.

  2. Sending address and message ID are generated by the web program in the mobile browser.

Dive into the source code script.js in to confirm these. Will explain it later in the Programmers' section.

All data are here. It is easy to conclude whether passwords are sent to the cloud by comparing the transported data with the filling password. But we cannot confirm that: is it possible to send the encryption key to the cloud and let the cloud decipher the encrypted data?

Deep inspection of encryption data

We will then show you how to perform an in-depth inspection to verify whether the app sends the encryption key to the cloud.

by Metinegrioglu

The encryption parameters look weird and long(other data are quite simple). Is it possible they contain the encryption key?

  1. Does key piggyback encryption key?

    Method: Is it 160 characters long?


    • The length of the public key of ECC P-384 is 120 bytes in spki format.

    • Base64 encoding transforms every 3 bytes into 4 characters.


    The captured key(MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAELzVA+9qJXZJShDcwWxo5/WWQTOGi/uaRAi1+HrcLWw6vISQmzusRptXE+CTSVi2HWxQ3BQjCDDd/PqTyATgkeUyv3GbfBBXVw2q8LjVpt1wnlrFG729QsnExYVqgI5WP) is 160 characters. No piggybacked data.

  2. Does iv piggyback encryption key?

    Method: Is it 16 characters?


    • IV of AES-256-GCM is a 12 random binary data.

    • Base64 encoding transforms every 3 bytes into 4 characters.


    The captured iv(v6DyQ+mx16mt71Ab) is 16 characters. No piggybacked data.

    We can check whether the iv is different each time, even for the same account or password.

    Programmers can print the derived encryption key to see if they are the same.

  3. Does cipher piggyback encryption key?

    Method: Can the extension fill password?


    The encryption algorithm AES-256-GCM is an authenticated encryption that assures data's confidentiality and authenticity. Passwords cannot be decrypted whenever the ciphertext changes.

By doing these 3 checks, we can verify whether it is possible to send the encryption key to the cloud.

For programmers

We just explained how to verify the security of transportation without source code. But programmers love source code. Let's dive in.

The source code of both extension and the web program is not minimized nor obfuscated. Easy to read, debug, and audit.

Send data

Look into the source code of , we can find the main source code, script.js.

  1. Parse parameters from the mobile app.

    const params = new URLSearchParams(window.location.hash); const timestamp = params.get('t'); const host = params.get('host'); const to = params.get('to'); const key = params.get('key'); const iv = params.get('iv'); const cipher = params.get('cipher');
  2. Make a JSON message from the parsed info 't, to, key, iv, cipher`.

    const data = JSON.stringify({key: key, iv: iv, cipher: cipher}); const uuid = uuidv4(); const request = {to: to, from: uuid, ts: timestamp, id: uuidv4(), data: data};

    host is not in the message. The cloud side has no idea what websites we are filling into. You can have peace of mind.

  3. Then send the message to the cloud via AJAX.

Receive data

The message is received by websocket.onmessage event. Then the message is passed to the onServerMessage function. The decryption is in the decryptMessage function in crypto.js.

importPublicKeyText = (Base64Text) => window.crypto.subtle.importKey(this.publicKeyFormat, Base64.decode(Base64Text), this.curve, true, []); deriveKey = (publicKey, privateKey) => window.crypto.subtle.deriveKey({name: "ECDH", public: publicKey}, privateKey, {name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]); decrypt = (ivBytes, cipherBytes, secretKey) => window.crypto.subtle.decrypt({name: "AES-GCM", iv: ivBytes}, secretKey, cipherBytes); decryptMessage = async function(keyPair, data) { const encrypted = JSON.parse(data); const publicKey = await this.importPublicKeyText(encrypted.key); const secretKey = await this.deriveKey(publicKey, keyPair.privateKey); const ivBytes = Uint8Array.from(window.atob(encrypted.iv), c => c.charCodeAt(0)); const cipherBytes = Uint8Array.from(window.atob(encrypted.cipher), c => c.charCodeAt(0)); const bytes = await this.decrypt(ivBytes, cipherBytes, secretKey); return new TextDecoder().decode(bytes); };

Key steps:

  1. importPublicKeyText imports app's public key in spki format;
  2. deriveKey derives 256 bits AES shared secret/encryption key with ECDH algorithm;
  3. decrypt decrypts plaintext from the ciphertext with AES-GCM mode. The GCM mode of AES is an authenticated encryption that assures data's confidentiality and authenticity. Any change in the ciphertext can be detected and cause decryption failure.


Although cryptography and network security are both very professional technical fields, we still hope that as many people can understand and verify the security technologies we use. We strive to create the most advanced security technology and try our best to provide verification methods when designing ID Guard Offline.

Some users may still have questions in mind if having no relevant knowledge. However, professionals in the area can figure out every detail by reading this explanation of the verification method.

More articles about ID Guard Offline extension...