blob: 8466c06033bcd8f0be36effeaa01418c574ae92c [file] [log] [blame]
syntax = "proto3";
package leak_detection;
option optimize_for = LITE_RUNTIME;
// See internal/identity/passwords/leak/check/v1/service.proto for the server
// side definition.
service PasswordsLeakCheckService {
// Enables clients to privately check whether given username-password pairs
// are part of a leak that we collected.
//
// The protocol used here requires the client to request buckets of known
// leaks identified by a username-hash prefix (username_hash_prefix).
// In response, the server returns all the leaks (hashed username-password
// pairs) of the requested buckets (leak_match).
//
// In order to not leak the database of hashed username-password pairs
// to the client, we added the blinders protocol (go/blinders) into the mix.
// This allows the server to only return an encrypted version of the hashes
// to the clients (encrypted_leak_hash). The clients will not know the key
// with which the server encrypted the hashes.
// In order for the client to figure out if their credentials actually got
// leaked, they need to encrypt their username-password pair hashes with their
// own secret key and send the encrypted result to the server
// (encrypted_lookup_hash).
// The server will then reencrypt encrypted_lookup_hash with their own secret
// key and return that in the result (reencrypted_lookup_hash).
// The client will then reverse their own encryption on
// reencrypted_lookup_hash and look up if the result is in the list of
// returned leaks (leak_match). If so, the client has identified a leak.
rpc LookupLeaks(LookupLeaksRequest) returns (LookupLeaksResponse) {}
}
message LookupLeaksRequest {
// The prefix of the username hash (algorithm: SHA-256;
// string encoding: UTF8).
//
// The underlying username is expected to be canonicalized by lower-casing
// and stripping a mail-address host in case the username is a mail address.
//
// Only a most significant bit prefix with the length of
// username_hash_prefix_length bits is to be set, the rest needs to be filled
// with 0.
//
// The client can request all known leaks for a given username bucket.
// This specifies the requested username buckets. All returned
// `leak_match` values will belong to one of the requested username
// buckets.
repeated bytes username_hash_prefix = 1;
// The length of the username hash prefix in bits.
// We only allow 24 bits at the moment.
//
// Note: the prefix length is limited in order to:
// - Protect client against too low anonymity (upper limit)
// - Protect server against full database download (lower limit)
uint32 username_hash_prefix_length = 2;
// The full hash of username and password which was encrypted using a
// commutative cipher.
//
// The underlying username is expected to be canonicalized the same as
// described for username_hash_prefix.
//
// The key should be randomly generated by the client. It can choose a new one
// per request, or even per hash. The server can't decrypt this and
// won't know the difference.
repeated bytes encrypted_lookup_hash = 3;
}
message LookupLeaksResponse {
// The leaks that match the requested `username_hash_prefix`.
// This list is sorted by `encrypted_leak_hash` in order to enable binary
// search for matches.
repeated LeakMatch leak_match = 1;
// The reencrypted `encrypted_lookup_hash` from the request. In order for the
// clients to check for matches, it needs the server to reencrypt the
// `encrypted_lookup_hash` that they sent. The client can then reverse their
// own encryption and check `leak_match` for the resulting values.
repeated ReencryptedLookupHash reencrypted_lookup_hash = 2;
message LeakMatch {
// The requested username_hash_prefix that the leak matches belong to.
bytes username_hash_prefix = 2;
// The full hash of username and password that was discovered in a leak
// which was encrypted using a commutative cipher with a private key picked
// by the server.
// The hashing algorithm and cipher used are the same as defined in the
// request.
// Note: There are no guarantees that the server key stays the same between
// subsequent requests.
repeated bytes encrypted_leak_hash = 1;
}
message ReencryptedLookupHash {
// The same as `encrypted_lookup_hash` from the request. This can be used by
// the client to link the reencrypted hash to the originally requested
// one.
bytes encrypted_lookup_hash = 1;
// The `encrypted_lookup_hash` reencrypted with the server's private key
// (the same key that is used for encrypting `encrypted_leak_hash`).
// This enables the client to reverse their own encryption, giving the
// client a server-side only encrypted leak entry which it can use to check
// if `leak_match` contains it.
bytes reencrypted_lookup_hash = 2;
}
}