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 *      https://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.regex.Pattern;
023
024/**
025 * Unix crypt(3) algorithm implementation.
026 * <p>
027 * This class only implements the traditional 56 bit DES based algorithm. Please use Crypt.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 String CRYPT_SALT_REGEX = "^[" + B64.B64T_STRING + "]{2,}$";
047    private static final Pattern CRYPT_SALT_PATTERN = Pattern.compile(CRYPT_SALT_REGEX);
048
049    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,
050            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,
051            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,
052            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,
053            54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0 };
054
055    private static final int[] COV2CHAR = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
056            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,
057            103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 };
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    private static int[] body(final int[] schedule, final int eSwap0, final int eSwap1) {
177        int left = 0;
178        int right = 0;
179        int t = 0;
180        for (int j = 0; j < 25; j++) {
181            for (int i = 0; i < 32; i += 4) {
182                left = dEncrypt(left, right, i, eSwap0, eSwap1, schedule);
183                right = dEncrypt(right, left, i + 2, eSwap0, eSwap1, schedule);
184            }
185            t = left;
186            left = right;
187            right = t;
188        }
189
190        t = right;
191        right = left >>> 1 | left << 31;
192        left = t >>> 1 | t << 31;
193        final int[] results = new int[2];
194        permOp(right, left, 1, 0x55555555, results);
195        right = results[0];
196        left = results[1];
197        permOp(left, right, 8, 0xff00ff, results);
198        left = results[0];
199        right = results[1];
200        permOp(right, left, 2, 0x33333333, results);
201        right = results[0];
202        left = results[1];
203        permOp(left, right, 16, 65535, results);
204        left = results[0];
205        right = results[1];
206        permOp(right, left, 4, 0xf0f0f0f, results);
207        right = results[0];
208        left = results[1];
209        final int[] out = new int[2];
210        out[0] = left;
211        out[1] = right;
212        return out;
213    }
214
215    private static int byteToUnsigned(final byte b) {
216        return b & 0xff;
217    }
218
219    /**
220     * Generates a crypt(3) compatible hash using the DES algorithm.
221     * <p>
222     * A salt is generated for you using {@link SecureRandom}.
223     * </p>
224     *
225     * @param original
226     *            plaintext password
227     * @return a 13 character string starting with the salt string
228     */
229    public static String crypt(final byte[] original) {
230        return crypt(original, null);
231    }
232
233    /**
234     * Generates a crypt(3) compatible hash using the DES algorithm.
235     * <p>
236     * Using unspecified characters as salt results incompatible hash values.
237     * </p>
238     *
239     * @param original
240     *            plaintext password
241     * @param salt
242     *            a two character string drawn from [a-zA-Z0-9./]. The salt may be null, in which case a salt is
243     *            generated for you using {@link B64#getRandomSalt(int)}.
244     * @return a 13 character string starting with the salt string
245     * @throws IllegalArgumentException
246     *             if the salt does not match the allowed pattern
247     */
248    public static String crypt(final byte[] original, String salt) {
249        if (salt == null) {
250            salt = B64.getRandomSalt(2);
251        } else if (!CRYPT_SALT_PATTERN.matcher(salt).matches()) {
252            throw new IllegalArgumentException("Invalid salt value: " + salt);
253        }
254
255        final StringBuilder buffer = new StringBuilder("             ");
256        final char charZero = salt.charAt(0);
257        final char charOne = salt.charAt(1);
258        buffer.setCharAt(0, charZero);
259        buffer.setCharAt(1, charOne);
260        final int eSwap0 = CON_SALT[charZero];
261        final int eSwap1 = CON_SALT[charOne] << 4;
262        final byte[] key = new byte[8];
263        Arrays.fill(key, (byte) 0);
264
265        final int originalLength = original.length;
266        for (int i = 0; i < key.length && i < originalLength; i++) {
267            final int iChar = original[i];
268            key[i] = (byte) (iChar << 1);
269        }
270
271        final int[] schedule = desSetKey(key);
272        final int[] out = body(schedule, eSwap0, eSwap1);
273        final byte[] b = new byte[9];
274        intToFourBytes(out[0], b, 0);
275        intToFourBytes(out[1], b, 4);
276        b[8] = 0;
277        int i = 2;
278        int y = 0;
279        int u = 128;
280        for (; i < 13; i++) {
281            int j = 0;
282            int c = 0;
283            for (; j < 6; j++) {
284                c <<= 1;
285                if ((b[y] & u) != 0) {
286                    c |= 0x1;
287                }
288                u >>>= 1;
289                if (u == 0) {
290                    y++;
291                    u = 128;
292                }
293                buffer.setCharAt(i, (char) COV2CHAR[c]);
294            }
295        }
296        return buffer.toString();
297    }
298
299    /**
300     * Generates a crypt(3) compatible hash using the DES algorithm.
301     * <p>
302     * A salt is generated for you using {@link SecureRandom}.
303     * </p>
304     *
305     * @param original
306     *            plaintext password
307     * @return a 13 character string starting with the salt string
308     */
309    public static String crypt(final String original) {
310        return crypt(original.getBytes(StandardCharsets.UTF_8));
311    }
312
313    /**
314     * Generates a crypt(3) compatible hash using the DES algorithm.
315     *
316     * @param original
317     *            plaintext password
318     * @param salt
319     *            a two character string drawn from [a-zA-Z0-9./]. The salt may be null, in which case a salt is
320     *            generated for you using {@link SecureRandom}.
321     * @return a 13 character string starting with the salt string
322     * @throws IllegalArgumentException
323     *             if the salt does not match the allowed pattern
324     */
325    public static String crypt(final String original, final String salt) {
326        return crypt(original.getBytes(StandardCharsets.UTF_8), salt);
327    }
328
329    private static int dEncrypt(int el, final int r, final int s, final int e0, final int e1, final int[] sArr) {
330        int v = r ^ r >>> 16;
331        int u = v & e0;
332        v &= e1;
333        u = u ^ u << 16 ^ r ^ sArr[s];
334        int t = v ^ v << 16 ^ r ^ sArr[s + 1];
335        t = t >>> 4 | t << 28;
336        el ^= SPTRANS[1][t & 0x3f] | SPTRANS[3][t >>> 8 & 0x3f] | SPTRANS[5][t >>> 16 & 0x3f] |
337                SPTRANS[7][t >>> 24 & 0x3f] | SPTRANS[0][u & 0x3f] | SPTRANS[2][u >>> 8 & 0x3f] |
338                SPTRANS[4][u >>> 16 & 0x3f] | SPTRANS[6][u >>> 24 & 0x3f];
339        return el;
340    }
341
342    private static int[] desSetKey(final byte[] key) {
343        final int[] schedule = new int[32];
344        int c = fourBytesToInt(key, 0);
345        int d = fourBytesToInt(key, 4);
346        final int[] results = new int[2];
347        permOp(d, c, 4, 0xf0f0f0f, results);
348        d = results[0];
349        c = results[1];
350        c = hPermOp(c, -2, 0xcccc0000);
351        d = hPermOp(d, -2, 0xcccc0000);
352        permOp(d, c, 1, 0x55555555, results);
353        d = results[0];
354        c = results[1];
355        permOp(c, d, 8, 0xff00ff, results);
356        c = results[0];
357        d = results[1];
358        permOp(d, c, 1, 0x55555555, results);
359        d = results[0];
360        c = results[1];
361        d = (d & 0xff) << 16 | d & 0xff00 | (d & 0xff0000) >>> 16 | (c & 0xf0000000) >>> 4;
362        c &= 0xfffffff;
363        int j = 0;
364        for (int i = 0; i < 16; i++) {
365            if (SHIFT2[i]) {
366                c = c >>> 2 | c << 26;
367                d = d >>> 2 | d << 26;
368            } else {
369                c = c >>> 1 | c << 27;
370                d = d >>> 1 | d << 27;
371            }
372            c &= 0xfffffff;
373            d &= 0xfffffff;
374            int s = SKB[0][c & 0x3f] | SKB[1][c >>> 6 & 0x3 | c >>> 7 & 0x3c] |
375                    SKB[2][c >>> 13 & 0xf | c >>> 14 & 0x30] |
376                    SKB[3][c >>> 20 & 0x1 | c >>> 21 & 0x6 | c >>> 22 & 0x38];
377            final int t = SKB[4][d & 0x3f] | SKB[5][d >>> 7 & 0x3 | d >>> 8 & 0x3c] | SKB[6][d >>> 15 & 0x3f] |
378                    SKB[7][d >>> 21 & 0xf | d >>> 22 & 0x30];
379            schedule[j++] = t << 16 | s & 0xffff;
380            s = s >>> 16 | t & 0xffff0000;
381            s = s << 4 | s >>> 28;
382            schedule[j++] = s;
383        }
384
385        return schedule;
386    }
387
388    private static int fourBytesToInt(final byte[] b, int offset) {
389        int value = byteToUnsigned(b[offset++]);
390        value |= byteToUnsigned(b[offset++]) << 8;
391        value |= byteToUnsigned(b[offset++]) << 16;
392        value |= byteToUnsigned(b[offset++]) << 24;
393        return value;
394    }
395
396    private static int hPermOp(final int a, final int n, final int m) {
397        final int t = (a << 16 - n ^ a) & m;
398        return a ^ t ^ t >>> 16 - n;
399    }
400
401    private static void intToFourBytes(final int iValue, final byte[] b, int offset) {
402        b[offset++] = (byte) (iValue & 0xff);
403        b[offset++] = (byte) (iValue >>> 8 & 0xff);
404        b[offset++] = (byte) (iValue >>> 16 & 0xff);
405        b[offset++] = (byte) (iValue >>> 24 & 0xff);
406    }
407
408    private static void permOp(int a, int b, final int n, final int m, final int[] results) {
409        final int t = (a >>> n ^ b) & m;
410        a ^= t << n;
411        b ^= t;
412        results[0] = a;
413        results[1] = b;
414    }
415
416    /**
417     * TODO Make private in 2.0.
418     *
419     * @deprecated TODO Make private in 2.0.
420     */
421    @Deprecated
422    public UnixCrypt() {
423        // empty
424    }
425}