function md5crypt(password, salt, magic) {
  var rearranged = '',
      mixin, final, m, v, i;

  m = crypto.createHash('md5');
  m.update(password + magic + salt);
  mixin = crypto.createHash('md5').update(password + salt + password).digest("binary");

  for (i = 0; i < password.length; i++) {
    m.update(mixin[i % 16]);
  }

  // Weird shit..
  for (i = password.length; i > 0; i >>= 1) {
    if (i & 1) {
      m.update('\x00');
    } else {
      m.update(password[0]);
    }
  }

  final = m.digest("binary");

  // Slow it down there...
  for (i = 0; i < 1000; i ++) {
    m = crypto.createHash('md5');

    if (i & 1) {
      m.update(password);
    } else {
      m.update(final);
    }

    if (i % 3) {
      m.update(salt);
    }

    if (i % 7) {
      m.update(password);
    }

    if (i & 1) {
      m.update(final);
    } else {
      m.update(password);
    }

    final = m.digest("binary");
  }


  for (i = 0; i < TUPLES.length; i++) {
    v = final.charCodeAt(TUPLES[i][0]) << 16 | final.charCodeAt(TUPLES[i][1]) << 8 | final.charCodeAt(TUPLES[i][2]);
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
  }

  v = final.charCodeAt(11);
  rearranged += ITOA64[v & 0x3f]; v >>= 6;
  rearranged += ITOA64[v & 0x3f]; v >>= 6;

  return magic + salt + '$' + rearranged;
}
function md5crypt(password, salt, magic) {
  var rearranged = '',
      mixin, final, m, v, i;

  m = crypto.createHash('md5');
  m.update(password + magic + salt);
  mixin = crypto.createHash('md5').update(password + salt + password).digest("binary");

  for (i = 0; i < password.length; i++) {
    m.update(mixin[i % 16]);
  }

  
  for (i = password.length; i > 0; i >>= 1) {
    if (i & 1) {
      m.update('\x00');
    } else {
      m.update(password[0]);
    }
  }

  final = m.digest("binary");

  
  for (i = 0; i < 1000; i ++) {
    m = crypto.createHash('md5');

    if (i & 1) {
      m.update(password);
    } else {
      m.update(final);
    }

    if (i % 3) {
      m.update(salt);
    }

    if (i % 7) {
      m.update(password);
    }

    if (i & 1) {
      m.update(final);
    } else {
      m.update(password);
    }

    final = m.digest("binary");
  }


  for (i = 0; i < TUPLES.length; i++) {
    v = final.charCodeAt(TUPLES[i][0]) << 16 | final.charCodeAt(TUPLES[i][1]) << 8 | final.charCodeAt(TUPLES[i][2]);
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
    rearranged += ITOA64[v & 0x3f]; v >>= 6;
  }

  v = final.charCodeAt(11);
  rearranged += ITOA64[v & 0x3f]; v >>= 6;
  rearranged += ITOA64[v & 0x3f]; v >>= 6;

  return magic + salt + '$' + rearranged;
}
function md5crypt ( password , salt , magic ) { var rearranged = '' , mixin , final , m , v , i ; m = crypto . createHash ( 'md5' ) ; m . update ( password + magic + salt ) ; mixin = crypto . createHash ( 'md5' ) . update ( password + salt + password ) . digest ( "binary" ) ; for ( i = 0 ; i < password . length ; i ++ ) { m . update ( mixin [ i % 16 ] ) ; } // Weird shit.. for ( i = password . length ; i > 0 ; i >>= 1 ) { if ( i & 1 ) { m . update ( '\x00' ) ; } else { m . update ( password [ 0 ] ) ; } } final = m . digest ( "binary" ) ; // Slow it down there... for ( i = 0 ; i < 1000 ; i ++ ) { m = crypto . createHash ( 'md5' ) ; if ( i & 1 ) { m . update ( password ) ; } else { m . update ( final ) ; } if ( i % 3 ) { m . update ( salt ) ; } if ( i % 7 ) { m . update ( password ) ; } if ( i & 1 ) { m . update ( final ) ; } else { m . update ( password ) ; } final = m . digest ( "binary" ) ; } for ( i = 0 ; i < TUPLES . length ; i ++ ) { v = final . charCodeAt ( TUPLES [ i ] [ 0 ] ) << 16 | final . charCodeAt ( TUPLES [ i ] [ 1 ] ) << 8 | final . charCodeAt ( TUPLES [ i ] [ 2 ] ) ; rearranged += ITOA64 [ v & 0x3f ] ; v >>= 6 ; rearranged += ITOA64 [ v & 0x3f ] ; v >>= 6 ; rearranged += ITOA64 [ v & 0x3f ] ; v >>= 6 ; rearranged += ITOA64 [ v & 0x3f ] ; v >>= 6 ; } v = final . charCodeAt ( 11 ) ; rearranged += ITOA64 [ v & 0x3f ] ; v >>= 6 ; rearranged += ITOA64 [ v & 0x3f ] ; v >>= 6 ; return magic + salt + '$' + rearranged ; }
Ported to javascript from http://code.activestate.com/recipes/325204-passwd-file-compatible-1-md5-crypt/
Ported to javascript from http : // code . activestate . com / recipes / 325204 - passwd - file - compatible - 1 - md5 - crypt /