EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.security]

COVERAGE SUMMARY FOR SOURCE FILE [SecureFileStore.java]

nameclass, %method, %block, %line, %
SecureFileStore.java100% (1/1)100% (9/9)100% (313/313)100% (60/60)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SecureFileStore100% (1/1)100% (9/9)100% (313/313)100% (60/60)
SecureFileStore (DataHandler, String, String, String, byte [], int): void 100% (1/1)100% (28/28)100% (8/8)
generateSalt (): byte [] 100% (1/1)100% (3/3)100% (1/1)
initKey (byte []): void 100% (1/1)100% (37/37)100% (7/7)
readFully (byte [], int, int): void 100% (1/1)100% (38/38)100% (8/8)
readFullyDirect (byte [], int, int): void 100% (1/1)100% (13/13)100% (3/3)
seek (long): void 100% (1/1)100% (7/7)100% (3/3)
write (byte [], int, int): void 100% (1/1)100% (46/46)100% (8/8)
writeDirect (byte [], int, int): void 100% (1/1)100% (13/13)100% (3/3)
xorInitVector (byte [], int, int, long): void 100% (1/1)100% (128/128)100% (19/19)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.security;
7 
8import org.h2.engine.Constants;
9import org.h2.store.DataHandler;
10import org.h2.store.FileStore;
11import org.h2.util.MathUtils;
12 
13/**
14 * A file store that encrypts all data before writing, and decrypts all data
15 * after reading. Areas that were never written to (for example after calling
16 * setLength to enlarge the file) are not encrypted (contains 0 bytes).
17 */
18public class SecureFileStore extends FileStore {
19 
20    private byte[] key;
21    private final BlockCipher cipher;
22    private final BlockCipher cipherForInitVector;
23    private byte[] buffer = new byte[4];
24    private long pos;
25    private final byte[] bufferForInitVector;
26    private final int keyIterations;
27 
28    public SecureFileStore(DataHandler handler, String name, String mode,
29            String cipher, byte[] key, int keyIterations) {
30        super(handler, name, mode);
31        this.key = key;
32        this.cipher = CipherFactory.getBlockCipher(cipher);
33        this.cipherForInitVector = CipherFactory.getBlockCipher(cipher);
34        this.keyIterations = keyIterations;
35        bufferForInitVector = new byte[Constants.FILE_BLOCK_SIZE];
36    }
37 
38    @Override
39    protected byte[] generateSalt() {
40        return MathUtils.secureRandomBytes(Constants.FILE_BLOCK_SIZE);
41    }
42 
43    @Override
44    protected void initKey(byte[] salt) {
45        key = SHA256.getHashWithSalt(key, salt);
46        for (int i = 0; i < keyIterations; i++) {
47            key = SHA256.getHash(key, true);
48        }
49        cipher.setKey(key);
50        key = SHA256.getHash(key, true);
51        cipherForInitVector.setKey(key);
52    }
53 
54    @Override
55    protected void writeDirect(byte[] b, int off, int len) {
56        super.write(b, off, len);
57        pos += len;
58    }
59 
60    @Override
61    public void write(byte[] b, int off, int len) {
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    @Override
73    protected void readFullyDirect(byte[] b, int off, int len) {
74        super.readFully(b, off, len);
75        pos += len;
76    }
77 
78    @Override
79    public void readFully(byte[] b, int off, int len) {
80        super.readFully(b, off, len);
81        for (int i = 0; i < len; i++) {
82            if (b[i] != 0) {
83                cipher.decrypt(b, off, len);
84                xorInitVector(b, off, len, pos);
85                break;
86            }
87        }
88        pos += len;
89    }
90 
91    @Override
92    public void seek(long x) {
93        this.pos = x;
94        super.seek(x);
95    }
96 
97    private void xorInitVector(byte[] b, int off, int len, long p) {
98        byte[] iv = bufferForInitVector;
99        while (len > 0) {
100            for (int i = 0; i < Constants.FILE_BLOCK_SIZE; i += 8) {
101                long block = (p + i) >>> 3;
102                iv[i] = (byte) (block >> 56);
103                iv[i + 1] = (byte) (block >> 48);
104                iv[i + 2] = (byte) (block >> 40);
105                iv[i + 3] = (byte) (block >> 32);
106                iv[i + 4] = (byte) (block >> 24);
107                iv[i + 5] = (byte) (block >> 16);
108                iv[i + 6] = (byte) (block >> 8);
109                iv[i + 7] = (byte) block;
110            }
111            cipherForInitVector.encrypt(iv, 0, Constants.FILE_BLOCK_SIZE);
112            for (int i = 0; i < Constants.FILE_BLOCK_SIZE; i++) {
113                b[off + i] ^= iv[i];
114            }
115            p += Constants.FILE_BLOCK_SIZE;
116            off += Constants.FILE_BLOCK_SIZE;
117            len -= Constants.FILE_BLOCK_SIZE;
118        }
119    }
120 
121}

[all classes][org.h2.security]
EMMA 2.0.5312 (C) Vladimir Roubtsov