content: /*
   * Copyright 1999-2012 Alibaba Group.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
   * in compliance with the License. You may obtain a copy of the License at
   * 
   * http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software distributed under the License
   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
   * or implied. See the License for the specific language governing permissions and limitations under
   * the License.
   */
  package com.alibaba.cobar.mysql;
  
  import java.security.DigestException;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  
  /**
   * 加密解密工具类
   * 
   * @author xianmao.hexm 2010-4-14 下午03:22:05
   */
  public class SecurityUtil {
  
    private static final int CACHING_SHA2_DIGEST_LENGTH = 32;
  
    public static byte[] scrambleCachingSha2(byte[] password, byte[] seed) throws DigestException {
      MessageDigest md;
      try {
        md = MessageDigest.getInstance("SHA-256");
      } catch (NoSuchAlgorithmException ex) {
        throw new DigestException(ex);
      }
  
      byte[] dig1 = new byte[CACHING_SHA2_DIGEST_LENGTH];
      byte[] dig2 = new byte[CACHING_SHA2_DIGEST_LENGTH];
      byte[] scramble1 = new byte[CACHING_SHA2_DIGEST_LENGTH];
  
      // SHA2(src) => digest_stage1
      md.update(password, 0, password.length);
      md.digest(dig1, 0, CACHING_SHA2_DIGEST_LENGTH);
      md.reset();
  
      // SHA2(digest_stage1) => digest_stage2
      md.update(dig1, 0, dig1.length);
      md.digest(dig2, 0, CACHING_SHA2_DIGEST_LENGTH);
      md.reset();
  
      // SHA2(digest_stage2, m_rnd) => scramble_stage1
      md.update(dig2, 0, dig1.length);
      md.update(seed, 0, seed.length);
      md.digest(scramble1, 0, CACHING_SHA2_DIGEST_LENGTH);
  
      // XOR(digest_stage1, scramble_stage1) => scramble
      byte[] mysqlScrambleBuff = new byte[CACHING_SHA2_DIGEST_LENGTH];
      xorString(dig1, mysqlScrambleBuff, scramble1, CACHING_SHA2_DIGEST_LENGTH);
  
      return mysqlScrambleBuff;
    }
  
    public static final byte[] scramble411(byte[] pass, byte[] seed) throws NoSuchAlgorithmException {
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      byte[] pass1 = md.digest(pass);
      md.reset();
      byte[] pass2 = md.digest(pass1);
      md.reset();
      md.update(seed);
      byte[] pass3 = md.digest(pass2);
      for (int i = 0; i < pass3.length; i++) {
        pass3[i] = (byte) (pass3[i] ^ pass1[i]);
      }
      return pass3;
    }
  
    public static final String scramble323(String pass, String seed) {
      if ((pass == null) || (pass.length() == 0)) {
        return pass;
      }
      byte b;
      double d;
      long[] pw = hash(seed);
      long[] msg = hash(pass);
      long max = 0x3fffffffL;
      long seed1 = (pw[0] ^ msg[0]) % max;
      long seed2 = (pw[1] ^ msg[1]) % max;
      char[] chars = new char[seed.length()];
      for (int i = 0; i < seed.length(); i++) {
        seed1 = ((seed1 * 3) + seed2) % max;
        seed2 = (seed1 + seed2 + 33) % max;
        d = (double) seed1 / (double) max;
        b = (byte) java.lang.Math.floor((d * 31) + 64);
        chars[i] = (char) b;
      }
      seed1 = ((seed1 * 3) + seed2) % max;
      seed2 = (seed1 + seed2 + 33) % max;
      d = (double) seed1 / (double) max;
      b = (byte) java.lang.Math.floor(d * 31);
      for (int i = 0; i < seed.length(); i++) {
        chars[i] ^= (char) b;
      }
      return new String(chars);
    }
  
    private static long[] hash(String src) {
      long nr = 1345345333L;
      long add = 7;
      long nr2 = 0x12345671L;
      long tmp;
      for (int i = 0; i < src.length(); ++i) {
        switch (src.charAt(i)) {
          case ' ':
          case '\t':
            continue;
          default:
            tmp = (0xff & src.charAt(i));
            nr ^= ((((nr & 63) + add) * tmp) + (nr << 8));
            nr2 += ((nr2 << 8) ^ nr);
            add += tmp;
        }
      }
      long[] result = new long[2];
      result[0] = nr & 0x7fffffffL;
      result[1] = nr2 & 0x7fffffffL;
      return result;
    }
  
    private static void xorString(byte[] from, byte[] to, byte[] scramble, int length) {
      int pos = 0;
      int scrambleLength = scramble.length;
      while (pos < length) {
        to[pos] = (byte) (from[pos] ^ scramble[pos % scrambleLength]);
        pos++;
      }
    }
  
  }
  