Crypto++ 8.7
Free C++ class library of cryptographic schemes
des.cpp
1// des.cpp - modified by Wei Dai from Phil Karn's des.c
2// The original code and all modifications are in the public domain.
3
4/*
5 * This is a major rewrite of my old public domain DES code written
6 * circa 1987, which in turn borrowed heavily from Jim Gillogly's 1977
7 * public domain code. I pretty much kept my key scheduling code, but
8 * the actual encrypt/decrypt routines are taken from from Richard
9 * Outerbridge's DES code as printed in Schneier's "Applied Cryptography."
10 *
11 * This code is in the public domain. I would appreciate bug reports and
12 * enhancements.
13 *
14 * Phil Karn KA9Q, karn@unix.ka9q.ampr.org, August 1994.
15 */
16
17#include "pch.h"
18#include "misc.h"
19#include "des.h"
20
21NAMESPACE_BEGIN(CryptoPP)
22
24
25// Richard Outerbridge's initial permutation algorithm
26/*
27inline void IPERM(word32 &left, word32 &right)
28{
29 word32 work;
30
31 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
32 right ^= work;
33 left ^= work << 4;
34 work = ((left >> 16) ^ right) & 0xffff;
35 right ^= work;
36 left ^= work << 16;
37 work = ((right >> 2) ^ left) & 0x33333333;
38 left ^= work;
39 right ^= (work << 2);
40 work = ((right >> 8) ^ left) & 0xff00ff;
41 left ^= work;
42 right ^= (work << 8);
43 right = rotl(right, 1);
44 work = (left ^ right) & 0xaaaaaaaa;
45 left ^= work;
46 right ^= work;
47 left = rotl(left, 1);
48}
49inline void FPERM(word32 &left, word32 &right)
50{
51 word32 work;
52
53 right = rotr(right, 1);
54 work = (left ^ right) & 0xaaaaaaaa;
55 left ^= work;
56 right ^= work;
57 left = rotr(left, 1);
58 work = ((left >> 8) ^ right) & 0xff00ff;
59 right ^= work;
60 left ^= work << 8;
61 work = ((left >> 2) ^ right) & 0x33333333;
62 right ^= work;
63 left ^= work << 2;
64 work = ((right >> 16) ^ left) & 0xffff;
65 left ^= work;
66 right ^= work << 16;
67 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
68 left ^= work;
69 right ^= work << 4;
70}
71*/
72
73// Wei Dai's modification to Richard Outerbridge's initial permutation
74// algorithm, this one is faster if you have access to rotate instructions
75// (like in MSVC)
76static inline void IPERM(word32 &left, word32 &right)
77{
78 word32 work;
79
80 right = rotlConstant<4>(right);
81 work = (left ^ right) & 0xf0f0f0f0;
82 left ^= work;
83 right = rotrConstant<20>(right^work);
84 work = (left ^ right) & 0xffff0000;
85 left ^= work;
86 right = rotrConstant<18>(right^work);
87 work = (left ^ right) & 0x33333333;
88 left ^= work;
89 right = rotrConstant<6>(right^work);
90 work = (left ^ right) & 0x00ff00ff;
91 left ^= work;
92 right = rotlConstant<9>(right^work);
93 work = (left ^ right) & 0xaaaaaaaa;
94 left = rotlConstant<1>(left^work);
95 right ^= work;
96}
97
98static inline void FPERM(word32 &left, word32 &right)
99{
100 word32 work;
101
102 right = rotrConstant<1>(right);
103 work = (left ^ right) & 0xaaaaaaaa;
104 right ^= work;
105 left = rotrConstant<9>(left^work);
106 work = (left ^ right) & 0x00ff00ff;
107 right ^= work;
108 left = rotlConstant<6>(left^work);
109 work = (left ^ right) & 0x33333333;
110 right ^= work;
111 left = rotlConstant<18>(left^work);
112 work = (left ^ right) & 0xffff0000;
113 right ^= work;
114 left = rotlConstant<20>(left^work);
115 work = (left ^ right) & 0xf0f0f0f0;
116 right ^= work;
117 left = rotrConstant<4>(left^work);
118}
119
120void DES::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &)
121{
122 AssertValidKeyLength(length);
123
124 RawSetKey(GetCipherDirection(), userKey);
125}
126
127#ifndef CRYPTOPP_IMPORTS
128
129/* Tables defined in the Data Encryption Standard documents
130 * Three of these tables, the initial permutation, the final
131 * permutation and the expansion operator, are regular enough that
132 * for speed, we hard-code them. They're here for reference only.
133 * Also, the S and P boxes are used by a separate program, gensp.c,
134 * to build the combined SP box, Spbox[]. They're also here just
135 * for reference.
136 */
137#ifdef notdef
138/* initial permutation IP */
139static byte ip[] = {
140 58, 50, 42, 34, 26, 18, 10, 2,
141 60, 52, 44, 36, 28, 20, 12, 4,
142 62, 54, 46, 38, 30, 22, 14, 6,
143 64, 56, 48, 40, 32, 24, 16, 8,
144 57, 49, 41, 33, 25, 17, 9, 1,
145 59, 51, 43, 35, 27, 19, 11, 3,
146 61, 53, 45, 37, 29, 21, 13, 5,
147 63, 55, 47, 39, 31, 23, 15, 7
148};
149
150/* final permutation IP^-1 */
151static byte fp[] = {
152 40, 8, 48, 16, 56, 24, 64, 32,
153 39, 7, 47, 15, 55, 23, 63, 31,
154 38, 6, 46, 14, 54, 22, 62, 30,
155 37, 5, 45, 13, 53, 21, 61, 29,
156 36, 4, 44, 12, 52, 20, 60, 28,
157 35, 3, 43, 11, 51, 19, 59, 27,
158 34, 2, 42, 10, 50, 18, 58, 26,
159 33, 1, 41, 9, 49, 17, 57, 25
160};
161/* expansion operation matrix */
162static byte ei[] = {
163 32, 1, 2, 3, 4, 5,
164 4, 5, 6, 7, 8, 9,
165 8, 9, 10, 11, 12, 13,
166 12, 13, 14, 15, 16, 17,
167 16, 17, 18, 19, 20, 21,
168 20, 21, 22, 23, 24, 25,
169 24, 25, 26, 27, 28, 29,
170 28, 29, 30, 31, 32, 1
171};
172/* The (in)famous S-boxes */
173static byte sbox[8][64] = {
174 /* S1 */
175 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
176 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
177 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
178 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
179
180 /* S2 */
181 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
182 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
183 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
184 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
185
186 /* S3 */
187 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
188 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
189 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
190 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
191
192 /* S4 */
193 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
194 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
195 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
196 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
197
198 /* S5 */
199 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
200 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
201 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
202 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
203
204 /* S6 */
205 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
206 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
207 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
208 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
209
210 /* S7 */
211 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
212 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
213 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
214 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
215
216 /* S8 */
217 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
218 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
219 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
220 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
221};
222
223/* 32-bit permutation function P used on the output of the S-boxes */
224namespace {
225 const byte p32i[] = {
226 16, 7, 20, 21,
227 29, 12, 28, 17,
228 1, 15, 23, 26,
229 5, 18, 31, 10,
230 2, 8, 24, 14,
231 32, 27, 3, 9,
232 19, 13, 30, 6,
233 22, 11, 4, 25
234 };
235}
236#endif
237
238/* permuted choice table (key) */
239namespace {
240 const byte pc1[] = {
241 57, 49, 41, 33, 25, 17, 9,
242 1, 58, 50, 42, 34, 26, 18,
243 10, 2, 59, 51, 43, 35, 27,
244 19, 11, 3, 60, 52, 44, 36,
245
246 63, 55, 47, 39, 31, 23, 15,
247 7, 62, 54, 46, 38, 30, 22,
248 14, 6, 61, 53, 45, 37, 29,
249 21, 13, 5, 28, 20, 12, 4
250 };
251}
252
253/* number left rotations of pc1 */
254namespace {
255 const byte totrot[] = {
256 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
257 };
258}
259
260/* permuted choice key (table) */
261namespace {
262 const byte pc2[] = {
263 14, 17, 11, 24, 1, 5,
264 3, 28, 15, 6, 21, 10,
265 23, 19, 12, 4, 26, 8,
266 16, 7, 27, 20, 13, 2,
267 41, 52, 31, 37, 47, 55,
268 30, 40, 51, 45, 33, 48,
269 44, 49, 39, 56, 34, 53,
270 46, 42, 50, 36, 29, 32
271 };
272}
273
274/* End of DES-defined tables */
275
276/* bit 0 is left-most in byte */
277namespace {
278 const int bytebit[] = {
279 0200,0100,040,020,010,04,02,01
280 };
281}
282
283/* Set key (initialize key schedule array) */
284void RawDES::RawSetKey(CipherDir dir, const byte *key)
285{
286#if (_MSC_VER >= 1600) || (__cplusplus >= 201103L)
287# define REGISTER /* Define to nothing for C++11 and above */
288#else
289# define REGISTER register
290#endif
291
292 SecByteBlock buffer(56+56+8);
293 byte *const pc1m=buffer; /* place to modify pc1 into */
294 byte *const pcr=pc1m+56; /* place to rotate pc1 into */
295 byte *const ks=pcr+56;
296 REGISTER int i,j,l;
297 int m;
298
299 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
300 l=pc1[j]-1; /* integer bit location */
301 m = l & 07; /* find bit */
302 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
303 bytebit[m]) /* and which bit of that byte */
304 ? 1 : 0; /* and store 1-bit result */
305 }
306 for (i=0; i<16; i++) { /* key chunk for each iteration */
307 memset(ks,0,8); /* Clear key schedule */
308 for (j=0; j<56; j++) /* rotate pc1 the right amount */
309 pcr[j] = pc1m[(l=j+totrot[i])<(j<28? 28 : 56) ? l: l-28];
310 /* rotate left and right halves independently */
311 for (j=0; j<48; j++){ /* select bits individually */
312 /* check bit that goes to ks[j] */
313 if (pcr[pc2[j]-1]){
314 /* mask it in if it's there */
315 l= j % 6;
316 ks[j/6] |= bytebit[l] >> 2;
317 }
318 }
319 /* Now convert to odd/even interleaved form for use in F */
320 k[2*i] = ((word32)ks[0] << 24)
321 | ((word32)ks[2] << 16)
322 | ((word32)ks[4] << 8)
323 | ((word32)ks[6]);
324 k[2*i+1] = ((word32)ks[1] << 24)
325 | ((word32)ks[3] << 16)
326 | ((word32)ks[5] << 8)
327 | ((word32)ks[7]);
328 }
329
330 if (dir==DECRYPTION) // reverse key schedule order
331 for (i=0; i<16; i+=2)
332 {
333 std::swap(k[i], k[32-2-i]);
334 std::swap(k[i+1], k[32-1-i]);
335 }
336}
337
338void RawDES::RawProcessBlock(word32 &l_, word32 &r_) const
339{
340 word32 l = l_, r = r_;
341 const word32 *kptr=k;
342
343 for (unsigned i=0; i<8; i++)
344 {
345 word32 work = rotrConstant<4>(r) ^ kptr[4 * i + 0];
346 l ^= Spbox[6][(work) & 0x3f]
347 ^ Spbox[4][(work >> 8) & 0x3f]
348 ^ Spbox[2][(work >> 16) & 0x3f]
349 ^ Spbox[0][(work >> 24) & 0x3f];
350 work = r ^ kptr[4*i+1];
351 l ^= Spbox[7][(work) & 0x3f]
352 ^ Spbox[5][(work >> 8) & 0x3f]
353 ^ Spbox[3][(work >> 16) & 0x3f]
354 ^ Spbox[1][(work >> 24) & 0x3f];
355
356 work = rotrConstant<4>(l) ^ kptr[4 * i + 2];
357 r ^= Spbox[6][(work) & 0x3f]
358 ^ Spbox[4][(work >> 8) & 0x3f]
359 ^ Spbox[2][(work >> 16) & 0x3f]
360 ^ Spbox[0][(work >> 24) & 0x3f];
361 work = l ^ kptr[4*i+3];
362 r ^= Spbox[7][(work) & 0x3f]
363 ^ Spbox[5][(work >> 8) & 0x3f]
364 ^ Spbox[3][(work >> 16) & 0x3f]
365 ^ Spbox[1][(work >> 24) & 0x3f];
366 }
367
368 l_ = l; r_ = r;
369}
370
371void DES_EDE2::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &)
372{
373 AssertValidKeyLength(length);
374
375 m_des1.RawSetKey(GetCipherDirection(), userKey);
376 m_des2.RawSetKey(ReverseCipherDir(GetCipherDirection()), userKey+8);
377}
378
379void DES_EDE2::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
380{
381 word32 l,r;
382 Block::Get(inBlock)(l)(r);
383 IPERM(l,r);
384 m_des1.RawProcessBlock(l, r);
385 m_des2.RawProcessBlock(r, l);
386 m_des1.RawProcessBlock(l, r);
387 FPERM(l,r);
388 Block::Put(xorBlock, outBlock)(r)(l);
389}
390
391void DES_EDE3::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &)
392{
393 AssertValidKeyLength(length);
394
395 m_des1.RawSetKey(GetCipherDirection(), userKey + (IsForwardTransformation() ? 0 : 16));
396 m_des2.RawSetKey(ReverseCipherDir(GetCipherDirection()), userKey + 8);
397 m_des3.RawSetKey(GetCipherDirection(), userKey + (IsForwardTransformation() ? 16 : 0));
398}
399
400void DES_EDE3::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
401{
402 word32 l,r;
403 Block::Get(inBlock)(l)(r);
404 IPERM(l,r);
405 m_des1.RawProcessBlock(l, r);
406 m_des2.RawProcessBlock(r, l);
407 m_des3.RawProcessBlock(l, r);
408 FPERM(l,r);
409 Block::Put(xorBlock, outBlock)(r)(l);
410}
411
412#endif // #ifndef CRYPTOPP_IMPORTS
413
414static inline bool CheckParity(byte b)
415{
416 unsigned int a = b ^ (b >> 4);
417 return ((a ^ (a>>1) ^ (a>>2) ^ (a>>3)) & 1) == 1;
418}
419
420bool DES::CheckKeyParityBits(const byte *key)
421{
422 for (unsigned int i=0; i<8; i++)
423 if (!CheckParity(key[i]))
424 return false;
425 return true;
426}
427
429{
430 for (unsigned int i=0; i<8; i++)
431 if (!CheckParity(key[i]))
432 key[i] ^= 1;
433}
434
435// Encrypt or decrypt a block of data in ECB mode
436void DES::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
437{
438 word32 l,r;
439 Block::Get(inBlock)(l)(r);
440 IPERM(l,r);
441 RawProcessBlock(l, r);
442 FPERM(l,r);
443 Block::Put(xorBlock, outBlock)(r)(l);
444}
445
446void DES_XEX3::Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &)
447{
448 AssertValidKeyLength(length);
449
450 if (!m_des.get())
451 m_des.reset(new DES::Encryption);
452
453 memcpy(m_x1, key + (IsForwardTransformation() ? 0 : 16), BLOCKSIZE);
454 m_des->RawSetKey(GetCipherDirection(), key + 8);
455 memcpy(m_x3, key + (IsForwardTransformation() ? 16 : 0), BLOCKSIZE);
456}
457
458void DES_XEX3::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
459{
460 xorbuf(outBlock, inBlock, m_x1, BLOCKSIZE);
461 m_des->ProcessAndXorBlock(outBlock, xorBlock, outBlock);
462 xorbuf(outBlock, m_x3, BLOCKSIZE);
463}
464
465NAMESPACE_END
Provides class member functions to key a block cipher.
Definition: seckey.h:318
static bool CheckKeyParityBits(const byte *key)
check DES key parity bits
Definition: des.cpp:420
static void CorrectKeyParityBits(byte *key)
correct DES key parity bits
Definition: des.cpp:428
Interface for retrieving values given their names.
Definition: cryptlib.h:322
Access a block of memory.
Definition: misc.h:2807
SecBlock<byte> typedef.
Definition: secblock.h:1226
unsigned int word32
32-bit unsigned datatype
Definition: config_int.h:62
CipherDir
Specifies a direction for a cipher to operate.
Definition: cryptlib.h:123
@ DECRYPTION
the cipher is performing decryption
Definition: cryptlib.h:127
Classes for DES, 2-key Triple-DES, 3-key Triple-DES and DESX.
Utility functions for the Crypto++ library.
CRYPTOPP_DLL void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Crypto++ library namespace.
Precompiled header file.
void swap(::SecBlock< T, A > &a, ::SecBlock< T, A > &b)
Swap two SecBlocks.
Definition: secblock.h:1289
CipherDir ReverseCipherDir(CipherDir dir)
Inverts the cipher's direction.
Definition: seckey.h:32
Access a block of memory.
Definition: misc.h:2844