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