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 */
017package org.apache.commons.codec.digest;
018
019import java.util.Random;
020
021import 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 891688 2013-12-24 20:49:46Z ggregory $
038 * @since 1.7
039 */
040public 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}