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