001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.codec.digest;
018    
019    import java.util.Random;
020    
021    import org.apache.commons.codec.Charsets;
022    
023    /**
024     * Unix crypt(3) algorithm implementation.
025     * <p>
026     * This class only implements the traditional 56 bit DES based algorithm. Please use DigestUtils.crypt() for a method
027     * that distinguishes between all the algorithms supported in the current glibc's crypt().
028     * <p>
029     * The Java implementation was taken from the JetSpeed Portal project (see
030     * org.apache.jetspeed.services.security.ldap.UnixCrypt).
031     * <p>
032     * This class is slightly incompatible if the given salt contains characters that are not part of the allowed range
033     * [a-zA-Z0-9./].
034     * <p>
035     * This class is immutable and thread-safe.
036     *
037     * @version $Id: UnixCrypt.html 889935 2013-12-11 05:05:13Z ggregory $
038     * @since 1.7
039     */
040    public class UnixCrypt {
041    
042        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,
043                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,
044                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,
045                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,
046                54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0 };
047    
048        private static final int COV2CHAR[] = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
049                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,
050                103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 };
051    
052        private static final char SALT_CHARS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
053                .toCharArray();
054    
055        private static final boolean SHIFT2[] = { false, false, true, true, true, true, true, true, false, true, true,
056                true, true, true, true, false };
057    
058        private static final int SKB[][] = {
059                { 0, 16, 0x20000000, 0x20000010, 0x10000, 0x10010, 0x20010000, 0x20010010, 2048, 2064, 0x20000800,
060                        0x20000810, 0x10800, 0x10810, 0x20010800, 0x20010810, 32, 48, 0x20000020, 0x20000030, 0x10020,
061                        0x10030, 0x20010020, 0x20010030, 2080, 2096, 0x20000820, 0x20000830, 0x10820, 0x10830, 0x20010820,
062                        0x20010830, 0x80000, 0x80010, 0x20080000, 0x20080010, 0x90000, 0x90010, 0x20090000, 0x20090010,
063                        0x80800, 0x80810, 0x20080800, 0x20080810, 0x90800, 0x90810, 0x20090800, 0x20090810, 0x80020,
064                        0x80030, 0x20080020, 0x20080030, 0x90020, 0x90030, 0x20090020, 0x20090030, 0x80820, 0x80830,
065                        0x20080820, 0x20080830, 0x90820, 0x90830, 0x20090820, 0x20090830 },
066                { 0, 0x2000000, 8192, 0x2002000, 0x200000, 0x2200000, 0x202000, 0x2202000, 4, 0x2000004, 8196, 0x2002004,
067                        0x200004, 0x2200004, 0x202004, 0x2202004, 1024, 0x2000400, 9216, 0x2002400, 0x200400, 0x2200400,
068                        0x202400, 0x2202400, 1028, 0x2000404, 9220, 0x2002404, 0x200404, 0x2200404, 0x202404, 0x2202404,
069                        0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000,
070                        0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004,
071                        0x10000400, 0x12000400, 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400,
072                        0x10000404, 0x12000404, 0x10002404, 0x12002404, 0x10200404, 0x12200404, 0x10202404, 0x12202404 },
073                { 0, 1, 0x40000, 0x40001, 0x1000000, 0x1000001, 0x1040000, 0x1040001, 2, 3, 0x40002, 0x40003, 0x1000002,
074                        0x1000003, 0x1040002, 0x1040003, 512, 513, 0x40200, 0x40201, 0x1000200, 0x1000201, 0x1040200,
075                        0x1040201, 514, 515, 0x40202, 0x40203, 0x1000202, 0x1000203, 0x1040202, 0x1040203, 0x8000000,
076                        0x8000001, 0x8040000, 0x8040001, 0x9000000, 0x9000001, 0x9040000, 0x9040001, 0x8000002, 0x8000003,
077                        0x8040002, 0x8040003, 0x9000002, 0x9000003, 0x9040002, 0x9040003, 0x8000200, 0x8000201, 0x8040200,
078                        0x8040201, 0x9000200, 0x9000201, 0x9040200, 0x9040201, 0x8000202, 0x8000203, 0x8040202, 0x8040203,
079                        0x9000202, 0x9000203, 0x9040202, 0x9040203 },
080                { 0, 0x100000, 256, 0x100100, 8, 0x100008, 264, 0x100108, 4096, 0x101000, 4352, 0x101100, 4104, 0x101008,
081                        4360, 0x101108, 0x4000000, 0x4100000, 0x4000100, 0x4100100, 0x4000008, 0x4100008, 0x4000108,
082                        0x4100108, 0x4001000, 0x4101000, 0x4001100, 0x4101100, 0x4001008, 0x4101008, 0x4001108, 0x4101108,
083                        0x20000, 0x120000, 0x20100, 0x120100, 0x20008, 0x120008, 0x20108, 0x120108, 0x21000, 0x121000,
084                        0x21100, 0x121100, 0x21008, 0x121008, 0x21108, 0x121108, 0x4020000, 0x4120000, 0x4020100,
085                        0x4120100, 0x4020008, 0x4120008, 0x4020108, 0x4120108, 0x4021000, 0x4121000, 0x4021100, 0x4121100,
086                        0x4021008, 0x4121008, 0x4021108, 0x4121108 },
087                { 0, 0x10000000, 0x10000, 0x10010000, 4, 0x10000004, 0x10004, 0x10010004, 0x20000000, 0x30000000,
088                        0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x100000, 0x10100000,
089                        0x110000, 0x10110000, 0x100004, 0x10100004, 0x110004, 0x10110004, 0x20100000, 0x30100000,
090                        0x20110000, 0x30110000, 0x20100004, 0x30100004, 0x20110004, 0x30110004, 4096, 0x10001000, 0x11000,
091                        0x10011000, 4100, 0x10001004, 0x11004, 0x10011004, 0x20001000, 0x30001000, 0x20011000, 0x30011000,
092                        0x20001004, 0x30001004, 0x20011004, 0x30011004, 0x101000, 0x10101000, 0x111000, 0x10111000,
093                        0x101004, 0x10101004, 0x111004, 0x10111004, 0x20101000, 0x30101000, 0x20111000, 0x30111000,
094                        0x20101004, 0x30101004, 0x20111004, 0x30111004 },
095                { 0, 0x8000000, 8, 0x8000008, 1024, 0x8000400, 1032, 0x8000408, 0x20000, 0x8020000, 0x20008, 0x8020008,
096                        0x20400, 0x8020400, 0x20408, 0x8020408, 1, 0x8000001, 9, 0x8000009, 1025, 0x8000401, 1033,
097                        0x8000409, 0x20001, 0x8020001, 0x20009, 0x8020009, 0x20401, 0x8020401, 0x20409, 0x8020409,
098                        0x2000000, 0xa000000, 0x2000008, 0xa000008, 0x2000400, 0xa000400, 0x2000408, 0xa000408, 0x2020000,
099                        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    }