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