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