 David, good morning everyone. So I'm Trevor Perrin with OpenWhisper Systems and I'm gonna be talking about the text secure protocol for encrypted text messaging. I'll start with some background about whisper systems. It's an open source project founded by Moxie Marlin Spike with the goal of making private communications simple and ubiquitous. The main focus of whisper systems is the text secure protocol. This protocol is used by our own apps which are Signal for iOS and Text Secure for Android. It's also used by a couple other systems like Sanogen and WhatsApp. In general we think this is a good protocol where we'd like to see other people adopt it and we'd love to try to make it a more widely supported standard for secure and encrypted messaging. So I'm basically just gonna be telling you how it works, a bunch of nuts and bolts and crypto mechanics sort of details of the protocol. I'll start by talking about the sort of the threat model and the goals for this protocol which are pretty straightforward. It's an encrypted end-to-end messaging protocol. So when I send a message to someone else, I wanna encrypt that message on my device so they can decrypt it on their device so that anyone in the middle can't read the message, can't tamper with the message or can't forge the message to make it look like their messages are coming from me. So that's like very standard kind of cryptography sort of objectives. We wanna do these things and we're gonna talk a lot about this but we also wanna do these things in a forward secure manner and what that means to me is that if someone steals my private keys, whether that's hacking my device or stealing my device or the keys leaking out through some side channel or other means, we wanna limit the damage that that does to my messages and to my security. In particular, we worry a lot about the case where someone might say hack into like a messaging server or an email server, steal all the archived messages there that go back for a long time in history or someone might be eavesdropping and observing on messages at a large scale and we don't want that attacker to be able to choose anyone to attack, steal their keys and then go back and decrypt all of their messages. So we're gonna talk a lot about how we can change keys and make sure keys evolve over time so that compromise of a single key has a limited effect on the security of other messages. The trust model for this is an end-to-end trust model. So we want to not rely on infrastructure, just rely on the security of people's own devices and their own systems as much as possible, but we're gonna need a certain amount of infrastructure to make this practical. We're gonna need some key directories and we're going to try to design things so that you have to trust these as little as possible and you can verify that they're behaving correctly and we'll talk about how users can do that. So that's a little bit about just the goals and the trust model that we're gonna be trying to achieve. The components of this protocol, which I'm just gonna sort of talk about in order, are firstly, the heart of it is really just a two-party protocol for sending authenticated and encryption messages back and forth and with forward security and that protocol basically has two phases. There's an initial phase which happens in the very first message that someone, let's call her Alice, sends her first message to someone else, let's call him Bob. So when Alice sends that first message to Bob, she fetches some of Bob's keys from a server, she calculates what we call a key agreement, gets a special session key, when Bob receives that first message, he calculates a matching key agreement, gets the same session key and then they're gonna use that session key to encrypt not only the first message but also all subsequent messages. So there's an initial sort of key agreement phase that happens in the first message. For subsequent messages, we take that session key that was established by the first message and we keep using it and we roll it forward and update it as we communicate for forward security and we do all this because it's sort of more efficient to do a bunch of expensive things in the first message and then just kind of reuse those things for later messages. So that's why we have this sort of two phase stateful protocol and I'll be saying a lot more about how that works and the details of each of those mechanisms. Once we've got that two-party protocol set up, then I'll talk about how we can extend that to a multi-party case, like where there's group communications and to a multi-device case where a single user might want to be sending or receiving messages on multiple devices that they own. These are other cases we want to generalize the protocol to handle. And then finally I'll talk about how users can authenticate that the key directories are actually giving them the correct public keys for each other without having man in the middle attacks. So that's the basic outline of this talk. So let's start at the beginning, start, talk about just how a two-party, encrypted and authenticated messaging works in the tech secure protocol. As I mentioned, it's a stateful protocol. We use the first message to set up some state that's more expensive than we're gonna reuse that state over time for subsequent communications. And so we're gonna start talking first about the first message and what happens in that pre-key and key agreement process. And we're gonna assume that there's a setup that looks kind of like this. So Bob is gonna have a public key, he's gonna publish this public key through some directory where Alice can retrieve it. What exactly this key directory is, it could be different things from the protocol's perspective in a more centralized messaging system. There might just be one key directory that has everyone's public keys. If you think of a more federated or distributed system like email, you could imagine everyone's email server hosting their key directory. And so if Alice goes to send a message to Bob, she contacts his email server or something associated with it to get Bob's public key. But from the protocol perspective, we don't really need to care about where this comes from as long as Alice can fetch Bob's public key from somewhere. So let's assume she can do that. The question of how she knows this public key is authentic is really, is Bob's correct public key? That's a good question. It's a question we're not gonna answer right now. We'll get to that later. For now we're just gonna assume that Bob is going to, Alice is gonna use that public key she fetches. They're gonna trust the first key they see. This is gonna be a sort of trust on first use model at the moment. And we're just gonna talk about the mechanics of encrypting and authenticating messages between Alice's public key, sort of to Bob's public key. So we could kind of simplify this situation like here. We see Alice and Bob. We see Bob having a key pair, which is a private key and a matching public key. He's publishing his public key through a key directory and Alice is fetching it. These key pairs are going to be elliptic curve key pairs. We use the curve 25519 elliptic curve. And so that will be true for all the public and private keys that I'm talking about here. So that's like a 32 byte public key, for example, that Alice fetches. So you might look at this and say, okay, so this is a pretty simple setup. This is really easy to do encrypted messaging within. Alice just has to say, come up with a symmetric key and AES key, encrypt the message with the AES key, encrypt the AES key to Bob's public key, send all that to Bob, and she's done. She's sent an encrypted message. And you could do that and it would work, but you would not have forward secrecy then, or you'd not have forward security, because all of those messages that are inbound to Bob then, it would be encrypted under Bob's long-term private key. Someone can steal that private key, decrypt all of those messages. So we're gonna wanna do something a little bit better than that. And there's a couple things we can do. So let's talk about some options. One thing we could do is we could give Bob not just a long-term identity key, this key, but he could have a bunch of one-time use key pairs as well. He could generate like 100 one-time, what we call pre-keys, publish these pre-keys to his server. Then when Alice wants to send him a message, she fetches one of those pre-keys, encrypts the message so that it can only be decrypted by Bob who knows his long-term private key and his pre-key private key. And then when Bob decrypts the message, he can delete that pre-key private key right away, thus making the message undecryptable if he gets compromised. So that gives very good forward security because he's deleting a key the message was encrypted under immediately upon receiving that message. So that's very strong forward security in a sense, but there's a couple problems with this setup. One of them is that Bob might run out of pre-keys. He's publishing 100 at a time. As they get used up, he's gonna publish more. But so it's sort of unlikely in regular usage, say that Alice or someone is gonna send him like a hundred new messages from a hundred new parties before he has a chance to publish more pre-keys, but that could happen and it particularly could happen if someone is aggressively trying to steal his pre-keys to just kind of denial of service the system or degrade the security properties that Bob gets. So that's something we'd worry about a little bit. Another thing to worry about is that the key directory could lie about Bob's pre-key public key and it could serve Alice's correct authentic identity public key, but an incorrect pre-key public key that it knows the private key for. And that's kind of a weird attack. If it did that, Alice would encrypt a message that Bob can't decrypt. It would be kind of this weird broken message, but that message would also not have forward security because the attacker would just have to go and steal Bob's private key by itself to decrypt that message. So those are a couple kind of downsides to this system. So let's consider an alternative system. An alternative would be to have, instead of one time pre-keys, have pre-keys that are signed and that change on a timed basis. So Bob can use his identity key pair to sign a signed pre-key public key, post that key up. It'll be used for all messages that people send to him. I'll first message his people send to him for a week or so. And then he periodically signs a new key and replaces the old key. If he does this, we've sort of fixed a couple of the problems with the one time system in that this is not a one time key. It doesn't get used up. He's not gonna run out of it. Also it's signed so the key directory cannot lie about what it is and provide a false public key. The downside to this system is it doesn't have as optimal forward security as the previous system because Bob's holding onto that pre-key for a longer period of time. He's not deleting it right away. So if you think about the signed pre-key system and the one time pre-key system, they have sort of complimentary strengths and weaknesses. What we do in tech secures, we just do both. At any point in time, Bob has a long-term identity key. He has a signed pre-key. He has a bunch of one time pre-keys. When Alice goes to send him a message, she fetches his identity public key, his signed pre-key public key, a one time pre-key public key, if that exists. And she's gonna use all these to do a key agreement to send him that first message. So that's kind of the setup that we have. We can simplify it a little bit like this. So under Bob's column, we see the things that Alice is fetching from the key directory when she wants to send him an initial message. Under Alice's column, we see the things that Alice is gonna need to send in her initial message for Bob to complete the first phase of the protocol. And so just like Bob has a long-term identity key, we're gonna say that Alice has a long-term identity key. She's gonna need to send it in her first message so Bob knows what it is. So we have this setup of keys, of elliptic curve public keys. And what we wanna do, the calculation we wanna perform is to take all of them and construct a shared session key that Alice and Bob both share and that's known only to them. Because if we can get to that point, then we can use that shared session key for encrypting the first message and also all later messages. So we wanna get a shared session key that has forward security, but that it also is sort of authenticated so it's only known to the holders of Alice and Bob's respective private keys. So how do we do that? In an RSA world, if we were using RSA cryptography instead of elliptic curve cryptography, we could just think of this as like a public key encryption problem. So Alice could take all of Bob's two or three public keys, she could encrypt secrets to each of those public keys, hash those secrets together and call that the session key. The downside to that is that then Alice would be sending hundreds of bytes of ciphertext for each of those encryptions in her first message. So we don't really wanna do this, we want this to be a very efficient protocol. Luckily we can do something a lot better than that with elliptic curve cryptography. We don't have to do public key encryption, we get a better operation which is Diffy-Helman or elliptic curve Diffy-Helman. And what Diffy-Helman key agreement lets you do is it lets two parties with a key pair, with a private and public key, look at each other's public key, and only by seeing it they can calculate a shared secret that's only known to those two parties and they don't have to send any other data to do that. So that's really nice and we can use that in this sort of system. If Alice wants to come up with an agreed upon shared secret key that's only known to her and Bob that has forward security, all she has to do is add a sort of one time ephemeral Diffy-Helman public key that she freshly generates for this message. She adds its public key into her first message and she just calculates a bunch of Diffy-Helmans with all of the keys from Bob that she got. And so she just has to send an extra 32 bytes in her message, she doesn't have to send hundreds of bytes of RSA Cypher text. These are relatively fast operations that she constructs and gets the outputs of all these Diffy-Helman key agreements, hashes them together to get a secret key. And so that's gonna be part of how she creates the session key. So that's a simple and efficient way of doing things. What it doesn't do yet, what we haven't done yet is we haven't authenticated that this session key is known only to Alice because anyone could have created an ephemeral key and sent this message to Bob. So we also want to mix in something that authenticates Alice and we could do that a couple ways. In an RSA world, we could have Alice sign the message, do like an RSA signature, but again, that means we're adding hundreds of bytes of signature to the message. And once you start signing message contents, you lose a property you could call deniability. So Bob could take a signed message and show it to anyone else to prove to them that Alice said something that might have been embarrassing. So we don't wanna add that property into our system, we'd rather not create these permanent signed transcripts of everything everyone says. So we're gonna authenticate Alice in a simpler and more lightweight way just by constructing another Diffie Helman and hashing that into the session key as well. So we're gonna say Bob's signed pre-key is a relatively fresh key. We're just gonna do a sort of Diffie Helman between Alice's identity key. That's kind of like Bob challenging Alice to prove knowledge of her long-term private key. We hash all those things together and this is the key agreement that TechSecure does in an initial message to get a shared session key between Alice and Bob. You can look at this a couple ways. We tend to call this a triple Diffie Helman key agreement because if you look at the core here, there's really like three Diffie Helmans that are particularly kind of crucial. The ones that involve the identity keys are basically the other party challenging each other's identity keys. So those are serving for authentication. The one or two Diffie Helmans on the bottom are really just adding forward security because these are between more ephemeral keys that get deleted quickly. Once those private keys get deleted, you can no longer reconstruct the output from these so you get forward secrecy from them. So that's the function that's served by all of these calculations. So that gives us a good shared session key between Alice and Bob. But we don't wanna do this process on every message Alice sends because it's expensive. Alice had to contact a key directory, retrieve a bunch of keys, consume one of Bob's one time pre keys, which is a limited resource, and do a bunch of Diffie Helman calculations and send a bunch of things in her first message. So we don't wanna repeat this on every single message. What we wanna do is just take that session key and use it repeatedly in a more efficient way. But if we just use it directly to encrypt and decrypt every single message, we wouldn't get any sort of forward security. So now the question becomes, can we update that session key as we use it in a way that's more efficient than this, but also is gonna give us forward security if it's compromised? And so we could do something sort of like this. And we'll call this like a ratcheting algorithm or in particular a symmetric key ratchet. And the idea here is you take that session key that they agreed on in the first phase of the protocol, you derive a sending key, each party derives a sending key and a receiving key from the session key so that Alice's sending key matches Bob's receiving key and vice versa. And then whenever they encrypt messages to each other, Alice uses her sending key to encrypt, Bob uses his receiving key to decrypt that message. Then they both hash that key to create a new key and delete the old key. And this is sort of a one-way hash function. So you can only go forward, but you can't go back. You can create new keys, but from a new key you can't reverse the process and get old keys. So we call that a ratcheting algorithm. A ratchet is a tool that only goes in one direction, it only goes forward, it doesn't go backwards. And so with this we get a pretty good amount of forward security very cheaply because it's very cheap to just hash a key and delete the old key and throw away the old key. So this is a nice mechanism. One small downside of this, as I've shown it, is it doesn't handle out of order messages very well. So you could imagine that if some party receives a message encrypted under this key right here, this second key in the chain, what he'd like to do, if he receives that message, let's say he receives that message before he gets the first message, what he'd like to do is decrypt that second message, hash the key to get the third key, delete the second key, and have it be gone. But he might also like to hold on to the first key in case that out of order first message actually arrives later. So that's kind of a dilemma because if you hold on to the first key, you can always use the first key to re-derive the second key so that sort of defeats the purpose. Luckily there's kind of a minor modification to this that solves all that. We can just have two types of keys. So we could have keys in the chain that we hash to get the next element in the chain. And when we hash it, we could take some extra output and create a separate message key and that message key is what we're gonna use to encrypt and decrypt. And because that message key can't derive any other keys in the chain, we can hold on to it without impacting the security of later keys. So that lets us do this sort of forward secrecy updating while also handling out of order messages when they arrive. So this is what TechSecure does. At any point in time, it has a sending chain, it has a receiving chain. They're being updated just like this so that every message you send or receive, that old key gets destroyed, new chain keys and message keys get created, and out of order messages can be handled when they arrive. So that's a very simple, a very efficient thing to do. It has a downside though, which is that if someone comes and steals all of these keys, if they hack your machine or something, get a copy of these keys, they can passively decrypt all future messages. And we'd like to have more security and more resilience in that case. We'd like to make it so that even if someone steals all your keys, they would have to do active man in the middle attacks to decrypt all your future messages because an active attack is a harder, more intrusive thing. It's easier to detect. We have some possibility of detecting it. We don't want to make it that easy to just do passive attacks based on a key compromise. So there's a different way of doing a sort of ratcheting type thing which does achieve that property in a way that this does not. And that's to use the sort of ratchet that's used by the OTR protocol. And so I don't know how familiar people are with the OTR protocol, but it does something that I'm gonna call a Diffie-Hellman ratchet. And the idea here is that it's a little bit complicated, so bear with me for a moment. But the idea is that each party is gonna have a current ratchet key pair like a elliptic curve private key and public key. Each party is gonna advertise that public key with every message they send. And each party is gonna keep track of the latest public key they've seen advertised by the other party. And so then when you see a new key from the other party, you're going to create a new key on your own and start advertising that. And then when the other party sees your new key, they're gonna create a new key and start advertising that. So it's gonna be this sort of ping pong process that goes back and forth where the parties generate new keys once they see new keys from each other. So they're just generating new keys and advertising their new keys and taking turns doing that. And as they do that, as they generate those new keys, they're also doing Diffie-Hellman between every key they received and the previous key they had and then this new key that they just freshly generated. And it turns out that if you do all that, each party ends up driving the outputs of those Diffie-Hellmans are a sequence of shared secrets and it's the same sequence from both party because they're just doing Diffie-Hellman between the same keys. And so they're both calculating this evolving set of keys that match between each party. So this is how OTR works. I'm gonna try to explain this visually and see if that makes sense. So up here we're seeing Alice, this is her ratchet public key, she's advertising it, Bob has just received that message from Alice. He's calculating a Diffie-Hellman with his old ratchet private key which is very faint up here and that's this output. And then he's calculating a new ratchet private key and a new Diffie-Hellman which gives him a new Diffie-Hellman output. So we see here that like Bob is doing two DHH operations on receiving Alice's new key, the first one creates a key that matches Alice's latest key, then he creates a new key. He starts advertising his new public key when Alice receives it. She does essentially the exact same thing. She does two Diffie-Hellman operations, one of them, the first one gets the latest value Bob had calculated, the second one gets a new value, then the same process happens again. So she's advertising a new public key, eventually Bob will see that key in a message, he'll do two Diffie-Hellmans, calculate the same latest key Alice had and a new key. So they're just going back and forth taking turns generating the next key in the sequence or generating the key the previous party had generated and then the next key in the sequence and kind of leapfrogging each other in this fashion back and forth. This works in OTR and in TechSecure. It's a little complicated to think about but it's a nice algorithm because these Diffie-Hellman shared secrets are evolving. So once you delete your old ratchet private keys you can't go back in time and get the old keys but they're also evolving in the forward direction. So if someone steals your keys at some point in time they can't passively decrypt all future message because new Diffie-Hellmans are being introduced. They'd have to perform an active man in the middle attack and introduce their own Diffie-Hellmans. So this has some sort of complimentary properties with the old symmetric key ratchet that we'd also like to use because this ratchet deletes old keys right away. This ratchet has to hold on to them until it receives a response from the other party. So if I use one of these keys, one of these Diffie-Hellman outputs directly to encrypt like 10 messages in a row and I send 10 messages in a row without waiting for a response they'll all be encrypted like an OTR for example just with the same key. So we might like to do a little bit better than that and try to combine these approaches and that's kind of exactly what TechSecure does. And we call this the axolotl ratchet. It's just combining these two types of ratchets. And the idea is pretty simple. It's just we're doing this Diffie-Hellman OTR-like ratchet and whenever one party receives a new public key and does those two Diffie-Hellmans it uses the first one to reinitialize their receiving chain, the second one to reinitialize their sending chain. So we're just doing a Diffie-Hellman ratchet to reinitialize the keys that are used in the symmetric key ratchet. So this way if I send a bunch of messages in a row they each get good forward security but we're also evolving the keys based on new Diffie-Hellman values. And so you see the pattern here in a pretty straightforward way. When Bob receives Alice's new ratchet key his two Diffie-Hellmans reinitialize the new receiving chain key then a new sending chain key. When Alice receives a message from Bob she initializes a new receiving chain key and sending chain key and you can see how these sort of match up. So Bob's new sending chain ends up being equal to Alice's receiving chain which they need to be for messages to decrypt and then when Alice sends her public key to Bob the process just reverses. Her latest sending chain gets recalculated by Bob as his receiving chain. He calculates the new sending chain. So you have this shared sequence of keys that they're calculating with the Diffie-Hellmans and they're just being used alternatively as sending chains for each party if that makes sense. So that's something that TechSecure does. You might look at this and be a little confused though because you might say well if you're reinitializing the chain keys based on the Diffie-Hellmans why did we do that whole session key thing at the beginning? We wanted to get a session key and like that's authenticating the long-term keys shouldn't the sending and receiving chain keys be a function of that session key and in fact you would be right. You do want that to happen. So if you zoom in on this a little bit more you see there's a little bit more detail here. What we do is we actually take that initial session key that's output from the key agreement. We call it a root key and then whenever we reinitialize the chain keys from the Diffie-Hellmans ratchet we also mix in the root key and generate a new root key and also the chain key. All the chain keys end up being a function of that initial key agreement that has all the authentication in it as well as being functions of this Diffie-Hellmans ratchet. And so this is sort of with full detail what we're doing as messages fly back and forth in TechSecure. So let's circle back for one moment to the initial key agreement and just see how that connects up with the ratcheting protocol. So remember this is what happens when the first message Alice sends she fetches a bunch of keys from Bob, she creates a key on her own, she calculates a bunch of Diffie-Hellmans, hashes them into a session key and uses that to initialize her sending chain that she's going to use to encrypt the first message to Bob. She also needs to advertise a ratchet key in every message she sends so we're going to add one other detail that we didn't mention before. She has to include a ratchet key in her first message. So this is the full set of what comes in Alice's first message to Bob. It's around 100 bytes of keys. And then once Bob receives that first message and responds to Alice, he's going to send a new ratchet key because that's how the Diffie-Hellman ratchet works and mix that into his latest sending chain that encrypts that message. She's gonna, when she receives that message calculate the same Diffie-Hellman, update her receiving chain so she can decrypt that message. Then Alice is going to calculate a new ratchet key for her new sending chain and use that to send a message to Bob and he's gonna calculate a new ratchet key to decrypt that or two, he's gonna calculate the same receiving chain and then a new sending chain and then they're just gonna go back and forth as they exchange your messages doing all of this ratcheting stuff. So it's the key agreement sets up an initial key, sets up the state and then they evolve the state as they continue to communicate. So that's the basic two-party protocol that we do at any point in time, that both parties have sending and receiving chain keys and there's these Diffie-Hellman updating of those keys going on. So let's take that two-party protocol now and just assume it works and look at how it generalizes to multi-party or multi-device cases. So you can handle multi-party communications very easily. If you're sending a message, if you can send a message to one person and you wanna send a message to five people, you can just send five copies of that message and that's something we do. It works fine. You just have a bunch of separate ratcheting states, separate sessions set up and you use those with every message you send. In the general case, that's the best you could do. You could imagine in like an email case where everyone, you're sending a message to five people under five different email servers, you need to send five copies of that message in any case. But in some situations where there might be multiple people at one email server or multiple people behind a single server, that starts to look a little bit inefficient. If you see the top here, the pink person is sending three messages to people who are at one server and it might be nice if it just had to send one copy of that message. So you might want something a little bit more like this. You send one copy, the server can fan that out into three separate copies and we support that as an optimization. It's an optional optimization and what we do there is the sender can send a special message to all of these parties. So they send a special sort of pairwise message to each party that has a special sender key. We call it a sender key. It's like an AES key and a signing key and then the sender uses that special key to create a special chain that it uses just to send messages that can be decrypted by all of these people. So it's sort of, you know, we've talked about having sending and receiving chains between each party. You can also set up a sending chain that represents a group of people you're sending to and then you just have to encrypt that message once and everyone can decrypt it and you don't have to encrypt multiple copies of it. So that's an optimization to make multi-party communications more efficient. So we do that. Let's look at the multi-device case as well because people might, you know, people do have multiple devices, you know, phones, laptops, tablets, et cetera. We want the protocol generic enough to handle the case where people are sending and receiving messages on multiple devices. And so the way we would handle that is if you have your original device, you would synchronize its long-term private key to the new device in some fashion and so then the new device would become a sort of clone of the old device and it would have the same private key. It would generate its own pre-keys and then when Alice goes to send a message to it, she would just treat each of those devices as sort of like a separate party and so we're building multi-device support on top of multi-party support. In a case like this, Alice is sending, you know, a message to two parties. One of them has three devices, so she just sends four messages and we could make that more efficient by using the sender keys thing I talked about where she just sends them all like a sender key and then she can just send one message in the future and have the server, you know, display that out or send that out to all the other parties. So that gives us multi-device support. So that gives us, and that really gives us, you know, kind of the basic core mechanics of everything we want from the low-level crypto protocol. I mean, we can send and receive messages back and forth based on public keys, based on long-term keys with pretty good forward security. We can do group messaging, we can have messages spread out across, you know, multiple devices that people own. That's kind of all we want from the low-level, you know, crypto mechanics and crypto plumbing here. So let's, you know, now turn to this, you know, kind of question of how we authenticate and make sure that the keys you're retrieving from this key directory are actually authentic, are actually owned by the other party because we haven't said anything about that yet. And I'm gonna set back a little bit and just talk about our sort of philosophy or approach to that here. And our basic philosophy is that end-to-end authentication of keys is a harder problem than end-to-end encryption of messages. We can make end-to-end encryption happen, essentially, invisibly, so that users never see it. They don't know it's there. You're using your messaging app. You're generating keys, publishing keys, fetching keys, encrypting everything. You know, that's easy to kind of slide under the covers and make exist without users even noticing it. It's harder to do end-to-end authentication because users are gonna have to be involved somehow. You know, they don't wanna just trust everything that's happening in the infrastructure. They wanna, like, do something for themselves to get trust. That might be verifying a key fingerprint. That might be signing someone else's keys in, like, a web of trust type system. That might be paying attention to warning messages that tell you that someone else's key is changing or that your key has changed. But users are gonna have to do something and most users, most of the time, are probably not gonna wanna do that. They're not gonna wanna spend a lot of effort on end-to-end authentication. So we have this sort of paradox where end-to-end encryption is easy, end-to-end authentication is a lot harder and is probably always gonna be done by a smaller population of people. And so now what do we do? It's a hard question and one approach, some people say, well, end-to-end authentication is really important. We should try to force people to do it. We should make it so that if you don't do end-to-end authentication, you don't get encryption so that that's just like a requirement of being part of the system. And if you take that approach, you end up with something like this where a small set of your larger population is doing more authentication and getting encryption and everyone else isn't really getting anything out of this. I think the downsides of this sort of system are that the people who really do care about security and are really trying to secure their messages are kind of standing out. It's obvious that they're doing extra authentication and doing encryption. They're making themselves obvious targets and they're kind of signaling which messages and which communications they really care about. So that's not very good. Another problem is that for all these other people who aren't spending this extra effort on authentication, they're not getting anything out of this at all. They're not getting any default encryption. They're just not getting any security. So the other approach and the philosophy that we kind of take is to just encrypt everything and say, let's just have default encryption as built into these systems. Some of these people will be doing authentication. Some of them will not be doing end-to-end authentication but we wanna make it so that you can't actually tell who is who. It just looks like everyone's doing the same thing. It looks like everyone's encrypted. And then we get a couple of advantages. Firstly, we get the advantage that the people who are doing this extra authentication are not advertising themselves. They're not making themselves obvious targets. They just kind of fit into the crowd. But also those people sort of protect everyone else because if you're looking at this as an outsider, you're trying to figure out which communications to man in the middle and attack, you don't know who's vulnerable and who isn't. You don't know which man in the middle attacks might get you detected and which might not. The larger population is hiding the smaller population. The smaller population is protecting the larger population and so that's how we kind of try to deal with this world where end-to-end authentication is more difficult than end-to-end encryption. But we still need to do something for it of course and so we provide ways that you can do sort of manual and out-of-band checks of public keys. An example of that would be letting one party display a QR code. The other person scans the QR code. That tells them that they're seeing the right public key for that party. And that's something you could do, you could imagine having other ways to try to streamline that or optimize that. The protocol is sort of agnostic to how you want to do that. But we take the idea that some subset of people will do this and in doing so will sort of help keep the whole system honest. So it's about all I have to say about the kind of tech secure protocol and the basics of how it works. I run a mailing list that talks about a lot of these topics. If people think that's interesting, you can find it up here. Whisper Systems is also hiring some full-time development positions if you want to move to San Francisco and work on this stuff. It's all I have and I hope I have some time for questions.