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