cryptography for developers PHẦN 9 docx

45 170 0
cryptography for developers PHẦN 9 docx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

TIP In most modern operating systems, the memory used by a program (or process) is known as virtual memory. The memory has no fixed physical address and can be moved between locations and even swapped to disk (through page invalida- tion). This latter action is typically known as swap memory, as it allows users to emulate having more physical memory than they really do. The downside to swap memory, however, is that the process memory could contain sensitive information such as private keys, usernames, passwords, and other credentials. To prevent this, an application can lock memory. In operating systems such as those based on the NT kernel (e.g., Win2K, WinXP), locking is entirely voluntary and the OS can choose to later swap nonkernel data out. In POSIX compatible operating systems, such as those based on the Linux and the BSD kernels, a set of functions such as mlock(), munlock(), mlockall(), and so forth have been provided to facilitate locking. Physical memory in most systems can be costly, so the polite and proper application will request to lock as little memory as possible. In most cases, locked memory will span a region that contains pages of memory. On the x86 series of processors, a page is four kilobytes. This means that all locked memory will actually lock a multiple of four kilobytes. Ideally, an application will pool its related credentials to reduce the number of physical pages required to lock them in memory. 345 error: 346 if (skey != uskey) { 347 XFREE(skey); 348 } 349 350 return err; 351 } Upon successful completion of this function, the user now has the ciphertext (or plain- text depending on the direction) and the CCM tag. While the function may be a tad long, it is nicely bundled up in a single function call, making its deployment rather trivial. Putting It All Together This chapter introduced the two standard encrypt and authenticate modes as specified by both NIST and IEEE.They are both designed to take a single key and IV (nonce) and pro- duce a ciphertext and message authentication code tag, thereby simplifying the process for developers by reducing the number of different standards they must support, and in practice the number of functions they have to call to accomplish the same results. www.syngress.com 338 Chapter 7 • Encrypt and Authenticate Modes 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 338 Knowing how to use these modes is a matter of properly choosing an IV, making ideal use of the additional authentication data (AAD), and checking the MAC tag they produce. Neither of these two modes will manage any of these properties for the developer, so they must look after them carefully. For most applications, it is highly advisable to use these modes over an ad hoc combina- tion of encryption and authentication, if not solely for the reason of code simplicity, then also for proper adherence to cryptographic standards. What Are These Modes For? We saw in the previous chapter how we could accomplish both privacy and authentication of data through the combined use of a symmetric cipher and chaining mode with a MAC algorithm. Here, the goal of these modes is to combine the two.This accomplishes several key goals simultaneously. As we alluded to in the previous chapter, CCM and GCM are also meant for small packet messages, ideal for securing a stream of messages between parties. CCM and GCM can be used for offline tasks such as file encryption, but they are not meant for such tasks (especially CCM since it needs the length of the plaintext in advance). First, combining the modes makes development simpler—there is only one key and one IV to keep track of.The mode will handle using both for both tasks.This makes key deriva- tion easier and quicker, as less session data must be derived. It also means there are fewer variables floating around to keep track of. These combined modes also mean it’s possible to perform both goals with a single func- tion call. In code where we specifically must trap error codes (usually by looking at the return codes), having fewer functions to call means the code is easier to write safely. While there are other ways to trap errors such as signals and internal masking, making threadsafe global error detection in C is rather difficult. In addition to making the code easier to read and write, combined modes make the security easier to analyze. CCM, for instance, is a combination of CBC-MAC and CTR encryption mode. In various ways, we can reduce the security of CCM to the security of these modes. In general, with a full length MAC tag, the security of CCM reduces to the security of the block cipher (assuming a unique nonce and random key are used). What we mean by reduce is that we can make an argument for equivalence. For example, if the security of CTR is reducible to the security of the cipher, we are saying it is as secure as the latter. By this reasoning, if one could break the cipher, he could also break CTR mode. (Strictly speaking, the security of CTR reduces to the determination of whether the cipher is a PRP.) So, in this context, if we say CCM reduces to the security of the cipher in terms of being a proper pseudo-random permutation (PRP), then if we can break the cipher (by showing it is not a PRP), we can likely break CCM. Similarly, GCM reduces to the security of the cipher for privacy and to universal hashing for the MAC. It is more complicated to prove that it can be secure. www.syngress.com Encrypt and Authenticate Modes • Chapter 7 339 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 339 Choosing a Nonce Both CCM and GCM require a unique nonce (N used once) value to maintain their pri- vacy and authenticity goals. In both cases, the value need not be random, but merely unique for a given key.That is, you can safely use the same nonce (only once, though) between two different keys. Once you use the nonce for a particular key, you cannot use it again. GCM Nonces GCM was designed to be most efficient with 12-byte nonce values. Any longer or shorter and GHASH is used to create an IV for the mode. In this case, we can simply use the 12- byte nonce as a packet counter. Since we have to send the nonce to the other party anyway, this means we can double up on the purpose of this field. Each packet would get its own 12-byte nonce (by incrementing it), and the receiver can check for replays and out of order packets by checking the nonce as if it were a 96-bit number. You can use the 12-byte number as either a big or little endian value, as GCM will not truncate the nonce. CCM Nonces CCM was not designed as favorably to the nonces as GCM was. Still, if you know all your packets will be shorter than 65,536 bytes, you can safely assume your nonce is allowed to be up to 13 bytes. Like GCM, you can use it as a 104-bit counter and increment it for every packet you send out. If you cannot determine the length of your packets ahead of time, it is best to default to a shorter nonce (say 11 bytes, allowing up to four-gigabyte packets) as your counter. Remember, there is no magic property to the length of the nonce other than you have to have a long enough nonce to have unique values for every packet you send out under the same key. CCM will truncate the nonce if the packet is too long (to have room to store the length), so in practice it is best to treat it as a little endian counter.The most significant bytes would be truncated. It is even better to just use a shorter nonce than worry about it. Additional Authentication Data Both CCM and GCM support a sort of side channel known as additional authentication data (AAD).This data is meant to be nonprivate data that should influence the MAC tag output.That is, if the plaintext and AAD are not present together and unmodified, the tag should reflect that. The usual use for AAD is to store session metadata along with the packet.Things such as username, session ID, and transaction ID are common.You would never use a user credential, since it would not really be something you need on a per-packet basis. Both protocols support empty AAD strings. Only GCM is optimized to handle AAD strings that are a multiple of 16 bytes long. CCM inserts a four- or six-byte header that off- www.syngress.com 340 Chapter 7 • Encrypt and Authenticate Modes 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 340 sets the data and makes it harder to optimize for. In general, if you are using CCM, try to have very short AAD strings, preferably less than 10 bytes, as you can cram that into a single encrypt invocation. For GCM, try to have your AAD strings a multiple of 16 bytes even if you have to pad with zero bytes (the implementation cannot do this padding for you, as it would change the meaning of the AAD). MAC Tag Data The MAC tag produced by both implementations is not checked internally.The typical usage would involve transmitting the MAC tag with the ciphertext, and the recipient would compare it against the one he generated while decrypting the message. In theory at least, you can truncate the MAC tag to short lengths such as 80 or 96 bits. However, some evidence points to the contrary with GCM, and in reality the savings are trivial. As the research evolves, it would be best to read up on the latest analysis papers of GCM and CCM to see if short tags are still in fact secure. In practice, you can save more space if you aggregate packets over a stable channel. For example, instead of sending 128-byte packets, send 196- or 256-byte packets.You will send fewer nonces (and protocol data), and the difference can allow you to use a longer MAC tag. Clearly, this does not work in low latency switching cases (e.g., VoIP), so it is not a bullet- proof suggestion. Example Construction For our example, we will borrow from the example of Chapter 6, except instead of using HMAC and CTR mode, we will use CCM.The rest of the demo works the same.Again, we will be using LibTomCrypt, as it provides a nice CCM interface that is very easy to use in fielded applications. encmac.c: 001 #include <tomcrypt.h> 002 003 #define KEYLEN 16 We only have one key and its 16 bytes long. 005 /* Our Per Packet Sizes, Nonce len and MAC len */ 006 #define NONCELEN 4 007 #define MACLEN 12 008 #define OVERHEAD (NONCELEN+MACLEN) As in the previous example, we have a packet counter length (the length of our nonce), MAC tag length, and the composite overhead. Here we have a 32-bit counter and a 96-bit MAC. 010 /* errors */ 011 #define MAC_FAILED -3 012 #define PKTCTR_FAILED -4 013 www.syngress.com Encrypt and Authenticate Modes • Chapter 7 341 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 341 014 /* our nice containers */ 015 typedef struct { 016 unsigned char PktCTR[NONCELEN], 017 key[KEYLEN]; 018 symmetric_key skey; 019 } encauth_channel; Our encrypted and authenticated channel is similar to the previous example.The differ- ences here are that we are using a generic scheduled key, and we do not have a MAC key. 021 typedef struct { 022 encauth_channel channels[2]; 023 } encauth_stream; 024 025 026 void register_algorithms(void) 027 { 028 register_cipher(&aes_desc); 029 register_hash(&sha256_desc); 030 } 031 032 int init_stream(const unsigned char *masterkey, 033 unsigned masterkeylen, 034 const unsigned char *salt, 035 unsigned saltlen, 036 encauth_stream *stream, 037 int node) 038 { 039 unsigned char tmp[2*KEYLEN]; 040 unsigned long tmplen; 041 int err; 042 encauth_channel tmpswap; 043 044 /* derive keys */ 045 tmplen = sizeof(tmp); 046 if ((err = pkcs_5_alg2(masterkey, masterkeylen, 047 salt, saltlen, 048 16, find_hash("sha256"), 049 tmp, &tmplen)) != CRYPT_OK) { 050 return err; 051 } 052 053 /* copy keys */ 054 memcpy(stream->channels[0].key, 055 tmp, KEYLEN); 056 memcpy(stream->channels[1].key, 057 tmp + KEYLEN, KEYLEN); 058 059 /* reset counters */ 060 memset(stream->channels[0].PktCTR, 0, 061 sizeof(stream->channels[0].PktCTR)); 062 memset(stream->channels[1].PktCTR, 0, 063 sizeof(stream->channels[1].PktCTR)); 064 065 /* schedule keys+setup mode */ www.syngress.com 342 Chapter 7 • Encrypt and Authenticate Modes 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 342 066 if ((err = rijndael_setup(stream->channels[0].key, 067 KEYLEN, 0, 068 &stream->channels[0].skey)) 069 != CRYPT_OK) { 070 return err; 071 } 072 073 if ((err = rijndael_setup(stream->channels[1].key, 074 KEYLEN, 0, 075 &stream->channels[1].skey)) 076 != CRYPT_OK) { 077 return err; 078 } 079 080 /* do we swap? */ 081 if (node != 0) { 082 tmpswap = stream->channels[0]; 083 stream->channels[0] = stream->channels[1]; 084 stream->channels[1] = tmpswap; 085 zeromem(&tmpswap, sizeof(tmpswap)); 086 } 087 088 zeromem(tmp, sizeof(tmp)); 089 090 return 0; 091 } This initialization function is essentially the same. We only change how much PKCS #5 data is to be generated. 093 int encode_frame(const unsigned char *in, 094 unsigned inlen, 095 unsigned char *out, 096 encauth_stream *stream) 097 { 098 int x, err; 099 unsigned long taglen; 100 101 /* increment counter */ 102 for (x = NONCELEN-1; x >= 0; x ) { 103 if (++(stream->channels[0].PktCTR[x]) & 255) break; 104 } 105 106 /* store counter */ 107 for (x = 0; x < NONCELEN; x++) { 108 out[x] = stream->channels[0].PktCTR[x]; 109 } We use our packet counter PktCTR as the a method of keeping the packets in order. We also use it as a nonce for the CCM algorithm.The output generated will first consist of the nonce, followed by the ciphertext, and then the MAC tag. 111 /* encrypt it */ 112 taglen = MACLEN; 113 if ((err = ccm_memory( www.syngress.com Encrypt and Authenticate Modes • Chapter 7 343 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 343 This function call will generate the ciphertext and MAC tag for us. Libraries are nice. 114 find_cipher("aes"), First, we need the index of the cipher we want to use. In this case, AES with CCM. We could otherwise use any other 128-bit block cipher such as Twofish, Anubis, or Serpent. 115 stream->channels[0].key, KEYLEN, This is the byte array of the key we want to use and the key length. 116 &stream->channels[0].skey, This is the pre-scheduled key. Our CCM routine will use this instead of scheduling the key on the fly. We pass the byte array for completeness (accelerators may need it). 117 stream->channels[0].PktCTR, NONCELEN, This is the nonce for the packet. 118 NULL, 0, This is the AAD; in this case, we are sending none. We pass NULL and 0 to signal this to the library. 119 (unsigned char*)in, inlen, out + NONCELEN, 120 out+inlen+NONCELEN, &taglen, CCM_ENCRYPT)) These are the plaintext and ciphertext buffers.The plaintext is always specified first regardless of the direction we are using. It may get a bit confusing for those expecting an “input” and “output” order of arguments. 121 != CRYPT_OK) { 122 return err; 123 } 124 return CRYPT_OK; 125 } The ccm_memory() function call produces the ciphertext and MAC tag.The format of our packet contains the nonce, followed by the ciphertext, and then the MAC tag. From a security standpoint, this function provides for the same security goals as the previous chapter’s incarnation of this function.The improvement in this case is that we have short- ened the code and removed a few variables from our structure. 127 int decode_frame(const unsigned char *in, 128 unsigned inlen, 129 unsigned char *out, 130 encauth_stream *stream) 131 { 132 int err; 133 unsigned char tag[MACLEN]; 134 unsigned long taglen; 135 136 /* restore our original inlen */ www.syngress.com 344 Chapter 7 • Encrypt and Authenticate Modes 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 344 137 if (inlen < MACLEN+NONCELEN) { return -1; } 138 inlen -= MACLEN+NONCELEN; As before, we assume that inlen is the length of the entire packet and not just the plain- text. We first make sure it is a valid length, and then subtract the MAC tag and nonce from the length. 140 /* decrypt it */ 141 taglen = sizeof(tag); 142 if ((err = ccm_memory( 143 find_cipher("aes"), 144 stream->channels[1].key, KEYLEN, 145 &stream->channels[1].skey, 146 (unsigned char*)in, NONCELEN, 147 NULL, 0, 148 out, inlen, (unsigned char*)in + NONCELEN, 149 tag, &taglen, CCM_DECRYPT)) 150 != CRYPT_OK) { 151 return CRYPT_OK; 152 } For both encryption and decryption, the ccm_memory() function is used. In decrypt mode, it is used much the same, except our out buffer goes in the plaintext argument posi- tion.Therefore, it appears before the input, which seems a bit awkward. Note that we store the MAC tag locally since we need to compare it next. 154 /* compare */ 155 if (memcmp(tag, in+inlen+NONCELEN, MACLEN)) { 156 return MAC_FAILED; 157 } 158 159 /* compare CTR */ 160 if (memcmp(in, stream->channels[1].PktCTR, NONCELEN) <= 0) { 161 return PKTCTR_FAILED; 162 } These checks are the same as they were in the previous incarnation.The first avoids alterations, and the second avoids replay attacks. We still do not handle out of order packets (e.g., with a window), but that should be trivial to accommodate. 164 /* copy the pktctr */ 165 memcpy(stream->channels[1].PktCTR, in, NONCELEN); At this point, our packet is valid, so we copy the nonce out and store it locally, thus pre- venting future replay attacks. 167 return CRYPT_OK; 168 } 169 <snip> The rest of our demonstration program is the same as our previous incarnation, as we have not changed the function interfaces. www.syngress.com Encrypt and Authenticate Modes • Chapter 7 345 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 345 Q: What is an Encrypt and Authenticate algorithm? A: These are algorithms designed to accept a single key and IV, and allow the caller to both encrypt and authenticate his message. Unlike distinct encrypt and authenticate protocols, these modes do not require two independent keys for security. Q: What are the benefits of these modes over the distinct modes? A: There are two essential benefits to these modes. First, they are easier to incorporate into cryptosystems, as they require fewer keys, and perform two functions at the same time. This means a developer can accomplish two goals with a single function call. It also means they are more likely to start authenticating traffic.The second benefit is that they are often reducible to the security of the underlying cipher or primitive. Q: What does reducible mean? A: When we say one problem is reducible to another, we imply that solving the former involves a solution to the latter. For instance, the security of CTR-AES reduces to the problem of whether AES is a true pseudo random permutation (PRP). If AES is not a PRP, CTR-AES is not secure. Q: What Encrypt and Authenticate modes are standardized? A: CCM is specified in the NIST publication SP 800-38C. GCM is an IEEE standard and will be specified in the NIST publication SP 800-38D in the future. Q: Should I use these modes over distinct modes such as AES-CTR and SHA1-HMAC? A: That depends on whether you are trying to adhere to an older standard. If you are not, most likely GCM or CCM make better use of system resources to accomplish equiva- lent goals.The distinct modes can be just as secure in practice, but are generally harder to implement and verify in fielded applications.They also rely on more security assump- tions, which poses a security risk. www.syngress.com 346 Chapter 7 • Encrypt and Authenticate Modes Frequently Asked Questions The following Frequently Asked Questions, answered by the authors of this book, are designed to both measure your understanding of the concepts presented in this chapter and to assist you with real-life implementation of these concepts. To have your questions about this chapter answered by the author, browse to www.syngress.com/solutions and click on the “Ask the Author” form. 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 346 Q: What is a nonce and what is the importance of it? A: A nonce is a parameter (like an initial value) that is meant to be used only once. Nonces are used to introduce entropy into an otherwise static and fully deterministic process (that is, after the key has been chosen). Nonces must be unique under one key, but may be reused across different keys. Usually, they are simply packet counters. Without a unique nonce, both GCM and CCM have no provable security properties. Q: What is additional authentication data? AAD? Header data? A: Additional authentication Data (AAD), also known as header data and associated data (in EAX), is data related to a message, that must be part of the MAC tag computation but not encrypted.Typically, it is simple metadata related to the session that is not private but affects the interpretation of the messages. For instance, an IP datagram encoder could use parts of the IP datagram as part of the header data.That way, if the routing is changed it is detectable, and since the IP header cannot be encrypted (without using another IP standard), it must remain in plaintext form.That is only one example of AAD; there are others. In practice, it is not used much but provided nonetheless. Q: Which mode should I use? GCM or CCM? A: That depends on the standard you are trying to comply with (if any). CCM is cur- rently the only NIST standard of the two. If you are working with wireless standards, chances are you will need GCM. Outside of those two cases, it depends on the plat- form. GCM is very fast, but requires a huge 64-kilobyte table to achieve this speed (at least in software). CCM is a slight bit slower, but is much simpler in design and imple- mentation. CCM also does not require huge tables to achieve its performance claims. If you removed the tables from GCM, it would be much slower than CCM. Q: Are there any patents on these modes? A: Neither of GCM and CCM is patented.They are free for any use. Q: Where can I find implementations? A: Currently, only LibTomCrypt provides both GCM and CCM in a library form. Brian Gladman has independent copyrighted implementations available. Crypto++ has neither, but the author is aware of this. Q: What do I do with the MAC tag? A: If you are encrypting, transmit it along with your ciphertext and AAD data (if any). If you are decrypting, the decryption will generate a MAC tag; compare that with the value stored along with the ciphertext. If they do not compare as equal, the message has been altered or the stored MAC tag is invalid. www.syngress.com Encrypt and Authenticate Modes • Chapter 7 347 404_CRYPTO_07.qxd 10/30/06 11:51 AM Page 347 [...]... printf("SQRADDDB; "); if ((x&1) == 0) { www.syngress.com 365 404_CRYPTO_08.qxd 366 10/30/06 11:53 AM Page 366 Chapter 8 • Large Integer Arithmetic 078 0 79 080 081 082 083 084 085 086 087 088 0 89 090 091 092 093 094 095 096 // add the square printf("SQRADD(a[%d], a[%d]); ", x/2, x/2); } } printf("\n COMBA_STORE(b[%d]);\n", x); } printf(" COMBA_STORE2(b[%d]);\n", N+N-1); printf( " COMBA_FINI;\n" "\n" " B->used... loop 0 39 040 041 042 043 044 045 for (y = 0; y < N; y++) { for (z = 0; z < N; z++) { if ((y+z)==x) { printf(" MULADD(at[%d], at[%d]); ", y, z+N); } } } This constructs the inner loop in a brute force fashion Fortunately, we only have to execute this once to create the source code Essentially, we step through both inputs, and whenever their location adds to x, we perform a MULADD 046 047 048 0 49 050... initialization required for the inner loop 024 025 026 027 for (x = 0; x < pa; x++) { fp_digit cy = 0; /* get Mu for this round */ LOOP_START; The LOOP_START macro multiplies c[x] by mp to create the Mu digit for this iteration of the loop It can be done by assembler code, but as we will see, it is simpler to just use C on most platforms 028 0 29 030 031 032 033 034 035 _c = c + x; tmpm = m->dp; y = 0; for (; y . char *in, 094 unsigned inlen, 095 unsigned char *out, 096 encauth_stream *stream) 097 { 098 int x, err; 099 unsigned long taglen; 100 101 /* increment counter */ 102 for (x = NONCELEN-1; x >=. sizeof(tmp)); 0 89 090 return 0; 091 } This initialization function is essentially the same. We only change how much PKCS #5 data is to be generated. 093 int encode_frame(const unsigned char *in, 094 unsigned. also meant for small packet messages, ideal for securing a stream of messages between parties. CCM and GCM can be used for offline tasks such as file encryption, but they are not meant for such tasks

Ngày đăng: 12/08/2014, 16:20

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan