neverend的日志

不记录,终将被遗忘。 一万年太久,只争朝夕。 他们用数字构建了整个世界。

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  62 Posts :: 1 Stories :: 17 Comments :: 0 Trackbacks

Linux/BSD在/etc/shadow文件中存放加密过的密码,加密函数是crypt(),具体的源程序在glibc里面的crypt目录下。

crypt()函数最初使用DES算法加密密码明文,生成的密文格式是2个字符的salt和11个字符的DES输出;

后来又出现了使用MD5算法生成密文的crypt()函数,这种方式更加安全。

ReadHat命令行下使用authconfig-tui命令可以设置是否使用MD5加密,grub-md5-crypt命令可以生成密文。

下面列出Java版的crypt(),包括DES版的和MD5版的。

DES版:
从这个地址可以得到DES版的crypt()函数:http://www.dynamic.net.au/christos/crypt/,或者看下面的代码:


/**
 * Crypt is the class that implements UFC crypt
 * (ultra fast crypt implementation ).
 * <pre>
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * JAVA version.
 * </pre>
 * 
@author Michael Glad (glad@daimi.aau.dk)
 * 
@author Pawel Veselov (vps@manticore.2y.net)
 
*/

public class Crypt {

    
private static Object lock = new Object();

    
/**
     * Do 32 but permutation and E selection
     *
     * The first index is the byte number in the 32 bit value to be permuted
     *  -  second  -   is the value of this byte
     *  -  third   -   selects the two 32 bit value
     *
     * The table is used and generated internally in initDes() to speed it up.
     
*/

    
private static long ePerm32Tab[][][] = new long[4][256][2];
    
    
private static int pc1_1 = 128;
    
private static int pc1_2 = 2;
    
private static int pc1_3 = 8;

    
private static int pc2_1 = 128;
    
private static int pc2_2 = 8;

    
/**
     * doPc1: perform pc1 permutation in the key schedule generation.
     *
     * The first index is the byte number in the 8 byte ASCII key
     *  -  second  -      -   the two 28 bits halfs on the result
     *  -  third   -      selects the 7 bits actually used of each byte
     *
     *  The result is kept with 28 bit per 32 bit with the 4 most significant
     *  bits zero.
     
*/

    
private static long doPc1[] = new long[pc1_1*pc1_2*pc1_3];

    
/**
     * doPc2: perform pc2 permutation in the key schedule generation.
     *
     * The first index is the septet number in the two 28 bit intermediate values
     *  -  second  -    -  -  speted values
     *
     * Knowledge of the structure of the pc2 permutation is used.
     *
     * The result is kept with 28 bit per 32 bit with the 4 most significant
     * bits zero.
     
*/

    
private static long doPc2[] = new long[pc2_1*pc2_2];

    
/**
     * efp: undo an extra e selection and do final
     * permutation gibing the DES result.
     *
     * Invoked 6 bit a time on two 48 bit vales
     * giving two 32 bit longs.
     
*/

    
private static long efp[][][] = new long[16][64][2];
    
private static int byteMask[]=0x800x400x200x10,
    
0x080x040x020x01 }
;


    
/**
     * Permutation done once on the 56 bit
     * key derived from the original 8 byte ASCII key.
     
*/

    
private static int pc1[] = {
    
574941332517,  9,  1585042342618,
    
10,  259514335271911,  360524436,
    
63554739312315,  7625446383022,
    
14,  661534537292113,  5282012,  4 
    }
;

    
/**
     * How much to rotate each 28 bit half of the pc1 permutated
     * 56 bit key before using pc2 to give i' key.
     
*/

    
private static int rots[] = 112222221,
    
2222221 }
;

    
/**
     * Permutation giving the key of the i' DES round.
     
*/

    
private static int pc2[] = {
    
14171124,  1,  5,  32815,  62110,
    
231912,  426,  816,  7272013,  2,
    
415231374755304051453348,
    
444939563453464250362932
    }
;

    
/**
     * The E expansion table wich selects
     * bits from the 32 bit intermediate result.
     
*/

    
private static int esel[] = {
    
32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,
    
8,  910111213121314151617,
    
161718192021202122232425,
    
2425262728292829303132,  1
    }
