UnixCrypt.java

  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.  *      https://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. import java.nio.charset.StandardCharsets;
  19. import java.security.SecureRandom;
  20. import java.util.Arrays;
  21. import java.util.regex.Pattern;

  22. /**
  23.  * Unix crypt(3) algorithm implementation.
  24.  * <p>
  25.  * This class only implements the traditional 56 bit DES based algorithm. Please use Crypt.crypt() for a method
  26.  * that distinguishes between all the algorithms supported in the current glibc's crypt().
  27.  * </p>
  28.  * <p>
  29.  * The Java implementation was taken from the JetSpeed Portal project (see
  30.  * org.apache.jetspeed.services.security.ldap.UnixCrypt).
  31.  * </p>
  32.  * <p>
  33.  * This class is slightly incompatible if the given salt contains characters that are not part of the allowed range
  34.  * [a-zA-Z0-9./].
  35.  * </p>
  36.  * <p>
  37.  * This class is immutable and thread-safe.
  38.  * </p>
  39.  *
  40.  * @since 1.7
  41.  */
  42. public class UnixCrypt {

  43.     private static final String CRYPT_SALT_REGEX = "^[" + B64.B64T_STRING + "]{2,}$";
  44.     private static final Pattern CRYPT_SALT_PATTERN = Pattern.compile(CRYPT_SALT_REGEX);

  45.     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,
  46.             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,
  47.             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,
  48.             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,
  49.             54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0 };

  50.     private static final int[] COV2CHAR = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
  51.             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,
  52.             103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 };

  53.     private static final boolean[] SHIFT2 = { false, false, true, true, true, true, true, true, false, true, true,
  54.             true, true, true, true, false };

  55.     private static final int[][] SKB = {
  56.             { 0, 16, 0x20000000, 0x20000010, 0x10000, 0x10010, 0x20010000, 0x20010010, 2048, 2064, 0x20000800,
  57.                     0x20000810, 0x10800, 0x10810, 0x20010800, 0x20010810, 32, 48, 0x20000020, 0x20000030, 0x10020,
  58.                     0x10030, 0x20010020, 0x20010030, 2080, 2096, 0x20000820, 0x20000830, 0x10820, 0x10830, 0x20010820,
  59.                     0x20010830, 0x80000, 0x80010, 0x20080000, 0x20080010, 0x90000, 0x90010, 0x20090000, 0x20090010,
  60.                     0x80800, 0x80810, 0x20080800, 0x20080810, 0x90800, 0x90810, 0x20090800, 0x20090810, 0x80020,
  61.                     0x80030, 0x20080020, 0x20080030, 0x90020, 0x90030, 0x20090020, 0x20090030, 0x80820, 0x80830,
  62.                     0x20080820, 0x20080830, 0x90820, 0x90830, 0x20090820, 0x20090830 },
  63.             { 0, 0x2000000, 8192, 0x2002000, 0x200000, 0x2200000, 0x202000, 0x2202000, 4, 0x2000004, 8196, 0x2002004,
  64.                     0x200004, 0x2200004, 0x202004, 0x2202004, 1024, 0x2000400, 9216, 0x2002400, 0x200400, 0x2200400,
  65.                     0x202400, 0x2202400, 1028, 0x2000404, 9220, 0x2002404, 0x200404, 0x2200404, 0x202404, 0x2202404,
  66.                     0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000,
  67.                     0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004,
  68.                     0x10000400, 0x12000400, 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400,
  69.                     0x10000404, 0x12000404, 0x10002404, 0x12002404, 0x10200404, 0x12200404, 0x10202404, 0x12202404 },
  70.             { 0, 1, 0x40000, 0x40001, 0x1000000, 0x1000001, 0x1040000, 0x1040001, 2, 3, 0x40002, 0x40003, 0x1000002,
  71.                     0x1000003, 0x1040002, 0x1040003, 512, 513, 0x40200, 0x40201, 0x1000200, 0x1000201, 0x1040200,
  72.                     0x1040201, 514, 515, 0x40202, 0x40203, 0x1000202, 0x1000203, 0x1040202, 0x1040203, 0x8000000,
  73.                     0x8000001, 0x8040000, 0x8040001, 0x9000000, 0x9000001, 0x9040000, 0x9040001, 0x8000002, 0x8000003,
  74.                     0x8040002, 0x8040003, 0x9000002, 0x9000003, 0x9040002, 0x9040003, 0x8000200, 0x8000201, 0x8040200,
  75.                     0x8040201, 0x9000200, 0x9000201, 0x9040200, 0x9040201, 0x8000202, 0x8000203, 0x8040202, 0x8040203,
  76.                     0x9000202, 0x9000203, 0x9040202, 0x9040203 },
  77.             { 0, 0x100000, 256, 0x100100, 8, 0x100008, 264, 0x100108, 4096, 0x101000, 4352, 0x101100, 4104, 0x101008,
  78.                     4360, 0x101108, 0x4000000, 0x4100000, 0x4000100, 0x4100100, 0x4000008, 0x4100008, 0x4000108,
  79.                     0x4100108, 0x4001000, 0x4101000, 0x4001100, 0x4101100, 0x4001008, 0x4101008, 0x4001108, 0x4101108,
  80.                     0x20000, 0x120000, 0x20100, 0x120100, 0x20008, 0x120008, 0x20108, 0x120108, 0x21000, 0x121000,
  81.                     0x21100, 0x121100, 0x21008, 0x121008, 0x21108, 0x121108, 0x4020000, 0x4120000, 0x4020100,
  82.                     0x4120100, 0x4020008, 0x4120008, 0x4020108, 0x4120108, 0x4021000, 0x4121000, 0x4021100, 0x4121100,
  83.                     0x4021008, 0x4121008, 0x4021108, 0x4121108 },
  84.             { 0, 0x10000000, 0x10000, 0x10010000, 4, 0x10000004, 0x10004, 0x10010004, 0x20000000, 0x30000000,
  85.                     0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x100000, 0x10100000,
  86.                     0x110000, 0x10110000, 0x100004, 0x10100004, 0x110004, 0x10110004, 0x20100000, 0x30100000,
  87.                     0x20110000, 0x30110000, 0x20100004, 0x30100004, 0x20110004, 0x30110004, 4096, 0x10001000, 0x11000,
  88.                     0x10011000, 4100, 0x10001004, 0x11004, 0x10011004, 0x20001000, 0x30001000, 0x20011000, 0x30011000,
  89.                     0x20001004, 0x30001004, 0x20011004, 0x30011004, 0x101000, 0x10101000, 0x111000, 0x10111000,
  90.                     0x101004, 0x10101004, 0x111004, 0x10111004, 0x20101000, 0x30101000, 0x20111000, 0x30111000,
  91.                     0x20101004, 0x30101004, 0x20111004, 0x30111004 },
  92.             { 0, 0x8000000, 8, 0x8000008, 1024, 0x8000400, 1032, 0x8000408, 0x20000, 0x8020000, 0x20008, 0x8020008,
  93.                     0x20400, 0x8020400, 0x20408, 0x8020408, 1, 0x8000001, 9, 0x8000009, 1025, 0x8000401, 1033,
  94.                     0x8000409, 0x20001, 0x8020001, 0x20009, 0x8020009, 0x20401, 0x8020401, 0x20409, 0x8020409,
  95.                     0x2000000, 0xa000000, 0x2000008, 0xa000008, 0x2000400, 0xa000400, 0x2000408, 0xa000408, 0x2020000,
  96.                     0xa020000, 0x2020008, 0xa020008, 0x2020400, 0xa020400, 0x2020408, 0xa020408, 0x2000001, 0xa000001,
  97.                     0x2000009, 0xa000009, 0x2000401, 0xa000401, 0x2000409, 0xa000409, 0x2020001, 0xa020001, 0x2020009,
  98.                     0xa020009, 0x2020401, 0xa020401, 0x2020409, 0xa020409 },
  99.             { 0, 256, 0x80000, 0x80100, 0x1000000, 0x1000100, 0x1080000, 0x1080100, 16, 272, 0x80010, 0x80110,
  100.                     0x1000010, 0x1000110, 0x1080010, 0x1080110, 0x200000, 0x200100, 0x280000, 0x280100, 0x1200000,
  101.                     0x1200100, 0x1280000, 0x1280100, 0x200010, 0x200110, 0x280010, 0x280110, 0x1200010, 0x1200110,
  102.                     0x1280010, 0x1280110, 512, 768, 0x80200, 0x80300, 0x1000200, 0x1000300, 0x1080200, 0x1080300, 528,
  103.                     784, 0x80210, 0x80310, 0x1000210, 0x1000310, 0x1080210, 0x1080310, 0x200200, 0x200300, 0x280200,
  104.                     0x280300, 0x1200200, 0x1200300, 0x1280200, 0x1280300, 0x200210, 0x200310, 0x280210, 0x280310,
  105.                     0x1200210, 0x1200310, 0x1280210, 0x1280310 },
  106.             { 0, 0x4000000, 0x40000, 0x4040000, 2, 0x4000002, 0x40002, 0x4040002, 8192, 0x4002000, 0x42000, 0x4042000,
  107.                     8194, 0x4002002, 0x42002, 0x4042002, 32, 0x4000020, 0x40020, 0x4040020, 34, 0x4000022, 0x40022,
  108.                     0x4040022, 8224, 0x4002020, 0x42020, 0x4042020, 8226, 0x4002022, 0x42022, 0x4042022, 2048,
  109.                     0x4000800, 0x40800, 0x4040800, 2050, 0x4000802, 0x40802, 0x4040802, 10240, 0x4002800, 0x42800,
  110.                     0x4042800, 10242, 0x4002802, 0x42802, 0x4042802, 2080, 0x4000820, 0x40820, 0x4040820, 2082,
  111.                     0x4000822, 0x40822, 0x4040822, 10272, 0x4002820, 0x42820, 0x4042820, 10274, 0x4002822, 0x42822,
  112.                     0x4042822 } };

  113.     private static final int[][] SPTRANS = {
  114.             { 0x820200, 0x20000, 0x80800000, 0x80820200, 0x800000, 0x80020200, 0x80020000, 0x80800000, 0x80020200,
  115.                     0x820200, 0x820000, 0x80000200, 0x80800200, 0x800000, 0, 0x80020000, 0x20000, 0x80000000,
  116.                     0x800200, 0x20200, 0x80820200, 0x820000, 0x80000200, 0x800200, 0x80000000, 512, 0x20200,
  117.                     0x80820000, 512, 0x80800200, 0x80820000, 0, 0, 0x80820200, 0x800200, 0x80020000, 0x820200,
  118.                     0x20000, 0x80000200, 0x800200, 0x80820000, 512, 0x20200, 0x80800000, 0x80020200, 0x80000000,
  119.                     0x80800000, 0x820000, 0x80820200, 0x20200, 0x820000, 0x80800200, 0x800000, 0x80000200, 0x80020000,
  120.                     0, 0x20000, 0x800000, 0x80800200, 0x820200, 0x80000000, 0x80820000, 512, 0x80020200 },
  121.             { 0x10042004, 0, 0x42000, 0x10040000, 0x10000004, 8196, 0x10002000, 0x42000, 8192, 0x10040004, 4,
  122.                     0x10002000, 0x40004, 0x10042000, 0x10040000, 4, 0x40000, 0x10002004, 0x10040004, 8192, 0x42004,
  123.                     0x10000000, 0, 0x40004, 0x10002004, 0x42004, 0x10042000, 0x10000004, 0x10000000, 0x40000, 8196,
  124.                     0x10042004, 0x40004, 0x10042000, 0x10002000, 0x42004, 0x10042004, 0x40004, 0x10000004, 0,
  125.                     0x10000000, 8196, 0x40000, 0x10040004, 8192, 0x10000000, 0x42004, 0x10002004, 0x10042000, 8192, 0,
  126.                     0x10000004, 4, 0x10042004, 0x42000, 0x10040000, 0x10040004, 0x40000, 8196, 0x10002000, 0x10002004,
  127.                     4, 0x10040000, 0x42000 },
  128.             { 0x41000000, 0x1010040, 64, 0x41000040, 0x40010000, 0x1000000, 0x41000040, 0x10040, 0x1000040, 0x10000,
  129.                     0x1010000, 0x40000000, 0x41010040, 0x40000040, 0x40000000, 0x41010000, 0, 0x40010000, 0x1010040,
  130.                     64, 0x40000040, 0x41010040, 0x10000, 0x41000000, 0x41010000, 0x1000040, 0x40010040, 0x1010000,
  131.                     0x10040, 0, 0x1000000, 0x40010040, 0x1010040, 64, 0x40000000, 0x10000, 0x40000040, 0x40010000,
  132.                     0x1010000, 0x41000040, 0, 0x1010040, 0x10040, 0x41010000, 0x40010000, 0x1000000, 0x41010040,
  133.                     0x40000000, 0x40010040, 0x41000000, 0x1000000, 0x41010040, 0x10000, 0x1000040, 0x41000040,
  134.                     0x10040, 0x1000040, 0, 0x41010000, 0x40000040, 0x41000000, 0x40010040, 64, 0x1010000 },
  135.             { 0x100402, 0x4000400, 2, 0x4100402, 0, 0x4100000, 0x4000402, 0x100002, 0x4100400, 0x4000002, 0x4000000,
  136.                     1026, 0x4000002, 0x100402, 0x100000, 0x4000000, 0x4100002, 0x100400, 1024, 2, 0x100400, 0x4000402,
  137.                     0x4100000, 1024, 1026, 0, 0x100002, 0x4100400, 0x4000400, 0x4100002, 0x4100402, 0x100000,
  138.                     0x4100002, 1026, 0x100000, 0x4000002, 0x100400, 0x4000400, 2, 0x4100000, 0x4000402, 0, 1024,
  139.                     0x100002, 0, 0x4100002, 0x4100400, 1024, 0x4000000, 0x4100402, 0x100402, 0x100000, 0x4100402, 2,
  140.                     0x4000400, 0x100402, 0x100002, 0x100400, 0x4100000, 0x4000402, 1026, 0x4000000, 0x4000002,
  141.                     0x4100400 },
  142.             { 0x2000000, 16384, 256, 0x2004108, 0x2004008, 0x2000100, 16648, 0x2004000, 16384, 8, 0x2000008, 16640,
  143.                     0x2000108, 0x2004008, 0x2004100, 0, 16640, 0x2000000, 16392, 264, 0x2000100, 16648, 0, 0x2000008,
  144.                     8, 0x2000108, 0x2004108, 16392, 0x2004000, 256, 264, 0x2004100, 0x2004100, 0x2000108, 16392,
  145.                     0x2004000, 16384, 8, 0x2000008, 0x2000100, 0x2000000, 16640, 0x2004108, 0, 16648, 0x2000000, 256,
  146.                     16392, 0x2000108, 256, 0, 0x2004108, 0x2004008, 0x2004100, 264, 16384, 16640, 0x2004008,
  147.                     0x2000100, 264, 8, 16648, 0x2004000, 0x2000008 },
  148.             { 0x20000010, 0x80010, 0, 0x20080800, 0x80010, 2048, 0x20000810, 0x80000, 2064, 0x20080810, 0x80800,
  149.                     0x20000000, 0x20000800, 0x20000010, 0x20080000, 0x80810, 0x80000, 0x20000810, 0x20080010, 0, 2048,
  150.                     16, 0x20080800, 0x20080010, 0x20080810, 0x20080000, 0x20000000, 2064, 16, 0x80800, 0x80810,
  151.                     0x20000800, 2064, 0x20000000, 0x20000800, 0x80810, 0x20080800, 0x80010, 0, 0x20000800, 0x20000000,
  152.                     2048, 0x20080010, 0x80000, 0x80010, 0x20080810, 0x80800, 16, 0x20080810, 0x80800, 0x80000,
  153.                     0x20000810, 0x20000010, 0x20080000, 0x80810, 0, 2048, 0x20000010, 0x20000810, 0x20080800,
  154.                     0x20080000, 2064, 16, 0x20080010 },
  155.             { 4096, 128, 0x400080, 0x400001, 0x401081, 4097, 4224, 0, 0x400000, 0x400081, 129, 0x401000, 1, 0x401080,
  156.                     0x401000, 129, 0x400081, 4096, 4097, 0x401081, 0, 0x400080, 0x400001, 4224, 0x401001, 4225,
  157.                     0x401080, 1, 4225, 0x401001, 128, 0x400000, 4225, 0x401000, 0x401001, 129, 4096, 128, 0x400000,
  158.                     0x401001, 0x400081, 4225, 4224, 0, 128, 0x400001, 1, 0x400080, 0, 0x400081, 0x400080, 4224, 129,
  159.                     4096, 0x401081, 0x400000, 0x401080, 1, 4097, 0x401081, 0x400001, 0x401080, 0x401000, 4097 },
  160.             { 0x8200020, 0x8208000, 32800, 0, 0x8008000, 0x200020, 0x8200000, 0x8208020, 32, 0x8000000, 0x208000,
  161.                     32800, 0x208020, 0x8008020, 0x8000020, 0x8200000, 32768, 0x208020, 0x200020, 0x8008000, 0x8208020,
  162.                     0x8000020, 0, 0x208000, 0x8000000, 0x200000, 0x8008020, 0x8200020, 0x200000, 32768, 0x8208000, 32,
  163.                     0x200000, 32768, 0x8000020, 0x8208020, 32800, 0x8000000, 0, 0x208000, 0x8200020, 0x8008020,
  164.                     0x8008000, 0x200020, 0x8208000, 32, 0x200020, 0x8008000, 0x8208020, 0x200000, 0x8200000,
  165.                     0x8000020, 0x208000, 32800, 0x8008020, 0x8200000, 32, 0x8208000, 0x208020, 0, 0x8000000,
  166.                     0x8200020, 32768, 0x208020 } };

  167.     private static int[] body(final int[] schedule, final int eSwap0, final int eSwap1) {
  168.         int left = 0;
  169.         int right = 0;
  170.         int t = 0;
  171.         for (int j = 0; j < 25; j++) {
  172.             for (int i = 0; i < 32; i += 4) {
  173.                 left = dEncrypt(left, right, i, eSwap0, eSwap1, schedule);
  174.                 right = dEncrypt(right, left, i + 2, eSwap0, eSwap1, schedule);
  175.             }
  176.             t = left;
  177.             left = right;
  178.             right = t;
  179.         }

  180.         t = right;
  181.         right = left >>> 1 | left << 31;
  182.         left = t >>> 1 | t << 31;
  183.         final int[] results = new int[2];
  184.         permOp(right, left, 1, 0x55555555, results);
  185.         right = results[0];
  186.         left = results[1];
  187.         permOp(left, right, 8, 0xff00ff, results);
  188.         left = results[0];
  189.         right = results[1];
  190.         permOp(right, left, 2, 0x33333333, results);
  191.         right = results[0];
  192.         left = results[1];
  193.         permOp(left, right, 16, 65535, results);
  194.         left = results[0];
  195.         right = results[1];
  196.         permOp(right, left, 4, 0xf0f0f0f, results);
  197.         right = results[0];
  198.         left = results[1];
  199.         final int[] out = new int[2];
  200.         out[0] = left;
  201.         out[1] = right;
  202.         return out;
  203.     }

  204.     private static int byteToUnsigned(final byte b) {
  205.         return b & 0xff;
  206.     }

  207.     /**
  208.      * Generates a crypt(3) compatible hash using the DES algorithm.
  209.      * <p>
  210.      * A salt is generated for you using {@link SecureRandom}.
  211.      * </p>
  212.      *
  213.      * @param original
  214.      *            plaintext password
  215.      * @return a 13 character string starting with the salt string
  216.      */
  217.     public static String crypt(final byte[] original) {
  218.         return crypt(original, null);
  219.     }

  220.     /**
  221.      * Generates a crypt(3) compatible hash using the DES algorithm.
  222.      * <p>
  223.      * Using unspecified characters as salt results incompatible hash values.
  224.      * </p>
  225.      *
  226.      * @param original
  227.      *            plaintext password
  228.      * @param salt
  229.      *            a two character string drawn from [a-zA-Z0-9./]. The salt may be null, in which case a salt is
  230.      *            generated for you using {@link B64#getRandomSalt(int)}.
  231.      * @return a 13 character string starting with the salt string
  232.      * @throws IllegalArgumentException
  233.      *             if the salt does not match the allowed pattern
  234.      */
  235.     public static String crypt(final byte[] original, String salt) {
  236.         if (salt == null) {
  237.             salt = B64.getRandomSalt(2);
  238.         } else if (!CRYPT_SALT_PATTERN.matcher(salt).matches()) {
  239.             throw new IllegalArgumentException("Invalid salt value: " + salt);
  240.         }

  241.         final StringBuilder buffer = new StringBuilder("             ");
  242.         final char charZero = salt.charAt(0);
  243.         final char charOne = salt.charAt(1);
  244.         buffer.setCharAt(0, charZero);
  245.         buffer.setCharAt(1, charOne);
  246.         final int eSwap0 = CON_SALT[charZero];
  247.         final int eSwap1 = CON_SALT[charOne] << 4;
  248.         final byte[] key = new byte[8];
  249.         Arrays.fill(key, (byte) 0);

  250.         final int originalLength = original.length;
  251.         for (int i = 0; i < key.length && i < originalLength; i++) {
  252.             final int iChar = original[i];
  253.             key[i] = (byte) (iChar << 1);
  254.         }

  255.         final int[] schedule = desSetKey(key);
  256.         final int[] out = body(schedule, eSwap0, eSwap1);
  257.         final byte[] b = new byte[9];
  258.         intToFourBytes(out[0], b, 0);
  259.         intToFourBytes(out[1], b, 4);
  260.         b[8] = 0;
  261.         int i = 2;
  262.         int y = 0;
  263.         int u = 128;
  264.         for (; i < 13; i++) {
  265.             int j = 0;
  266.             int c = 0;
  267.             for (; j < 6; j++) {
  268.                 c <<= 1;
  269.                 if ((b[y] & u) != 0) {
  270.                     c |= 0x1;
  271.                 }
  272.                 u >>>= 1;
  273.                 if (u == 0) {
  274.                     y++;
  275.                     u = 128;
  276.                 }
  277.                 buffer.setCharAt(i, (char) COV2CHAR[c]);
  278.             }
  279.         }
  280.         return buffer.toString();
  281.     }

  282.     /**
  283.      * Generates a crypt(3) compatible hash using the DES algorithm.
  284.      * <p>
  285.      * A salt is generated for you using {@link SecureRandom}.
  286.      * </p>
  287.      *
  288.      * @param original
  289.      *            plaintext password
  290.      * @return a 13 character string starting with the salt string
  291.      */
  292.     public static String crypt(final String original) {
  293.         return crypt(original.getBytes(StandardCharsets.UTF_8));
  294.     }

  295.     /**
  296.      * Generates a crypt(3) compatible hash using the DES algorithm.
  297.      *
  298.      * @param original
  299.      *            plaintext password
  300.      * @param salt
  301.      *            a two character string drawn from [a-zA-Z0-9./]. The salt may be null, in which case a salt is
  302.      *            generated for you using {@link SecureRandom}.
  303.      * @return a 13 character string starting with the salt string
  304.      * @throws IllegalArgumentException
  305.      *             if the salt does not match the allowed pattern
  306.      */
  307.     public static String crypt(final String original, final String salt) {
  308.         return crypt(original.getBytes(StandardCharsets.UTF_8), salt);
  309.     }

  310.     private static int dEncrypt(int el, final int r, final int s, final int e0, final int e1, final int[] sArr) {
  311.         int v = r ^ r >>> 16;
  312.         int u = v & e0;
  313.         v &= e1;
  314.         u = u ^ u << 16 ^ r ^ sArr[s];
  315.         int t = v ^ v << 16 ^ r ^ sArr[s + 1];
  316.         t = t >>> 4 | t << 28;
  317.         el ^= SPTRANS[1][t & 0x3f] | SPTRANS[3][t >>> 8 & 0x3f] | SPTRANS[5][t >>> 16 & 0x3f] |
  318.                 SPTRANS[7][t >>> 24 & 0x3f] | SPTRANS[0][u & 0x3f] | SPTRANS[2][u >>> 8 & 0x3f] |
  319.                 SPTRANS[4][u >>> 16 & 0x3f] | SPTRANS[6][u >>> 24 & 0x3f];
  320.         return el;
  321.     }

  322.     private static int[] desSetKey(final byte[] key) {
  323.         final int[] schedule = new int[32];
  324.         int c = fourBytesToInt(key, 0);
  325.         int d = fourBytesToInt(key, 4);
  326.         final int[] results = new int[2];
  327.         permOp(d, c, 4, 0xf0f0f0f, results);
  328.         d = results[0];
  329.         c = results[1];
  330.         c = hPermOp(c, -2, 0xcccc0000);
  331.         d = hPermOp(d, -2, 0xcccc0000);
  332.         permOp(d, c, 1, 0x55555555, results);
  333.         d = results[0];
  334.         c = results[1];
  335.         permOp(c, d, 8, 0xff00ff, results);
  336.         c = results[0];
  337.         d = results[1];
  338.         permOp(d, c, 1, 0x55555555, results);
  339.         d = results[0];
  340.         c = results[1];
  341.         d = (d & 0xff) << 16 | d & 0xff00 | (d & 0xff0000) >>> 16 | (c & 0xf0000000) >>> 4;
  342.         c &= 0xfffffff;
  343.         int j = 0;
  344.         for (int i = 0; i < 16; i++) {
  345.             if (SHIFT2[i]) {
  346.                 c = c >>> 2 | c << 26;
  347.                 d = d >>> 2 | d << 26;
  348.             } else {
  349.                 c = c >>> 1 | c << 27;
  350.                 d = d >>> 1 | d << 27;
  351.             }
  352.             c &= 0xfffffff;
  353.             d &= 0xfffffff;
  354.             int s = SKB[0][c & 0x3f] | SKB[1][c >>> 6 & 0x3 | c >>> 7 & 0x3c] |
  355.                     SKB[2][c >>> 13 & 0xf | c >>> 14 & 0x30] |
  356.                     SKB[3][c >>> 20 & 0x1 | c >>> 21 & 0x6 | c >>> 22 & 0x38];
  357.             final int t = SKB[4][d & 0x3f] | SKB[5][d >>> 7 & 0x3 | d >>> 8 & 0x3c] | SKB[6][d >>> 15 & 0x3f] |
  358.                     SKB[7][d >>> 21 & 0xf | d >>> 22 & 0x30];
  359.             schedule[j++] = t << 16 | s & 0xffff;
  360.             s = s >>> 16 | t & 0xffff0000;
  361.             s = s << 4 | s >>> 28;
  362.             schedule[j++] = s;
  363.         }

  364.         return schedule;
  365.     }

  366.     private static int fourBytesToInt(final byte[] b, int offset) {
  367.         int value = byteToUnsigned(b[offset++]);
  368.         value |= byteToUnsigned(b[offset++]) << 8;
  369.         value |= byteToUnsigned(b[offset++]) << 16;
  370.         value |= byteToUnsigned(b[offset++]) << 24;
  371.         return value;
  372.     }

  373.     private static int hPermOp(final int a, final int n, final int m) {
  374.         final int t = (a << 16 - n ^ a) & m;
  375.         return a ^ t ^ t >>> 16 - n;
  376.     }

  377.     private static void intToFourBytes(final int iValue, final byte[] b, int offset) {
  378.         b[offset++] = (byte) (iValue & 0xff);
  379.         b[offset++] = (byte) (iValue >>> 8 & 0xff);
  380.         b[offset++] = (byte) (iValue >>> 16 & 0xff);
  381.         b[offset++] = (byte) (iValue >>> 24 & 0xff);
  382.     }

  383.     private static void permOp(int a, int b, final int n, final int m, final int[] results) {
  384.         final int t = (a >>> n ^ b) & m;
  385.         a ^= t << n;
  386.         b ^= t;
  387.         results[0] = a;
  388.         results[1] = b;
  389.     }

  390.     /**
  391.      * TODO Make private in 2.0.
  392.      *
  393.      * @deprecated TODO Make private in 2.0.
  394.      */
  395.     @Deprecated
  396.     public UnixCrypt() {
  397.         // empty
  398.     }
  399. }