PKI RSA & SSL
Ik kom bijna dagelijks in aanraking met collega's die vragen hebben over het aanvragen/verlengen en beheren van certificaten. De éne keer voor HTTPS, de andere keer voor een ander systeem gebaseerd op SSL.
Gezien dit component vaak centraal staat in een aantal security oplossingen is het essentieel dat men weet hoe wel en niet te handelen. Je hele omgeving kan bijvoorbeeld vallen of staan met het beschermen van de private key.
Daarom probeer ik hieronder een uitleg te geven welke te begrijpen is maar tegelijk ook niet alleen de concepten dekt.
RSA is een algoritme voor public-key cryptografie. Bij dit algortime spelen 2 sleutels de hoofdrol:
- Public key: Voor iedereen bekend, gebruikt voor encryptie (!!)
- Private key: Alleen bekend voor eigenaar, gebruikt voor decryptie (!!)
Deze 2 sleutels worden berekend op basis van priemgetallen. Door de relatie tussen deze 2 sleutels kan je berichten welke met de ene zijn versleuteld, alleen met de andere ontsleutelen. Het bewijs van deze stelling ga ik hier niet bespreken. Het concept is wat nu belangrijk is. Voor de uitwerking zie [bijvoorbeeld hier]
Het is van groot belang dat een zo'n groot mogelijk publiek in het bezit is van je public key. Je kan immers alleen versleutelde berichten ontvangen van deze groep mensen. Tegelijk is het essentieel om je private key te beschermen. De gehele veiligheid van RSA is hierop gebaseerd.
Het is technisch prima mogelijk om het systeem om te draaien. Dus om een bericht te versleutelen met de private key. Omdat iedereen de public key heeft is het daarentegen niet slim om op deze manier informatie geheim te willen houden. Alleen de public key is dat vereist om het bericht te lezen.
Als je een bericht versleuteld met je private key, kan deze enkele en alleen ontsleuteld worden met de bijbehorende public key. Hieruit is te concluderen: Als de private key niet is uitgelekt en je kan met iemands public key het bericht ontcijferen; het bericht komt dan gegarandeerd van de eigenaar van de private key. Iedereen met de public key kan dit bericht lezen en iedereen kan verifieren dat deze is verzonden door de eigenaar van de private key.
Omdat geheimhouding niet mogelijk is wordt het bericht vaak in plain text verzonden. Door dan alleen de hash te encrypten is het zonder tools mogelijk het bericht te lezen. Door ook de tools te gebruiken kan dan de hash worden gecontroleerd en daarmee de afzender worden geverifieerd.
Signature = hash(bericht) versleuteld met de private key van de afzender
Zoals eerder vermeld is het essentieel voor RSA om de public key op een betrouwbare manier te verspreiden naar de client. Deze kan namelijk geen veilige sessie starten zonder deze key.
De meest gebruikte manier om dit te realiseren is doormiddel van certificaten.
Een certificaat is een document met daarin een aantal verplichte en een aantal optionele velden.
- Versie nummer
- Subject (o.a. hostname)
- Issuer (referentie naar een bovenliggend certificaat)
- Public Key
- hash van velden encrypted met de private key van de issuer
Hoe weet de client of een certificaat vertrouwd is? Aka: Hoe krijg ik de juiste public keys veilig bij de client?
- Keystore met trusted CA Authorities
- Intermediate certificaten / chain of trust
- SSL: Stuur hele chain!!!
Aanvraag voor certificaat
- Bereken public & private key
- Bewaar private key (nooit versturen)
- Verstuur public key + metadata (subject ed) als CSR naar de CA Authority
- Toetsen metadata
- Opnemen van metadata + public key en signen met private key van de CA
- Certificaten chain presenteren aan de aanvrager
Filetypes: PKCS7, PKCS12
RSA voor opbouw
Geen RSA, gebruikt session encryption key uit de opbouw
Een goede uitleg van SSL kwam ik tegen in 1 van de podcasts van security now. Hieronder heb ik een stuk gekopierd uit het transcript van aflevering 183.
Source: [SN183 @ grc.com]
Steve: Okay. We've discussed at length the concept of symmetric and asymmetric ciphers. An asymmetric cipher, also sometimes called "public key encryption," is one where you use one key to encrypt and the other key to decrypt.
Leo: Which is a wonderful technology. I have a - if you go to my website, you could download my key. And people will say, well, wait a minute, I'm downloading your PGP key? No, that's the public key. Anybody can have that.
Steve: Right. It's the key of the key pair that you chose to make public. And again, it's one of the things that's very cool about this is that somebody could use it to decrypt something that you encrypted with your private key, meaning the one that you have not disclosed. Or they could use your public key to encrypt something that they would know only you could decrypt. So it works both ways. If somebody used your public key to decrypt something, they'd know that it came from you because only you could encrypt something that your public key could decrypt using your private key, and vice versa. So it's handy. The problem is, it's extremely computationally intensive. The keys are long. They need to be long. They're, like, 10,000, I mean, 1,024 bits. They're like 1K bit long or longer, sometimes 2K bits because the algorithm requires that much bit length in order to get the equivalent security of much shorter keys using symmetric or private key encryption as opposed to public key encryption. So that length requires, and the nature of the public key algorithms requires, much more computation. So it's never feasible to encrypt an actual communication with public key crypto. Technically you could, but it would just be hugely slow.
So instead what's done is that a random number is picked, just out of the air, a big cryptographically strong, really high-quality random number. And that is used as the key to a symmetric encryption algorithm. And then that key, only that key is encrypted using the public key technology. So then so what happens is, the encrypted document and the encrypted key are sent to someone, and they use the public key technology to decrypt the key, which they then use with a symmetric key algorithm to decrypt the document.
Leo: Isn't that clever.
Steve: It's very clever. And in fact what we're going to talk about today is symmetric key algorithms. We've talked about symmetric key ciphers. And of course the famous one that's become very popular is the so-called "Rijndael" cipher that was chosen as the Advanced Encryption Standard, the AES cipher, after much competition among many different competing ciphers. And we did a whole episode some time ago on exactly how Rijndael works. Just to refresh people about, in general, the way a symmetric cipher looks from the outside, sort of treating it as a black box, you have some number of bits. You can think of them sort of like signal lines, like electrical wires going into this. And they're either - each bit is a one or a zero. And older block ciphers had sometimes, for example, 64 bits was popular. The problem was that, as computers have gotten stronger, the concern has been that there aren't enough combinations of 64 bits to really make the result strong. So modern block ciphers have doubled that to 128 bits. And it's important to remember that when we double the number of bits, we're not doubling the number of combinations. Every bit we add doubles the number of combinations. So when we go from a 64-bit block to a 128-bit block, we're adding 64 bits, meaning that we're doubling and doubling and doubling and doubling the number of combinations 64 times.
Steve: So the total number of possible combinations is - it's computable, but it's really, really huge.
Steve: It's 2^64 times more than there were before.
Steve: So imagine we've got 128 bits going into this black box, and 128 bits comes out. So the idea is, I mean, that's the Rijndael cipher, or any similar symmetric cipher. And these 128 bits are transformed through the algorithm in the cipher into a different 128 bits. And the nature of the - essentially it's a permutation. It's not like one bit goes in and comes out somewhere else. It's that, for example, if you were to change one bit going in, on average half of the bits coming out would change. And you never know which half because, if you changed a different bit, a different set of bits on average would change. And not always exactly half, but on average half. Or another example of this is if, say that you had all zeroes, but then you turned on five different bits going in. Well, you would end up with about half of the - a half of one's one bits coming out. The point is that this is for any pattern of 128 bits you put in, you get out a completely different specific 128 bits. Always the same. When you put the 128 bits in, you get the same 128 bits out, given the key. Because the other input to this black box, in addition to the block of data going in, that is, this block of bits going in and a block of bits coming out, the other factor is the key. And keys can range basically, for example, DES was a very popular - the Data Encryption Standard, basically the prior main government standard, DES, that used a 56-bit key. And in fact that was the source of concern over DES was that, gee, you know, before we had computers, or when they were a lot slower, that seemed to be just fine. But 56 bits just doesn't have enough combinations.
So, for example, the Rijndael cipher allows you, and the AES standard allows you to use a key of 128 bits, 192 bits, or 256 bits. Which is just an insanely long key. I mean, already 128 bits is a huge amount of combinations, so much so, I think I remember reading that, if it took you a second to crack DES with a 56-bit key, it would take something like 142 trillion years with the same amount of processing power to crack it with 128 - crack a cipher with a 128-bit key. So, I mean, so that's the difference in key length in terms of just, you know, the actual number of possibilities given binary bit length growth. It's easy to underappreciate what it means to increase the length of these things. I mean, these things get stronger exponentially as you increase their length, every bit doubling the number of prior combinations.
So we have this cipher, this symmetric cipher. We've put a combination of 128 bits in under the influence of a key that's probably going to be 128 bits. And out comes a different pattern. What's cool about this is that it's a one-for-one mapping. Every 128 bits we put in, we get out a different, I mean, unrelated 128 bits. There's no way looking at this to figure out what magic is going on inside this box that gives us this result. In other words, it is a pseudorandom output. But it's always the same, and it's reversible. So that gets us encryption.
So say that we now - the question is, and the real focus of what I wanted to explain today, was how do we take that and actually do something useful with it? Which is something we haven't really covered explicitly. That is, say I've got a document with multiple pages. How do I take this symmetric cipher, assume that I've got a secret key that I know, that is, we talked about how the key can be known. It could have been encrypted with a public key technology so that when I got the key, the document was encrypted and the key was encrypted. I used the public key technology to decrypt the key, so now I've got the key.
Or going the other direction, say that we have a plaintext document, that is, a document not yet encrypted. I use a pseudorandom number generator to generate a random 128-bit key. Now, that's the key I'm going to use to encrypt the document. And I will use a public key technology to encrypt that key when I send it with the document, knowing that only the person who's got the matching public key to my private key that I use to encrypt the random key used for the symmetric cipher, will be able to do the decryption.
So the question is, I've got my 128-bit pseudorandom key, and I've got this cool cipher algorithm, this Rijndael AES, or any other symmetric cipher. Now what do I do? Well, the most obvious thing to do is take bytes of the document at a time. 128 bits is 16 bytes. Is that right?
Steve: 32 bytes.
Leo: No, 16, yes.
Steve: So 32 bytes is 256 bits, so it's 16 bytes. So I take the first 16 bytes of the document, and that makes 128 bits, put them into the cipher, and out comes gibberish. I mean, just noise, nonsense, nothing. But I write them down. Then I go to the next 16 characters, or 16 bytes of the document, put them into the cipher, and out comes, again, nonsense, gibberish, completely different, given that the second set of 16 bytes are different than the first set of 16. So it's just no relationship that I can see between what goes in and what comes out. And then I take the third set of 16 bytes, put it in, and out comes another 128 bits of garbage, as far as I can tell. And I proceed. So now you would think, okay, fine, we've successfully encrypted the document. And in fact we have. But there is a problem with this that makes the crypto people feel uncomfortable. And that is, any time we put in the same 16 bytes, we're going to get out the same 16 bytes, or 128 bits, of garbage. Well, in other words, even though we don't know what the 16 bytes were that we put in, someone looking at the enciphered, the encrypted result could say wait a minute, here's the same phrase, here's the same expression.
Now, obviously those bytes would need to be aligned on the block boundaries in the same way. But the point is, there is some information leakage happening. There is something you're able to glean from looking at the pseudorandom noise. Even though it's pseudorandom and it's noise, it's noise with the possibility of a pattern. And that pattern is, I mean, the pattern reflects, one for one, a pattern in the plaintext. And that's not good. You would say, well, they don't know what the plaintext is. But you've leaked some information.
And, for example, in the case of a - say that we were, instead of encrypting a static document we were encrypting packets. And every packet that was being encrypted was using the same key, which was negotiated once at the beginning of the connection. Well, now all these packets are going by, and there's things that are known about the unencrypted format of the packet, like the header of the packet that contains IP and port number and so forth. And so, if you had enough samples of these packets, and you know that the key was the same, and you know that, because the assumption is always that an attacker knows everything that is known publicly about the protocol, they know you're using Rijndael; they know you've got 128-bit blocks; they know you've got a 128-bit key.
The point is that, in cryptography, you define well what is secret, and you define well what is public. And the whole goal is that the only thing we have to keep secret is the key. If we keep the key secret, we can publish everything else that we are doing, and the result is still private. We still have security. So that we clearly delineate what it is that we're requiring for security.
So the problem we've got now with this first approach is that patterns will easily show through our encryption because we've got a nice cipher which takes blocks at a time. But because the same input always produces the same output, just by looking at the output we can see that what we're seeing we've seen before, and that's information leakage. Well, so this simple approach is known as electronic code book, or ECB, algorithm. Because, think of it, a code book traditionally takes some input and gives you some output. It says here's my code book. I look up this word, and I get this word. I look up this word, I get this word. So that's essentially what this is doing. ECB just - it takes whatever you give it, and it gives you something else. But when used as a protocol, the problem is that it always gives you the same thing out for the same thing in. We need something a little fancier.
So the first thing people came up with was something called "counter mode." Or whereas this first one was Electronic Code Book, ECB, the counter mode just has the acronym CTR. So with counter mode, we operate a little differently. We imagine that we have going into the encryption block, instead of actually putting the data to be encrypted into the top of this cipher, instead we put a counter. We have a binary counter which starts at some particular value. We could start it at zero, but not starting it at zero gives us some additional strength. So imagine for now we just - we'll start our counter at zero for the sake of explanation.
So this 128-bit counter feeds into our encryption algorithm. Well, we already know that what's going to come out is pseudorandom data, even though we're putting all zeroes in, then 000001, 000010, 000011, you know, we're basically doing a simple binary progression feeding into the cipher. What comes out is noise. Thanks to the brilliance of a good symmetric cipher, you can even just put simple progressive counts in. And what you get out is just static. There's no discernible pattern. And remember that, again, this is under the influence of the symmetric key, which is also going into this black box. So now we've got noise coming out.
Well, we've talked a lot about the XOR operation, the exclusive OR, where the idea is that essentially one bits in one of the terms of the XOR serve to invert the bits of the other term of the XOR. In other words, if you were to XOR something with all zeroes, you'd just get it back out again. There's no change. If you were to XOR something with all ones, then all of the input bits would be inverted when they come out. So if you XOR something with random noise, this is one of our other, like, cool fundamental principles. You XOR data, good, normal, plaintext data, with random noise. What you get out is random noise. The XOR, I mean, even though it doesn't seem like you've done enough to, like, really encrypt something, if it's random noise, what it's done is it's randomly inverted the bits of your data. And when you do that, your data is gone. They're just like they were as random as if you had random data coming in in the first place. So this...
Leo: But it's reversible. That's the key.
Steve: Exactly. Because, exactly, because since the bits are being inverted under the influence of one of the terms of the XOR, when you do it again, those bits that were inverted get reinverted, which puts them back the way they were. So exactly. It's reversible. Okay. So now we have our counter set to zero. We feed that zero value through the cipher under the influence of the key, and out comes 128 bits of noise. We then take the first 16 bytes of our document and XOR them with the first 16 bytes of noise, and we get more noise. But we get special noise because it encodes, it encrypts the original plaintext. Now we increment the counter to one, and we feed that through the cipher and get a new 16 bytes of new noise, which we XOR with the second 16 bytes of our document. And now we get a second block of 16 bytes of noise. And we proceed with each 16 bytes at a time, with the counter incrementing by one every time. Well, now it looks like - now look at what we've got. We're using our cipher to turn a sequential count into a keyed sequential system of noise. That is, even though the counter might start at zero and go one, two, three, four, five, under one particular input key we'll get one series of pseudorandom noise. Under a different input key we get a completely different series. But unlike electronic code book mode, notice that even if we gave the same 16 bytes into this system some time later, the counter is guaranteed to be at a different count because it's counting sequentially. So it won't - and it's 128 bits long. It's not going to repeat in the lifetime of the universe. So that means that even the same data being encrypted with the same block alignment will give us a completely different output. We've solved the problem of there being any patterns. That is, we've solved the problem of any pattern that exists in the plaintext surviving and showing up in our cipher text. So we've got an improvement.
Well, this was better. But there was one next stage that the cryptographers decided would make them feel more comfortable because there is still a property that we have which we could improve on. And that is, each block stands alone. There is no interblock influence. That is, for example, nothing that we're encrypting is dependent upon anything that came before. And it would be nicer, even though this seems strong, it would be nicer if a change in the input text that we're encrypting changed more than just its 16 bytes. Remember, since we're doing this right now a block at a time, block of 16 bytes at a time, each block is isolated. Well, it would be nice if changing - if there was, like, more influence with our plaintext.
And it turns out it's simple to do that. All we have to do in order to create that is, again, change our algorithm a little bit. We'll step back from this counter mode and imagine that we sort of go back now to this electronic code book mode, remember, where we're actually encrypting our data through the block cipher to get our encrypted result. Now imagine that we take the encrypted output from the first block and XOR that with the second block's plaintext, the source data, before we encrypt it. What that does is, that essentially it takes that pseudorandom output from the first block of encryption, and by XORing it with the second block's input, it completely randomizes it, then encrypts it, giving us our second block of encrypted data. And we similarly, we take that and use it to XOR the input of the third block, and so forth. And this has turned out to be - that algorithm is called Cipher Block Chaining, or CBC. And it is the - one of the most popular encryption protocols because it is very fast. An XOR operation is something computers just do, I mean, they've got instructions built in, unless you're a PDP-8, and in that case you don't even have an XOR.