KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > tools > ChangePassword


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.tools;
6
7 import java.io.IOException JavaDoc;
8 import java.sql.SQLException JavaDoc;
9
10 import org.h2.engine.Database;
11 import org.h2.message.Message;
12 import org.h2.security.SHA256;
13 import org.h2.store.FileStore;
14 import org.h2.util.FileUtils;
15
16 /**
17  * A tools to change, remove or set a file password of a database without opening it.
18  */

19 public class ChangePassword extends FileBase {
20     
21     private String JavaDoc dir;
22     private String JavaDoc cipher;
23     private byte[] decrypt;
24     private byte[] encrypt;
25     private boolean testRenameOnly;
26     
27     // TODO security: maybe allow functions in the url
28
// jdbc:h2:test;action=[decrypt|encrypt|check|reindex|recover|compress...]
29
// and/or implement SQL commands that call this functions (only for the admin)
30

31     private void showUsage() {
32         System.out.println("java "+getClass().getName()
33                 + " [-dir <dir>] [-db <database>] [-cipher <cipher>] [-decrypt <pwd>] [-encrypt <pwd>] [-quiet]");
34     }
35     
36     /**
37      * The command line interface for this tool.
38      * The options must be split into strings like this: "-db", "test",...
39      * The following options are supported:
40      * <ul>
41      * <li>-help or -? (print the list of options)
42      * <li>-dir directory (the default is the current directory)
43      * <li>-db databaseName (all databases if no name is specified)
44      * <li>-cipher type (AES or XTEA)
45      * <li>-decrypt password (null if the database is not encrypted)
46      * <li>-encrypt password (null if the database should not be encrypted)
47      * <li>-quiet does not print progress information
48      * </ul>
49      *
50      * @param args the command line arguments
51      * @throws SQLException
52      */

53     public static void main(String JavaDoc[] args) throws SQLException JavaDoc {
54         new ChangePassword().run(args);
55     }
56
57     private void run(String JavaDoc[] args) throws SQLException JavaDoc {
58         String JavaDoc dir = ".";
59         String JavaDoc cipher = null;
60         byte[] decrypt = null;
61         byte[] encrypt = null;
62         String JavaDoc db = null;
63         boolean quiet = false;
64         for(int i=0; args != null && i<args.length; i++) {
65             if(args[i].equals("-dir")) {
66                 dir = args[++i];
67             } else if(args[i].equals("-cipher")) {
68                 cipher = args[++i];
69             } else if(args[i].equals("-db")) {
70                 db = args[++i];
71             } else if(args[i].equals("-decrypt")) {
72                 decrypt = getFileEncryptionKey(args[++i].toCharArray());
73             } else if(args[i].equals("-encrypt")) {
74                 encrypt = getFileEncryptionKey(args[++i].toCharArray());
75             } else if(args[i].equals("-quiet")) {
76                 quiet = true;
77             }
78         }
79         if(encrypt==null && decrypt==null) {
80             showUsage();
81             return;
82         }
83         execute(dir, db, cipher, decrypt, encrypt, quiet);
84     }
85     
86     /**
87      * Get the file encryption key for a given password.
88      *
89      * @param password
90      * @return the encryption key
91      */

92     public byte[] getFileEncryptionKey(char[] password) {
93         SHA256 sha = new SHA256();
94         return sha.getKeyPasswordHash("file", password);
95     }
96
97     /**
98      * Changes the password for a database.
99      *
100      * @param dir the directory (. for the current directory)
101      * @param db the database name (null for all databases)
102      * @param cipher the cipher (AES, XTEA)
103      * @param decrypt the decryption key
104      * @param encrypt the encryption key
105      * @param quiet don't print progress information
106      * @throws SQLException
107      */

108     public static void execute(String JavaDoc dir, String JavaDoc db, String JavaDoc cipher, byte[] decrypt, byte[] encrypt, boolean quiet) throws SQLException JavaDoc {
109         ChangePassword change = new ChangePassword();
110         change.dir = dir;
111         change.cipher = cipher;
112         change.decrypt = decrypt;
113         change.encrypt = encrypt;
114
115         // first, test only if the file can be renamed (to find errors with locked files early)
116
change.testRenameOnly = true;
117         change.processFiles(dir, db, !quiet);
118         // if this worked, the operation will (hopefully) be successful
119
// TODO changePassword: this is a workaround! make the operation atomic (all files or none)
120
change.testRenameOnly = false;
121         change.processFiles(dir, db, !quiet);
122     }
123
124     protected void process(String JavaDoc fileName) throws SQLException JavaDoc {
125         if(FileUtils.isDirectory(fileName)) {
126             return;
127         }
128         if(testRenameOnly) {
129             String JavaDoc temp = dir + "/temp.db";
130             FileUtils.delete(temp);
131             FileUtils.rename(fileName, temp);
132             FileUtils.rename(temp, fileName);
133         } else {
134             boolean textStorage = Database.isTextStorage(fileName, false);
135             byte[] magic = Database.getMagic(textStorage);
136             FileStore in;
137             if(decrypt == null) {
138                 in = FileStore.open(null, fileName, magic);
139             } else {
140                 in = FileStore.open(null, fileName, magic, cipher, decrypt);
141             }
142             in.init();
143             copy(fileName, textStorage, in, encrypt);
144         }
145     }
146     
147     private void copy(String JavaDoc fileName, boolean textStorage, FileStore in, byte[] key) throws SQLException JavaDoc {
148         String JavaDoc temp = dir + "/temp.db";
149         FileUtils.delete(temp);
150         byte[] magic = Database.getMagic(textStorage);
151         FileStore out;
152         if(key == null) {
153             out = FileStore.open(null, temp, magic);
154         } else {
155             out = FileStore.open(null, temp, magic, cipher, key);
156         }
157         out.init();
158         byte[] buffer = new byte[4 * 1024];
159         long remaining = in.length() - FileStore.HEADER_LENGTH;
160         long total = remaining;
161         in.seek(FileStore.HEADER_LENGTH);
162         out.seek(FileStore.HEADER_LENGTH);
163         long time = System.currentTimeMillis();
164         while(remaining > 0) {
165             if(System.currentTimeMillis() - time > 1000) {
166                 System.out.println(fileName+": "+(100-100*remaining/total)+"%");
167                 time = System.currentTimeMillis();
168             }
169             int len = (int) Math.min(buffer.length, remaining);
170             in.readFully(buffer, 0, len);
171             out.write(buffer, 0, len);
172             remaining -= len;
173         }
174         try {
175             in.close();
176             out.close();
177         } catch(IOException JavaDoc e) {
178             throw Message.convert(e);
179         }
180         FileUtils.delete(fileName);
181         FileUtils.rename(temp, fileName);
182     }
183
184 }
185
Popular Tags