View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.codec.digest;
18  
19  import java.nio.charset.StandardCharsets;
20  import java.security.SecureRandom;
21  import java.util.Arrays;
22  import java.util.regex.Pattern;
23  
24  /**
25   * Unix crypt(3) algorithm implementation.
26   * <p>
27   * This class only implements the traditional 56 bit DES based algorithm. Please use DigestUtils.crypt() for a method
28   * that distinguishes between all the algorithms supported in the current glibc's crypt().
29   * </p>
30   * <p>
31   * The Java implementation was taken from the JetSpeed Portal project (see
32   * org.apache.jetspeed.services.security.ldap.UnixCrypt).
33   * </p>
34   * <p>
35   * This class is slightly incompatible if the given salt contains characters that are not part of the allowed range
36   * [a-zA-Z0-9./].
37   * </p>
38   * <p>
39   * This class is immutable and thread-safe.
40   * </p>
41   *
42   * @since 1.7
43   */
44  public class UnixCrypt {
45  
46      private static final String CRYPT_SALT_REGEX = "^[" + B64.B64T_STRING + "]{2,}$";
47      private static final Pattern CRYPT_SALT_PATTERN = Pattern.compile(CRYPT_SALT_REGEX);
48  
49      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,
50              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,
51              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,
52              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,
53              54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0 };
54  
55      private static final int[] COV2CHAR = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
56              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,
57              103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 };
58  
59      private static final char[] SALT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
60              .toCharArray();
61  
62      private static final boolean[] SHIFT2 = { false, false, true, true, true, true, true, true, false, true, true,
63              true, true, true, true, false };
64  
65      private static final int[][] SKB = {
66              { 0, 16, 0x20000000, 0x20000010, 0x10000, 0x10010, 0x20010000, 0x20010010, 2048, 2064, 0x20000800,
67                      0x20000810, 0x10800, 0x10810, 0x20010800, 0x20010810, 32, 48, 0x20000020, 0x20000030, 0x10020,
68                      0x10030, 0x20010020, 0x20010030, 2080, 2096, 0x20000820, 0x20000830, 0x10820, 0x10830, 0x20010820,
69                      0x20010830, 0x80000, 0x80010, 0x20080000, 0x20080010, 0x90000, 0x90010, 0x20090000, 0x20090010,
70                      0x80800, 0x80810, 0x20080800, 0x20080810, 0x90800, 0x90810, 0x20090800, 0x20090810, 0x80020,
71                      0x80030, 0x20080020, 0x20080030, 0x90020, 0x90030, 0x20090020, 0x20090030, 0x80820, 0x80830,
72                      0x20080820, 0x20080830, 0x90820, 0x90830, 0x20090820, 0x20090830 },
73              { 0, 0x2000000, 8192, 0x2002000, 0x200000, 0x2200000, 0x202000, 0x2202000, 4, 0x2000004, 8196, 0x2002004,
74                      0x200004, 0x2200004, 0x202004, 0x2202004, 1024, 0x2000400, 9216, 0x2002400, 0x200400, 0x2200400,
75                      0x202400, 0x2202400, 1028, 0x2000404, 9220, 0x2002404, 0x200404, 0x2200404, 0x202404, 0x2202404,
76                      0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000,
77                      0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004,
78                      0x10000400, 0x12000400, 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400,
79                      0x10000404, 0x12000404, 0x10002404, 0x12002404, 0x10200404, 0x12200404, 0x10202404, 0x12202404 },
80              { 0, 1, 0x40000, 0x40001, 0x1000000, 0x1000001, 0x1040000, 0x1040001, 2, 3, 0x40002, 0x40003, 0x1000002,
81                      0x1000003, 0x1040002, 0x1040003, 512, 513, 0x40200, 0x40201, 0x1000200, 0x1000201, 0x1040200,
82                      0x1040201, 514, 515, 0x40202, 0x40203, 0x1000202, 0x1000203, 0x1040202, 0x1040203, 0x8000000,
83                      0x8000001, 0x8040000, 0x8040001, 0x9000000, 0x9000001, 0x9040000, 0x9040001, 0x8000002, 0x8000003,
84                      0x8040002, 0x8040003, 0x9000002, 0x9000003, 0x9040002, 0x9040003, 0x8000200, 0x8000201, 0x8040200,
85                      0x8040201, 0x9000200, 0x9000201, 0x9040200, 0x9040201, 0x8000202, 0x8000203, 0x8040202, 0x8040203,
86                      0x9000202, 0x9000203, 0x9040202, 0x9040203 },
87              { 0, 0x100000, 256, 0x100100, 8, 0x100008, 264, 0x100108, 4096, 0x101000, 4352, 0x101100, 4104, 0x101008,
88                      4360, 0x101108, 0x4000000, 0x4100000, 0x4000100, 0x4100100, 0x4000008, 0x4100008, 0x4000108,
89                      0x4100108, 0x4001000, 0x4101000, 0x4001100, 0x4101100, 0x4001008, 0x4101008, 0x4001108, 0x4101108,
90                      0x20000, 0x120000, 0x20100, 0x120100, 0x20008, 0x120008, 0x20108, 0x120108, 0x21000, 0x121000,
91                      0x21100, 0x121100, 0x21008, 0x121008, 0x21108, 0x121108, 0x4020000, 0x4120000, 0x4020100,
92                      0x4120100, 0x4020008, 0x4120008, 0x4020108, 0x4120108, 0x4021000, 0x4121000, 0x4021100, 0x4121100,
93                      0x4021008, 0x4121008, 0x4021108, 0x4121108 },
94              { 0, 0x10000000, 0x10000, 0x10010000, 4, 0x10000004, 0x10004, 0x10010004, 0x20000000, 0x30000000,
95                      0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x100000, 0x10100000,
96                      0x110000, 0x10110000, 0x100004, 0x10100004, 0x110004, 0x10110004, 0x20100000, 0x30100000,
97                      0x20110000, 0x30110000, 0x20100004, 0x30100004, 0x20110004, 0x30110004, 4096, 0x10001000, 0x11000,
98                      0x10011000, 4100, 0x10001004, 0x11004, 0x10011004, 0x20001000, 0x30001000, 0x20011000, 0x30011000,
99                      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 }