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