;

    
private static int eInverse[] = new int[64];

    
/**
     * Permutation done on the result of sbox lookups.
     
*/

    
private static int perm32[] = {
    
16,  7202129122817,  1152326,  5183110,
    
2,   824143227,  3,  9191330,  62211,  425
    }
;


    
/**
     * The sboxes.
     
*/

    
private static int sbox[][][] = {
    
14,  413,  1,  21511,  8,  310,  612,  5,  9,  0,  7 },
      
{  015,  7,  414,  213,  110,  61211,  9,  5,  3,  8 },
      
{  4,  114,  813,  6,  2111512,  9,  7,  310,  5,  0 },
      
1512,  8,  2,  4,  9,  1,  7,  511,  31410,  0,  613 }}
,

    
15,  1,  814,  611,  3,  4,  9,  7,  21312,  0,  510 },
      
{  313,  4,  715,  2,  81412,  0,  110,  6,  911,  5 },
      
{  014,  71110,  413,  1,  5,  812,  6,  9,  3,  215 },
      
13,  810,  1,  315,  4,  211,  6,  712,  0,  514,  9 }}
,

    
10,  0,  914,  6,  315,  5,  11312,  711,  4,  2,  8 },
      
13,  7,  0,  9,  3,  4,  610,  2,  8,  514121115,  1 },
      
13,  6,  4,  9,  815,  3,  011,  1,  212,  51014,  7 },
      
{  11013,  0,  6,  9,  8,  7,  41514,  311,  5,  212 }}
,

    
{  71314,  3,  0,  6,  910,  1,  2,  8,  51112,  415 },
      
13,  811,  5,  615,  0,  3,  4,  7,  212,  11014,  9 },
      
10,  6,  9,  01211,  71315,  1,  314,  5,  2,  8,  4 },
      
{  315,  0,  610,  113,  8,  9,  4,  51112,  7,  214 }}
,

    
{  212,  4,  1,  71011,  6,  8,  5,  31513,  014,  9 },
      
1411,  212,  4,  713,  1,  5,  01510,  3,  9,  8,  6 },
      
{  4,  2,  1111013,  7,  815,  912,  5,  6,  3,  014 },
      
11,  812,  7,  114,  213,  615,  0,  910,  4,  5,  3 }}
,

    
12,  11015,  9,  2,  6,  8,  013,  3,  414,  7,  511 },
      
1015,  4,  2,  712,  9,  5,  6,  11314,  011,  3,  8 },
      
{  91415,  5,  2,  812,  3,  7,  0,  410,  11311,  6 },
      
{  4,  3,  212,  9,  515101114,  1,  7,  6,  0,  813 }}
,

    
{  411,  21415,  0,  813,  312,  9,  7,  510,  6,  1 },
      
13,  011,  7,  4,  9,  11014,  3,  512,  215,  8,  6 },
      
{  1,  4111312,  3,  7141015,  6,  8,  0,  5,  9,  2 },
      
{  61113,  8,  1,  410,  7,  9,  5,  01514,  2,  312 }}
,

    
13,  2,  8,  4,  61511,  110,  9,  314,  5,  012,  7 },
      
{  11513,  810,  3,  7,  412,  5,  611,  014,  9,  2 },
      
{  711,  4,  1,  91214,  2,  0,  6101315,  3,  5,  8 },
      
{  2,  114,  7,  410,  8131512,  9,  0,  3,  5,  611 }}

    }
;

    
/**
     * This is the initial permutation matrix
     
*/

    
private static int initialPerm[] = {
    
58504234261810,  2605244362820124,
    
62544638302214,  6645648403224168,
    
574941332517,  9,  1595143352719113,
    
61534537292113,  5635547393123157
    }
;

    
/**
     * This is final permutation matrix.
     
*/

    
private static int finalPerm[] = {
    
40,  848165624643239,  7471555236331,
    
38,  646145422623037,  5451353216129,
    
36,  444125220602835,  3431151195927,
    
34,  242105018582633,  141,  949175725
    }
