1 5 package org.h2.security; 6 7 import java.sql.SQLException ; 8 9 import org.h2.engine.Constants; 10 import org.h2.message.Message; 11 import org.h2.store.DataHandler; 12 import org.h2.store.FileStore; 13 import org.h2.util.RandomUtils; 14 15 public class SecureFileStore extends FileStore { 16 17 private byte[] key; 18 private BlockCipher cipher; 19 private BlockCipher cipherForInitVector; 20 private byte[] buffer = new byte[4]; 21 private long pos; 22 private byte[] bufferForInitVector; 23 private int keyIterations; 24 25 public SecureFileStore(DataHandler handler, String name, byte[] magic, String cipher, byte[] key, int keyIterations) throws SQLException { 26 super(handler, name, magic); 27 this.key = key; 28 if ("XTEA".equalsIgnoreCase(cipher)) { 29 this.cipher = new XTEA(); 30 this.cipherForInitVector = new XTEA(); 31 } else if ("AES".equalsIgnoreCase(cipher)) { 32 this.cipher = new AES(); 33 this.cipherForInitVector = new AES(); 34 } else { 35 throw Message.getSQLException(Message.UNSUPPORTED_CIPHER, cipher); 36 } 37 this.keyIterations = keyIterations; 38 bufferForInitVector = new byte[Constants.FILE_BLOCK_SIZE]; 39 } 40 41 protected byte[] generateSalt() { 42 return RandomUtils.getSecureBytes(Constants.FILE_BLOCK_SIZE); 43 } 44 45 protected void initKey(byte[] salt) { 46 SHA256 sha = new SHA256(); 47 key = sha.getHashWithSalt(key, salt); 48 for (int i = 0; i < keyIterations; i++) { 49 key = sha.getHash(key); 50 } 51 cipher.setKey(key); 52 key = sha.getHash(key); 53 cipherForInitVector.setKey(key); 54 } 55 56 protected void writeDirect(byte[] b, int off, int len) throws SQLException { 57 super.write(b, off, len); 58 pos += len; 59 } 60 61 public void write(byte[] b, int off, int len) throws SQLException { 62 if (buffer.length < b.length) { 63 buffer = new byte[len]; 64 } 65 System.arraycopy(b, off, buffer, 0, len); 66 xorInitVector(buffer, 0, len, pos); 67 cipher.encrypt(buffer, 0, len); 68 super.write(buffer, 0, len); 69 pos += len; 70 } 71 72 protected void readFullyDirect(byte[] b, int off, int len) throws SQLException { 73 super.readFully(b, off, len); 74 pos += len; 75 } 76 77 public void readFully(byte[] b, int off, int len) throws SQLException { 78 super.readFully(b, off, len); 79 cipher.decrypt(b, off, len); 80 xorInitVector(b, off, len, pos); 81 pos += len; 82 } 83 84 public void seek(long x) throws SQLException { 85 this.pos = x; 86 super.seek(x); 87 } 88 89 public void setLength(long newLength) throws SQLException { 90 long oldPos = pos; 91 byte[] buff = new byte[Constants.FILE_BLOCK_SIZE]; 92 long length = length(); 93 if(newLength > length) { 94 seek(length); 95 for(long i = length; i<newLength; i+= Constants.FILE_BLOCK_SIZE) { 96 write(buff, 0, Constants.FILE_BLOCK_SIZE); 97 } 98 seek(oldPos); 99 } else { 100 super.setLength(newLength); 101 } 102 } 103 104 private void xorInitVector(byte[] b, int off, int len, long pos) { 105 byte[] iv = bufferForInitVector; 106 while(len > 0) { 107 for(int i=0; i<Constants.FILE_BLOCK_SIZE; i+=8) { 108 long block = ((pos+i) >>> 3); 109 iv[i] = (byte) (block >> 56); 110 iv[i+1] = (byte) (block >> 48); 111 iv[i+2] = (byte) (block >> 40); 112 iv[i+3] = (byte) (block >> 32); 113 iv[i+4] = (byte) (block >> 24); 114 iv[i+5] = (byte) (block >> 16); 115 iv[i+6] = (byte) (block >> 8); 116 iv[i+7] = (byte) block; 117 } 118 cipherForInitVector.encrypt(iv, 0, Constants.FILE_BLOCK_SIZE); 119 for(int i=0; i<Constants.FILE_BLOCK_SIZE; i++) { 120 b[off + i] ^= iv[i]; 121 } 122 pos += Constants.FILE_BLOCK_SIZE; 123 off += Constants.FILE_BLOCK_SIZE; 124 len -= Constants.FILE_BLOCK_SIZE; 125 } 126 } 127 128 } 129 | Popular Tags |