View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.codec.digest;
18  
19  import java.nio.charset.StandardCharsets;
20  import java.security.SecureRandom;
21  import java.util.Arrays;
22  import java.util.regex.Pattern;
23  
24  /**
25   * Unix <a href="https://man7.org/linux/man-pages/man3/crypt.3.html">crypt(3)</a> algorithm implementation.
26   *
27   * <p>
28   * This class only implements the traditional 56 bit DES based algorithm. Please use Crypt.crypt() for a method
29   * that distinguishes between all the algorithms supported in the current glibc's crypt().
30   * </p>
31   * <p>
32   * The initial Java implementation was taken from the JetSpeed Portal project (see
33   * org.apache.jetspeed.services.security.ldap.UnixCrypt).
34   * </p>
35   * <p>
36   * This class is slightly incompatible if the given salt contains characters that are not part of the allowed range
37   * {@code [a-zA-Z0-9./]}.
38   * </p>
39   * <p>
40   * This class is immutable and thread-safe.
41   * </p>
42   *
43   * @since 1.7
44   */
45  public class UnixCrypt {
46  
47      private static final String CRYPT_SALT_REGEX = "^[" + B64.B64T_STRING + "]{2,}$";
48      private static final Pattern CRYPT_SALT_PATTERN = Pattern.compile(CRYPT_SALT_REGEX);
49  
50      private static final int[] CON_SALT = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 5, 6,
52              7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
53              34, 35, 36, 37, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54              54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0 };
55  
56      private static final int[] COV2CHAR = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
57              71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102,
58              103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 };
59  
60      private static final boolean[] SHIFT2 = { false, false, true, true, true, true, true, true, false, true, true,
61              true, true, true, true, false };
62  
63      private static final int[][] SKB = {
64              { 0, 16, 0x20000000, 0x20000010, 0x10000, 0x10010, 0x20010000, 0x20010010, 2048, 2064, 0x20000800,
65                      0x20000810, 0x10800, 0x10810, 0x20010800, 0x20010810, 32, 48, 0x20000020, 0x20000030, 0x10020,
66                      0x10030, 0x20010020, 0x20010030, 2080, 2096, 0x20000820, 0x20000830, 0x10820, 0x10830, 0x20010820,
67                      0x20010830, 0x80000, 0x80010, 0x20080000, 0x20080010, 0x90000, 0x90010, 0x20090000, 0x20090010,
68                      0x80800, 0x80810, 0x20080800, 0x20080810, 0x90800, 0x90810, 0x20090800, 0x20090810, 0x80020,
69                      0x80030, 0x20080020, 0x20080030, 0x90020, 0x90030, 0x20090020, 0x20090030, 0x80820, 0x80830,
70                      0x20080820, 0x20080830, 0x90820, 0x90830, 0x20090820, 0x20090830 },
71              { 0, 0x2000000, 8192, 0x2002000, 0x200000, 0x2200000, 0x202000, 0x2202000, 4, 0x2000004, 8196, 0x2002004,
72                      0x200004, 0x2200004, 0x202004, 0x2202004, 1024, 0x2000400, 9216, 0x2002400, 0x200400, 0x2200400,
73                      0x202400, 0x2202400, 1028, 0x2000404, 9220, 0x2002404, 0x200404, 0x2200404, 0x202404, 0x2202404,
74                      0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000,
75                      0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004,
76                      0x10000400, 0x12000400, 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400,
77                      0x10000404, 0x12000404, 0x10002404, 0x12002404, 0x10200404, 0x12200404, 0x10202404, 0x12202404 },
78              { 0, 1, 0x40000, 0x40001, 0x1000000, 0x1000001, 0x1040000, 0x1040001, 2, 3, 0x40002, 0x40003, 0x1000002,
79                      0x1000003, 0x1040002, 0x1040003, 512, 513, 0x40200, 0x40201, 0x1000200, 0x1000201, 0x1040200,
80                      0x1040201, 514, 515, 0x40202, 0x40203, 0x1000202, 0x1000203, 0x1040202, 0x1040203, 0x8000000,
81                      0x8000001, 0x8040000, 0x8040001, 0x9000000, 0x9000001, 0x9040000, 0x9040001, 0x8000002, 0x8000003,
82                      0x8040002, 0x8040003, 0x9000002, 0x9000003, 0x9040002, 0x9040003, 0x8000200, 0x8000201, 0x8040200,
83                      0x8040201, 0x9000200, 0x9000201, 0x9040200, 0x9040201, 0x8000202, 0x8000203, 0x8040202, 0x8040203,
84                      0x9000202, 0x9000203, 0x9040202, 0x9040203 },
85              { 0, 0x100000, 256, 0x100100, 8, 0x100008, 264, 0x100108, 4096, 0x101000, 4352, 0x101100, 4104, 0x101008,
86                      4360, 0x101108, 0x4000000, 0x4100000, 0x4000100, 0x4100100, 0x4000008, 0x4100008, 0x4000108,
87                      0x4100108, 0x4001000, 0x4101000, 0x4001100, 0x4101100, 0x4001008, 0x4101008, 0x4001108, 0x4101108,
88                      0x20000, 0x120000, 0x20100, 0x120100, 0x20008, 0x120008, 0x20108, 0x120108, 0x21000, 0x121000,
89                      0x21100, 0x121100, 0x21008, 0x121008, 0x21108, 0x121108, 0x4020000, 0x4120000, 0x4020100,
90                      0x4120100, 0x4020008, 0x4120008, 0x4020108, 0x4120108, 0x4021000, 0x4121000, 0x4021100, 0x4121100,
91                      0x4021008, 0x4121008, 0x4021108, 0x4121108 },
92              { 0, 0x10000000, 0x10000, 0x10010000, 4, 0x10000004, 0x10004, 0x10010004, 0x20000000, 0x30000000,
93                      0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x100000, 0x10100000,
94                      0x110000, 0x10110000, 0x100004, 0x10100004, 0x110004, 0x10110004, 0x20100000, 0x30100000,
95                      0x20110000, 0x30110000, 0x20100004, 0x30100004, 0x20110004, 0x30110004, 4096, 0x10001000, 0x11000,
96                      0x10011000, 4100, 0x10001004, 0x11004, 0x10011004, 0x20001000, 0x30001000, 0x20011000, 0x30011000,
97                      0x20001004, 0x30001004, 0x20011004, 0x30011004, 0x101000, 0x10101000, 0x111000, 0x10111000,
98                      0x101004, 0x10101004, 0x111004, 0x10111004, 0x20101000, 0x30101000, 0x20111000, 0x30111000,
99                      0x20101004, 0x30101004, 0x20111004, 0x30111004 },
100             { 0, 0x8000000, 8, 0x8000008, 1024, 0x8000400, 1032, 0x8000408, 0x20000, 0x8020000, 0x20008, 0x8020008,
101                     0x20400, 0x8020400, 0x20408, 0x8020408, 1, 0x8000001, 9, 0x8000009, 1025, 0x8000401, 1033,
102                     0x8000409, 0x20001, 0x8020001, 0x20009, 0x8020009, 0x20401, 0x8020401, 0x20409, 0x8020409,
103                     0x2000000, 0xa000000, 0x2000008, 0xa000008, 0x2000400, 0xa000400, 0x2000408, 0xa000408, 0x2020000,
104                     0xa020000, 0x2020008, 0xa020008, 0x2020400, 0xa020400, 0x2020408, 0xa020408, 0x2000001, 0xa000001,
105                     0x2000009, 0xa000009, 0x2000401, 0xa000401, 0x2000409, 0xa000409, 0x2020001, 0xa020001, 0x2020009,
106                     0xa020009, 0x2020401, 0xa020401, 0x2020409, 0xa020409 },
107             { 0, 256, 0x80000, 0x80100, 0x1000000, 0x1000100, 0x1080000, 0x1080100, 16, 272, 0x80010, 0x80110,
108                     0x1000010, 0x1000110, 0x1080010, 0x1080110, 0x200000, 0x200100, 0x280000, 0x280100, 0x1200000,
109                     0x1200100, 0x1280000, 0x1280100, 0x200010, 0x200110, 0x280010, 0x280110, 0x1200010, 0x1200110,
110                     0x1280010, 0x1280110, 512, 768, 0x80200, 0x80300, 0x1000200, 0x1000300, 0x1080200, 0x1080300, 528,
111                     784, 0x80210, 0x80310, 0x1000210, 0x1000310, 0x1080210, 0x1080310, 0x200200, 0x200300, 0x280200,
112                     0x280300, 0x1200200, 0x1200300, 0x1280200, 0x1280300, 0x200210, 0x200310, 0x280210, 0x280310,
113                     0x1200210, 0x1200310, 0x1280210, 0x1280310 },
114             { 0, 0x4000000, 0x40000, 0x4040000, 2, 0x4000002, 0x40002, 0x4040002, 8192, 0x4002000, 0x42000, 0x4042000,
115                     8194, 0x4002002, 0x42002, 0x4042002, 32, 0x4000020, 0x40020, 0x4040020, 34, 0x4000022, 0x40022,
116                     0x4040022, 8224, 0x4002020, 0x42020, 0x4042020, 8226, 0x4002022, 0x42022, 0x4042022, 2048,
117                     0x4000800, 0x40800, 0x4040800, 2050, 0x4000802, 0x40802, 0x4040802, 10240, 0x4002800, 0x42800,
118                     0x4042800, 10242, 0x4002802, 0x42802, 0x4042802, 2080, 0x4000820, 0x40820, 0x4040820, 2082,
119                     0x4000822, 0x40822, 0x4040822, 10272, 0x4002820, 0x42820, 0x4042820, 10274, 0x4002822, 0x42822,
120                     0x4042822 } };
121 
122     private static final int[][] SPTRANS = {
123             { 0x820200, 0x20000, 0x80800000, 0x80820200, 0x800000, 0x80020200, 0x80020000, 0x80800000, 0x80020200,
124                     0x820200, 0x820000, 0x80000200, 0x80800200, 0x800000, 0, 0x80020000, 0x20000, 0x80000000,
125                     0x800200, 0x20200, 0x80820200, 0x820000, 0x80000200, 0x800200, 0x80000000, 512, 0x20200,
126                     0x80820000, 512, 0x80800200, 0x80820000, 0, 0, 0x80820200, 0x800200, 0x80020000, 0x820200,
127                     0x20000, 0x80000200, 0x800200, 0x80820000, 512, 0x20200, 0x80800000, 0x80020200, 0x80000000,
128                     0x80800000, 0x820000, 0x80820200, 0x20200, 0x820000, 0x80800200, 0x800000, 0x80000200, 0x80020000,
129                     0, 0x20000, 0x800000, 0x80800200, 0x820200, 0x80000000, 0x80820000, 512, 0x80020200 },
130             { 0x10042004, 0, 0x42000, 0x10040000, 0x10000004, 8196, 0x10002000, 0x42000, 8192, 0x10040004, 4,
131                     0x10002000, 0x40004, 0x10042000, 0x10040000, 4, 0x40000, 0x10002004, 0x10040004, 8192, 0x42004,
132                     0x10000000, 0, 0x40004, 0x10002004, 0x42004, 0x10042000, 0x10000004, 0x10000000, 0x40000, 8196,
133                     0x10042004, 0x40004, 0x10042000, 0x10002000, 0x42004, 0x10042004, 0x40004, 0x10000004, 0,
134                     0x10000000, 8196, 0x40000, 0x10040004, 8192, 0x10000000, 0x42004, 0x10002004, 0x10042000, 8192, 0,
135                     0x10000004, 4, 0x10042004, 0x42000, 0x10040000, 0x10040004, 0x40000, 8196, 0x10002000, 0x10002004,
136                     4, 0x10040000, 0x42000 },
137             { 0x41000000, 0x1010040, 64, 0x41000040, 0x40010000, 0x1000000, 0x41000040, 0x10040, 0x1000040, 0x10000,
138                     0x1010000, 0x40000000, 0x41010040, 0x40000040, 0x40000000, 0x41010000, 0, 0x40010000, 0x1010040,
139                     64, 0x40000040, 0x41010040, 0x10000, 0x41000000, 0x41010000, 0x1000040, 0x40010040, 0x1010000,
140                     0x10040, 0, 0x1000000, 0x40010040, 0x1010040, 64, 0x40000000, 0x10000, 0x40000040, 0x40010000,
141                     0x1010000, 0x41000040, 0, 0x1010040, 0x10040, 0x41010000, 0x40010000, 0x1000000, 0x41010040,
142                     0x40000000, 0x40010040, 0x41000000, 0x1000000, 0x41010040, 0x10000, 0x1000040, 0x41000040,
143                     0x10040, 0x1000040, 0, 0x41010000, 0x40000040, 0x41000000, 0x40010040, 64, 0x1010000 },
144             { 0x100402, 0x4000400, 2, 0x4100402, 0, 0x4100000, 0x4000402, 0x100002, 0x4100400, 0x4000002, 0x4000000,
145                     1026, 0x4000002, 0x100402, 0x100000, 0x4000000, 0x4100002, 0x100400, 1024, 2, 0x100400, 0x4000402,
146                     0x4100000, 1024, 1026, 0, 0x100002, 0x4100400, 0x4000400, 0x4100002, 0x4100402, 0x100000,
147                     0x4100002, 1026, 0x100000, 0x4000002, 0x100400, 0x4000400, 2, 0x4100000, 0x4000402, 0, 1024,
148                     0x100002, 0, 0x4100002, 0x4100400, 1024, 0x4000000, 0x4100402, 0x100402, 0x100000, 0x4100402, 2,
149                     0x4000400, 0x100402, 0x100002, 0x100400, 0x4100000, 0x4000402, 1026, 0x4000000, 0x4000002,
150                     0x4100400 },
151             { 0x2000000, 16384, 256, 0x2004108, 0x2004008, 0x2000100, 16648, 0x2004000, 16384, 8, 0x2000008, 16640,
152                     0x2000108, 0x2004008, 0x2004100, 0, 16640, 0x2000000, 16392, 264, 0x2000100, 16648, 0, 0x2000008,
153                     8, 0x2000108, 0x2004108, 16392, 0x2004000, 256, 264, 0x2004100, 0x2004100, 0x2000108, 16392,
154                     0x2004000, 16384, 8, 0x2000008, 0x2000100, 0x2000000, 16640, 0x2004108, 0, 16648, 0x2000000, 256,
155                     16392, 0x2000108, 256, 0, 0x2004108, 0x2004008, 0x2004100, 264, 16384, 16640, 0x2004008,
156                     0x2000100, 264, 8, 16648, 0x2004000, 0x2000008 },
157             { 0x20000010, 0x80010, 0, 0x20080800, 0x80010, 2048, 0x20000810, 0x80000, 2064, 0x20080810, 0x80800,
158                     0x20000000, 0x20000800, 0x20000010, 0x20080000, 0x80810, 0x80000, 0x20000810, 0x20080010, 0, 2048,
159                     16, 0x20080800, 0x20080010, 0x20080810, 0x20080000, 0x20000000, 2064, 16, 0x80800, 0x80810,
160                     0x20000800, 2064, 0x20000000, 0x20000800, 0x80810, 0x20080800, 0x80010, 0, 0x20000800, 0x20000000,
161                     2048, 0x20080010, 0x80000, 0x80010, 0x20080810, 0x80800, 16, 0x20080810, 0x80800, 0x80000,
162                     0x20000810, 0x20000010, 0x20080000, 0x80810, 0, 2048, 0x20000010, 0x20000810, 0x20080800,
163                     0x20080000, 2064, 16, 0x20080010 },
164             { 4096, 128, 0x400080, 0x400001, 0x401081, 4097, 4224, 0, 0x400000, 0x400081, 129, 0x401000, 1, 0x401080,
165                     0x401000, 129, 0x400081, 4096, 4097, 0x401081, 0, 0x400080, 0x400001, 4224, 0x401001, 4225,
166                     0x401080, 1, 4225, 0x401001, 128, 0x400000, 4225, 0x401000, 0x401001, 129, 4096, 128, 0x400000,
167                     0x401001, 0x400081, 4225, 4224, 0, 128, 0x400001, 1, 0x400080, 0, 0x400081, 0x400080, 4224, 129,
168                     4096, 0x401081, 0x400000, 0x401080, 1, 4097, 0x401081, 0x400001, 0x401080, 0x401000, 4097 },
169             { 0x8200020, 0x8208000, 32800, 0, 0x8008000, 0x200020, 0x8200000, 0x8208020, 32, 0x8000000, 0x208000,
170                     32800, 0x208020, 0x8008020, 0x8000020, 0x8200000, 32768, 0x208020, 0x200020, 0x8008000, 0x8208020,
171                     0x8000020, 0, 0x208000, 0x8000000, 0x200000, 0x8008020, 0x8200020, 0x200000, 32768, 0x8208000, 32,
172                     0x200000, 32768, 0x8000020, 0x8208020, 32800, 0x8000000, 0, 0x208000, 0x8200020, 0x8008020,
173                     0x8008000, 0x200020, 0x8208000, 32, 0x200020, 0x8008000, 0x8208020, 0x200000, 0x8200000,
174                     0x8000020, 0x208000, 32800, 0x8008020, 0x8200000, 32, 0x8208000, 0x208020, 0, 0x8000000,
175                     0x8200020, 32768, 0x208020 } };
176 
177     private static int[] body(final int[] schedule, final int eSwap0, final int eSwap1) {
178         int left = 0;
179         int right = 0;
180         int t = 0;
181         for (int j = 0; j < 25; j++) {
182             for (int i = 0; i < 32; i += 4) {
183                 left = dEncrypt(left, right, i, eSwap0, eSwap1, schedule);
184                 right = dEncrypt(right, left, i + 2, eSwap0, eSwap1, schedule);
185             }
186             t = left;
187             left = right;
188             right = t;
189         }
190 
191         t = right;
192         right = left >>> 1 | left << 31;
193         left = t >>> 1 | t << 31;
194         final int[] results = new int[2];
195         permOp(right, left, 1, 0x55555555, results);
196         right = results[0];
197         left = results[1];
198         permOp(left, right, 8, 0xff00ff, results);
199         left = results[0];
200         right = results[1];
201         permOp(right, left, 2, 0x33333333, results);
202         right = results[0];
203         left = results[1];
204         permOp(left, right, 16, 65535, results);
205         left = results[0];
206         right = results[1];
207         permOp(right, left, 4, 0xf0f0f0f, results);
208         right = results[0];
209         left = results[1];
210         final int[] out = new int[2];
211         out[0] = left;
212         out[1] = right;
213         return out;
214     }
215 
216     private static int byteToUnsigned(final byte b) {
217         return b & 0xff;
218     }
219 
220     /**
221      * Generates a crypt(3) compatible hash using the DES algorithm.
222      *
223      * <p>
224      * A salt is generated for you using {@link SecureRandom}.
225      * </p>
226      *
227      * @param original Plaintext password.
228      * @return A 13 character string starting with the salt string.
229      */
230     public static String crypt(final byte[] original) {
231         return crypt(original, null);
232     }
233 
234     /**
235      * Generates a crypt(3) compatible hash using the DES algorithm.
236      * <p>
237      * Using unspecified characters as salt results incompatible hash values.
238      * </p>
239      *
240      * @param original Plaintext password.
241      * @param salt     a two character string drawn from [a-zA-Z0-9./]. The salt may be null, in which case a salt is generated for you using
242      *                 {@link B64#getRandomSalt(int)}. Only the first two characters are used, others are ignored.
243      * @return A 13 character string starting with the salt string.
244      * @throws IllegalArgumentException Thrown if the salt does not match the allowed pattern.
245      */
246     public static String crypt(final byte[] original, String salt) {
247         if (salt == null) {
248             salt = B64.getRandomSalt(2);
249         } else if (!CRYPT_SALT_PATTERN.matcher(salt).matches()) {
250             throw new IllegalArgumentException("Invalid salt value: " + salt);
251         }
252 
253         final StringBuilder buffer = new StringBuilder("             ");
254         final char charZero = salt.charAt(0);
255         final char charOne = salt.charAt(1);
256         buffer.setCharAt(0, charZero);
257         buffer.setCharAt(1, charOne);
258         final int eSwap0 = CON_SALT[charZero];
259         final int eSwap1 = CON_SALT[charOne] << 4;
260         final byte[] key = new byte[8];
261         Arrays.fill(key, (byte) 0);
262 
263         final int originalLength = original.length;
264         for (int i = 0; i < key.length && i < originalLength; i++) {
265             final int iChar = original[i];
266             key[i] = (byte) (iChar << 1);
267         }
268 
269         final int[] schedule = desSetKey(key);
270         final int[] out = body(schedule, eSwap0, eSwap1);
271         final byte[] b = new byte[9];
272         intToFourBytes(out[0], b, 0);
273         intToFourBytes(out[1], b, 4);
274         b[8] = 0;
275         int i = 2;
276         int y = 0;
277         int u = 128;
278         for (; i < 13; i++) {
279             int j = 0;
280             int c = 0;
281             for (; j < 6; j++) {
282                 c <<= 1;
283                 if ((b[y] & u) != 0) {
284                     c |= 0x1;
285                 }
286                 u >>>= 1;
287                 if (u == 0) {
288                     y++;
289                     u = 128;
290                 }
291                 buffer.setCharAt(i, (char) COV2CHAR[c]);
292             }
293         }
294         return buffer.toString();
295     }
296 
297     /**
298      * Generates a crypt(3) compatible hash using the DES algorithm.
299      *
300      * <p>
301      * A salt is generated for you using {@link SecureRandom}.
302      * </p>
303      *
304      * @param original Plaintext password.
305      * @return A 13 character string starting with the salt string.
306      */
307     public static String crypt(final String original) {
308         return crypt(original.getBytes(StandardCharsets.UTF_8));
309     }
310 
311     /**
312      * Generates a crypt(3) compatible hash using the DES algorithm.
313      *
314      * @param original Plaintext password.
315      * @param salt     A two character string drawn from [a-zA-Z0-9./]. The salt may be null, in which case a salt is generated for you using
316      *                 {@link SecureRandom}.
317      * @return A 13 character string starting with the salt string.
318      * @throws IllegalArgumentException if the salt does not match the allowed pattern.
319      */
320     public static String crypt(final String original, final String salt) {
321         return crypt(original.getBytes(StandardCharsets.UTF_8), salt);
322     }
323 
324     private static int dEncrypt(int el, final int r, final int s, final int e0, final int e1, final int[] sArr) {
325         int v = r ^ r >>> 16;
326         int u = v & e0;
327         v &= e1;
328         u = u ^ u << 16 ^ r ^ sArr[s];
329         int t = v ^ v << 16 ^ r ^ sArr[s + 1];
330         t = t >>> 4 | t << 28;
331         el ^= SPTRANS[1][t & 0x3f] | SPTRANS[3][t >>> 8 & 0x3f] | SPTRANS[5][t >>> 16 & 0x3f] |
332                 SPTRANS[7][t >>> 24 & 0x3f] | SPTRANS[0][u & 0x3f] | SPTRANS[2][u >>> 8 & 0x3f] |
333                 SPTRANS[4][u >>> 16 & 0x3f] | SPTRANS[6][u >>> 24 & 0x3f];
334         return el;
335     }
336 
337     private static int[] desSetKey(final byte[] key) {
338         final int[] schedule = new int[32];
339         int c = fourBytesToInt(key, 0);
340         int d = fourBytesToInt(key, 4);
341         final int[] results = new int[2];
342         permOp(d, c, 4, 0xf0f0f0f, results);
343         d = results[0];
344         c = results[1];
345         c = hPermOp(c, -2, 0xcccc0000);
346         d = hPermOp(d, -2, 0xcccc0000);
347         permOp(d, c, 1, 0x55555555, results);
348         d = results[0];
349         c = results[1];
350         permOp(c, d, 8, 0xff00ff, results);
351         c = results[0];
352         d = results[1];
353         permOp(d, c, 1, 0x55555555, results);
354         d = results[0];
355         c = results[1];
356         d = (d & 0xff) << 16 | d & 0xff00 | (d & 0xff0000) >>> 16 | (c & 0xf0000000) >>> 4;
357         c &= 0xfffffff;
358         int j = 0;
359         for (int i = 0; i < 16; i++) {
360             if (SHIFT2[i]) {
361                 c = c >>> 2 | c << 26;
362                 d = d >>> 2 | d << 26;
363             } else {
364                 c = c >>> 1 | c << 27;
365                 d = d >>> 1 | d << 27;
366             }
367             c &= 0xfffffff;
368             d &= 0xfffffff;
369             int s = SKB[0][c & 0x3f] | SKB[1][c >>> 6 & 0x3 | c >>> 7 & 0x3c] |
370                     SKB[2][c >>> 13 & 0xf | c >>> 14 & 0x30] |
371                     SKB[3][c >>> 20 & 0x1 | c >>> 21 & 0x6 | c >>> 22 & 0x38];
372             final int t = SKB[4][d & 0x3f] | SKB[5][d >>> 7 & 0x3 | d >>> 8 & 0x3c] | SKB[6][d >>> 15 & 0x3f] |
373                     SKB[7][d >>> 21 & 0xf | d >>> 22 & 0x30];
374             schedule[j++] = t << 16 | s & 0xffff;
375             s = s >>> 16 | t & 0xffff0000;
376             s = s << 4 | s >>> 28;
377             schedule[j++] = s;
378         }
379 
380         return schedule;
381     }
382 
383     private static int fourBytesToInt(final byte[] b, int offset) {
384         int value = byteToUnsigned(b[offset++]);
385         value |= byteToUnsigned(b[offset++]) << 8;
386         value |= byteToUnsigned(b[offset++]) << 16;
387         value |= byteToUnsigned(b[offset++]) << 24;
388         return value;
389     }
390 
391     private static int hPermOp(final int a, final int n, final int m) {
392         final int t = (a << 16 - n ^ a) & m;
393         return a ^ t ^ t >>> 16 - n;
394     }
395 
396     private static void intToFourBytes(final int iValue, final byte[] b, int offset) {
397         b[offset++] = (byte) (iValue & 0xff);
398         b[offset++] = (byte) (iValue >>> 8 & 0xff);
399         b[offset++] = (byte) (iValue >>> 16 & 0xff);
400         b[offset++] = (byte) (iValue >>> 24 & 0xff);
401     }
402 
403     private static void permOp(int a, int b, final int n, final int m, final int[] results) {
404         final int t = (a >>> n ^ b) & m;
405         a ^= t << n;
406         b ^= t;
407         results[0] = a;
408         results[1] = b;
409     }
410 
411     /**
412      * TODO Make private in 2.0.
413      *
414      * @deprecated TODO Make private in 2.0.
415      */
416     @Deprecated
417     public UnixCrypt() {
418         // empty
419     }
420 }