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