1 module dcrypt.crypto.macs.poly1305;
2 
3 import dcrypt.crypto.macs.mac;
4 import dcrypt.crypto.blockcipher;
5 import dcrypt.bitmanip;
6 
7 static assert(isMAC!(Poly1305!void), "Poly1305!void is not a valid mac.");
8 
9 private {
10 	enum ubyte rMaskLow2 = 0xFC;
11 	enum ubyte rMaskHigh4 = 0x0F;
12 }
13 
14 alias Poly1305!void Poly1305Raw;
15 
16 @safe nothrow @nogc
17 public struct Poly1305(Cipher) if ((isBlockCipher!Cipher && Cipher.blockSize == 16) || is(Cipher == void)) {
18 
19 	static if(useCipher) {
20 		public enum name = "Poly1305-" ~ Cipher.name;
21 	} else {
22 		public enum name = "Poly1305";
23 	}
24 
25 	public enum macSize = blockSize;
26 
27 	private {
28 		enum useCipher = !is(Cipher == void);
29 		enum blockSize = 16;
30 
31 		static if(useCipher) {
32 			Cipher cipher;
33 		}
34 		// Initialised state
35 
36 		/** Polynomial key */
37 		int r0, r1, r2, r3, r4;
38 
39 		/** Precomputed 5 * r[1..4] */
40 		int s1, s2, s3, s4;
41 
42 		/** Encrypted nonce */
43 		int k0, k1, k2, k3;
44 
45 		// Accumulating state
46 
47 		/** Current block of buffered input */
48 		ubyte[blockSize] currentBlock;
49 
50 		/** Current offset in input buffer */
51 		uint currentBlockOffset = 0;
52 
53 		/** Polynomial accumulator */
54 		int h0, h1, h2, h3, h4;
55 	}
56 
57 	/// Wipe sensitive data.
58 	~this() {
59 		r0 = r1 = r2 = r3 = r4 = 0;
60 		s1 = s2 = s3 = s4 = 0;
61 		k0 = k1 = k2 = k2 = 0;
62 		
63 		currentBlock[] = 0;
64 		h0 = h1 = h2 = h3 = h4 = 0;
65 	}
66 
67 	/// Initializes the Poly1305 MAC.
68 	/// Params:
69 	/// key = 32 byte key.
70 	/// nonce = 16 byte nonce. Required if used with block cipher.
71 	public void start(in ubyte[] key, in ubyte[] nonce = null)
72 	{
73 		setKey(key, nonce);
74 		
75 		reset();
76 	}
77 
78 	private void setKey(in ubyte[] key, in ubyte[] nonce)
79 	in {
80 		if(useCipher) {
81 			assert(nonce !is null && nonce.length == blockSize, "Poly1305 requires an 256 bit IV when used with a block cipher.");
82 		}
83 
84 		assert(key !is null && key.length == 32, "Poly1305 requires a 32 byte key.");
85 
86 	}
87 	body {
88 
89 		ubyte[16] r, s;
90 		r[] = key[0..16];
91 		clamp(r);
92 		s[] = key[16..32];
93 		
94 		assert(checkKey(r), "Invalid format for r portion of Poly1305 key.");
95 
96 		// Extract r portion of key
97 
98 		int t0 = fromLittleEndian!int(r[0..4]);
99 		int t1 = fromLittleEndian!int(r[4..8]);
100 		int t2 = fromLittleEndian!int(r[8..12]);
101 		int t3 = fromLittleEndian!int(r[12..16]);
102 		
103 		r0 = t0 & 0x3ffffff; t0 >>>= 26; t0 |= t1 << 6;
104 		r1 = t0 & 0x3ffff03; t1 >>>= 20; t1 |= t2 << 12;
105 		r2 = t1 & 0x3ffc0ff; t2 >>>= 14; t2 |= t3 << 18;
106 		r3 = t2 & 0x3f03fff; t3 >>>= 8;
107 		r4 = t3 & 0x00fffff;
108 		
109 		// Precompute multipliers
110 		s1 = r1 * 5;
111 		s2 = r2 * 5;
112 		s3 = r3 * 5;
113 		s4 = r4 * 5;
114 
115 		static if (useCipher)
116 		{
117 			cipher.start(true, s);
118 			cipher.processBlock(nonce, s);
119 		}
120 		
121 		k0 = fromLittleEndian!int(s[0..4]);
122 		k1 = fromLittleEndian!int(s[4..8]);
123 		k2 = fromLittleEndian!int(s[8..12]);
124 		k3 = fromLittleEndian!int(s[12..16]);
125 	}
126 
127 	public void put(in ubyte[] inp...) {
128 
129 		import std.algorithm: min;
130 
131 		const(ubyte)[] input = inp;
132 
133 		uint copied = 0;
134 		while (input.length > 0)
135 		{
136 			if (currentBlockOffset == blockSize)
137 			{
138 				processBlock();
139 				currentBlockOffset = 0;
140 			}
141 
142 			uint toCopy = min(input.length, blockSize - currentBlockOffset);
143 			//System.arraycopy(in, copied + inOff, currentBlock, currentBlockOffset, toCopy);
144 			currentBlock[currentBlockOffset..currentBlockOffset+toCopy] = input[0..toCopy];
145 			input = input[toCopy..$];
146 			copied += toCopy;
147 			currentBlockOffset += toCopy;
148 		}
149 		
150 	}
151 
152 	private void processBlock()
153 	{
154 		if (currentBlockOffset < blockSize)
155 		{
156 			currentBlock[currentBlockOffset] = 1;
157 			for (uint i = currentBlockOffset + 1; i < blockSize; i++)
158 			{
159 				currentBlock[i] = 0;
160 			}
161 		}
162 
163 		immutable long t0 = 0xffffffffL & fromLittleEndian!int(currentBlock[0..4]);
164 		immutable long t1 = 0xffffffffL & fromLittleEndian!int(currentBlock[4..8]);
165 		immutable long t2 = 0xffffffffL & fromLittleEndian!int(currentBlock[8..12]);
166 		immutable long t3 = 0xffffffffL & fromLittleEndian!int(currentBlock[12..16]);
167 		
168 		h0 += t0 & 0x3ffffff;
169 		h1 += (((t1 << 32) | t0) >>> 26) & 0x3ffffff;
170 		h2 += (((t2 << 32) | t1) >>> 20) & 0x3ffffff;
171 		h3 += (((t3 << 32) | t2) >>> 14) & 0x3ffffff;
172 		h4 += (t3 >>> 8);
173 		
174 		if (currentBlockOffset == blockSize)
175 		{
176 			h4 += (1 << 24);
177 		}
178 		
179 		long tp0 = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
180 		long tp1 = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
181 		long tp2 = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
182 		long tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
183 		long tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
184 		
185 		long b;
186 		h0 = cast(int)tp0 & 0x3ffffff; b = (tp0 >>> 26);
187 		tp1 += b; h1 = cast(int)tp1 & 0x3ffffff; b = ((tp1 >>> 26) & 0xffffffff);
188 		tp2 += b; h2 = cast(int)tp2 & 0x3ffffff; b = ((tp2 >>> 26) & 0xffffffff);
189 		tp3 += b; h3 = cast(int)tp3 & 0x3ffffff; b = (tp3 >>> 26);
190 		tp4 += b; h4 = cast(int)tp4 & 0x3ffffff; b = (tp4 >>> 26);
191 		h0 += b * 5;
192 	}
193 
194 	public ubyte[macSize] finish() {
195 		ubyte[macSize] mac;
196 		finish(mac);
197 		return mac;
198 	}
199 
200 	public ubyte[] finish(ubyte[] output)
201 	in {
202 		assert(output.length >= blockSize, "Output buffer is too short.");
203 	}
204 	body {
205 		if (currentBlockOffset > 0)
206 		{
207 			// Process padded final block
208 			processBlock();
209 		}
210 		
211 		long f0, f1, f2, f3;
212 		
213 		int b = h0 >>> 26;
214 		h0 = h0 & 0x3ffffff;
215 		h1 += b; b = h1 >>> 26; h1 = h1 & 0x3ffffff;
216 		h2 += b; b = h2 >>> 26; h2 = h2 & 0x3ffffff;
217 		h3 += b; b = h3 >>> 26; h3 = h3 & 0x3ffffff;
218 		h4 += b; b = h4 >>> 26; h4 = h4 & 0x3ffffff;
219 		h0 += b * 5;
220 		
221 		int g0, g1, g2, g3, g4;
222 		g0 = h0 + 5; b = g0 >>> 26; g0 &= 0x3ffffff;
223 		g1 = h1 + b; b = g1 >>> 26; g1 &= 0x3ffffff;
224 		g2 = h2 + b; b = g2 >>> 26; g2 &= 0x3ffffff;
225 		g3 = h3 + b; b = g3 >>> 26; g3 &= 0x3ffffff;
226 		g4 = h4 + b - (1 << 26);
227 		
228 		b = (g4 >>> 31) - 1;
229 		int nb = ~b;
230 		h0 = (h0 & nb) | (g0 & b);
231 		h1 = (h1 & nb) | (g1 & b);
232 		h2 = (h2 & nb) | (g2 & b);
233 		h3 = (h3 & nb) | (g3 & b);
234 		h4 = (h4 & nb) | (g4 & b);
235 		
236 		f0 = (((h0       ) | (h1 << 26)) & 0xffffffffL) + (0xffffffffL & k0);
237 		f1 = (((h1 >>> 6 ) | (h2 << 20)) & 0xffffffffL) + (0xffffffffL & k1);
238 		f2 = (((h2 >>> 12) | (h3 << 14)) & 0xffffffffL) + (0xffffffffL & k2);
239 		f3 = (((h3 >>> 18) | (h4 << 8 )) & 0xffffffffL) + (0xffffffffL & k3);
240 
241 		toLittleEndian!int(cast(int)f0, output[0..4]);
242 		f1 += (f0 >>> 32);
243 		toLittleEndian!int(cast(int)f1, output[4..8]);
244 		f2 += (f1 >>> 32);
245 		toLittleEndian!int(cast(int)f2, output[8..12]);
246 		f3 += (f2 >>> 32);
247 		toLittleEndian!int(cast(int)f3, output[12..16]);
248 		
249 		reset();
250 		return output[0..blockSize];
251 	}
252 
253 	/// Resets the internal state such that a new MAC can be computed.
254 	public void reset()
255 	{
256 		currentBlockOffset = 0;
257 		
258 		h0 = h1 = h2 = h3 = h4 = 0;
259 	}
260 
261 	/// Returns: i1*i2 as long
262 	private long mul32x32_64(in int i1, in int i2) pure
263 	{
264 		return (cast(long)i1) * i2;
265 	}
266 
267 	/// Check if r has right format.
268 	private bool checkKey(in ubyte[] key) pure {
269 		assert(key.length == 16, "r must be 128 bits.");
270 
271 		bool checkMask(in ubyte b, in ubyte mask) pure
272 		{
273 			return (b & (~mask)) == 0;
274 		}
275 
276 		return 
277 			checkMask(key[3], rMaskHigh4) &&
278 				checkMask(key[7], rMaskHigh4) &&
279 				checkMask(key[11], rMaskHigh4) &&
280 				checkMask(key[15], rMaskHigh4) &&
281 				
282 				checkMask(key[4], rMaskLow2) &&
283 				checkMask(key[8], rMaskLow2) &&
284 				checkMask(key[12], rMaskLow2);
285 	}
286 
287 	/// Clears bits in key:
288 	/// Clears top four bits of bytes 3,7,11,15
289 	/// Clears bottom two bits of bytes 4,8,12
290 	/// 
291 	/// Params:
292 	/// key = Some bits of this key get cleared.
293 	private void clamp(ref ubyte[16] key)
294 	{
295 		// r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
296 		key[3] &= rMaskHigh4;
297 		key[7] &= rMaskHigh4;
298 		key[11] &= rMaskHigh4;
299 		key[15] &= rMaskHigh4;
300 
301 		// r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
302 		key[4] &= rMaskLow2;
303 		key[8] &= rMaskLow2;
304 		key[12] &= rMaskLow2;
305 	}
306 }
307 
308 
309 
310 // Raw Poly1305
311 // onetimeauth.c from nacl-20110221
312 unittest {
313 
314 	poly1305Test!(Poly1305!void)(
315 		x"eea6a7251c1e72916d11c2cb214d3c25 2539121d8e234e652d651fa4c8cff880",
316 		null,
317 		x"8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a
318                         c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738
319                         b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da
320                         99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
321 		x"f3ffc7703f9400e52a7dfb4b3d3305d9"
322 		);
323 	
324 }
325 
326 unittest {
327 	import dcrypt.crypto.engines.aes;
328 
329 	poly1305Test!(Poly1305!AES)(
330 		x"0000000000000000000000000000000000000000000000000000000000000000",
331 		x"00000000000000000000000000000000",
332 		x"",
333 		x"66e94bd4ef8a2c3b884cfa59ca342b2e"
334 		);
335 	
336 }
337 
338 unittest {
339 	import dcrypt.crypto.engines.aes;
340 	
341 	poly1305Test!(Poly1305!AES)(
342 		x"f795bd0a50e29e0710d3130a20e98d0c f795bd4a52e29ed713d313fa20e98dbc",
343 		x"917cf69ebd68b2ec9b9fe9a3eadda692",
344 		x"66f7",
345 		x"5ca585c75e8f8f025e710cabc9a1508b"
346 		);
347 	
348 }
349 
350 // Test vectors from RFC7539, A.3. #1
351 unittest {
352 	
353 	poly1305Test!(Poly1305!void)(
354 		x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
355 		null,
356 		x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
357 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
358 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
359 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
360 		x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
361 		);
362 	
363 }
364 
365 // Test vectors from RFC7539, A.3. #2
366 unittest {
367 	
368 	poly1305Test!(Poly1305!void)(
369 		x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e",
370 		null,
371 		longTestData0,
372 		x"36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e"
373 		);
374 	
375 }
376 
377 // Test vectors from RFC7539, A.3. #3
378 unittest {
379 	
380 	poly1305Test!(Poly1305!void)(
381 		x"36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
382 		null,
383 		longTestData0,
384 		x"f3 47 7e 7c d9 54 17 af 89 a6 b8 79 4c 31 0c f0"
385 		);
386 	
387 }
388 
389 // Test vectors from RFC7539, A.3. #4
390 unittest {
391 	
392 	poly1305Test!(Poly1305!void)(
393 		x"1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0",
394 		null,
395 		x"
396 		  27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61
397 		  6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f
398 		  76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64
399 		  20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77
400 		  61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77
401 		  65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65
402 		  73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20
403 		  72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e
404 		",
405 		x"45 41 66 9a 7e aa ee 61 e7 08 dc 7c bc c5 eb 62"
406 		);
407 	
408 }
409 
410 // Test vectors from RFC7539, A.3. #5
411 // If one uses 130-bit partial reduction, does the code handle the case where partially reduced final result is not fully reduced?
412 unittest {
413 	
414 	poly1305Test!(Poly1305!void)(
415 		x"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
416 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
417 		null,
418 		x"
419 		  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
420 		",
421 		x"03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
422 		);
423 	
424 }
425 
426 // Test vectors from RFC7539, A.3. #6
427 // What happens if addition of s overflows modulo 2^128?
428 unittest {
429 	
430 	poly1305Test!(Poly1305!void)(
431 		x"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
432 		FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
433 		null,
434 		x"
435 		  02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
436 		",
437 		x"03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
438 		);
439 	
440 }
441 
442 // Test vectors from RFC7539, A.3. #7
443 // What happens if data limb is all ones and there is carry from lower limb?
444 unittest {
445 	
446 	poly1305Test!(Poly1305!void)(
447 		x"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
448 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
449 		null,
450 		x"
451 			FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
452 			F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
453 			11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
454 		",
455 		x"05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
456 		);
457 	
458 }
459 
460 // Test vectors from RFC7539, A.3. #8
461 // What happens if final result from polynomial part is exactly 2^130-5?
462 unittest {
463 	
464 	poly1305Test!(Poly1305!void)(
465 		x"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
466 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
467 		null,
468 		x"
469 			FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
470 			FB FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE
471 			01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
472 		",
473 		x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
474 		);
475 	
476 }
477 
478 // Test vectors from RFC7539, A.3. #9
479 // What happens if final result from polynomial part is exactly 2^130-6?
480 unittest {
481 	
482 	poly1305Test!(Poly1305!void)(
483 		x"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
484 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
485 		null,
486 		x"
487 		  FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
488 		",
489 		x"FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF"
490 		);
491 	
492 }
493 
494 // Test vectors from RFC7539, A.3. #10
495 // What happens if 5*H+L-type reduction produces 131-bit intermediate result?
496 unittest {
497 	
498 	poly1305Test!(Poly1305!void)(
499 		x"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
500 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
501 		null,
502 		x"
503 			E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00
504 			33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00
505 			00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
506 			01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
507 		",
508 		x"14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00"
509 		);
510 	
511 }
512 
513 // Test vectors from RFC7539, A.3. #11
514 // What happens if 5*H+L-type reduction produces131-bit final result?
515 unittest {
516 	
517 	poly1305Test!(Poly1305!void)(
518 		x"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
519 		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
520 		null,
521 		x"
522 			E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00
523 			33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00
524 			00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
525 		",
526 		x"13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
527 		);
528 	
529 }
530 
531 version(unittest) {
532 	// Helper function for unittests.
533 private:
534 
535 	void poly1305Test(P)(string key, string iv, string data, string expectedMac) {
536 
537 		alias const(ubyte[]) octets;
538 
539 		P poly;
540 		poly.start(cast(octets) key, cast(octets) iv);
541 		poly.put(cast(octets) data);
542 
543 		assert(poly.finish() == expectedMac, "Poly1305 failed!");
544 		
545 	}
546 
547 	enum longTestData0 = x"
548 		  41 6e 79 20 73 75 62 6d 69 73 73 69 6f 6e 20 74
549 		  6f 20 74 68 65 20 49 45 54 46 20 69 6e 74 65 6e
550 		  64 65 64 20 62 79 20 74 68 65 20 43 6f 6e 74 72
551 		  69 62 75 74 6f 72 20 66 6f 72 20 70 75 62 6c 69
552 		  63 61 74 69 6f 6e 20 61 73 20 61 6c 6c 20 6f 72
553 		  20 70 61 72 74 20 6f 66 20 61 6e 20 49 45 54 46
554 		  20 49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 20
555 		  6f 72 20 52 46 43 20 61 6e 64 20 61 6e 79 20 73
556 		  74 61 74 65 6d 65 6e 74 20 6d 61 64 65 20 77 69
557 		  74 68 69 6e 20 74 68 65 20 63 6f 6e 74 65 78 74
558 		  20 6f 66 20 61 6e 20 49 45 54 46 20 61 63 74 69
559 		  76 69 74 79 20 69 73 20 63 6f 6e 73 69 64 65 72
560 		  65 64 20 61 6e 20 22 49 45 54 46 20 43 6f 6e 74
561 		  72 69 62 75 74 69 6f 6e 22 2e 20 53 75 63 68 20
562 		  73 74 61 74 65 6d 65 6e 74 73 20 69 6e 63 6c 75
563 		  64 65 20 6f 72 61 6c 20 73 74 61 74 65 6d 65 6e
564 		  74 73 20 69 6e 20 49 45 54 46 20 73 65 73 73 69
565 		  6f 6e 73 2c 20 61 73 20 77 65 6c 6c 20 61 73 20
566 		  77 72 69 74 74 65 6e 20 61 6e 64 20 65 6c 65 63
567 		  74 72 6f 6e 69 63 20 63 6f 6d 6d 75 6e 69 63 61
568 		  74 69 6f 6e 73 20 6d 61 64 65 20 61 74 20 61 6e
569 		  79 20 74 69 6d 65 20 6f 72 20 70 6c 61 63 65 2c
570 		  20 77 68 69 63 68 20 61 72 65 20 61 64 64 72 65
571 		  73 73 65 64 20 74 6f
572 		";
573 }