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