blob: 052864a72cc18ea1f74a6472dfa42286b3501df0 [file] [log] [blame]
Thomas Klausner1334a6f2016-12-02 14:56:16 +01001AES Coding Tips for Developers
2
3NOTE: WinZip^(R) users do not need to read or understand the information
4contained on this page. It is intended for developers of Zip file utilities.
5
6This document contains information that may be helpful to developers and other
7interested parties who wish to support the AE-1 and AE-2 AES encryption formats
8in their own Zip file utilities. WinZip Computing makes no warranties regarding
9the information provided in this document. In particular, WinZip Computing does
10not represent or warrant that the information provided here is free from errors
11or is suitable for any particular use, or that the file formats described here
12will be supported in future versions of WinZip. You should test and validate
13all code and techniques in accordance with good programming practice.
14
15This information supplements the basic encryption specification document found
16here.
17
18This document assumes that you are using Dr. Brian Gladman's AES encryption
19package. Dr. Gladman has generously made public a sample application that
20demonstrates the use of his encryption/decryption and other routines, and the
21code samples shown below are derived from this sample application. Dr.
22Gladman's AES library and the sample application are available from the AES
23project page on Dr. Gladman's web site.
24
25━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
26
27Generating a salt value
28
29Please read the discussion of salt values in the encryption specification.
30
31Dr. Gladman has provided a pseudo-random number generator in the files PRNG.C
32and PRNG.H. You may find this suitable for generating salt values. These files
33are included in the sample package available through the AES project page on
34Dr. Gladman's web site.
35
36Here are guidelines for using Dr. Gladman's generator. Note that the generator
37is used rather like an I/O stream: it is opened (initialized), used, and
38finally closed. To obtain the best results, it is recommended that you
39initialize the generator when your application starts and close it when your
40application closes. (If you are coding in C++, you may wish to wrap these
41actions in a C++ class that initializes the generator on construction and
42closes it on destruction.)
43
44 1. You will need to provide an entropy function in your code for
45 initialization of the generator. The entropy function need not be
46 particularly sophisticated for this use. Here is one possibility for such a
47 function, based primarily upon the Windows performance counter:
48
49 int entropy_fun(
50 unsigned char buf[],
51 unsigned int len)
52 {
53 unsigned __int64 pentium_tsc[1];
54 unsigned int i;
55 static unsigned int num = 0;
56 // this sample code returns the following sequence of entropy information
57 // - the current 8-byte Windows performance counter value
58 // - an 8-byte representation of the current date/time
59 // - an 8-byte value built from the current process ID and thread ID
60 // - all subsequent calls return the then-current 8-byte performance
61 // counter value
62 switch (num)
63 {
64 case 1:
65 ++num;
66 // use a value that is unlikely to repeat across system reboots
67 GetSystemTimeAsFileTime((FILETIME *)pentium_tsc);
68 break;
69 case 2:
70 ++num;
71 {
72 // use a value that distinguishes between different instances of this
73 // code that might be running on different processors at the same time
74 unsigned __int32 processtest = GetCurrentProcessId();
75 unsigned __int32 threadtest = GetCurrentThreadId();
76 pentium_tsc[0] = processtest;
77 pentium_tsc[0] = (pentium_tsc[0] << 32) + threadtest;
78 }
79 break;
80 case 0:
81 ++num;
82 // fall through to default case
83 default:
84 // use a rapidly-changing value
85 // Note: check QueryPerformanceFrequency() first to
86 // ensure that QueryPerformanceCounter() will work.
87 QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc);
88 break;
89 }
90 for(i = 0; i < 8 && i < len; ++i)
91 buf[i] = ((unsigned char*)pentium_tsc)[i];
92 return i;
93 }
94
95 Note: the required prototype for the entropy function is defined in PRNG.H.
96
97 2. Initialize the generator by calling prng_init(), providing the addresses of
98 your entropy function and of an instance of a prng_ctx structure (defined
99 in PRNG.H). The prng_ctx variable maintains a context for the generator and
100 is used as a parameter for the other generator functions. Therefore, the
101 variable's state must be maintained until the generator is closed.
102
103 prng_ctx ctx;
104 prng_init(entropy_fun, &ctx);
105
106 You only need to do this once per application session (as long as you keep
107 the "stream" open).
108
109 3. To obtain a sequence of random bytes of arbitrary size, use prng_rand().
110 This code obtains 16 random bytes, suitable for use as a salt value for
111 256-bit AES encryption:
112
113 unsigned char buffer[16];
114 prng_rand(buffer, sizeof(buffer), &ctx);
115
116 Note that the ctx parameter is the same prng_ctx variable that was used in
117 the initialization call.
118
119 4. When you are done with the generator (this would normally be when your
120 application closes), close it by calling prng_end:
121
122 prng_end(&ctx);
123
124 Again, the ctx parameter is the same prng_ctx variable that was used in the
125 initialization call.
126
127Encryption and decryption
128
129The actual encryption and decryption of data are handled quite similarly, and
130again are rather stream-like: a stream is "opened", data is passed to it for
131encryption or decryption, and then it is closed. The password verifier is
132returned when the stream is opened, and the authentication code is returned
133when the stream is closed.
134
135Here is the basic technique:
136
137 1. Initialize the "stream" for encryption or decryption and obtain the
138 password verification value.
139
140 There is no difference in the initialization, regardless of whether you are
141 encrypting or decrypting:
142
143 fcrypt_ctx zctx; // the encryption context
144 int rc = fcrypt_init(
145 KeySize, // extra data value indicating key size
146 pszPassword, // the password
147 strlen(pszPassword), // number of bytes in password
148 achSALT, // the salt
149 achPswdVerifier, // on return contains password verifier
150 &zctx); // encryption context
151
152 The return value is 0 if the initialization was successful; non-zero values
153 indicate errors. Note that passwords are null-terminated ANSI strings;
154 embedded nulls must not be used. (To avoid incompatibilities between the
155 various character sets in use, especially in different versions of Windows,
156 users should be encouraged to use passwords containing only the "standard"
157 characters in the range 32-127.)
158
159 The function returns the password verification value in achPswdVerifier,
160 which must be a 2-byte buffer. If you are encrypting, store this value in
161 the Zip file as indicated by the encryption specification. If you are
162 decrypting, compare this returned value to the value stored in the Zip
163 file. If they are different, then either the password provided by your user
164 was incorrect or the encrypted file has been altered in some way since it
165 was encrypted. (Note that if they match, there is still a 1 in 65,536
166 chance that an incorrect password was provided.)
167
168 The initialized encryption context (zctx) is used as a parameter to the
169 encryption/decryption functions. Therefore, its state must be maintained
170 until the "stream" is closed.
171
172 2. Encrypt or decrypt the data.
173
174 To encrypt:
175
176 fcrypt_encrypt(
177 pchData, // pointer to the data to encrypt
178 cb, // how many bytes to encrypt
179 &zctx); // encryption context
180
181 To decrypt:
182
183 fcrypt_decrypt(
184 pchData, // pointer to the data to decrypt
185 cb, // how many bytes to decrypt
186 &zctx); // decryption context
187
188 You may need to call the encrypt or decrypt function multiple times,
189 passing in successive chunks of data in the buffer. For AE-1 and AE-2
190 compatibility, the buffer size must be a multiple of 16 bytes except for
191 the last buffer, which may be smaller. For efficiency, a larger buffer size
192 such as 32,768 would generally be used.
193
194 Note: to encrypt zero-length files, simply skip this step. You will still
195 obtain and use the password verifier (step 1) and authentication code (step
196 3).
197
198 3. Close the "stream" and obtain the authentication code.
199
200 When encryption/decryption is complete, close the "stream" as follows:
201
202 int rc = fcrypt_end(
203 achMAC, // on return contains the authentication code
204 &zctx); // encryption context
205
206 The return value is the size of the authentication code, which will always
207 be 10 for AE-1 and AE-2. The authentication code itself is returned in your
208 buffer at achMAC, which is an array of char, sized to hold at least 10
209 characters. If you are encrypting, store this value in the Zip file as
210 indicated by the encryption specification; if you are decrypting, compare
211 this value to the value stored in the Zip file. If the values are
212 different, either the password is incorrect or the encrypted data has been
213 altered subsequent to storage.
214
215 Note that decryption can fail even if the encrypted data is unaltered and
216 the password verifier was correct in step 1. The password verifier is
217 useful as a quick way to detect most incorrect passwords, but it is not
218 perfect and on rare occasions (1 out of 65,536) it will fail to detect an
219 incorrect password. It is therefore important for you to check the
220 authentication code on completion even though the password verifier was
221 correct.
222
223Notes
224
225 • Dr. Gladman's AES code depends on the byte order (little-endian or
226 big-endian) used by the computing platform the code will run on. This is
227 determined by a C preprocessor constant called PLATFORM_BYTE_ORDER, which
228 is defined in the file AESOPT.H. You should be sure that
229 PLATFORM_BYTE_ORDER gets the proper value for your platform; if it does
230 not, you will need to define it yourself to the correct value. When using
231 the Microsoft compiler on Intel platforms it does get the proper value,
232 which on these platforms is AES_LITTLE_ENDIAN. We have, however, had a
233 report that it does not default properly when Borland C++ Builder is used,
234 and that manual assignment is necessary. For additional information on this
235 topic, refer to the comments within AESOPT.H.
236
237Change history
238
239Changes made in document version 1.04, July, 2008:
240
241 A. Sample Entropy Function
242
243 The sample entropy function was changed to include information near the
244 very beginning of the entropy stream that's unique to the day and to the
245 process and thread.
246
247━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
248
249Document version: 1.04
250Last modified: July 21, 2008
251
252Copyright(C) 2003-2016 WinZip International LLC.
253All Rights Reserved