← Documents Documentation/crypto/descore-readme.rst GitHub 원문 ↗

Linux 6.18.37 · Crypto

Fast & Portable DES Encryption & Decryption

1992년 desCore README의 라이선스, 성능 비교, 이식·최적화·coding 가정, bit 배치, routine 사용법과 Kerberos 호환 interface를 번역합니다.

Source pathDocumentation/crypto/descore-readme.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

descore-readme.rst:1-414

이 문서는 현재 Crypto API 설계 문서라기보다 Linux source에 포함된 역사적 `descore.shar` README입니다. 1992년 당시 SPARC·68000·i386 환경에서 DES 성능과 table·register tradeoff를 기록합니다.

기술적으로는 byte-order 독립성, 32-bit `word` 가정, S-box 두 개를 한 lookup으로 처리하는 bit 배치, Small·Quick 및 Fips·Core variant, 768-bit 내부 key 형식이 핵심입니다. 시대적이고 주관적인 성능 평가는 원문의 관점임을 유지해 번역했으며 수치·함수명·source path를 보존했습니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2 .. include:: <isonum.txt>
3
4 ===========================================
5 Fast & Portable DES encryption & decryption
6 ===========================================
7
8 .. note::
9
10 Below is the original README file from the descore.shar package,
11 converted to ReST format.
12
13 ------------------------------------------------------------------------------
14
15 des - fast & portable DES encryption & decryption.
16
17 Copyright |copy| 1992 Dana L. How
18
19 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU Library General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU Library General Public License for more details.
28
29 You should have received a copy of the GNU Library General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32
33 Author's address: how@isl.stanford.edu
34
35 .. README,v 1.15 1992/05/20 00:25:32 how E
36
37 ==>> To compile after untarring/unsharring, just ``make`` <<==
38
39 This package was designed with the following goals:
40
41 1. Highest possible encryption/decryption PERFORMANCE.
42 2. PORTABILITY to any byte-addressable host with a 32bit unsigned C type
43 3. Plug-compatible replacement for KERBEROS's low-level routines.
44
45 This second release includes a number of performance enhancements for
46 register-starved machines. My discussions with Richard Outerbridge,
47 71755.204@compuserve.com, sparked a number of these enhancements.
48
49 To more rapidly understand the code in this package, inspect desSmallFips.i
50 (created by typing ``make``) BEFORE you tackle desCode.h. The latter is set
51 up in a parameterized fashion so it can easily be modified by speed-daemon
52 hackers in pursuit of that last microsecond. You will find it more
53 illuminating to inspect one specific implementation,
54 and then move on to the common abstract skeleton with this one in mind.
55
56
57 performance comparison to other available des code which i could
58 compile on a SPARCStation 1 (cc -O4, gcc -O2):
59
60 this code (byte-order independent):
61
62 - 30us per encryption (options: 64k tables, no IP/FP)
63 - 33us per encryption (options: 64k tables, FIPS standard bit ordering)
64 - 45us per encryption (options: 2k tables, no IP/FP)
65 - 48us per encryption (options: 2k tables, FIPS standard bit ordering)
66 - 275us to set a new key (uses 1k of key tables)
67
68 this has the quickest encryption/decryption routines i've seen.
69 since i was interested in fast des filters rather than crypt(3)
70 and password cracking, i haven't really bothered yet to speed up
71 the key setting routine. also, i have no interest in re-implementing
72 all the other junk in the mit kerberos des library, so i've just
73 provided my routines with little stub interfaces so they can be
74 used as drop-in replacements with mit's code or any of the mit-
75 compatible packages below. (note that the first two timings above
76 are highly variable because of cache effects).
77
78 kerberos des replacement from australia (version 1.95):
79
80 - 53us per encryption (uses 2k of tables)
81 - 96us to set a new key (uses 2.25k of key tables)
82
83 so despite the author's inclusion of some of the performance
84 improvements i had suggested to him, this package's
85 encryption/decryption is still slower on the sparc and 68000.
86 more specifically, 19-40% slower on the 68020 and 11-35% slower
87 on the sparc, depending on the compiler;
88 in full gory detail (ALT_ECB is a libdes variant):
89
90 =============== ============== =============== =================
91 compiler machine desCore libdes ALT_ECB slower by
92 =============== ============== =============== =================
93 gcc 2.1 -O2 Sun 3/110 304 uS 369.5uS 461.8uS 22%
94 cc -O1 Sun 3/110 336 uS 436.6uS 399.3uS 19%
95 cc -O2 Sun 3/110 360 uS 532.4uS 505.1uS 40%
96 cc -O4 Sun 3/110 365 uS 532.3uS 505.3uS 38%
97 gcc 2.1 -O2 Sun 4/50 48 uS 53.4uS 57.5uS 11%
98 cc -O2 Sun 4/50 48 uS 64.6uS 64.7uS 35%
99 cc -O4 Sun 4/50 48 uS 64.7uS 64.9uS 35%
100 =============== ============== =============== =================
101
102 (my time measurements are not as accurate as his).
103
104 the comments in my first release of desCore on version 1.92:
105
106 - 68us per encryption (uses 2k of tables)
107 - 96us to set a new key (uses 2.25k of key tables)
108
109 this is a very nice package which implements the most important
110 of the optimizations which i did in my encryption routines.
111 it's a bit weak on common low-level optimizations which is why
112 it's 39%-106% slower. because he was interested in fast crypt(3) and
113 password-cracking applications, he also used the same ideas to
114 speed up the key-setting routines with impressive results.
115 (at some point i may do the same in my package). he also implements
116 the rest of the mit des library.
117
118 (code from eay@psych.psy.uq.oz.au via comp.sources.misc)
119
120 fast crypt(3) package from denmark:
121
122 the des routine here is buried inside a loop to do the
123 crypt function and i didn't feel like ripping it out and measuring
124 performance. his code takes 26 sparc instructions to compute one
125 des iteration; above, Quick (64k) takes 21 and Small (2k) takes 37.
126 he claims to use 280k of tables but the iteration calculation seems
127 to use only 128k. his tables and code are machine independent.
128
129 (code from glad@daimi.aau.dk via alt.sources or comp.sources.misc)
130
131 swedish reimplementation of Kerberos des library
132
133 - 108us per encryption (uses 34k worth of tables)
134 - 134us to set a new key (uses 32k of key tables to get this speed!)
135
136 the tables used seem to be machine-independent;
137 he seems to have included a lot of special case code
138 so that, e.g., ``long`` loads can be used instead of 4 ``char`` loads
139 when the machine's architecture allows it.
140
141 (code obtained from chalmers.se:pub/des)
142
143 crack 3.3c package from england:
144
145 as in crypt above, the des routine is buried in a loop. it's
146 also very modified for crypt. his iteration code uses 16k
147 of tables and appears to be slow.
148
149 (code obtained from aem@aber.ac.uk via alt.sources or comp.sources.misc)
150
151 ``highly optimized`` and tweaked Kerberos/Athena code (byte-order dependent):
152
153 - 165us per encryption (uses 6k worth of tables)
154 - 478us to set a new key (uses <1k of key tables)
155
156 so despite the comments in this code, it was possible to get
157 faster code AND smaller tables, as well as making the tables
158 machine-independent.
159 (code obtained from prep.ai.mit.edu)
160
161 UC Berkeley code (depends on machine-endedness):
162 - 226us per encryption
163 - 10848us to set a new key
164
165 table sizes are unclear, but they don't look very small
166 (code obtained from wuarchive.wustl.edu)
167
168
169 motivation and history
170 ======================
171
172 a while ago i wanted some des routines and the routines documented on sun's
173 man pages either didn't exist or dumped core. i had heard of kerberos,
174 and knew that it used des, so i figured i'd use its routines. but once
175 i got it and looked at the code, it really set off a lot of pet peeves -
176 it was too convoluted, the code had been written without taking
177 advantage of the regular structure of operations such as IP, E, and FP
178 (i.e. the author didn't sit down and think before coding),
179 it was excessively slow, the author had attempted to clarify the code
180 by adding MORE statements to make the data movement more ``consistent``
181 instead of simplifying his implementation and cutting down on all data
182 movement (in particular, his use of L1, R1, L2, R2), and it was full of
183 idiotic ``tweaks`` for particular machines which failed to deliver significant
184 speedups but which did obfuscate everything. so i took the test data
185 from his verification program and rewrote everything else.
186
187 a while later i ran across the great crypt(3) package mentioned above.
188 the fact that this guy was computing 2 sboxes per table lookup rather
189 than one (and using a MUCH larger table in the process) emboldened me to
190 do the same - it was a trivial change from which i had been scared away
191 by the larger table size. in his case he didn't realize you don't need to keep
192 the working data in TWO forms, one for easy use of half the sboxes in
193 indexing, the other for easy use of the other half; instead you can keep
194 it in the form for the first half and use a simple rotate to get the other
195 half. this means i have (almost) half the data manipulation and half
196 the table size. in fairness though he might be encoding something particular
197 to crypt(3) in his tables - i didn't check.
198
199 i'm glad that i implemented it the way i did, because this C version is
200 portable (the ifdef's are performance enhancements) and it is faster
201 than versions hand-written in assembly for the sparc!
202
203
204 porting notes
205 =============
206
207 one thing i did not want to do was write an enormous mess
208 which depended on endedness and other machine quirks,
209 and which necessarily produced different code and different lookup tables
210 for different machines. see the kerberos code for an example
211 of what i didn't want to do; all their endedness-specific ``optimizations``
212 obfuscate the code and in the end were slower than a simpler machine
213 independent approach. however, there are always some portability
214 considerations of some kind, and i have included some options
215 for varying numbers of register variables.
216 perhaps some will still regard the result as a mess!
217
218 1) i assume everything is byte addressable, although i don't actually
219 depend on the byte order, and that bytes are 8 bits.
220 i assume word pointers can be freely cast to and from char pointers.
221 note that 99% of C programs make these assumptions.
222 i always use unsigned char's if the high bit could be set.
223 2) the typedef ``word`` means a 32 bit unsigned integral type.
224 if ``unsigned long`` is not 32 bits, change the typedef in desCore.h.
225 i assume sizeof(word) == 4 EVERYWHERE.
226
227 the (worst-case) cost of my NOT doing endedness-specific optimizations
228 in the data loading and storing code surrounding the key iterations
229 is less than 12%. also, there is the added benefit that
230 the input and output work areas do not need to be word-aligned.
231
232
233 OPTIONAL performance optimizations
234 ==================================
235
236 1) you should define one of ``i386,`` ``vax,`` ``mc68000,`` or ``sparc,``
237 whichever one is closest to the capabilities of your machine.
238 see the start of desCode.h to see exactly what this selection implies.
239 note that if you select the wrong one, the des code will still work;
240 these are just performance tweaks.
241 2) for those with functional ``asm`` keywords: you should change the
242 ROR and ROL macros to use machine rotate instructions if you have them.
243 this will save 2 instructions and a temporary per use,
244 or about 32 to 40 instructions per en/decryption.
245
246 note that gcc is smart enough to translate the ROL/R macros into
247 machine rotates!
248
249 these optimizations are all rather persnickety, yet with them you should
250 be able to get performance equal to assembly-coding, except that:
251
252 1) with the lack of a bit rotate operator in C, rotates have to be synthesized
253 from shifts. so access to ``asm`` will speed things up if your machine
254 has rotates, as explained above in (3) (not necessary if you use gcc).
255 2) if your machine has less than 12 32-bit registers i doubt your compiler will
256 generate good code.
257
258 ``i386`` tries to configure the code for a 386 by only declaring 3 registers
259 (it appears that gcc can use ebx, esi and edi to hold register variables).
260 however, if you like assembly coding, the 386 does have 7 32-bit registers,
261 and if you use ALL of them, use ``scaled by 8`` address modes with displacement
262 and other tricks, you can get reasonable routines for DesQuickCore... with
263 about 250 instructions apiece. For DesSmall... it will help to rearrange
264 des_keymap, i.e., now the sbox # is the high part of the index and
265 the 6 bits of data is the low part; it helps to exchange these.
266
267 since i have no way to conveniently test it i have not provided my
268 shoehorned 386 version. note that with this release of desCore, gcc is able
269 to put everything in registers(!), and generate about 370 instructions apiece
270 for the DesQuickCore... routines!
271
272 coding notes
273 ============
274
275 the en/decryption routines each use 6 necessary register variables,
276 with 4 being actively used at once during the inner iterations.
277 if you don't have 4 register variables get a new machine.
278 up to 8 more registers are used to hold constants in some configurations.
279
280 i assume that the use of a constant is more expensive than using a register:
281
282 a) additionally, i have tried to put the larger constants in registers.
283 registering priority was by the following:
284
285 - anything more than 12 bits (bad for RISC and CISC)
286 - greater than 127 in value (can't use movq or byte immediate on CISC)
287 - 9-127 (may not be able to use CISC shift immediate or add/sub quick),
288 - 1-8 were never registered, being the cheapest constants.
289
290 b) the compiler may be too stupid to realize table and table+256 should
291 be assigned to different constant registers and instead repetitively
292 do the arithmetic, so i assign these to explicit ``m`` register variables
293 when possible and helpful.
294
295 i assume that indexing is cheaper or equivalent to auto increment/decrement,
296 where the index is 7 bits unsigned or smaller.
297 this assumption is reversed for 68k and vax.
298
299 i assume that addresses can be cheaply formed from two registers,
300 or from a register and a small constant.
301 for the 68000, the ``two registers and small offset`` form is used sparingly.
302 all index scaling is done explicitly - no hidden shifts by log2(sizeof).
303
304 the code is written so that even a dumb compiler
305 should never need more than one hidden temporary,
306 increasing the chance that everything will fit in the registers.
307 KEEP THIS MORE SUBTLE POINT IN MIND IF YOU REWRITE ANYTHING.
308
309 (actually, there are some code fragments now which do require two temps,
310 but fixing it would either break the structure of the macros or
311 require declaring another temporary).
312
313
314 special efficient data format
315 ==============================
316
317 bits are manipulated in this arrangement most of the time (S7 S5 S3 S1)::
318
319 003130292827xxxx242322212019xxxx161514131211xxxx080706050403xxxx
320
321 (the x bits are still there, i'm just emphasizing where the S boxes are).
322 bits are rotated left 4 when computing S6 S4 S2 S0::
323
324 282726252423xxxx201918171615xxxx121110090807xxxx040302010031xxxx
325
326 the rightmost two bits are usually cleared so the lower byte can be used
327 as an index into an sbox mapping table. the next two x'd bits are set
328 to various values to access different parts of the tables.
329
330
331 how to use the routines
332
333 datatypes:
334 pointer to 8 byte area of type DesData
335 used to hold keys and input/output blocks to des.
336
337 pointer to 128 byte area of type DesKeys
338 used to hold full 768-bit key.
339 must be long-aligned.
340
341 DesQuickInit()
342 call this before using any other routine with ``Quick`` in its name.
343 it generates the special 64k table these routines need.
344 DesQuickDone()
345 frees this table
346
347 DesMethod(m, k)
348 m points to a 128byte block, k points to an 8 byte des key
349 which must have odd parity (or -1 is returned) and which must
350 not be a (semi-)weak key (or -2 is returned).
351 normally DesMethod() returns 0.
352
353 m is filled in from k so that when one of the routines below
354 is called with m, the routine will act like standard des
355 en/decryption with the key k. if you use DesMethod,
356 you supply a standard 56bit key; however, if you fill in
357 m yourself, you will get a 768bit key - but then it won't
358 be standard. it's 768bits not 1024 because the least significant
359 two bits of each byte are not used. note that these two bits
360 will be set to magic constants which speed up the encryption/decryption
361 on some machines. and yes, each byte controls
362 a specific sbox during a specific iteration.
363
364 you really shouldn't use the 768bit format directly; i should
365 provide a routine that converts 128 6-bit bytes (specified in
366 S-box mapping order or something) into the right format for you.
367 this would entail some byte concatenation and rotation.
368
369 Des{Small|Quick}{Fips|Core}{Encrypt|Decrypt}(d, m, s)
370 performs des on the 8 bytes at s into the 8 bytes at
371 ``d. (d,s: char *)``.
372
373 uses m as a 768bit key as explained above.
374
375 the Encrypt|Decrypt choice is obvious.
376
377 Fips|Core determines whether a completely standard FIPS initial
378 and final permutation is done; if not, then the data is loaded
379 and stored in a nonstandard bit order (FIPS w/o IP/FP).
380
381 Fips slows down Quick by 10%, Small by 9%.
382
383 Small|Quick determines whether you use the normal routine
384 or the crazy quick one which gobbles up 64k more of memory.
385 Small is 50% slower then Quick, but Quick needs 32 times as much
386 memory. Quick is included for programs that do nothing but DES,
387 e.g., encryption filters, etc.
388
389
390 Getting it to compile on your machine
391 =====================================
392
393 there are no machine-dependencies in the code (see porting),
394 except perhaps the ``now()`` macro in desTest.c.
395 ALL generated tables are machine independent.
396 you should edit the Makefile with the appropriate optimization flags
397 for your compiler (MAX optimization).
398
399
400 Speeding up kerberos (and/or its des library)
401 =============================================
402
403 note that i have included a kerberos-compatible interface in desUtil.c
404 through the functions des_key_sched() and des_ecb_encrypt().
405 to use these with kerberos or kerberos-compatible code put desCore.a
406 ahead of the kerberos-compatible library on your linker's command line.
407 you should not need to #include desCore.h; just include the header
408 file provided with the kerberos library.
409
410 Other uses
411 ==========
412
413 the macros in desCode.h would be very useful for putting inline des
414 functions in more complicated encryption routines.
415

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

빠르고 이식 가능한 DES 암호화·복호화

1-56

SPDX 라이선스 식별자: `GPL-2.0`

빠르고 이식 가능한 DES 암호화·복호화

아래 내용은 `descore.shar` package의 원본 README를 ReST 형식으로 변환한 것입니다.

`des`: 빠르고 이식 가능한 DES 암호화·복호화

Copyright © 1992 Dana L. How

이 프로그램은 자유 software입니다. Free Software Foundation이 공표한 GNU Library General Public License version 2 또는 선택에 따라 그 이후 version의 조건에 따라 재배포하거나 수정할 수 있습니다.

이 프로그램은 유용하기를 바라며 배포하지만 어떠한 보증도 하지 않습니다. 상품성 또는 특정 목적 적합성에 대한 묵시적 보증도 없습니다. 자세한 내용은 GNU Library General Public License를 참조하십시오.

이 프로그램과 함께 GNU Library General Public License 사본을 받았어야 합니다. 받지 못했다면 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA로 문의하십시오.

저자 주소: `how@isl.stanford.edu`

README revision: `1.15 1992/05/20 00:25:32 how E`

Archive를 푼 뒤 compile하려면 `make`만 실행하면 됩니다.

이 package의 설계 목표는 다음과 같습니다.

  • 1. 가능한 최고의 암호화·복호화 성능
  • 2. 32-bit unsigned C type을 갖고 byte 단위 주소 지정이 가능한 모든 host로의 이식성
  • 3. KERBEROS 저수준 routine과 plug-compatible한 대체 구현

두 번째 release에는 register가 부족한 machine을 위한 여러 성능 개선이 포함되었습니다. Richard Outerbridge(`71755.204@compuserve.com`)와의 논의가 이러한 개선 중 여러 가지의 계기가 되었습니다.

Code를 더 빨리 이해하려면 `desCode.h`보다 먼저 `make`로 생성되는 `desSmallFips.i`를 살펴보십시오. `desCode.h`는 마지막 microsecond까지 줄이려는 개발자가 쉽게 수정할 수 있도록 parameter화되어 있습니다. 구체적인 구현 하나를 먼저 본 다음 이를 염두에 두고 공통 추상 골격으로 넘어가는 편이 이해하기 쉽습니다.

SPARCStation 1에서의 자체 성능

57-77

SPARCStation 1에서 compile할 수 있었던 다른 DES code와의 성능 비교입니다. Compiler option은 `cc -O4`, `gcc -O2`입니다.

이 code는 byte order에 독립적이며 측정값은 다음과 같습니다.

  • 암호화당 30 µs: 64K table, IP/FP 없음
  • 암호화당 33 µs: 64K table, FIPS 표준 bit ordering
  • 암호화당 45 µs: 2K table, IP/FP 없음
  • 암호화당 48 µs: 2K table, FIPS 표준 bit ordering
  • 새 키 설정 275 µs: 1K key table 사용

저자는 이것이 자신이 본 가장 빠른 암호화·복호화 routine이라고 설명합니다. 관심 대상이 `crypt(3)`나 password cracking이 아니라 빠른 DES filter였으므로 key 설정 routine 최적화는 아직 하지 않았습니다. MIT Kerberos DES library의 나머지를 다시 구현하는 대신 작은 stub interface를 제공하여 MIT code나 아래의 MIT 호환 package에 drop-in replacement로 쓸 수 있게 했습니다. 앞의 두 측정은 cache 영향으로 변동이 큽니다.

호주 Kerberos DES 대체 구현

78-119

호주에서 만든 Kerberos DES 대체 구현 version 1.95의 측정값입니다.

  • 암호화당 53 µs: 2K table 사용
  • 새 키 설정 96 µs: 2.25K key table 사용

저자가 제안했던 성능 개선 일부가 포함되었지만 이 package의 암호화·복호화는 SPARC와 68000에서 여전히 더 느렸습니다. Compiler에 따라 68020에서 19~40%, SPARC에서 11~35% 느렸습니다. `ALT_ECB`는 libdes variant입니다.

CompilerMachinedesCorelibdesALT_ECB느린 비율
gcc 2.1 -O2Sun 3/110304 µs369.5 µs461.8 µs22%
cc -O1Sun 3/110336 µs436.6 µs399.3 µs19%
cc -O2Sun 3/110360 µs532.4 µs505.1 µs40%
cc -O4Sun 3/110365 µs532.3 µs505.3 µs38%
gcc 2.1 -O2Sun 4/5048 µs53.4 µs57.5 µs11%
cc -O2Sun 4/5048 µs64.6 µs64.7 µs35%
cc -O4Sun 4/5048 µs64.7 µs64.9 µs35%

저자는 자신의 시간 측정이 상대 저자의 측정보다 정확하지 않다고 덧붙입니다.

desCore 첫 release에서 version 1.92에 관해 남긴 측정은 다음과 같습니다.

  • 암호화당 68 µs: 2K table 사용
  • 새 키 설정 96 µs: 2.25K key table 사용

이 package는 저자의 암호화 routine에서 가장 중요한 최적화를 구현했지만 일반적인 저수준 최적화가 다소 약해 39~106% 느렸습니다. 반면 빠른 `crypt(3)`와 password cracking을 목표로 같은 아이디어를 key 설정에 적용하여 인상적인 결과를 냈고 MIT DES library의 나머지도 구현했습니다.

출처: `eay@psych.psy.uq.oz.au`, `comp.sources.misc` 경유

덴마크의 빠른 crypt(3) package

120-130

이 package의 DES routine은 `crypt` 함수 loop 안에 들어 있어 저자는 분리해 성능을 측정하지 않았습니다. 한 DES iteration에 SPARC instruction 26개를 사용합니다. 위 Quick(64K)은 21개, Small(2K)은 37개를 사용합니다.

저자는 상대 구현이 280K table을 사용한다고 주장했지만 iteration 계산은 128K만 사용하는 것으로 보였습니다. Table과 code는 machine 독립적입니다.

출처: `glad@daimi.aau.dk`, `alt.sources` 또는 `comp.sources.misc` 경유

스웨덴 Kerberos DES library 재구현

131-142
  • 암호화당 108 µs: 34K table 사용
  • 새 키 설정 134 µs: 이 속도를 위해 32K key table 사용

사용한 table은 machine 독립적으로 보입니다. Machine architecture가 허용하면 `long` load 하나를 `char` load 네 개 대신 사용하는 등 특수 case code가 많이 포함된 것으로 보입니다.

출처: `chalmers.se:pub/des`

영국 crack 3.3c package

143-150

앞의 `crypt`와 마찬가지로 DES routine이 loop 안에 들어 있고 `crypt` 용도로 크게 수정되어 있습니다. Iteration code는 16K table을 사용하며 느린 것으로 보입니다.

출처: `aem@aber.ac.uk`, `alt.sources` 또는 `comp.sources.misc` 경유

최적화된 Kerberos·Athena code

151-160

이 구현은 byte order에 의존하는 이른바 `highly optimized` Kerberos·Athena code입니다.

  • 암호화당 165 µs: 6K table 사용
  • 새 키 설정 478 µs: 1K 미만의 key table 사용

Code의 설명과 달리 table을 machine 독립적으로 만들면서도 더 빠른 code와 더 작은 table을 얻을 수 있었습니다.

출처: `prep.ai.mit.edu`

UC Berkeley code

161-168

이 구현은 machine endian 특성에 의존합니다.

  • 암호화당 226 µs
  • 새 키 설정 10,848 µs

Table 크기는 분명하지 않지만 작아 보이지 않습니다. 출처: `wuarchive.wustl.edu`.

동기와 역사

169-203

동기와 역사

저자는 DES routine이 필요했지만 Sun manual page에 문서화된 routine은 존재하지 않거나 core dump를 냈다고 설명합니다. Kerberos가 DES를 사용한다는 말을 듣고 그 routine을 쓰려 했으나 code가 지나치게 복잡하고 IP, E, FP 같은 연산의 규칙적인 구조를 활용하지 않았으며 매우 느렸다고 평가했습니다.

또한 기존 구현은 data 이동을 줄이고 단순화하는 대신 L1, R1, L2, R2 등을 사용해 data 이동을 더 일관되게 보이게 하려고 statement를 늘렸고, 성능 향상 없이 code만 흐리는 machine별 tweak가 많았다고 비판합니다. 그래서 검증 program의 test data만 가져오고 나머지를 다시 작성했습니다.

나중에 앞서 언급한 `crypt(3)` package가 table lookup 한 번에 S-box 두 개를 계산하는 것을 보고 같은 방식을 채택했습니다. 상대 구현은 절반의 S-box indexing에 편한 형태와 나머지 절반에 편한 형태 두 가지로 working data를 유지했지만, 저자는 첫 절반에 맞는 형태 하나만 유지하고 간단한 rotate로 다른 절반을 얻었습니다.

그 결과 data 조작과 table 크기를 거의 절반으로 줄였습니다. 다만 상대 table이 `crypt(3)` 전용 정보를 encoding했을 가능성은 확인하지 않았습니다.

저자는 이 C version이 이식 가능하고 `ifdef`는 성능 개선에만 쓰이며, SPARC용 hand-written assembly version보다 빠르다는 점을 장점으로 듭니다.

Porting 참고 사항

204-232

Porting 참고 사항

저자는 endian 특성과 다른 machine 특성에 의존하여 machine마다 다른 code와 lookup table을 만드는 거대한 구현을 피하려 했습니다. Kerberos의 endian별 최적화는 code를 흐리면서 더 단순한 machine 독립적 방식보다 느렸다고 평가합니다. 다만 이식성 고려는 필요하므로 register variable 수를 달리하는 option을 포함했습니다.

  • 1. 모든 대상은 byte 단위 주소 지정이 가능하고 byte는 8-bit라고 가정합니다. Byte order에는 의존하지 않습니다. Word pointer와 char pointer를 자유롭게 cast할 수 있다고 가정하며 high bit가 설정될 수 있으면 항상 `unsigned char`를 사용합니다.
  • 2. Typedef `word`는 32-bit unsigned integral type을 뜻합니다. `unsigned long`이 32-bit가 아니면 `desCore.h`의 typedef를 바꿔야 하며 모든 곳에서 `sizeof(word) == 4`를 가정합니다.

Key iteration 주변의 data load·store code에 endian별 최적화를 하지 않은 최악의 비용은 12% 미만입니다. 대신 input과 output 작업 영역을 word alignment에 맞출 필요가 없습니다.

선택적 성능 최적화

233-271

선택적 성능 최적화

  • 1. Machine capability와 가장 가까운 `i386`, `vax`, `mc68000`, `sparc` 중 하나를 정의하십시오. 정확한 효과는 `desCode.h` 시작 부분에 있습니다. 잘못 선택해도 DES code는 동작하며 이는 성능 tweak일 뿐입니다.
  • 2. 기능하는 `asm` keyword가 있다면 ROR·ROL macro를 machine rotate instruction으로 바꾸십시오. 사용할 때마다 instruction 두 개와 temporary 하나, 즉 암호화·복호화당 약 32~40 instruction을 줄입니다.

GCC는 ROL/R macro를 machine rotate로 변환할 만큼 영리하다고 설명합니다.

이 최적화를 사용하면 assembly code와 비슷한 성능을 얻을 수 있지만 예외가 있습니다.

  • 1. C에는 bit rotate operator가 없어 shift로 합성해야 합니다. Machine이 rotate를 지원하면 `asm` 접근이 빠르며 GCC 사용 시에는 필요하지 않습니다.
  • 2. Machine에 32-bit register가 12개 미만이면 compiler가 좋은 code를 생성하기 어려울 수 있습니다.

`i386` 설정은 register variable을 세 개만 선언하여 386에 맞춥니다. GCC는 `ebx`, `esi`, `edi`를 사용할 수 있는 것으로 보입니다. 386의 32-bit register 일곱 개를 모두 쓰고 displacement가 있는 `scaled by 8` address mode 등을 활용하면 `DesQuickCore` routine을 각각 약 250 instruction으로 구현할 수 있습니다.

`DesSmall`에는 `des_keymap`을 재배열하여 S-box 번호를 index의 상위 부분, 6-bit data를 하위 부분에 두는 현재 배치를 서로 바꾸는 것이 도움이 됩니다.

저자는 편리하게 시험할 방법이 없어 386 전용 version을 제공하지 않았습니다. 이 desCore release에서 GCC는 모든 것을 register에 넣고 `DesQuickCore` routine당 약 370 instruction을 생성할 수 있었습니다.

Coding 참고 사항

272-313

Coding 참고 사항

암호화·복호화 routine은 각각 필수 register variable 여섯 개를 사용하며 inner iteration 중 네 개를 동시에 사용합니다. 일부 설정에서는 constant 보관에 register를 최대 여덟 개 더 사용합니다.

저자는 constant 사용이 register 사용보다 비싸다고 가정합니다.

큰 constant를 register에 넣는 우선순위는 다음과 같습니다.

  • 12-bit보다 큰 값: RISC와 CISC 모두에 불리함
  • 127보다 큰 값: CISC에서 `movq` 또는 byte immediate를 사용할 수 없음
  • 9~127: CISC shift immediate 또는 add/sub quick을 쓰지 못할 수 있음
  • 1~8: 가장 저렴하므로 register에 넣지 않음

Compiler가 `table`과 `table+256`을 서로 다른 constant register에 할당해야 한다는 점을 알아채지 못하고 산술을 반복할 수 있으므로, 가능하고 유용할 때 이를 명시적인 `m` register variable에 할당합니다.

7-bit unsigned 이하 index에서는 indexing이 auto increment·decrement보다 저렴하거나 같다고 가정합니다. 68K와 VAX에서는 이 가정을 반대로 적용합니다.

Address는 register 두 개 또는 register 하나와 작은 constant로 저렴하게 만들 수 있다고 가정합니다. 68000에서는 `two registers and small offset` 형식을 제한적으로 사용합니다. 모든 index scaling은 명시적으로 수행하며 `log2(sizeof)`에 해당하는 숨은 shift는 없습니다.

단순한 compiler도 hidden temporary를 하나보다 많이 필요로 하지 않도록 code를 작성하여 모든 값이 register에 들어갈 가능성을 높였습니다. 다시 작성할 때 이 미묘한 점을 기억해야 합니다.

현재 temporary 두 개가 필요한 code fragment도 있지만 이를 고치면 macro 구조가 깨지거나 temporary를 하나 더 선언해야 합니다.

특수 고효율 data 형식

314-330

특수 고효율 data 형식

대부분의 경우 bit는 S7 S5 S3 S1 순서를 위한 다음 배치로 조작됩니다.

DES S-box bit 배치
용도Bit arrangement
S7 S5 S3 S1003130292827xxxx242322212019xxxx161514131211xxxx080706050403xxxx
S6 S4 S2 S0282726252423xxxx201918171615xxxx121110090807xxxx040302010031xxxx

`x` bit도 실제로 존재하며 S-box 위치를 강조한 표현입니다. S6 S4 S2 S0 계산 때는 4-bit left rotate를 적용합니다.

오른쪽 끝 두 bit는 보통 clear하여 하위 byte를 S-box mapping table index로 사용할 수 있게 합니다. 그다음 두 `x` bit에는 table의 다른 부분에 접근하기 위한 여러 값을 설정합니다.

Routine 사용법

331-389

Routine 사용법

`DesData` type의 8-byte 영역 pointer는 DES key와 input·output block을 보관합니다.

`DesKeys` type의 128-byte 영역 pointer는 전체 768-bit key를 보관하며 long alignment가 필요합니다.

`DesQuickInit()`은 이름에 `Quick`이 들어간 다른 routine보다 먼저 호출해야 하며 필요한 특수 64K table을 생성합니다. `DesQuickDone()`은 이 table을 해제합니다.

`DesMethod(m, k)`에서 `m`은 128-byte block, `k`는 8-byte DES key를 가리킵니다. Key는 odd parity여야 하며 그렇지 않으면 -1을 반환합니다. Weak 또는 semi-weak key여서는 안 되며 그렇지 않으면 -2를 반환합니다. 정상적으로는 0을 반환합니다.

`m`은 `k`로 채워져 이후 routine이 `m`을 사용하면 key `k`에 의한 표준 DES 암호화·복호화처럼 동작합니다. `DesMethod()`를 쓰면 표준 56-bit key를 제공하지만 `m`을 직접 채우면 비표준 768-bit key를 얻습니다.

1024-bit가 아니라 768-bit인 이유는 각 byte의 최하위 두 bit를 사용하지 않기 때문입니다. 이 두 bit에는 일부 machine에서 암호화·복호화를 빠르게 하는 magic constant가 들어가며 각 byte는 특정 iteration의 특정 S-box를 제어합니다.

768-bit 형식을 직접 사용하지 않는 것이 좋습니다. 저자는 S-box mapping 순서 등으로 지정된 128개의 6-bit byte를 올바른 형식으로 바꾸는 routine이 필요하며, 여기에는 byte 결합과 rotate가 필요하다고 설명합니다.

`Des{Small|Quick}{Fips|Core}{Encrypt|Decrypt}(d, m, s)`는 `s`의 8-byte에 DES를 수행하여 `d`의 8-byte에 기록합니다. `d`와 `s`는 `char *`이고 `m`은 앞에서 설명한 768-bit key입니다.

`Encrypt|Decrypt`는 암호화 또는 복호화를 선택합니다. `Fips|Core`는 완전한 표준 FIPS initial·final permutation 수행 여부를 정합니다. 수행하지 않으면 data를 비표준 bit order, 즉 IP/FP 없는 FIPS 형식으로 load·store합니다.

Fips는 Quick을 10%, Small을 9% 느리게 합니다.

`Small|Quick`은 일반 routine과 추가 memory 64K를 쓰는 고속 routine 중 하나를 선택합니다. Small은 Quick보다 50% 느리지만 Quick은 memory를 32배 사용합니다. Quick은 encryption filter처럼 DES만 수행하는 program을 위한 것입니다.

Machine에서 compile하기

390-399

Machine에서 compile하기

Porting 절에서 설명한 대로 code에는 `desTest.c`의 `now()` macro를 제외하면 machine dependency가 없습니다. 생성되는 모든 table은 machine 독립적입니다. Compiler에 맞는 최대 optimization flag로 Makefile을 수정해야 합니다.

Kerberos와 DES library 가속

400-409

Kerberos와 DES library 가속

`desUtil.c`에는 `des_key_sched()`과 `des_ecb_encrypt()` 함수로 Kerberos 호환 interface가 포함되어 있습니다. Kerberos 또는 호환 code에서 사용하려면 linker command line에서 `desCore.a`를 Kerberos 호환 library보다 앞에 두십시오.

`desCore.h`를 include할 필요는 없고 Kerberos library가 제공하는 header만 include하면 됩니다.

다른 용도

410-414

다른 용도

`desCode.h`의 macro는 더 복잡한 암호화 routine에 inline DES 함수를 넣는 데 유용합니다.