;

    
private static long longMask[] = {
    
0x800000000x400000000x200000000x10000000,
    
0x080000000x040000000x020000000x01000000,
    
0x008000000x004000000x002000000x00100000,
    
0x000800000x000400000x000200000x00010000,
    
0x000080000x000040000x000020000x00001000,
    
0x000008000x000004000x000002000x00000100,
    
0x000000800x000000400x000000200x00000010,
    
0x000000080x000000040x000000020x00000001
    }
;


    
/**
     * The 16 DES keys in BITMASK format
     
*/

    
private static long ufcKeytab[] = new long[16];

    
/**
     * sb arrays:
     *
     * Workhorses of the inner loop of the DES implementation.
     * The do sbox lookup, shifting of this value, 32 bit
     * permutation and E permutation for the next round.
     *
     * Kept in 'BITMASK' format.
     
*/

    
private static long sb[][] = new long[4][4096];

    
private static boolean inited = false;
    
private static byte currentSalt[] = new byte[2];
    
private static int currentSaltbits;
    
private static int direction = 0;

    
/**
     * This method test crypt.
     *
     * 
@param show if set to true, prints test results to STDERR stream
     * 
@return true, if test has succeeded, false otherwise
     
*/

    
public static boolean selfTest(boolean show) {

    String required 
= "arlEKn0OzVJn.";
    
    
if (inited) {
        
if (show) {
        System.err.println(
"Warning: initialization already done.");
        }

    }
 else {
        initDes();
    }


    String cryptTest 
= crypt("ar","foob");
    
    
boolean failed = !required.equals(cryptTest);
    
if (failed) {
        
if (show) {
        System.err.println(
"TEST FAILED! Got:"+cryptTest+" Wanted"+
            required);
        }

        
return false;

    }
 else {
        
if (show) {
        System.err.println(
"Test succeeded");
        }

    }


    
return true;

    }


    
/**
     * crypt function.
     *
     * 
@param salt      two elements byte array with salt.
     * 
@param original      array, maximum 8 bytes, string to encrypt
     
*/

    
public static String crypt(byte[] salt, byte[] original) {
    String originalString 
= new String(original);
    
return crypt(salt, originalString);
    }


    
/**
     * crypt function.
     *
     * 
@param salt      String, maximum length is 2, with salt.
     * 
@param original      String, maximum 8 bytes, string to encrypt
     
*/

    
public static String crypt(String salt, String original) {
    
return crypt(salt.getBytes(), original);
    }


    
