hashmodule.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 524 行

JAVA
524
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * *   Free Software Foundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.quercus.lib;import com.caucho.config.ConfigException;import com.caucho.quercus.annotation.Optional;import com.caucho.quercus.env.*;import com.caucho.quercus.module.*;import com.caucho.util.*;import com.caucho.vfs.*;import java.io.*;import java.security.*;import java.util.*;import java.util.logging.Level;import java.util.logging.Logger;import javax.crypto.*;import javax.crypto.spec.*;/** * Hash functions. * * This module uses the {@link MessageDigest} class to calculate * digests. Typical java installations support MD2, MD5, SHA1, SHA256, SHA384, * and SHA512. */public class HashModule extends AbstractQuercusModule {  private static final L10N L = new L10N(HashModule.class);  private static final Logger log    = Logger.getLogger(HashModule.class.getName());  public static final int HASH_HMAC = 1;  private static HashMap<String,String> _algorithmMap    = new HashMap<String,String>();  public HashModule()  {  }  public String []getLoadedExtensions()  {    return new String[] { "hash" };  }  /**   * Hashes a string   */  public Value hash(Env env,		    String algorithm,		    StringValue string,		    @Optional boolean isBinary)  {    try {      MessageDigest digest = MessageDigest.getInstance(algorithm);            int len = string.length();      for (int i = 0; i < len; i++) {	digest.update((byte) string.charAt(i));      }      byte []bytes = digest.digest();      return hashToValue(env, bytes, isBinary);    } catch (NoSuchAlgorithmException e) {      env.error(L.l("'{0}' is an unknown algorithm", algorithm), e);      return BooleanValue.FALSE;    }  }  /**   * Returns the list of known algorithms   */  public static Value hash_algos(Env env)  {    ArrayValue array = new ArrayValueImpl();    for (String name : _algorithmMap.keySet()) {      array.put(env.createString(name));    }    Collection<String> values = _algorithmMap.values();    for (String name : Security.getAlgorithms("MessageDigest")) {      if (! values.contains(name))	array.put(env.createString(name));    }        return array;  }  /**   * Copies a hash instance   */  public HashContext hash_copy(HashContext context)  {    if (context != null)      return context.copy();    else      return null;  }  /**   * Hashes a file   */  public Value hash_file(Env env,			 String algorithm,			 Path path,			 @Optional boolean isBinary)  {    try {      MessageDigest digest = MessageDigest.getInstance(algorithm);      TempBuffer tempBuffer = TempBuffer.allocate();      byte []buffer = tempBuffer.getBuffer();      ReadStream is = path.openRead();            try {        int len;        while ((len = is.read(buffer, 0, buffer.length)) > 0) {          digest.update(buffer, 0, len);        }        byte []bytes = digest.digest();        return hashToValue(env, bytes, isBinary);      } finally {        TempBuffer.free(tempBuffer);                is.close();      }    } catch (NoSuchAlgorithmException e) {      env.error(L.l("'{0}' is an unknown algorithm", algorithm), e);      return BooleanValue.FALSE;    } catch (IOException e) {      env.error(L.l("'{0}' is an unknown file", path), e);      return BooleanValue.FALSE;    }  }  /**   * Returns the final hash value   */  public Value hash_final(Env env,			  HashContext context,			  @Optional boolean isBinary)  {    if (context == null)      return BooleanValue.FALSE;    return hashToValue(env, context.digest(), isBinary);  }  /**   * Hashes a string with the algorithm.   */  public Value hash_hmac(Env env,			 String algorithm,			 StringValue data,			 StringValue key,			 @Optional boolean isBinary)  {    HashContext context = hash_init(env, algorithm, HASH_HMAC, key);        hash_update(env, context, data);    return hash_final(env, context, isBinary);  }  /**   * Hashes a file with the algorithm.   */  public Value hash_hmac_file(Env env,			      String algorithm,			      Path path,			      StringValue key,			      @Optional boolean isBinary)  {    HashContext context = hash_init(env, algorithm, HASH_HMAC, key);        hash_update_file(env, context, path);    return hash_final(env, context, isBinary);  }  /**   * Initialize a hash context.   */  public HashContext hash_init(Env env,			       String algorithm,			       @Optional int options,			       @Optional StringValue keyString)  {    try {      if (options == HASH_HMAC) {        algorithm = "Hmac" + algorithm;        KeyGenerator gen = KeyGenerator.getInstance(algorithm);        Mac mac = Mac.getInstance(algorithm);        int keySize = 64;        // php/530c        if (keyString != null)          keySize = keyString.length();        byte []keyBytes = new byte[keySize];        for (int i = 0; i < keyString.length(); i++) {          keyBytes[i] = (byte) keyString.charAt(i);        }        Key key = new SecretKeySpec(keyBytes, "dsa");        mac.init(key);        return new HashMacContext(mac);      }      else {        MessageDigest md = MessageDigest.getInstance(algorithm);        return new HashDigestContext(md);      }    } catch (Exception e) {      env.error(L.l("hash_init: '{0}' is an unknown algorithm",		    algorithm));      return null;    }  }  /**   * Updates the hash with more data   */  public Value hash_update(Env env,			   HashContext context,			   StringValue value)  {    if (context == null)      return BooleanValue.FALSE;    context.update(value);    return BooleanValue.TRUE;  }  /**   * Updates the hash with more data   */  public Value hash_update_file(Env env,				HashContext context,				Path path)  {    if (context == null)      return BooleanValue.FALSE;    TempBuffer tempBuffer = TempBuffer.allocate();    byte []buffer = tempBuffer.getBuffer();    ReadStream is = null;    try {      is = path.openRead();            int len;      while ((len = is.read(buffer, 0, buffer.length)) > 0) {	context.update(buffer, 0, len);      }    } catch (IOException e) {      log.log(Level.WARNING, e.toString(), e);    } finally {      TempBuffer.free(tempBuffer);      if (is != null)	is.close();    }    return BooleanValue.TRUE;  }  /**   * Updates the hash with more data   */  public int hash_update_stream(Env env,				HashContext context,				InputStream is,				@Optional("-1") int length)  {    if (context == null)      return -1;    if (length < 0)      length = Integer.MAX_VALUE - 1;    TempBuffer tempBuffer = TempBuffer.allocate();    byte []buffer = tempBuffer.getBuffer();        int readLength = 0;    try {      while (length > 0) {	int sublen = buffer.length;	if (length < sublen)	  sublen = length;	int len = is.read(buffer, 0, sublen);	if (len < 0)	  return readLength;	context.update(buffer, 0, len);	readLength += len;	length -= len;      }    } catch (IOException e) {      log.log(Level.WARNING, e.toString(), e);    } finally {      TempBuffer.free(tempBuffer);    }    return readLength;  }    // XXX: hash_update_file  // XXX: hash_update_stream  // XXX: hash_update  // XXX: hash  private static Value hashToValue(Env env, byte []bytes, boolean isBinary)  {    if (isBinary) {      StringValue v = env.createBinaryBuilder();      v.append(bytes, 0, bytes.length);      return v;    }    else {      StringValue v = env.createUnicodeBuilder();      for (int i = 0; i < bytes.length; i++) {	int ch = bytes[i];	int d1 = (ch >> 4) & 0xf;	int d2 = (ch) & 0xf;	if (d1 < 10)	  v.append((char) ('0' + d1));	else	  v.append((char) ('a' + d1 - 10));	if (d2 < 10)	  v.append((char) ('0' + d2));	else	  v.append((char) ('a' + d2 - 10));      }      return v;    }  }  public abstract static class HashContext  {    abstract void update(StringValue value);        abstract void update(byte []buffer, int offset, int length);        abstract byte []digest();    abstract HashContext copy();  }  public static class HashDigestContext extends HashContext  {    private MessageDigest _digest;    HashDigestContext(MessageDigest digest)    {      _digest = digest;    }    MessageDigest getDigest()    {      return _digest;    }        void update(byte value)    {      _digest.update(value);    }        void update(StringValue value)    {      int len = value.length();      MessageDigest digest = _digest;          for (int i = 0; i < len; i++) {	digest.update((byte) value.charAt(i));      }    }        void update(byte []buffer, int offset, int length)    {      _digest.update(buffer, offset, length);    }    byte []digest()    {      return _digest.digest();    }    HashContext copy()    {      try {	return new HashDigestContext((MessageDigest) _digest.clone());      } catch (Exception e) {	log.log(Level.FINE, e.toString(), e);	return null;      }    }    public String toString()    {      return (getClass().getSimpleName() + "[" + _digest + "]");    }  }  public static class HashMacContext extends HashContext  {    private Mac _digest;    HashMacContext(Mac digest)    {      _digest = digest;    }        void update(byte value)    {      _digest.update(value);    }        void update(StringValue value)    {      int len = value.length();      Mac digest = _digest;          for (int i = 0; i < len; i++) {	digest.update((byte) value.charAt(i));      }    }        void update(byte []buffer, int offset, int length)    {      _digest.update(buffer, offset, length);    }    byte []digest()    {      return _digest.doFinal();    }    HashContext copy()    {      try {	return new HashDigestContext((MessageDigest) _digest.clone());      } catch (Exception e) {	log.log(Level.FINE, e.toString(), e);	return null;      }    }    public String toString()    {      return (getClass().getSimpleName() + "[" + _digest + "]");    }  }  static {    _algorithmMap.put("md2", "MD2");    _algorithmMap.put("md5", "MD5");    _algorithmMap.put("sha1", "SHA");    _algorithmMap.put("sha256", "SHA-256");    _algorithmMap.put("sha384", "SHA-384");    _algorithmMap.put("sha512", "SHA-512");  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?