提交 145ab625 authored 作者: Thomas Mueller's avatar Thomas Mueller

mainly javadocs

上级 9c7fd89d
......@@ -16,7 +16,6 @@ import org.h2.constraint.ConstraintReferential;
import org.h2.constraint.ConstraintUnique;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.DbObject;
import org.h2.engine.Right;
import org.h2.engine.Session;
import org.h2.expression.Expression;
......@@ -75,9 +74,9 @@ public class AlterTableAddConstraint extends SchemaCommand {
super(session, schema);
}
private String generateConstraintName(DbObject obj) {
private String generateConstraintName(Table table) {
if (constraintName == null) {
constraintName = getSchema().getUniqueConstraintName(obj);
constraintName = getSchema().getUniqueConstraintName(table);
}
return constraintName;
}
......
......@@ -10,10 +10,10 @@ import java.sql.SQLException;
import org.h2.command.Prepared;
import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.result.LocalResult;
import org.h2.table.Column;
import org.h2.util.ObjectArray;
import org.h2.value.Value;
import org.h2.value.ValueString;
......@@ -44,10 +44,11 @@ public class ExplainPlan extends Prepared {
public LocalResult query(int maxrows) throws SQLException {
// TODO rights: are rights required for explain?
ObjectArray expressions = new ObjectArray();
Column column = new Column("PLAN", Value.STRING);
ExpressionColumn expr = new ExpressionColumn(session.getDatabase(), column);
expressions.add(expr);
Expression[] expressions = new Expression[] {
expr
};
result = new LocalResult(session, expressions, 1);
if (maxrows >= 0) {
String plan = command.getPlanSQL();
......
......@@ -34,6 +34,7 @@ import org.h2.engine.Setting;
import org.h2.engine.User;
import org.h2.engine.UserAggregate;
import org.h2.engine.UserDataType;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.index.Cursor;
import org.h2.index.Index;
......@@ -114,9 +115,9 @@ public class ScriptCommand extends ScriptBase {
}
private LocalResult createResult() {
ObjectArray cols = new ObjectArray();
cols.add(new ExpressionColumn(session.getDatabase(), new Column("SCRIPT", Value.STRING)));
return new LocalResult(session, cols, 1);
Expression[] expressions = new Expression[] { new ExpressionColumn(session.getDatabase(), new Column("SCRIPT",
Value.STRING)) };
return new LocalResult(session, expressions, 1);
}
public LocalResult query(int maxrows) throws SQLException {
......
......@@ -1356,6 +1356,7 @@ public class Database implements DataHandler {
throw Message.getInternalError("object already exists: " + newName);
}
}
obj.checkRename();
int id = obj.getId();
removeMeta(session, id);
map.remove(obj.getName());
......
......@@ -56,6 +56,12 @@ public class User extends RightOwner {
this.passwordHash = hash;
}
/**
* Set the user name password hash. A random salt is generated as well.
* The parameter is nulled out after use.
*
* @param userPasswordHash the user name password hash
*/
public void setUserPasswordHash(byte[] userPasswordHash) {
if (userPasswordHash != null) {
salt = RandomUtils.getSecureBytes(Constants.SALT_LEN);
......
......@@ -1141,7 +1141,7 @@ public class Function extends Expression implements FunctionCall {
private byte[] getHash(String algorithm, byte[] bytes, int iterations) throws SQLException {
SHA256 hash = CipherFactory.getHash(algorithm);
for (int i = 0; i < iterations; i++) {
bytes = hash.getHash(bytes);
bytes = hash.getHash(bytes, false);
}
return bytes;
}
......
......@@ -46,6 +46,14 @@ public class LocalResult implements ResultInterface {
private boolean distinct;
private boolean closed;
/**
* Construct a local result set by reading all data from a regular result set.
*
* @param session the session
* @param rs the result set
* @param maxrows the maximum number of rows to read (0 for no limit)
* @return the local result set
*/
public static LocalResult read(Session session, ResultSet rs, int maxrows) throws SQLException {
ObjectArray cols = getExpressionColumns(session, rs);
int columnCount = cols.size();
......@@ -80,10 +88,20 @@ public class LocalResult implements ResultInterface {
return cols;
}
/**
* Construct a local result object.
*/
public LocalResult() {
// nothing to do
}
/**
* Construct a local result object.
*
* @param session the session
* @param expressions the expression array
* @param the number of visible columns
*/
public LocalResult(Session session, Expression[] expressions, int visibleColumnCount) {
this.session = session;
if (session == null) {
......@@ -96,7 +114,24 @@ public class LocalResult implements ResultInterface {
rowId = -1;
this.expressions = expressions;
}
/**
* Construct a local result object.
*
* @param session the session
* @param expressions the expression list
* @param the number of visible columns
*/
public LocalResult(Session session, ObjectArray expressionList, int visibleColumnCount) {
this(session, getList(expressionList), visibleColumnCount);
}
/**
* Create a shallow copy of the result set. The data and a temporary table (if there is any) is not copied.
*
* @param session the session
* @return the copy
*/
public LocalResult createShallowCopy(Session session) {
if (disk == null && (rows == null || rows.size() < rowCount)) {
return null;
......@@ -120,25 +155,34 @@ public class LocalResult implements ResultInterface {
return copy;
}
public LocalResult(Session session, ObjectArray expressionList, int visibleColumnCount) {
this(session, getList(expressionList), visibleColumnCount);
}
private static Expression[] getList(ObjectArray expressionList) {
Expression[] expressions = new Expression[expressionList.size()];
expressionList.toArray(expressions);
return expressions;
}
/**
* Set the sort order.
*
* @param sort the sort order
*/
public void setSortOrder(SortOrder sort) {
this.sort = sort;
}
/**
* Remove duplicate rows.
*/
public void setDistinct() {
distinct = true;
distinctRows = new ValueHashMap(session.getDatabase());
}
/**
* Remove the row from the result set if it exists.
*
* @param values the row
*/
public void removeDistinct(Value[] values) throws SQLException {
if (!distinct) {
throw Message.getInternalError();
......@@ -152,6 +196,12 @@ public class LocalResult implements ResultInterface {
}
}
/**
* Check if this result set contains the given row.
*
* @param values the row
* @return true if the row exists
*/
public boolean containsDistinct(Value[] values) throws SQLException {
if (!distinct) {
throw Message.getInternalError();
......@@ -199,6 +249,11 @@ public class LocalResult implements ResultInterface {
return rowId;
}
/**
* Add a row to this object.
*
* @param values the row to add
*/
public void addRow(Value[] values) throws SQLException {
if (distinct) {
if (distinctRows != null) {
......@@ -234,6 +289,9 @@ public class LocalResult implements ResultInterface {
return visibleColumnCount;
}
/**
* This method is called after all rows have been added.
*/
public void done() throws SQLException {
if (distinct) {
if (distinctRows != null) {
......@@ -283,6 +341,11 @@ public class LocalResult implements ResultInterface {
return rowCount;
}
/**
* Set the number of rows that this result will return at the maximum.
*
* @param limit the limit
*/
public void setLimit(int limit) {
this.limit = limit;
}
......@@ -303,6 +366,11 @@ public class LocalResult implements ResultInterface {
}
}
/**
* Check if this result set is buffered using a temporary file.
*
* @return true if it is
*/
public boolean needToClose() {
return disk != null;
}
......@@ -355,6 +423,11 @@ public class LocalResult implements ResultInterface {
return expressions[i].getScale();
}
/**
* Set the offset of the first row to return.
*
* @param offset the offset
*/
public void setOffset(int offset) {
this.offset = offset;
}
......@@ -387,6 +460,11 @@ public class LocalResult implements ResultInterface {
return "columns: " + visibleColumnCount + " rows: " + rowCount + " pos: " + rowId;
}
/**
* Check if this result set is closed.
*
* @return true if it is
*/
public boolean isClosed() {
return closed;
}
......
......@@ -25,6 +25,11 @@ public class ResultColumn {
boolean autoIncrement;
int nullable;
/**
* Read an object from the given transfer object.
*
* @param in the object from where to read the data
*/
ResultColumn(Transfer in) throws IOException {
alias = in.readString();
schemaName = in.readString();
......@@ -38,6 +43,13 @@ public class ResultColumn {
nullable = in.readInt();
}
/**
* Write a result column to the given output.
*
* @param out the object to where to write the data
* @param result the result
* @param i the column index
*/
public static void writeColumn(Transfer out, ResultInterface result, int i) throws IOException {
out.writeString(result.getAlias(i));
out.writeString(result.getSchemaName(i));
......
......@@ -17,20 +17,58 @@ import org.h2.value.Value;
*/
public interface ResultExternal {
/**
* Reset the current position of this object.
*/
void reset() throws SQLException;
/**
* Get the next row from the result.
*
* @return the next row or null
*/
Value[] next() throws SQLException;
/**
* Add a number of rows to the result.
*
* @param rows the list of rows to add
*/
void addRows(ObjectArray rows) throws SQLException;
/**
* This method is called after all rows have been added.
*/
void done() throws SQLException;
/**
* Close this object and delete the temporary file.
*/
void close();
/**
* Remove the row with the given values from this object if such a row
* exists.
*
* @param values the row
* @return the new row count
*/
int removeRow(Value[] values) throws SQLException;
/**
* Check if the given row exists in this object.
*
* @param values the row
* @return true if it exists
*/
boolean contains(Value[] values) throws SQLException;
/**
* Add a row to this object.
*
* @param values the row to add
* @return the new number of rows in this object
*/
int addRow(Value[] values) throws SQLException;
}
......@@ -38,7 +38,11 @@ public class RowList {
private boolean written;
private boolean readUncached;
/**
* Construct a new row list for this session.
*
* @param session the session
*/
public RowList(Session session) {
this.session = session;
if (SysProperties.DEFAULT_MAX_OPERATION_MEMORY > 0 && session.getDatabase().isPersistent()) {
......@@ -114,6 +118,12 @@ public class RowList {
file.write(buff.getBytes(), 0, buff.length());
}
/**
* Add a row to the list.
*
* @param r the row to add
*/
public void add(Row r) throws SQLException {
list.add(r);
memory += r.getMemorySize();
......@@ -123,6 +133,9 @@ public class RowList {
size++;
}
/**
* Remove all rows from the list.
*/
public void reset() throws SQLException {
index = 0;
if (file != null) {
......@@ -136,6 +149,11 @@ public class RowList {
}
}
/**
* Check if there are more rows in this list.
*
* @return true it there are more rows
*/
public boolean hasNext() {
return index < size;
}
......@@ -182,6 +200,11 @@ public class RowList {
return row;
}
/**
* Get the next row from the list.
*
* @return the next row
*/
public Row next() throws SQLException {
Row r;
if (file == null) {
......@@ -214,14 +237,25 @@ public class RowList {
return r;
}
/**
* Get the number of rows in this list.
*
* @return the number of rows
*/
public int size() {
return size;
}
/**
* Do not use the cache.
*/
public void invalidateCache() {
readUncached = true;
}
/**
* Close the result list and delete the temporary file.
*/
public void close() {
if (file != null) {
file.closeAndDeleteSilently();
......
......@@ -20,7 +20,12 @@ import org.h2.table.Table;
* CREATE SEQUENCE
*/
public class Sequence extends SchemaObjectBase {
/**
* The default cache size for sequences.
*/
public static final int DEFAULT_CACHE_SIZE = 32;
private long value = 1;
private long valueWithMargin;
private long increment = 1;
......@@ -83,6 +88,12 @@ public class Sequence extends SchemaObjectBase {
return buff.toString();
}
/**
* Get the next value for this sequence.
*
* @param session the session
* @return the next value
*/
public synchronized long getNext(Session session) throws SQLException {
if ((increment > 0 && value >= valueWithMargin) || (increment < 0 && value <= valueWithMargin)) {
valueWithMargin += increment * cacheSize;
......@@ -93,6 +104,11 @@ public class Sequence extends SchemaObjectBase {
return v;
}
/**
* Flush the current value, including the margin, to disk.
*
* @param session the session
*/
public synchronized void flush(Session session) throws SQLException {
Session sysSession = database.getSystemSession();
if (session == null || !database.isSysTableLocked()) {
......@@ -118,6 +134,9 @@ public class Sequence extends SchemaObjectBase {
}
}
/**
* Flush the current value to disk and close this object.
*/
public void close() throws SQLException {
valueWithMargin = value;
flush(null);
......
......@@ -28,6 +28,9 @@ import org.h2.value.Value;
*/
public class TriggerObject extends SchemaObjectBase {
/**
* The default queue size.
*/
public static final int DEFAULT_QUEUE_SIZE = 1024;
private boolean before;
......@@ -65,6 +68,14 @@ public class TriggerObject extends SchemaObjectBase {
}
}
/**
* Set the trigger class name and load the class if possible.
*
* @param session the session
* @param triggerClassName the name of the trigger class
* @param force whether exceptions (due to missing class or access rights)
* should be ignored
*/
public void setTriggerClassName(Session session, String triggerClassName, boolean force) throws SQLException {
this.triggerClassName = triggerClassName;
try {
......@@ -76,6 +87,14 @@ public class TriggerObject extends SchemaObjectBase {
}
}
/**
* Call the trigger class if required. This method does nothing if the
* trigger is not defined for the given action. This method is called before
* or after any rows have been processed, once for each statement.
*
* @param session the session
* @param beforeAction if this method is called before applying the changes
*/
public void fire(Session session, boolean beforeAction) throws SQLException {
if (rowBased || before != beforeAction) {
return;
......@@ -106,7 +125,10 @@ public class TriggerObject extends SchemaObjectBase {
}
/**
* Call the fire method of the user-defined trigger class.
* Call the fire method of the user-defined trigger class if required. This
* method does nothing if the trigger is not defined for the given action.
* This method is called before or after a row is processed, possibly many
* times for each statement.
*
* @param session the session
* @param oldRow the old row
......@@ -172,6 +194,11 @@ public class TriggerObject extends SchemaObjectBase {
}
}
/**
* Set the trigger type.
*
* @param typeMask the type
*/
public void setTypeMask(int typeMask) {
this.typeMask = typeMask;
}
......@@ -267,14 +294,29 @@ public class TriggerObject extends SchemaObjectBase {
// nothing to do
}
/**
* Get the table of this trigger.
*
* @return the table
*/
public Table getTable() {
return table;
}
/**
* Check if this is a before trigger.
*
* @return true if it is
*/
public boolean getBefore() {
return before;
}
/**
* Get the trigger class name
*
* @return the class name
*/
public String getTriggerClassName() {
return triggerClassName;
}
......
......@@ -28,6 +28,10 @@ public class AES implements BlockCipher {
private static final int[] RT3 = new int[256];
private int[] encKey = new int[44];
private int[] decKey = new int[44];
AES() {
// do nothing
}
private static int rot8(int x) {
return (x >>> 8) | (x << 24);
......@@ -117,12 +121,12 @@ public class AES implements BlockCipher {
decKey[d++] = encKey[e++];
}
public void encrypt(byte[] buff, int off, int len) {
public void encrypt(byte[] bytes, int off, int len) {
if (SysProperties.CHECK && (len % ALIGN != 0)) {
throw Message.getInternalError("unaligned len " + len);
}
for (int i = off; i < off + len; i += 16) {
encryptBlock(buff, buff, i);
encryptBlock(bytes, bytes, i);
}
}
......
......@@ -11,8 +11,8 @@ package org.h2.security;
*/
public interface BlockCipher {
/*
* Blocks sizes are always multiples of this number
/**
* Blocks sizes are always multiples of this number.
*/
int ALIGN = 16;
......
......@@ -16,6 +16,12 @@ import org.h2.message.Message;
*/
public class CipherFactory {
/**
* Get a new block cipher object for the given algorithm.
*
* @param algorithm the algorithm
* @return a new cipher object
*/
public static BlockCipher getBlockCipher(String algorithm) throws SQLException {
if ("XTEA".equalsIgnoreCase(algorithm)) {
return new XTEA();
......@@ -26,6 +32,12 @@ public class CipherFactory {
}
}
/**
* Get a new cryptographic hash object for the given algorithm.
*
* @param algorithm the algorithm
* @return a new hash object
*/
public static SHA256 getHash(String algorithm) throws SQLException {
if ("SHA256".equalsIgnoreCase(algorithm)) {
return new SHA256();
......
......@@ -15,13 +15,35 @@ public class SHA256 {
// TODO maybe implement WHIRLPOOL
/**
* Calculate the hash code by using the given salt. The salt is appended
* after the data before the hash code is calculated. After generating the
* hash code, the data and all internal buffers are nulled out to avoid
* keeping insecure data in memory longer than required (and possibly
* swapped to disk).
*
* @param data the data to hash
* @param salt the salt to use
* @return the hash code
*/
public byte[] getHashWithSalt(byte[] data, byte[] salt) {
byte[] buff = new byte[data.length + salt.length];
System.arraycopy(data, 0, buff, 0, data.length);
System.arraycopy(salt, 0, buff, data.length, salt.length);
return getHash(buff);
return getHash(buff, true);
}
/**
* Calculate the hash of a password by prepending the user name and a '@'
* character. Both the user name and the password are encoded to a byte
* array using UTF-16. After generating the hash code, the password array
* and all internal buffers are nulled out to avoid keeping the plain text
* password in memory longer than required (and possibly swapped to disk).
*
* @param userName the user name
* @param the password
* @return the hash code
*/
public byte[] getKeyPasswordHash(String userName, char[] password) {
String user = userName + "@";
byte[] buff = new byte[2 * (user.length() + password.length)];
......@@ -37,11 +59,13 @@ public class SHA256 {
buff[n++] = (byte) (c);
}
Arrays.fill(password, (char) 0);
return getHash(buff);
return getHash(buff, true);
}
// The first 32 bits of the fractional parts of the cube roots of the first
// sixty-four prime numbers
/**
* The first 32 bits of the fractional parts of the cube roots of the first
* sixty-four prime numbers.
*/
private static final int[] K = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
......@@ -56,12 +80,21 @@ public class SHA256 {
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814,
0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
public byte[] getHash(byte[] data) {
/**
* Calculate the hash code for the given data.
*
* @param data the data to hash
* @param nullData if the data should be nulled after calculating the hash code
* @return the hash code
*/
public byte[] getHash(byte[] data, boolean nullData) {
int byteLen = data.length;
int intLen = ((byteLen + 9 + 63) / 64) * 16;
byte[] bytes = new byte[intLen * 4];
System.arraycopy(data, 0, bytes, 0, byteLen);
if (nullData) {
Arrays.fill(data, (byte) 0);
}
bytes[byteLen] = (byte) 0x80;
int[] buff = new int[intLen];
for (int i = 0, j = 0; j < intLen; i += 4, j++) {
......@@ -72,7 +105,6 @@ public class SHA256 {
int[] w = new int[64];
int[] hh = new int[] { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
for (int block = 0; block < intLen; block += 16) {
for (int i = 0; i < 16; i++) {
w[i] = buff[block + i];
......
......@@ -53,10 +53,10 @@ public class SecureFileStore extends FileStore {
SHA256 sha = new SHA256();
key = sha.getHashWithSalt(key, salt);
for (int i = 0; i < keyIterations; i++) {
key = sha.getHash(key);
key = sha.getHash(key, true);
}
cipher.setKey(key);
key = sha.getHash(key);
key = sha.getHash(key, true);
cipherForInitVector.setKey(key);
}
......
......@@ -34,7 +34,6 @@ import org.h2.message.Message;
import org.h2.util.ByteUtils;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.NetUtils;
/**
* A factory to create encrypted sockets. To generate new keystore, use the
......@@ -42,26 +41,24 @@ import org.h2.util.NetUtils;
*/
public class SecureSocketFactory {
/**
* The default password to use for the .h2.keystore file
*/
public static final String KEYSTORE_PASSWORD = "h2pass";
private static final String KEYSTORE = ".h2.keystore";
private static final String KEYSTORE_KEY = "javax.net.ssl.keyStore";
private static final String KEYSTORE_PASSWORD_KEY = "javax.net.ssl.keyStorePassword";
public static final String KEYSTORE_PASSWORD = "h2pass";
private static SecureSocketFactory factory;
private static final String ANONYMOUS_CIPHER_SUITE = "SSL_DH_anon_WITH_RC4_128_MD5";
private static void setFactory(SecureSocketFactory f) {
factory = f;
}
public static SecureSocketFactory getInstance() {
if (factory == null) {
setFactory(new SecureSocketFactory());
}
return factory;
}
public Socket createSocket(InetAddress address, int port) throws IOException {
/**
* Create a secure client socket that is connected to the given address and port.
*
* @param address the address to connect to
* @param port the port
* @return the socket
*/
public static Socket createSocket(InetAddress address, int port) throws IOException {
Socket socket = null;
//## Java 1.4 begin ##
setKeystore();
......@@ -77,13 +74,19 @@ public class SecureSocketFactory {
return socket;
}
public ServerSocket createServerSocket(int port) throws IOException {
/**
* Create a secure server socket. If a bind address is specified, the socket is only bound to this address.
*
* @param port the port to listen on
* @param bindAddress the address to bind to, or null to bind to all addresses
* @return the server socket
*/
public static ServerSocket createServerSocket(int port, InetAddress bindAddress) throws IOException {
ServerSocket socket = null;
//## Java 1.4 begin ##
setKeystore();
ServerSocketFactory f = SSLServerSocketFactory.getDefault();
SSLServerSocket secureSocket;
InetAddress bindAddress = NetUtils.getBindAddress();
if (bindAddress == null) {
secureSocket = (SSLServerSocket) f.createServerSocket(port);
} else {
......@@ -113,7 +116,16 @@ public class SecureSocketFactory {
}
return bout.toByteArray();
}
//## Java 1.4 end ##
/**
* Get the keystore object using the given password.
*
* @param password the keystore password
* @return the keystore
*/
//## Java 1.4 begin ##
public static KeyStore getKeyStore(String password) throws IOException {
try {
// The following source code can be re-generated
......@@ -145,7 +157,7 @@ public class SecureSocketFactory {
}
}
private void setKeystore() throws IOException {
private static void setKeystore() throws IOException {
Properties p = System.getProperties();
if (p.getProperty(KEYSTORE_KEY) == null) {
String fileName = FileUtils.getFileInUserHome(KEYSTORE);
......@@ -176,7 +188,7 @@ public class SecureSocketFactory {
}
}
private String[] addAnonymous(String[] list) {
private static String[] addAnonymous(String[] list) {
String[] newList = new String[list.length + 1];
System.arraycopy(list, 0, newList, 1, list.length);
newList[0] = ANONYMOUS_CIPHER_SUITE;
......
......@@ -21,6 +21,10 @@ public class XTEA implements BlockCipher {
private static final int DELTA = 0x9E3779B9;
private int k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15;
private int k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31;
XTEA() {
// do nothing
}
public void setKey(byte[] b) {
int[] key = new int[4];
......@@ -57,7 +61,7 @@ public class XTEA implements BlockCipher {
}
}
public void encryptBlock(byte[] in, byte[] out, int off) {
private void encryptBlock(byte[] in, byte[] out, int off) {
int y = (in[off] << 24) | ((in[off+1] & 255) << 16) | ((in[off+2] & 255) << 8) | (in[off+3] & 255);
int z = (in[off+4] << 24) | ((in[off+5] & 255) << 16) | ((in[off+6] & 255) << 8) | (in[off+7] & 255);
y += (((z << 4) ^ (z >>> 5)) + z) ^ k0; z += (((y >>> 5) ^ (y << 4)) + y) ^ k1;
......@@ -80,7 +84,7 @@ public class XTEA implements BlockCipher {
out[off+4] = (byte) (z >> 24); out[off+5] = (byte) (z >> 16); out[off+6] = (byte) (z >> 8); out[off+7] = (byte) z;
}
public void decryptBlock(byte[] in, byte[] out, int off) {
private void decryptBlock(byte[] in, byte[] out, int off) {
int y = (in[off] << 24) | ((in[off+1] & 255) << 16) | ((in[off+2] & 255) << 8) | (in[off+3] & 255);
int z = (in[off+4] << 24) | ((in[off+5] & 255) << 16) | ((in[off+6] & 255) << 8) | (in[off+7] & 255);
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k31; y -= (((z << 4) ^ (z >>> 5)) + z) ^ k30;
......
......@@ -26,6 +26,13 @@ public class NetUtils {
private static InetAddress bindAddress;
/**
* Create a loopback socket (a socket that is connected to localhost) on this port.
*
* @param port the port
* @param ssl if SSL should be used
* @return the socket
*/
public static Socket createLoopbackSocket(int port, boolean ssl) throws IOException {
InetAddress address = getBindAddress();
if (address == null) {
......@@ -34,6 +41,14 @@ public class NetUtils {
return createSocket(address.getHostAddress(), port, ssl);
}
/**
* Create a client socket that is connected to the given address and port.
*
* @param server to connect to (including an optional port)
* @param defaultPort the default port (if not specified in the server address)
* @param ssl if SSL should be used
* @return the socket
*/
public static Socket createSocket(String server, int defaultPort, boolean ssl) throws IOException {
int port = defaultPort;
// IPv6: RFC 2732 format is '[a:b:c:d:e:f:g:h]' or
......@@ -50,14 +65,29 @@ public class NetUtils {
return createSocket(address, port, ssl);
}
/**
* Create a client socket that is connected to the given address and port.
*
* @param address the address to connect to
* @param port the port
* @param ssl if SSL should be used
* @return the socket
*/
public static Socket createSocket(InetAddress address, int port, boolean ssl) throws IOException {
if (ssl) {
SecureSocketFactory f = SecureSocketFactory.getInstance();
return f.createSocket(address, port);
return SecureSocketFactory.createSocket(address, port);
}
return new Socket(address, port);
}
/**
* Create a server socket. The system property h2.bindAddress is used if
* set.
*
* @param port the port to listen on
* @param ssl if SSL should be used
* @return the server socket
*/
public static ServerSocket createServerSocket(int port, boolean ssl) throws SQLException {
try {
return createServerSocketTry(port, ssl);
......@@ -73,7 +103,7 @@ public class NetUtils {
*
* @return the bind address
*/
public static InetAddress getBindAddress() throws UnknownHostException {
private static InetAddress getBindAddress() throws UnknownHostException {
String host = SysProperties.BIND_ADDRESS;
if (host == null || host.length() == 0) {
return null;
......@@ -88,11 +118,10 @@ public class NetUtils {
private static ServerSocket createServerSocketTry(int port, boolean ssl) throws SQLException {
try {
InetAddress bindAddress = getBindAddress();
if (ssl) {
SecureSocketFactory f = SecureSocketFactory.getInstance();
return f.createServerSocket(port);
return SecureSocketFactory.createServerSocket(port, bindAddress);
}
InetAddress bindAddress = getBindAddress();
if (bindAddress == null) {
return new ServerSocket(port);
}
......@@ -105,6 +134,12 @@ public class NetUtils {
}
}
/**
* Check if a socket is connected to localhost.
*
* @param socket the socket
* @return true if it is
*/
public static boolean isLoopbackAddress(Socket socket) {
boolean result = true;
//## Java 1.4 begin ##
......@@ -113,6 +148,12 @@ public class NetUtils {
return result;
}
/**
* Close a server socket and ignore any exceptions.
*
* @param socket the socket
* @return null
*/
public static ServerSocket closeSilently(ServerSocket socket) {
if (socket != null) {
try {
......@@ -124,6 +165,11 @@ public class NetUtils {
return null;
}
/**
* Get the local host address as a string.
*
* @return the local host address
*/
public static String getLocalAddress() {
InetAddress bind = null;
try {
......
......@@ -160,12 +160,13 @@ java org.h2.test.TestAll timer
/*
http://patir.rubyforge.org/rutema/index.html
Rutema is a test execution and management tool for heterogeneous development environments written in Ruby.
jazoon
upload and test javadoc/index.html
download PostgreSQL docs
in help.csv, use complete examples for functions; add a test case
improve javadocs
......@@ -233,6 +234,9 @@ Roadmap:
sometimes a stack overflow exception was thrown instead of a IO exception.
The H2 Console could not be shut down from within the tool if the
browser supports keepAlive (most browsers do).
If the password was passed as a char array, it was kept in an internal buffer
longer than required. Theoretically the password could have been stolen
if the main memory was swapped to disk before the garbage collection was run.
*/
if (args.length > 0) {
......
--- special grammar and test cases ---------------------------------------------------------------------------------------------
alter table information_schema.help rename to information_schema.help2;
> exception
help abc;
> ID SECTION TOPIC SYNTAX TEXT EXAMPLE
> -- ------- ----- ------ ---- -------
> rows: 0
CREATE TABLE test (id int(25) NOT NULL auto_increment, name varchar NOT NULL, PRIMARY KEY (id,name));
> ok
......
......@@ -6,9 +6,9 @@
*/
package org.h2.test.unit;
import org.h2.security.AES;
import org.h2.security.BlockCipher;
import org.h2.security.CipherFactory;
import org.h2.security.SHA256;
import org.h2.security.XTEA;
import org.h2.test.TestBase;
import org.h2.util.ByteUtils;
......@@ -28,8 +28,11 @@ public class TestSecurity extends TestBase {
testOneSHA(sha);
}
private String getHashString(SHA256 sha, byte[] data) {
byte[] result = sha.getHash(data);
private String getHashString(SHA256 sha, byte[] data) throws Exception {
byte[] result = sha.getHash(data, true);
if (data.length > 0) {
check(data[0], 0);
}
return ByteUtils.convertBytesToString(result);
}
......@@ -63,21 +66,21 @@ public class TestSecurity extends TestBase {
void checkSHA256(String message, String expected) throws Exception {
SHA256 sha = new SHA256();
String hash = ByteUtils.convertBytesToString(sha.getHash(message.getBytes())).toUpperCase();
String hash = ByteUtils.convertBytesToString(sha.getHash(message.getBytes(), true)).toUpperCase();
check(expected, hash);
}
public void testXTEA() throws Exception {
byte[] test = new byte[4096];
XTEA xtea = new XTEA();
BlockCipher xtea = CipherFactory.getBlockCipher("XTEA");
xtea.setKey("abcdefghijklmnop".getBytes());
for (int i = 0; i < 10; i++) {
xtea.decryptBlock(test, test, 0);
xtea.decrypt(test, 0, test.length);
}
}
private void testAES() throws Exception {
AES test = new AES();
BlockCipher test = CipherFactory.getBlockCipher("AES");
test.setKey(ByteUtils.convertStringToBytes("000102030405060708090A0B0C0D0E0F"));
byte[] in = new byte[128];
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论