/**
     * crypt function.
     *
     * 
@param salt      two elements byte array with salt.
     * 
@param original      String, maximum 8 characters, string to encrypt.
     
*/

    
public static String crypt(byte[] salt, String original) {

    
if (!inited)
        initDes();

    String res;

    
synchronized (lock) {

        
byte ktab[] = new byte[9];
        
        
for (int i=0; i<9; i++{
        ktab[i]
=0;
        }


        setupSalt(salt);

        
int orig=original.length();
        
for (int i=0; i<(orig>8?9:orig); i++{
        ktab[i] 
= (byte)original.charAt(i);
        }


        ufcMkKeytab(ktab);

        
int s[] = ufcDoit(0,0,0,0,25);

        res 
= outputConversion(s[0], s[1], salt);
    }


    
return res;

    }


    
/** 
     * Crypt only: convert from 64 bit to 11 bit ASCII
     
*/

    
private static String outputConversion(int v1, int v2, byte[] salt) {
    
char outbuf[] = new char[13];

    outbuf[
0= (char)salt[0];
    outbuf[
1= (char)((salt[1]!=0)?salt[1]:salt[0]);

    
for (int i = 0; i < 5; i++{
        outbuf[i
+2= binToAscii((v1 >>> (26 - 6 * i)) & 0x3f);
    }


    
int s = (v2 & 0xf<< 2;
    v2 
= (v2 >>> 2| ((v1 & 0x3<< 30);

    
for (int i = 5; i < 10; i++{
        outbuf[i
+2= binToAscii((v2>>>(56 - 6 * i)) & 0x3f);
    }


    outbuf[
12= binToAscii(s);

    
return new String(outbuf);

    }


    
/**
     * Lookup a 6 bit value in sbox
     
*/

    
private static int sLookup(int i, int s) {
    
return sbox[i] [((s>>>4)&0x02)|(s&0x1)] [(s>>>1)&0xf];
    }


    
/**
     * Function to set a bit (0..23)
     
*/

    
private static long bitMask(long i) {
    
long l = (1<<(11-(i)%12+3));
    
long r = ((i)<12?16:0);
    
return (l<<r);
    }



    
/**
     * Initialze unit - can be invoked directly by user. Anyway
     * it is invoked automatically from crypt()
     
*/

    
public static void initDes() {

    
synchronized (lock) {
    
    inited 
= true;
    
for (int bit = 0; bit < 56; bit++{
        
int comesFromBit = pc1[bit] - 1;
        
long mask1 = byteMask[comesFromBit % 8 + 1];
        
long mask2 = longMask[bit % 28 + 4];
        
for (int j=0; j<128; j++{
        
if ((j & mask1) != 0{
            doPc1[j 
+ (bit/28)*pc1_1 +
            (comesFromBit 
/ 8)*pc1_1*pc1_2] |= mask2;
        }

        }

    }



    
for (int bit = 0; bit < 48; bit++{
        
int comesFromBit = pc2[bit]-1;
        
long mask1 = byteMask[comesFromBit % 7 + 1];
        
long mask2 = bitMask(bit % 24);
        
for (int j = 0; j < 128; j++{
        
if ((j & mask1) != 0{
            doPc2[j 
+ (comesFromBit / 7* pc2_1] |= mask2;
        }

        }

    }


    
for (int i=0; i<4; i++)
        
for (int j=0; j<256; j++)
        
for (int k=0; k<2; k++)
            ePerm32Tab[i][j][k] 
= 0;

    
for (int bit=0; bit< 48; bit++{
        
        
int comesFrom = perm32[esel[bit]-1]-1;
        
int mask1     = byteMask[comesFrom % 8];

        
for (int j=255; j>=0; j--{
        
if ((j & mask1) != 0{
            ePerm32Tab[comesFrom
/8][j][bit/24|= bitMask(bit%24);
        }

        }

    }


    
for (int sg = 0; sg<4; sg++{
        
for (int j1 = 0; j1 < 64; j1++{
        
int s1 = sLookup(2*sg, j1);
        
for (int j2 = 0; j2 < 64; j2++{
            
int s2 = sLookup(2*sg+1,j2);
            
int toPermute = ((s1 << 4| s2) << (24 - 8 * sg);

            
int inx = ((j1<<6)|j2);

            sb[sg][inx] 
=(ePerm32Tab[0][(toPermute>>>24)&0xff][0]<<32)|
                     ePerm32Tab[
0][(toPermute>>>24)&0xff][1];
            sb[sg][inx]
|=(ePerm32Tab[1][(toPermute>>>16)&0xff][0]<<32)|
                     ePerm32Tab[
1][(toPermute>>>16)&0xff][1];
            sb[sg][inx]
|=(ePerm32Tab[2][(toPermute>>> 8)&0xff][0]<<32)|
                     ePerm32Tab[
2][(toPermute>>> 8)&0xff][1];
            sb[sg][inx]
|=(ePerm32Tab[3][(toPermute    )&0xff][0]<<32)|
                     ePerm32Tab[
3][(toPermute    )&0xff][1];

        }

        }

    }


    
for (int bit=47; bit>=0; bit--{
        eInverse[esel[bit] 
- 1     ] = bit;
        eInverse[esel[bit] 
- 1 + 32= bit + 48;
    }


    
for (int i=0; i < 16; i++)
        
for (int j=0; j < 64 ; j++)
        
for (int k=0; k < 2; k++)
            efp[i][j][k] 
= 0;
    
    
for (int bit=0; bit < 64; bit++{
        
int oLong = bit / 32;
        
int oBit = bit % 32;

        
int comesFromFBit = finalPerm[bit] - 1;
        
int comesFromEBit = eInverse[comesFromFBit];
        
int comesFromWord = comesFromEBit / 6;
        
int bitWithinWord = comesFromEBit % 6;

        
long mask1 = longMask[bitWithinWord + 26];
        
long mask2 = longMask[oBit];

        
for (int wordValue = 63; wordValue>=0; wordValue--{
        
if ((wordValue & mask1) != 0{
            efp[comesFromWord][wordValue][oLong] 
|= mask2;
        }

        }

    }


    }

    
    }


    
/**
     * Setup the unit for a new salt.
     * Hopefully we'll not see a new salt in each crypt call.
     
*/

    
private static void setupSalt(byte[] s) {

    
if ((s[0== currentSalt[0]) && (s[1== currentSalt[1]))
        
return;

    currentSalt[
0= s[0];
    currentSalt[
1= s[1];

    
int saltbits = 0;
    
for (int i=0; i<2; i++{
        
long c = asciiToBin(s[i]);
        
if (c<0 || c>63{
        c 
= 0;
        }


        
for (int j=0; j < 6; j++{
        
if (((c>>>j)&0x1!= 0{
            saltbits 
|= bitMask(6*i+j);
        }

        }

    }


    shuffleSb(sb[
0], currentSaltbits ^ saltbits);
    shuffleSb(sb[
1], currentSaltbits ^ saltbits);
    shuffleSb(sb[
2], currentSaltbits ^ saltbits);
    shuffleSb(sb[
3], currentSaltbits ^ saltbits);

    currentSaltbits 
= saltbits;
    }


    
/**
     * Process the elements of the sb table permuting the
     * bits swapped in the expansion by the current salt.
     
*/

    
private static void shuffleSb(long[] k, int saltbits) {
    
int i = 0;
    
for (int j=4095; j>=0; j--{
        
long x=((k[i]>>>32^ k[i]) & saltbits;
        k[i
++^= (x << 32| x;
    }

    }


    
private static long asciiToBin(byte c) {
    
return (c>='a'?(c-59):c>='A'?(c-53):c-'.');
    }


    
private static char binToAscii(long c) {
    
return (char)(c>=38?(c-38+'a'):c>=12?(c-12+'A'):c+'.');
    }


    
private static void ufcMkKeytab(byte[] keyInd) {

    
int k1 = 0;
    
int k2 = 0;
    
int key = 0;

    
long v1 = 0;
    
long v2 = 0;
    
    
for (int i=7; i>=0; i--{
        v1 
|= doPc1[(int)(k1 + (keyInd[key  ] & 0x7f))]; k1 += 128;
        v2 
|= doPc1[(int)(k1 + (keyInd[key++& 0x7f))]; k1 += 128;
    }


    
for (int i=0; i< 16; i++{
        k1 
= 0;

        v1 
= (v1 << rots[i]) | (v1 >>> (28 - rots[i]));
        
long v;
        v  
= doPc2[k1+(int)((v1 >>> 21& 0x7f)]; k1 += 128;
        v 
|= doPc2[k1+(int)((v1 >>> 14& 0x7f)]; k1 += 128;
        v 
|= doPc2[k1+(int)((v1 >>>  7& 0x7f)]; k1 += 128;
        v 
|= doPc2[k1+(int)((v1      ) & 0x7f)]; k1 += 128;

        v 
<<= 32;

        v2 
= (v2 << rots[i]) | (v2 >>> (28 - rots[i]));
        v 
|= doPc2[k1+(int)((v2 >>> 21& 0x7f)]; k1 += 128;
        v 
|= doPc2[k1+(int)((v2 >>> 14& 0x7f)]; k1 += 128;
        v 
|= doPc2[k1+(int)((v2 >>>  7& 0x7f)]; k1 += 128;
        v 
|= doPc2[k1+(int)((v2      ) & 0x7f)];

        ufcKeytab[k2] 
= v;
        k2
++;
    }

    direction 
= 0;
    }


    
private static long sba(long[] sb, long v) {
    
if (((v>>>3)<<3!= v) {
        
new Exception("FATAL : non aligned V:"+v).printStackTrace();
    }

    
return sb[(int)(v>>>3)];
    }


    
/**
     * Undo an extra E selection and do final permutations.
     
*/

    
private static int[] ufcDoFinalPerm(int l1, int l2, int r1, int r2) {

    
int v1,v2,x;
    
int ary[] = new int[2];

    x 
= (l1 ^ l2) & currentSaltbits; l1 ^= x; l2 ^= x;
    x 
= (r1 ^ r2) & currentSaltbits; r1 ^= x; r2 ^= x;

    v1
=0;
    v2
=0;

    l1 
>>>= 3;
    l2 
>>>= 3;
    r1 
>>>= 3;
    r2 
>>>= 3;

    v1 
|= efp[15][ r2          & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1];
    v1 
|= efp[14][(r2 >>>= 6)  & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1];
    v1 
|= efp[13][(r2 >>>= 10& 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1];
    v1 
|= efp[12][(r2 >>>= 6)  & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1];

    v1 
|= efp[11][ r1          & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1];
    v1 
|= efp[10][(r1 >>>= 6)  & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1];
    v1 
|= efp[ 9][(r1 >>>= 10& 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1];
    v1 
|= efp[ 8][(r1 >>>= 6)  & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1];

    v1 
|= efp[ 7][ l2          & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1];
    v1 
|= efp[ 6][(l2 >>>= 6)  & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1];
    v1 
|= efp[ 5][(l2 >>>= 10& 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1];
    v1 
|= efp[ 4][(l2 >>>= 6)  & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1];

    v1 
|= efp[ 3][ l1          & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1];
    v1 
|= efp[ 2][(l1 >>>= 6)  & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1];
    v1 
|= efp[ 1][(l1 >>>= 10& 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1];
    v1 
|= efp[ 0][(l1 >>>= 6)  & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1];

    ary[
0= v1;
    ary[
1= v2;

    
return ary;
    }


    
private static int[] ufcDoit(int l1, int l2, int r1, int r2, int itr) {

    
long l = (((long)l1) << 32| ((long)l2);
    
long r = (((long)r1) << 32| ((long)r2);

    
while (itr-- != 0{
        
int k = 0;
        
for (int i=7; i>=0; i--{
        
long s = ufcKeytab[k++^ r;
        l 
^= sba(sb[3], (s >>>  0& 0xffff);
        l 
^= sba(sb[2], (s >>> 16& 0xffff);
        l 
^= sba(sb[1], (s >>> 32& 0xffff);
        l 
^= sba(sb[0], (s >>> 48& 0xffff);

        s 
= ufcKeytab[k++^ l;
        r 
^= sba(sb[3], (s >>>  0& 0xffff);
        r 
^= sba(sb[2], (s >>> 16& 0xffff);
        r 
^= sba(sb[1], (s >>> 32& 0xffff);
        r 
^= sba(sb[0], (s >>> 48& 0xffff);

        }


        
long s = l;
        l 
= r;
        r 
= s;

    }


    l1 
= (int)(l >>> 32); l2 = (int)(l & 0xffffffff);
    r1 
= (int)(r >>> 32); r2 = (int)(r & 0xffffffff);
    
return ufcDoFinalPerm(l1,l2,r1,r2);
    }

}

 

MD5版:

 

import java.security.*;
import java.security.NoSuchAlgorithmException;
import java.security.MessageDigest;

/**
 * A Java Implementation of the MD5Crypt function
 * Modified from the GANYMEDE network directory management system
 * released under the GNU General Public License
 * by the University of Texas at Austin 
 * 
http://tools.arlut.utexas.edu/gash2/
 * Original version from :Jonathan Abbey, jonabbey@arlut.utexas.edu
 * Modified by: Vladimir Silva, vladimir_silva@yahoo.com
 * Modification history:
 * 9/2005
 *      - Removed dependencies on a MD5 private implementation
 *      - Added built-in java.security.MessageDigest (MD5) support
 *      - Code cleanup
 
*/


public class MD5Crypt
{
    
// Character set allowed for the salt string
    static private final String SALTCHARS 
        
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

    
// Character set of the encrypted password: A-Za-z0-9./ 
    static private final String itoa64 
        
= "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    
/**
     * Function to return a string from the set: A-Za-z0-9./
     * 
@return A string of size (size) from the set A-Za-z0-9./
     * 
@param size Length of the string
     * 
@param v value to be converted
     
*/

    
static private final String to64( long v, int size )
    
{
        StringBuffer result 
= new StringBuffer();

        
while ( --size >= 0 )
        
{
            result.append( itoa64.charAt( ( 
int )( v & 0x3f ) ) );
            v 
>>>= 6;
        }


        
return result.toString();
    }


    
static private final void clearbits( byte bits[] )
    
{
        
for ( int i = 0; i < bits.length; i++ )
        
{
            bits[i] 
= 0;
        }

    }


    
/** 
     * convert an encoded unsigned byte value 
     * into a int with the unsigned value. 
     
*/

    
static private final int bytes2u( byte inp )
    
{
        
return ( int )inp & 0xff;
    }


    
/**
     * LINUX/BSD MD5Crypt function
     * 
@return The encrypted password as an MD5 hash
     * 
@param password Password to be encrypted
     
*/

    
static public final String crypt(String password) 
    
{
        StringBuffer salt 
= new StringBuffer();
        java.util.Random rnd 
= new java.util.Random();
        
        
// build a random 8 chars salt        
        while (salt.length() < 8)
        
{
            
int index = (int) (rnd.nextFloat() * SALTCHARS.length());
            salt.append(SALTCHARS.substring(index, index
+1));
        }

        
        
// crypt
        return crypt(password, salt.toString(), "$1$");
    }


    
/**
     * LINUX/BSD MD5Crypt function
     * 
@return The encrypted password as an MD5 hash
     * 
@param salt Random string used to initialize the MD5 engine
     * 
@param password Password to be encrypted
     
*/

    
static public final String crypt(String password, String salt)
    
{
        
return crypt(password, salt, "$1$");
    }


    
/**
     * Linux/BSD MD5Crypt function
     * 
@throws java.lang.Exception
     * 
@return The encrypted password as an MD5 hash
     * 
@param magic $1$ for Linux/BSB, $apr1$ for Apache crypt
     * 
@param salt 8 byte permutation string
     * 
@param password user password
     
*/

    
static public final String crypt( String password, String salt, String magic ) 
    
{

        
byte finalState[];
        
long l;
        
        
/**
         * Two MD5 hashes are used
         
*/

        MessageDigest ctx, ctx1;
        
        
try 
        
{
            ctx 
= MessageDigest.getInstance( "md5" );
            ctx1 
= MessageDigest.getInstance( "md5" );
        }
 
        
catch (NoSuchAlgorithmException ex) 
        
{
            System.err.println(ex);
            
return null;
        }


        
/* Refine the Salt first */
        
/* If it starts with the magic string, then skip that */

        
if ( salt.startsWith( magic ) )
        
{
            salt 
= salt.substring( magic.length() );
        }


        
/* It stops at the first '$', max 8 chars */

        
if ( salt.indexOf( '$' ) != -1 )
        
{
            salt 
= salt.substring( 0, salt.indexOf( '$' ) );
        }


        
if ( salt.length() > 8 )
        
{
            salt 
= salt.substring( 08 );
        }


        
/**
         * Transformation set #1:
         * The password first, since that is what is most unknown
         * Magic string
         * Raw salt
         
*/

        ctx.update( password.getBytes() ); 
        ctx.update( magic.getBytes() ); 
        ctx.update( salt.getBytes() ); 


        
/* Then just as many characters of the MD5(pw,salt,pw) */

        ctx1.update( password.getBytes() );
        ctx1.update( salt.getBytes() );
        ctx1.update( password.getBytes() );
        finalState 
= ctx1.digest(); // ctx1.Final();

        
for ( int pl = password.length(); pl > 0; pl -= 16 )
        
{
            ctx.update( finalState, 
0, pl > 16 ? 16 : pl );
        }


        
/** the original code claimed that finalState was being cleared
        to keep dangerous bits out of memory, 
        but doing this is also required in order to get the right output. 
*/


        clearbits( finalState );

        
/* Then something really weird */

        
for ( int i = password.length(); i != 0; i >>>= 1 )
        
{
            
if ( ( i & 1 ) != 0 )
            
{
                ctx.update( finalState, 
01 );
            }

            
else
            
{
                ctx.update( password.getBytes(), 
01 );
            }

        }


        finalState 
= ctx.digest();

        
/** and now, just to make sure things don't run too fast 
         * On a 60 Mhz Pentium this takes 34 msec, so you would
        * need 30 seconds to build a 1000 entry dictionary 
        * (The above timings from the C version) 
        
*/


        
for ( int i = 0; i < 1000; i++ )
        
{
            
try {
                ctx1 
= MessageDigest.getInstance( "md5" ); 
            }

            
catch (NoSuchAlgorithmException e0 ) return null;}

            
if ( ( i & 1 ) != 0 )
            
{
                ctx1.update( password.getBytes() );
            }

            
else
            
{
                ctx1.update( finalState, 
016 );
            }


            
if ( ( i % 3 ) != 0 )
            
{
                ctx1.update( salt.getBytes() );
            }


            
if ( ( i % 7 ) != 0 )
            
{
                ctx1.update( password.getBytes() );
            }


            
if ( ( i & 1 ) != 0 )
            
{
                ctx1.update( finalState, 
016 );
            }

            
else
            
{
                ctx1.update( password.getBytes() );
            }


            finalState 
= ctx1.digest(); // Final();
        }


        
/* Now make the output string */

        StringBuffer result 
= new StringBuffer();

        result.append( magic );
        result.append( salt );
        result.append( 
"$" );

        
/**
         * Build a 22 byte output string from the set: A-Za-z0-9./
         
*/

        l 
= ( bytes2u( finalState[0] ) << 16 ) 
            
| ( bytes2u( finalState[6] ) << 8 ) | bytes2u( finalState[12] );
        result.append( to64( l, 
4 ) );

        l 
= ( bytes2u( finalState[1] ) << 16 ) 
            
| ( bytes2u( finalState[7] ) << 8 ) | bytes2u( finalState[13] );
        result.append( to64( l, 
4 ) );

        l 
= ( bytes2u( finalState[2] ) << 16 ) 
            
| ( bytes2u( finalState[8] ) << 8 ) | bytes2u( finalState[14] );
        result.append( to64( l, 
4 ) );

        l 
= ( bytes2u( finalState[3] ) << 16 ) 
            
| ( bytes2u( finalState[9] ) << 8 ) | bytes2u( finalState[15] );
        result.append( to64( l, 
4 ) );

        l 
= ( bytes2u( finalState[4] ) << 16 ) 
            
| ( bytes2u( finalState[10] ) << 8 ) | bytes2u( finalState[5] );
        result.append( to64( l, 
4 ) );

        l 
= bytes2u( finalState[11] );
        result.append( to64( l, 
2 ) );

        
/* Don't leave anything around in vm they could use. */
        clearbits( finalState );

        
return result.toString();
    }


    
/**
     * Test subroutine
     * 
@param args
     
*/

    
static final String USAGE = "MD5Crypt <password> <salt>";
    
    
public static void main(String[] args)
    
{
//        try 
//        {
//            if ( args.length != 2) 
//                System.err.println(USAGE);
//            else
//                System.out.println(MD5Crypt.crypt(args[0], args[1]));
//            
//        } catch (Exception ex) 
//        {
//            System.err.println(ex);
//        }
        System.out.println(MD5Crypt.crypt("password123"));
        System.out.println(MD5Crypt.crypt(
"admin""TTBNq/"));
    }

    
}




 

posted on 2010-11-06 21:14 neverend 阅读(1989) 评论(0)  编辑  收藏 所属分类: 编程语言

只有注册用户登录后才能发表评论。


网站导航: