Anonymous tokens
What are anonymous tokens?
If you use a qwant.us key, you will receive a randomly generated password that your browser sends to us with each search query so that we can enable ad-free search. If you use our Android app, or our web extension for Chrome and Firefox, instead of the password, your browser sends us a randomly generated password (anonymous token) with each search request for authentication, which is generated locally. This ensures that each password is unique and has no connection with the actual qwant.us key, nor between the individual passwords.
What problem are anonymous tokens supposed to solve?
If your browser always sends us the same password with every search query, we would at least theoretically have the possibility to establish a correlation between all searches performed with the same key. Even if we don't do that, of course, trust would still be necessary to be sure of your anonymous search. So that we do not only have to promise the anonymous search, but can also prove it, we have introduced the anonymous tokens.
How does it work?
So we want to have one-time passwords generated directly from your endpoint device, which you then send to us for authentication during your searches. However, for each anonymous token on your end device, we need to make sure that a regular token has been subtracted from your qwant.us key for it, without (and this is the crux) telling us which qwant.us key was used to generate the anonymous token.
Traditionally, we would use some form of cryptographic signature for this purpose. In this case, we would sign the generated anonymous token. Then, when you send us the anonymous token along with the signature at a later time, we can be sure that the anonymous token is valid. However, to get the signature, you would have sent us the anonymous token along with your real key, which would nullify the anonymity.
Therefore, we use a modified form of cryptographic signature instead, the so-called blind signature. To create a real-life analogy, it's like sending us your anonymous token in a carbon paper envelope. In this example, we would not be able to open the envelope, but we would be able to sign from the outside, so our signature would be transferred to the anonymous token inside. When you get the envelope back, you could remove it and send us the password and signature back later. We could then confirm that it is indeed our signature.
In fact, this analogy is a bit misleading, because in the actual process, at the moment you send us the anonymous token and the signature, we have not only never seen the anonymous token before, but also never seen the signature itself. And yet we can verify that the signature was generated by us.
What does this mean for your authenticated searches?
By using the described algorithm, we and you alike can ensure that a new random password unrelated to your qwant.us key is used each time for your authenticated searches.
The special thing about this algorithm is that all components that ensure anonymity are executed locally on your device. This executed source code can be viewed and verified by anyone at any time.
Best of all, you don't need to configure anything to use anonymous tokens. Simply installing/using our browser extension/Android app is enough to make your device use anonymous tokens for all searches.
The algorithm behind it:
In a classic RSA signature, we would take the anonymous token m
, the secret exponent d
, and the public modulus N
of our private key and create the signature using m^d (mod N)
. However, we want m
to remain secret.
Therefore, your terminal creates a random number r
using a random number generator, which is divisor-unrelated to N
. So the greatest common divisor of r
and N
must be 1
.
Because r
is a random number, it follows that m'
does not reveal any information about the locally stored anonymous token m
.
Our server now receives the obfuscated anonymous token m'
from your end device together with the qwant.us key to be used. We subtract a token from the key and send the also obfuscated signature s'≡ (m')^d (mod N)
back to your end device.
Your terminal can now compute the actual valid RSA signature s
for the unencrypted anonymous token: s≡ s' r^-1 (mod N)
. This works because for RSA keys, r^(e*d)≡ r (mod N)
. And therefore also: s ≡ s' * r^-1 ≡ (m')^d*r^-1 ≡ m^d*r^(e*d)*r^-1 ≡ m^d*r*r^-1 ≡ m^d (mod N)
.
Your end device now sends us the unencrypted anonymous token together with the associated signature for authorization during a search. The key itself is no longer sent to us during the search.