reformat all zipsigner code with Android Studio Ctrl-Alt-L
This commit is contained in:
parent
a3d9850a42
commit
4e4dd2385b
@ -13,14 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.logging;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class AbstractLogger implements LoggerInterface
|
||||
{
|
||||
public abstract class AbstractLogger implements LoggerInterface {
|
||||
|
||||
protected String category;
|
||||
|
||||
@ -91,6 +90,4 @@ public abstract class AbstractLogger implements LoggerInterface
|
||||
public boolean isWarningEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.logging;
|
||||
|
||||
public class ConsoleLoggerFactory implements LoggerFactory {
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.logging;
|
||||
|
||||
public interface LoggerFactory {
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.logging;
|
||||
|
||||
public interface LoggerInterface {
|
||||
@ -23,20 +24,28 @@ public interface LoggerInterface {
|
||||
public static final String DEBUG = "DEBUG";
|
||||
|
||||
public boolean isErrorEnabled();
|
||||
|
||||
public void error(String message);
|
||||
|
||||
public void error(String message, Throwable t);
|
||||
|
||||
|
||||
public boolean isWarningEnabled();
|
||||
|
||||
public void warning(String message);
|
||||
|
||||
public void warning(String message, Throwable t);
|
||||
|
||||
public boolean isInfoEnabled();
|
||||
|
||||
public void info(String message);
|
||||
|
||||
public void info(String message, Throwable t);
|
||||
|
||||
public boolean isDebugEnabled();
|
||||
|
||||
public void debug(String message);
|
||||
|
||||
public void debug(String message, Throwable t);
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.logging;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.logging;
|
||||
|
||||
public class NullLoggerFactory implements LoggerFactory {
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.logging;
|
||||
|
||||
import java.io.PrintStream;
|
||||
@ -21,8 +22,7 @@ public class StreamLogger extends AbstractLogger {
|
||||
|
||||
PrintStream out;
|
||||
|
||||
public StreamLogger( String category, PrintStream out)
|
||||
{
|
||||
public StreamLogger(String category, PrintStream out) {
|
||||
super(category);
|
||||
this.out = out;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
public class AutoKeyException extends RuntimeException {
|
||||
|
@ -15,15 +15,16 @@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
/*
|
||||
* This class provides Base64 encoding services using one of several possible
|
||||
* implementations available elsewhere in the classpath. Supported implementations
|
||||
@ -63,8 +64,8 @@ public class Base64 {
|
||||
aEncodeMethod = clazz.getMethod("encode", byte[].class, Integer.TYPE);
|
||||
aDecodeMethod = clazz.getMethod("decode", byte[].class, Integer.TYPE);
|
||||
logger.info(clazz.getName() + " is available.");
|
||||
}
|
||||
catch (ClassNotFoundException x) {} // Ignore
|
||||
} catch (ClassNotFoundException x) {
|
||||
} // Ignore
|
||||
catch (Exception x) {
|
||||
logger.error("Failed to initialize use of android.util.Base64", x);
|
||||
}
|
||||
@ -78,8 +79,8 @@ public class Base64 {
|
||||
// Looking for decode( byte[] input, int offset, int length, OutputStream output)
|
||||
bDecodeMethod = clazz.getMethod("decode", byte[].class, Integer.TYPE, Integer.TYPE, OutputStream.class);
|
||||
|
||||
}
|
||||
catch (ClassNotFoundException x) {} // Ignore
|
||||
} catch (ClassNotFoundException x) {
|
||||
} // Ignore
|
||||
catch (Exception x) {
|
||||
logger.error("Failed to initialize use of org.bouncycastle.util.encoders.Base64Encoder", x);
|
||||
}
|
||||
@ -95,14 +96,12 @@ public class Base64 {
|
||||
// Invoking a static method call, using null for the instance value
|
||||
byte[] encodedBytes = (byte[]) aEncodeMethod.invoke(null, data, 2);
|
||||
return new String(encodedBytes);
|
||||
}
|
||||
else if (bEncodeMethod != null) {
|
||||
} else if (bEncodeMethod != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bEncodeMethod.invoke(bEncoder, data, 0, data.length, baos);
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
}
|
||||
catch (Exception x) {
|
||||
} catch (Exception x) {
|
||||
throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage());
|
||||
}
|
||||
|
||||
@ -116,14 +115,12 @@ public class Base64 {
|
||||
// Invoking a static method call, using null for the instance value
|
||||
byte[] decodedBytes = (byte[]) aDecodeMethod.invoke(null, data, 2);
|
||||
return decodedBytes;
|
||||
}
|
||||
else if (bDecodeMethod != null) {
|
||||
} else if (bDecodeMethod != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bDecodeMethod.invoke(bEncoder, data, 0, data.length, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
catch (Exception x) {
|
||||
} catch (Exception x) {
|
||||
throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage());
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
/**
|
||||
|
@ -15,16 +15,17 @@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/** Produces the classic hex dump with an address column, hex data
|
||||
/**
|
||||
* Produces the classic hex dump with an address column, hex data
|
||||
* section (16 bytes per row) and right-column printable character dislpay.
|
||||
*/
|
||||
public class HexDumpEncoder
|
||||
{
|
||||
public class HexDumpEncoder {
|
||||
|
||||
static HexEncoder encoder = new HexEncoder();
|
||||
|
||||
@ -64,8 +65,7 @@ public class HexDumpEncoder
|
||||
}
|
||||
|
||||
return hexDumpOut.toString();
|
||||
}
|
||||
catch (IOException x) {
|
||||
} catch (IOException x) {
|
||||
throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
/*
|
||||
@ -32,8 +33,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class HexEncoder
|
||||
{
|
||||
public class HexEncoder {
|
||||
protected final byte[] encodingTable =
|
||||
{
|
||||
(byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7',
|
||||
@ -45,10 +45,8 @@ public class HexEncoder
|
||||
*/
|
||||
protected final byte[] decodingTable = new byte[128];
|
||||
|
||||
protected void initialiseDecodingTable()
|
||||
{
|
||||
for (int i = 0; i < encodingTable.length; i++)
|
||||
{
|
||||
protected void initialiseDecodingTable() {
|
||||
for (int i = 0; i < encodingTable.length; i++) {
|
||||
decodingTable[encodingTable[i]] = (byte) i;
|
||||
}
|
||||
|
||||
@ -60,8 +58,7 @@ public class HexEncoder
|
||||
decodingTable['F'] = decodingTable['f'];
|
||||
}
|
||||
|
||||
public HexEncoder()
|
||||
{
|
||||
public HexEncoder() {
|
||||
initialiseDecodingTable();
|
||||
}
|
||||
|
||||
@ -75,10 +72,8 @@ public class HexEncoder
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
for (int i = off; i < (off + length); i++)
|
||||
{
|
||||
throws IOException {
|
||||
for (int i = off; i < (off + length); i++) {
|
||||
int v = data[i] & 0xff;
|
||||
|
||||
out.write(encodingTable[(v >>> 4)]);
|
||||
@ -89,8 +84,7 @@ public class HexEncoder
|
||||
}
|
||||
|
||||
private boolean ignore(
|
||||
char c)
|
||||
{
|
||||
char c) {
|
||||
return (c == '\n' || c == '\r' || c == '\t' || c == ' ');
|
||||
}
|
||||
|
||||
@ -105,17 +99,14 @@ public class HexEncoder
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
byte b1, b2;
|
||||
int outLen = 0;
|
||||
|
||||
int end = off + length;
|
||||
|
||||
while (end > off)
|
||||
{
|
||||
if (!ignore((char)data[end - 1]))
|
||||
{
|
||||
while (end > off) {
|
||||
if (!ignore((char) data[end - 1])) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -123,17 +114,14 @@ public class HexEncoder
|
||||
}
|
||||
|
||||
int i = off;
|
||||
while (i < end)
|
||||
{
|
||||
while (i < end && ignore((char)data[i]))
|
||||
{
|
||||
while (i < end) {
|
||||
while (i < end && ignore((char) data[i])) {
|
||||
i++;
|
||||
}
|
||||
|
||||
b1 = decodingTable[data[i++]];
|
||||
|
||||
while (i < end && ignore((char)data[i]))
|
||||
{
|
||||
while (i < end && ignore((char) data[i])) {
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -156,17 +144,14 @@ public class HexEncoder
|
||||
public int decode(
|
||||
String data,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
byte b1, b2;
|
||||
int length = 0;
|
||||
|
||||
int end = data.length();
|
||||
|
||||
while (end > 0)
|
||||
{
|
||||
if (!ignore(data.charAt(end - 1)))
|
||||
{
|
||||
while (end > 0) {
|
||||
if (!ignore(data.charAt(end - 1))) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -174,17 +159,14 @@ public class HexEncoder
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (i < end)
|
||||
{
|
||||
while (i < end && ignore(data.charAt(i)))
|
||||
{
|
||||
while (i < end) {
|
||||
while (i < end && ignore(data.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
|
||||
b1 = decodingTable[data.charAt(i++)];
|
||||
|
||||
while (i < end && ignore(data.charAt(i)))
|
||||
{
|
||||
while (i < end && ignore(data.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010 Ken Ellinwood
|
||||
*
|
||||
@ -15,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
@ -38,16 +37,14 @@ public class KeySet {
|
||||
public KeySet() {
|
||||
}
|
||||
|
||||
public KeySet( String name, X509Certificate publicKey, PrivateKey privateKey, byte[] sigBlockTemplate)
|
||||
{
|
||||
public KeySet(String name, X509Certificate publicKey, PrivateKey privateKey, byte[] sigBlockTemplate) {
|
||||
this.name = name;
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
this.sigBlockTemplate = sigBlockTemplate;
|
||||
}
|
||||
|
||||
public KeySet( String name, X509Certificate publicKey, PrivateKey privateKey, String signatureAlgorithm, byte[] sigBlockTemplate)
|
||||
{
|
||||
public KeySet(String name, X509Certificate publicKey, PrivateKey privateKey, String signatureAlgorithm, byte[] sigBlockTemplate) {
|
||||
this.name = name;
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
public class ProgressEvent {
|
||||
@ -27,18 +28,23 @@ public class ProgressEvent {
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getPercentDone() {
|
||||
return percentDone;
|
||||
}
|
||||
|
||||
public void setPercentDone(int percentDone) {
|
||||
this.percentDone = percentDone;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -23,8 +24,7 @@ public class ProgressHelper {
|
||||
private int progressCurrentItem = 0;
|
||||
private ProgressEvent progressEvent = new ProgressEvent();
|
||||
|
||||
public void initProgress()
|
||||
{
|
||||
public void initProgress() {
|
||||
progressTotalItems = 10000;
|
||||
progressCurrentItem = 0;
|
||||
}
|
||||
@ -65,16 +65,14 @@ public class ProgressHelper {
|
||||
private ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized void addProgressListener( ProgressListener l)
|
||||
{
|
||||
public synchronized void addProgressListener(ProgressListener l) {
|
||||
ArrayList<ProgressListener> list = (ArrayList<ProgressListener>) listeners.clone();
|
||||
list.add(l);
|
||||
listeners = list;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized void removeProgressListener( ProgressListener l)
|
||||
{
|
||||
public synchronized void removeProgressListener(ProgressListener l) {
|
||||
ArrayList<ProgressListener> list = (ArrayList<ProgressListener>) listeners.clone();
|
||||
list.remove(l);
|
||||
listeners = list;
|
||||
|
@ -13,12 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
public interface ProgressListener {
|
||||
|
||||
/** Called to notify the listener that progress has been made during
|
||||
the zip signing operation.
|
||||
/**
|
||||
* Called to notify the listener that progress has been made during
|
||||
* the zip signing operation.
|
||||
*/
|
||||
public void onProgress(ProgressEvent event);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
/**
|
||||
@ -14,7 +15,9 @@ public interface ResourceAdapter {
|
||||
GENERATING_SIGNATURE_FILE,
|
||||
GENERATING_SIGNATURE_BLOCK,
|
||||
COPYING_ZIP_ENTRY
|
||||
};
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
public String getString(Item item, Object... args);
|
||||
}
|
||||
|
@ -13,18 +13,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class ZipSignature {
|
||||
|
||||
@ -41,14 +41,12 @@ public class ZipSignature {
|
||||
MessageDigest md;
|
||||
|
||||
|
||||
public ZipSignature() throws IOException, GeneralSecurityException
|
||||
{
|
||||
public ZipSignature() throws IOException, GeneralSecurityException {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
}
|
||||
|
||||
public void initSign( PrivateKey privateKey) throws InvalidKeyException
|
||||
{
|
||||
public void initSign(PrivateKey privateKey) throws InvalidKeyException {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
|
||||
}
|
||||
|
||||
@ -60,8 +58,7 @@ public class ZipSignature {
|
||||
md.update(data, offset, count);
|
||||
}
|
||||
|
||||
public byte[] sign() throws BadPaddingException, IllegalBlockSizeException
|
||||
{
|
||||
public byte[] sign() throws BadPaddingException, IllegalBlockSizeException {
|
||||
cipher.update(beforeAlgorithmIdBytes);
|
||||
cipher.update(algorithmIdBytes);
|
||||
cipher.update(afterAlgorithmIdBytes);
|
||||
|
@ -26,6 +26,7 @@
|
||||
* using signature block template files.
|
||||
*/
|
||||
|
||||
|
||||
package kellinwood.security.zipsigner;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
@ -38,17 +39,40 @@ import javax.crypto.Cipher;
|
||||
import javax.crypto.EncryptedPrivateKeyInfo;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import java.io.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.security.*;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyStore;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.TreeMap;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
@ -58,11 +82,10 @@ import java.util.regex.Pattern;
|
||||
* This is a modified copy of com.android.signapk.SignApk.java. It provides an
|
||||
* API to sign JAR files (including APKs and Zip/OTA updates) in
|
||||
* a way compatible with the mincrypt verifier, using SHA1 and RSA keys.
|
||||
*
|
||||
* <p>
|
||||
* Please see the README.txt file in the root of this project for usage instructions.
|
||||
*/
|
||||
public class ZipSigner
|
||||
{
|
||||
public class ZipSigner {
|
||||
|
||||
private boolean canceled = false;
|
||||
|
||||
@ -102,8 +125,7 @@ public class ZipSigner
|
||||
|
||||
AutoKeyObservable autoKeyObservable = new AutoKeyObservable();
|
||||
|
||||
public ZipSigner() throws ClassNotFoundException, IllegalAccessException, InstantiationException
|
||||
{
|
||||
public ZipSigner() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
// MD5 of the first 1458 bytes of the signature block generated by the key, mapped to the key name
|
||||
autoKeyDetect.put("aa9852bc5a53272ac8031d49b65e4b0e", "media");
|
||||
autoKeyDetect.put("e60418c4b638f20d0721e115674ca11f", "platform");
|
||||
@ -129,14 +151,12 @@ public class ZipSigner
|
||||
return keymode;
|
||||
}
|
||||
|
||||
public void setKeymode(String km) throws IOException, GeneralSecurityException
|
||||
{
|
||||
public void setKeymode(String km) throws IOException, GeneralSecurityException {
|
||||
if (getLogger().isDebugEnabled()) getLogger().debug("setKeymode: " + km);
|
||||
keymode = km;
|
||||
if (keymode.startsWith(MODE_AUTO)) {
|
||||
keySet = null;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
progressHelper.initProgress();
|
||||
loadKeys(keymode);
|
||||
}
|
||||
@ -148,8 +168,7 @@ public class ZipSigner
|
||||
|
||||
|
||||
protected String autoDetectKey(String mode, Map<String, ZioEntry> zioEntries)
|
||||
throws NoSuchAlgorithmException, IOException
|
||||
{
|
||||
throws NoSuchAlgorithmException, IOException {
|
||||
boolean debug = getLogger().isDebugEnabled();
|
||||
|
||||
if (!mode.startsWith(MODE_AUTO)) return mode;
|
||||
@ -197,8 +216,7 @@ public class ZipSigner
|
||||
if (debug) getLogger().debug("Falling back to key=" + keyName);
|
||||
return KEY_TESTKEY;
|
||||
|
||||
}
|
||||
else if (mode.equals(MODE_AUTO_NONE)) {
|
||||
} else if (mode.equals(MODE_AUTO_NONE)) {
|
||||
// in auto-node mode, simply copy the input to the output when the key can't be determined.
|
||||
if (debug) getLogger().debug("Unable to determine key, returning: " + KEY_NONE);
|
||||
return KEY_NONE;
|
||||
@ -213,8 +231,7 @@ public class ZipSigner
|
||||
|
||||
// Loads one of the built-in keys (media, platform, shared, testkey)
|
||||
public void loadKeys(String name)
|
||||
throws IOException, GeneralSecurityException
|
||||
{
|
||||
throws IOException, GeneralSecurityException {
|
||||
|
||||
keySet = loadedKeys.get(name);
|
||||
if (keySet != null) return;
|
||||
@ -242,13 +259,11 @@ public class ZipSigner
|
||||
}
|
||||
}
|
||||
|
||||
public void setKeys( String name, X509Certificate publicKey, PrivateKey privateKey, byte[] signatureBlockTemplate)
|
||||
{
|
||||
public void setKeys(String name, X509Certificate publicKey, PrivateKey privateKey, byte[] signatureBlockTemplate) {
|
||||
keySet = new KeySet(name, publicKey, privateKey, signatureBlockTemplate);
|
||||
}
|
||||
|
||||
public void setKeys( String name, X509Certificate publicKey, PrivateKey privateKey, String signatureAlgorithm, byte[] signatureBlockTemplate)
|
||||
{
|
||||
public void setKeys(String name, X509Certificate publicKey, PrivateKey privateKey, String signatureAlgorithm, byte[] signatureBlockTemplate) {
|
||||
keySet = new KeySet(name, publicKey, privateKey, signatureAlgorithm, signatureBlockTemplate);
|
||||
}
|
||||
|
||||
@ -272,8 +287,7 @@ public class ZipSigner
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadProvider(String providerClassName)
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException
|
||||
{
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
Class providerClass = Class.forName(providerClassName);
|
||||
Provider provider = (Provider) providerClass.newInstance();
|
||||
Security.insertProviderAt(provider, 1);
|
||||
@ -293,7 +307,7 @@ public class ZipSigner
|
||||
|
||||
/**
|
||||
* Decrypt an encrypted PKCS 8 format private key.
|
||||
*
|
||||
* <p>
|
||||
* Based on ghstark's post on Aug 6, 2006 at
|
||||
* http://forums.sun.com/thread.jspa?threadID=758133&messageID=4330949
|
||||
*
|
||||
@ -326,15 +340,17 @@ public class ZipSigner
|
||||
}
|
||||
}
|
||||
|
||||
/** Fetch the content at the specified URL and return it as a byte array. */
|
||||
public byte[] readContentAsBytes( URL contentUrl) throws IOException
|
||||
{
|
||||
/**
|
||||
* Fetch the content at the specified URL and return it as a byte array.
|
||||
*/
|
||||
public byte[] readContentAsBytes(URL contentUrl) throws IOException {
|
||||
return readContentAsBytes(contentUrl.openStream());
|
||||
}
|
||||
|
||||
/** Fetch the content from the given stream and return it as a byte array. */
|
||||
public byte[] readContentAsBytes( InputStream input) throws IOException
|
||||
{
|
||||
/**
|
||||
* Fetch the content from the given stream and return it as a byte array.
|
||||
*/
|
||||
public byte[] readContentAsBytes(InputStream input) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buffer = new byte[2048];
|
||||
@ -349,7 +365,9 @@ public class ZipSigner
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/** Read a PKCS 8 format private key. */
|
||||
/**
|
||||
* Read a PKCS 8 format private key.
|
||||
*/
|
||||
public PrivateKey readPrivateKey(URL privateKeyUrl, String keyPassword)
|
||||
throws IOException, GeneralSecurityException {
|
||||
DataInputStream input = new DataInputStream(privateKeyUrl.openStream());
|
||||
@ -371,10 +389,11 @@ public class ZipSigner
|
||||
}
|
||||
}
|
||||
|
||||
/** Add the SHA1 of every file to the manifest, creating it if necessary. */
|
||||
/**
|
||||
* Add the SHA1 of every file to the manifest, creating it if necessary.
|
||||
*/
|
||||
private Manifest addDigestsToManifest(Map<String, ZioEntry> entries)
|
||||
throws IOException, GeneralSecurityException
|
||||
{
|
||||
throws IOException, GeneralSecurityException {
|
||||
Manifest input = null;
|
||||
ZioEntry manifestEntry = entries.get(JarFile.MANIFEST_NAME);
|
||||
if (manifestEntry != null) {
|
||||
@ -411,8 +430,7 @@ public class ZipSigner
|
||||
if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
|
||||
!name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
|
||||
(stripPattern == null ||
|
||||
!stripPattern.matcher(name).matches()))
|
||||
{
|
||||
!stripPattern.matcher(name).matches())) {
|
||||
|
||||
progressHelper.progress(ProgressEvent.PRORITY_NORMAL, resourceAdapter.getString(ResourceAdapter.Item.GENERATING_MANIFEST));
|
||||
InputStream data = entry.getInputStream();
|
||||
@ -435,7 +453,9 @@ public class ZipSigner
|
||||
}
|
||||
|
||||
|
||||
/** Write the signature file to the given output stream. */
|
||||
/**
|
||||
* Write the signature file to the given output stream.
|
||||
*/
|
||||
private void generateSignatureFile(Manifest manifest, OutputStream out)
|
||||
throws IOException, GeneralSecurityException {
|
||||
out.write(("Signature-Version: 1.0\r\n").getBytes());
|
||||
@ -473,11 +493,12 @@ public class ZipSigner
|
||||
|
||||
}
|
||||
|
||||
/** Write a .RSA file with a digital signature. */
|
||||
/**
|
||||
* Write a .RSA file with a digital signature.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeSignatureBlock(KeySet keySet, byte[] signatureFileBytes, OutputStream out)
|
||||
throws IOException, GeneralSecurityException
|
||||
{
|
||||
throws IOException, GeneralSecurityException {
|
||||
if (keySet.getSigBlockTemplate() != null) {
|
||||
|
||||
// Can't use default Signature on Android. Although it generates a signature that can be verified by jarsigner,
|
||||
@ -506,8 +527,7 @@ public class ZipSigner
|
||||
byte[] tmpData = cipher.doFinal(signatureBytes);
|
||||
getLogger().debug("Signature Decrypted: \n" + HexDumpEncoder.encode(tmpData));
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
try {
|
||||
byte[] sigBlock = null;
|
||||
// Use reflection to call the optional generator.
|
||||
@ -528,8 +548,7 @@ public class ZipSigner
|
||||
* more efficient.
|
||||
*/
|
||||
private void copyFiles(Manifest manifest, Map<String, ZioEntry> input, ZipOutput output, long timestamp)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
Map<String, Attributes> entries = manifest.getEntries();
|
||||
List<String> names = new ArrayList<String>(entries.keySet());
|
||||
Collections.sort(names);
|
||||
@ -549,8 +568,7 @@ public class ZipSigner
|
||||
* Copy all the files from input to output.
|
||||
*/
|
||||
private void copyFiles(Map<String, ZioEntry> input, ZipOutput output)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
int i = 1;
|
||||
for (ZioEntry inEntry : input.values()) {
|
||||
if (canceled) break;
|
||||
@ -571,8 +589,7 @@ public class ZipSigner
|
||||
String inputZipFilename,
|
||||
String outputZipFilename)
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException,
|
||||
IOException, GeneralSecurityException
|
||||
{
|
||||
IOException, GeneralSecurityException {
|
||||
signZip(keystoreURL, keystoreType, keystorePw.toCharArray(), certAlias, certPw.toCharArray(), "SHA1withRSA", inputZipFilename, outputZipFilename);
|
||||
}
|
||||
|
||||
@ -585,8 +602,7 @@ public class ZipSigner
|
||||
String inputZipFilename,
|
||||
String outputZipFilename)
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException,
|
||||
IOException, GeneralSecurityException
|
||||
{
|
||||
IOException, GeneralSecurityException {
|
||||
InputStream keystoreStream = null;
|
||||
|
||||
|
||||
@ -605,34 +621,31 @@ public class ZipSigner
|
||||
setKeys("custom", publicKey, privateKey, signatureAlgorithm, null);
|
||||
|
||||
signZip(inputZipFilename, outputZipFilename);
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
if (keystoreStream != null) keystoreStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Sign the input with the default test key and certificate.
|
||||
/**
|
||||
* Sign the input with the default test key and certificate.
|
||||
* Save result to output file.
|
||||
*/
|
||||
public void signZip(Map<String, ZioEntry> zioEntries, String outputZipFilename)
|
||||
throws IOException, GeneralSecurityException
|
||||
{
|
||||
throws IOException, GeneralSecurityException {
|
||||
progressHelper.initProgress();
|
||||
signZip(zioEntries, new FileOutputStream(outputZipFilename), outputZipFilename);
|
||||
}
|
||||
|
||||
|
||||
/** Sign the file using the given public key cert, private key,
|
||||
/**
|
||||
* Sign the file using the given public key cert, private key,
|
||||
* and signature block template. The signature block template
|
||||
* parameter may be null, but if so
|
||||
* android-sun-jarsign-support.jar must be in the classpath.
|
||||
*/
|
||||
public void signZip(String inputZipFilename, String outputZipFilename)
|
||||
throws IOException, GeneralSecurityException
|
||||
{
|
||||
throws IOException, GeneralSecurityException {
|
||||
File inFile = new File(inputZipFilename).getCanonicalFile();
|
||||
File outFile = new File(outputZipFilename).getCanonicalFile();
|
||||
|
||||
@ -649,21 +662,20 @@ public class ZipSigner
|
||||
input = ZipInput.read(inputZipFilename);
|
||||
outStream = new FileOutputStream(outputZipFilename);
|
||||
signZip(input.getEntries(), outStream, outputZipFilename);
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
if (input != null) input.close();
|
||||
if (outStream != null) outStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/** Sign the
|
||||
/**
|
||||
* Sign the
|
||||
* and signature block template. The signature block template
|
||||
* parameter may be null, but if so
|
||||
* android-sun-jarsign-support.jar must be in the classpath.
|
||||
*/
|
||||
public void signZip(Map<String, ZioEntry> zioEntries, OutputStream outputStream, String outputZipFilename)
|
||||
throws IOException, GeneralSecurityException
|
||||
{
|
||||
throws IOException, GeneralSecurityException {
|
||||
boolean debug = getLogger().isDebugEnabled();
|
||||
|
||||
progressHelper.initProgress();
|
||||
@ -683,7 +695,6 @@ public class ZipSigner
|
||||
}
|
||||
|
||||
|
||||
|
||||
ZipOutput zipOutput = null;
|
||||
|
||||
try {
|
||||
@ -705,8 +716,7 @@ public class ZipSigner
|
||||
if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
|
||||
!name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
|
||||
(stripPattern == null ||
|
||||
!stripPattern.matcher(name).matches()))
|
||||
{
|
||||
!stripPattern.matcher(name).matches())) {
|
||||
progressTotalItems += 3; // digest for manifest, digest in sig file, copy data
|
||||
}
|
||||
}
|
||||
@ -754,33 +764,28 @@ public class ZipSigner
|
||||
copyFiles(manifest, zioEntries, zipOutput, timestamp);
|
||||
if (canceled) return;
|
||||
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
if (zipOutput != null) zipOutput.close();
|
||||
if (canceled) {
|
||||
try {
|
||||
if (outputZipFilename != null) new File(outputZipFilename).delete();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
} catch (Throwable t) {
|
||||
getLogger().warning(t.getClass().getName() + ":" + t.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addProgressListener( ProgressListener l)
|
||||
{
|
||||
public void addProgressListener(ProgressListener l) {
|
||||
progressHelper.addProgressListener(l);
|
||||
}
|
||||
|
||||
public synchronized void removeProgressListener( ProgressListener l)
|
||||
{
|
||||
public synchronized void removeProgressListener(ProgressListener l) {
|
||||
progressHelper.removeProgressListener(l);
|
||||
}
|
||||
|
||||
|
||||
public static class AutoKeyObservable extends Observable
|
||||
{
|
||||
public static class AutoKeyObservable extends Observable {
|
||||
@Override
|
||||
public void notifyObservers(Object arg) {
|
||||
super.setChanged();
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import kellinwood.security.zipsigner.KeySet;
|
||||
@ -7,7 +8,10 @@ import org.bouncycastle.x509.X509V3CertificateGenerator;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Date;
|
||||
|
||||
@ -17,7 +21,8 @@ import java.util.Date;
|
||||
*/
|
||||
public class CertCreator {
|
||||
|
||||
/** Creates a new keystore and self-signed key. The key will have the same password as the key, and will be
|
||||
/**
|
||||
* Creates a new keystore and self-signed key. The key will have the same password as the key, and will be
|
||||
* RSA 2048, with the cert signed using SHA1withRSA. The certificate will have a validity of
|
||||
* 30 years).
|
||||
*
|
||||
@ -27,8 +32,7 @@ public class CertCreator {
|
||||
* @param distinguishedNameValues - contains Country, State, Locality,...,Common Name, etc.
|
||||
*/
|
||||
public static void createKeystoreAndKey(String storePath, char[] password,
|
||||
String keyName, DistinguishedNameValues distinguishedNameValues)
|
||||
{
|
||||
String keyName, DistinguishedNameValues distinguishedNameValues) {
|
||||
createKeystoreAndKey(storePath, password, "RSA", 2048, keyName, password, "SHA1withRSA", 30,
|
||||
distinguishedNameValues);
|
||||
}
|
||||
@ -63,8 +67,8 @@ public class CertCreator {
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a new key and store it in an existing keystore.
|
||||
*
|
||||
/**
|
||||
* Create a new key and store it in an existing keystore.
|
||||
*/
|
||||
public static KeySet createKey(String storePath, char[] storePass,
|
||||
String keyAlgorithm, int keySize, String keyName, char[] keyPass,
|
||||
@ -93,8 +97,7 @@ public class CertCreator {
|
||||
}
|
||||
|
||||
public static KeySet createKey(String keyAlgorithm, int keySize, String keyName,
|
||||
String certSignatureAlgorithm, int certValidityYears, DistinguishedNameValues distinguishedNameValues)
|
||||
{
|
||||
String certSignatureAlgorithm, int certValidityYears, DistinguishedNameValues distinguishedNameValues) {
|
||||
try {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
|
||||
keyPairGenerator.initialize(keySize);
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import kellinwood.security.zipsigner.ZipSigner;
|
||||
@ -12,7 +13,9 @@ import java.security.cert.X509Certificate;
|
||||
*/
|
||||
public class CustomKeySigner {
|
||||
|
||||
/** KeyStore-type agnostic. This method will sign the zip file, automatically handling JKS or BKS keystores. */
|
||||
/**
|
||||
* KeyStore-type agnostic. This method will sign the zip file, automatically handling JKS or BKS keystores.
|
||||
*/
|
||||
public static void signZip(ZipSigner zipSigner,
|
||||
String keystorePath,
|
||||
char[] keystorePw,
|
||||
@ -21,8 +24,7 @@ public class CustomKeySigner {
|
||||
String signatureAlgorithm,
|
||||
String inputZipFilename,
|
||||
String outputZipFilename)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
zipSigner.issueLoadingCertAndKeysProgressEvent();
|
||||
KeyStore keystore = KeyStoreFileManager.loadKeyStore(keystorePath, keystorePw);
|
||||
Certificate cert = keystore.getCertificate(certAlias);
|
||||
|
@ -1,10 +1,10 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||
import org.bouncycastle.jce.X509Principal;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
|
@ -23,15 +23,17 @@ power to enforce restrictions on reverse-engineering of their software,
|
||||
and it is irresponsible for them to claim they can. */
|
||||
|
||||
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import javax.crypto.EncryptedPrivateKeyInfo;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.Key;
|
||||
@ -42,29 +44,24 @@ import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.crypto.EncryptedPrivateKeyInfo;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* This is an implementation of Sun's proprietary key store
|
||||
* algorithm, called "JKS" for "Java Key Store". This implementation was
|
||||
* created entirely through reverse-engineering.
|
||||
*
|
||||
* <p>
|
||||
* <p>The format of JKS files is, from the start of the file:
|
||||
*
|
||||
* <p>
|
||||
* <ol>
|
||||
* <li>Magic bytes. This is a four-byte integer, in big-endian byte
|
||||
* order, equal to <code>0xFEEDFEED</code>.</li>
|
||||
@ -82,7 +79,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
* href="http://java.sun.com/j2se/1.4.1/docs/api/java/io/DataOutput.html#writeUTF(java.lang.String)">DataOutput.writeUTF(String)</a>.</li>
|
||||
* <li>An eight-byte integer, representing the entry's creation date,
|
||||
* in milliseconds since the epoch.
|
||||
*
|
||||
* <p>
|
||||
* <p>Then, if the entry is a private key entry:
|
||||
* <ol>
|
||||
* <li>The size of the encoded key as a four-byte int, then that
|
||||
@ -94,7 +91,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
* certificates, encoded as described in the trusted certificates
|
||||
* section.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
* <p>Otherwise, the entry is a trusted certificate, which is encoded
|
||||
* as the name of the encoding algorithm (e.g. X.509), encoded the same
|
||||
* way as alias names. Then, a four-byte integer representing the size
|
||||
@ -108,12 +105,12 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
* </ol>
|
||||
* </li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
* <p>(See <a href="genkey.java">this file</a> for some idea of how I
|
||||
* was able to figure out these algorithms)</p>
|
||||
*
|
||||
* <p>
|
||||
* <p>Decrypting the key works as follows:
|
||||
*
|
||||
* <p>
|
||||
* <ol>
|
||||
* <li>The key length is the length of the ciphertext minus 40. The
|
||||
* encrypted key, <code>ekey</code>, is the middle bytes of the
|
||||
@ -129,33 +126,34 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
* the last 20 bytes of the ciphertext, output <code>FAIL</code>. Otherwise,
|
||||
* output <code>key</code>.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
* <p>The signature is defined as <code>SHA-1(UTF-16BE(password) +
|
||||
* US_ASCII("Mighty Aphrodite") + encoded_keystore)</code> (yup, Sun
|
||||
* engineers are just that clever).
|
||||
*
|
||||
* <p>
|
||||
* <p>(Above, SHA-1 denotes the secure hash algorithm, UTF-16BE the
|
||||
* big-endian byte representation of a UTF-16 string, and US_ASCII the
|
||||
* ASCII byte representation of the string.)
|
||||
*
|
||||
* <p>
|
||||
* <p>The source code of this class should be available in the file <a
|
||||
* href="http://metastatic.org/source/JKS.java">JKS.java</a>.
|
||||
*
|
||||
* @author Casey Marshall (rsdio@metastatic.org)
|
||||
*
|
||||
* <p>
|
||||
* Changes by Ken Ellinwood:
|
||||
* ** Fixed a NullPointerException in engineLoad(). This method must return gracefully if the keystore input stream is null.
|
||||
* ** engineGetCertificateEntry() was updated to return the first cert in the chain for private key entries.
|
||||
* ** Lowercase the alias names, otherwise keytool chokes on the file created by this code.
|
||||
* ** Fixed the integrity check in engineLoad(), previously the exception was never thrown regardless of password value.
|
||||
*/
|
||||
public class JKS extends KeyStoreSpi
|
||||
{
|
||||
public class JKS extends KeyStoreSpi {
|
||||
|
||||
// Constants and fields.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Ah, Sun. So goddamned clever with those magic bytes. */
|
||||
/**
|
||||
* Ah, Sun. So goddamned clever with those magic bytes.
|
||||
*/
|
||||
private static final int MAGIC = 0xFEEDFEED;
|
||||
|
||||
private static final int PRIVATE_KEY = 1;
|
||||
@ -170,8 +168,7 @@ public class JKS extends KeyStoreSpi
|
||||
// Constructor.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public JKS()
|
||||
{
|
||||
public JKS() {
|
||||
super();
|
||||
aliases = new Vector();
|
||||
trustedCerts = new HashMap();
|
||||
@ -185,8 +182,7 @@ public class JKS extends KeyStoreSpi
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public Key engineGetKey(String alias, char[] password)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException
|
||||
{
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
alias = alias.toLowerCase();
|
||||
|
||||
if (!privateKeys.containsKey(alias))
|
||||
@ -194,32 +190,25 @@ public class JKS extends KeyStoreSpi
|
||||
byte[] key = decryptKey((byte[]) privateKeys.get(alias),
|
||||
charsToBytes(password));
|
||||
Certificate[] chain = engineGetCertificateChain(alias);
|
||||
if (chain.length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (chain.length > 0) {
|
||||
try {
|
||||
// Private and public keys MUST have the same algorithm.
|
||||
KeyFactory fact = KeyFactory.getInstance(
|
||||
chain[0].getPublicKey().getAlgorithm());
|
||||
return fact.generatePrivate(new PKCS8EncodedKeySpec(key));
|
||||
}
|
||||
catch (InvalidKeySpecException x)
|
||||
{
|
||||
} catch (InvalidKeySpecException x) {
|
||||
throw new UnrecoverableKeyException(x.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
return new SecretKeySpec(key, alias);
|
||||
}
|
||||
|
||||
public Certificate[] engineGetCertificateChain(String alias)
|
||||
{
|
||||
public Certificate[] engineGetCertificateChain(String alias) {
|
||||
alias = alias.toLowerCase();
|
||||
return (Certificate[]) certChains.get(alias);
|
||||
}
|
||||
|
||||
public Certificate engineGetCertificate(String alias)
|
||||
{
|
||||
public Certificate engineGetCertificate(String alias) {
|
||||
alias = alias.toLowerCase();
|
||||
if (engineIsKeyEntry(alias)) {
|
||||
Certificate[] certChain = (Certificate[]) certChains.get(alias);
|
||||
@ -228,8 +217,7 @@ public class JKS extends KeyStoreSpi
|
||||
return (Certificate) trustedCerts.get(alias);
|
||||
}
|
||||
|
||||
public Date engineGetCreationDate(String alias)
|
||||
{
|
||||
public Date engineGetCreationDate(String alias) {
|
||||
alias = alias.toLowerCase();
|
||||
return (Date) dates.get(alias);
|
||||
}
|
||||
@ -237,8 +225,7 @@ public class JKS extends KeyStoreSpi
|
||||
// XXX implement writing methods.
|
||||
|
||||
public void engineSetKeyEntry(String alias, Key key, char[] passwd, Certificate[] certChain)
|
||||
throws KeyStoreException
|
||||
{
|
||||
throws KeyStoreException {
|
||||
alias = alias.toLowerCase();
|
||||
if (trustedCerts.containsKey(alias))
|
||||
throw new KeyStoreException("\"" + alias + " is a trusted certificate entry");
|
||||
@ -247,25 +234,20 @@ public class JKS extends KeyStoreSpi
|
||||
certChains.put(alias, certChain);
|
||||
else
|
||||
certChains.put(alias, new Certificate[0]);
|
||||
if (!aliases.contains(alias))
|
||||
{
|
||||
if (!aliases.contains(alias)) {
|
||||
dates.put(alias, new Date());
|
||||
aliases.add(alias);
|
||||
}
|
||||
}
|
||||
|
||||
public void engineSetKeyEntry(String alias, byte[] encodedKey, Certificate[] certChain)
|
||||
throws KeyStoreException
|
||||
{
|
||||
throws KeyStoreException {
|
||||
alias = alias.toLowerCase();
|
||||
if (trustedCerts.containsKey(alias))
|
||||
throw new KeyStoreException("\"" + alias + "\" is a trusted certificate entry");
|
||||
try
|
||||
{
|
||||
try {
|
||||
new EncryptedPrivateKeyInfo(encodedKey);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
} catch (IOException ioe) {
|
||||
throw new KeyStoreException("encoded key is not an EncryptedPrivateKeyInfo");
|
||||
}
|
||||
privateKeys.put(alias, encodedKey);
|
||||
@ -273,67 +255,56 @@ public class JKS extends KeyStoreSpi
|
||||
certChains.put(alias, certChain);
|
||||
else
|
||||
certChains.put(alias, new Certificate[0]);
|
||||
if (!aliases.contains(alias))
|
||||
{
|
||||
if (!aliases.contains(alias)) {
|
||||
dates.put(alias, new Date());
|
||||
aliases.add(alias);
|
||||
}
|
||||
}
|
||||
|
||||
public void engineSetCertificateEntry(String alias, Certificate cert)
|
||||
throws KeyStoreException
|
||||
{
|
||||
throws KeyStoreException {
|
||||
alias = alias.toLowerCase();
|
||||
if (privateKeys.containsKey(alias))
|
||||
throw new KeyStoreException("\"" + alias + "\" is a private key entry");
|
||||
if (cert == null)
|
||||
throw new NullPointerException();
|
||||
trustedCerts.put(alias, cert);
|
||||
if (!aliases.contains(alias))
|
||||
{
|
||||
if (!aliases.contains(alias)) {
|
||||
dates.put(alias, new Date());
|
||||
aliases.add(alias);
|
||||
}
|
||||
}
|
||||
|
||||
public void engineDeleteEntry(String alias) throws KeyStoreException
|
||||
{
|
||||
public void engineDeleteEntry(String alias) throws KeyStoreException {
|
||||
alias = alias.toLowerCase();
|
||||
aliases.remove(alias);
|
||||
}
|
||||
|
||||
public Enumeration engineAliases()
|
||||
{
|
||||
public Enumeration engineAliases() {
|
||||
return aliases.elements();
|
||||
}
|
||||
|
||||
public boolean engineContainsAlias(String alias)
|
||||
{
|
||||
public boolean engineContainsAlias(String alias) {
|
||||
alias = alias.toLowerCase();
|
||||
return aliases.contains(alias);
|
||||
}
|
||||
|
||||
public int engineSize()
|
||||
{
|
||||
public int engineSize() {
|
||||
return aliases.size();
|
||||
}
|
||||
|
||||
public boolean engineIsKeyEntry(String alias)
|
||||
{
|
||||
public boolean engineIsKeyEntry(String alias) {
|
||||
alias = alias.toLowerCase();
|
||||
return privateKeys.containsKey(alias);
|
||||
}
|
||||
|
||||
public boolean engineIsCertificateEntry(String alias)
|
||||
{
|
||||
public boolean engineIsCertificateEntry(String alias) {
|
||||
alias = alias.toLowerCase();
|
||||
return trustedCerts.containsKey(alias);
|
||||
}
|
||||
|
||||
public String engineGetCertificateAlias(Certificate cert)
|
||||
{
|
||||
for (Iterator keys = trustedCerts.keySet().iterator(); keys.hasNext(); )
|
||||
{
|
||||
public String engineGetCertificateAlias(Certificate cert) {
|
||||
for (Iterator keys = trustedCerts.keySet().iterator(); keys.hasNext(); ) {
|
||||
String alias = (String) keys.next();
|
||||
if (cert.equals(trustedCerts.get(alias)))
|
||||
return alias;
|
||||
@ -342,8 +313,7 @@ public class JKS extends KeyStoreSpi
|
||||
}
|
||||
|
||||
public void engineStore(OutputStream out, char[] passwd)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||
md.update(charsToBytes(passwd));
|
||||
md.update("Mighty Aphrodite".getBytes("UTF-8"));
|
||||
@ -351,18 +321,14 @@ public class JKS extends KeyStoreSpi
|
||||
dout.writeInt(MAGIC);
|
||||
dout.writeInt(2);
|
||||
dout.writeInt(aliases.size());
|
||||
for (Enumeration e = aliases.elements(); e.hasMoreElements(); )
|
||||
{
|
||||
for (Enumeration e = aliases.elements(); e.hasMoreElements(); ) {
|
||||
String alias = (String) e.nextElement();
|
||||
if (trustedCerts.containsKey(alias))
|
||||
{
|
||||
if (trustedCerts.containsKey(alias)) {
|
||||
dout.writeInt(TRUSTED_CERT);
|
||||
dout.writeUTF(alias);
|
||||
dout.writeLong(((Date) dates.get(alias)).getTime());
|
||||
writeCert(dout, (Certificate) trustedCerts.get(alias));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
dout.writeInt(PRIVATE_KEY);
|
||||
dout.writeUTF(alias);
|
||||
dout.writeLong(((Date) dates.get(alias)).getTime());
|
||||
@ -380,8 +346,7 @@ public class JKS extends KeyStoreSpi
|
||||
}
|
||||
|
||||
public void engineLoad(InputStream in, char[] passwd)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
if (passwd != null) md.update(charsToBytes(passwd));
|
||||
md.update("Mighty Aphrodite".getBytes("UTF-8")); // HAR HAR
|
||||
@ -399,14 +364,12 @@ public class JKS extends KeyStoreSpi
|
||||
aliases.ensureCapacity(n);
|
||||
if (n < 0)
|
||||
throw new LoadKeystoreException("Malformed key store");
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
int type = din.readInt();
|
||||
String alias = din.readUTF();
|
||||
aliases.add(alias);
|
||||
dates.put(alias, new Date(din.readLong()));
|
||||
switch (type)
|
||||
{
|
||||
switch (type) {
|
||||
case PRIVATE_KEY:
|
||||
int len = din.readInt();
|
||||
byte[] encoded = new byte[len];
|
||||
@ -442,8 +405,7 @@ public class JKS extends KeyStoreSpi
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static Certificate readCert(DataInputStream in)
|
||||
throws IOException, CertificateException, NoSuchAlgorithmException
|
||||
{
|
||||
throws IOException, CertificateException, NoSuchAlgorithmException {
|
||||
String type = in.readUTF();
|
||||
int len = in.readInt();
|
||||
byte[] encoded = new byte[len];
|
||||
@ -453,8 +415,7 @@ public class JKS extends KeyStoreSpi
|
||||
}
|
||||
|
||||
private static void writeCert(DataOutputStream dout, Certificate cert)
|
||||
throws IOException, CertificateException
|
||||
{
|
||||
throws IOException, CertificateException {
|
||||
dout.writeUTF(cert.getType());
|
||||
byte[] b = cert.getEncoded();
|
||||
dout.writeInt(b.length);
|
||||
@ -462,10 +423,8 @@ public class JKS extends KeyStoreSpi
|
||||
}
|
||||
|
||||
private static byte[] decryptKey(byte[] encryptedPKI, byte[] passwd)
|
||||
throws UnrecoverableKeyException
|
||||
{
|
||||
try
|
||||
{
|
||||
throws UnrecoverableKeyException {
|
||||
try {
|
||||
EncryptedPrivateKeyInfo epki =
|
||||
new EncryptedPrivateKeyInfo(encryptedPKI);
|
||||
byte[] encr = epki.getEncryptedData();
|
||||
@ -476,14 +435,12 @@ public class JKS extends KeyStoreSpi
|
||||
byte[] key = new byte[encr.length - 40];
|
||||
MessageDigest sha = MessageDigest.getInstance("SHA1");
|
||||
int count = 0;
|
||||
while (count < key.length)
|
||||
{
|
||||
while (count < key.length) {
|
||||
sha.reset();
|
||||
sha.update(passwd);
|
||||
sha.update(keystream);
|
||||
sha.digest(keystream, 0, keystream.length);
|
||||
for (int i = 0; i < keystream.length && count < key.length; i++)
|
||||
{
|
||||
for (int i = 0; i < keystream.length && count < key.length; i++) {
|
||||
key[count] = (byte) (keystream[i] ^ encr[count + 20]);
|
||||
count++;
|
||||
}
|
||||
@ -494,18 +451,14 @@ public class JKS extends KeyStoreSpi
|
||||
if (!MessageDigest.isEqual(check, sha.digest()))
|
||||
throw new UnrecoverableKeyException("checksum mismatch");
|
||||
return key;
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
} catch (Exception x) {
|
||||
throw new UnrecoverableKeyException(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] encryptKey(Key key, byte[] passwd)
|
||||
throws KeyStoreException
|
||||
{
|
||||
try
|
||||
{
|
||||
throws KeyStoreException {
|
||||
try {
|
||||
MessageDigest sha = MessageDigest.getInstance("SHA1");
|
||||
SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
|
||||
byte[] k = key.getEncoded();
|
||||
@ -513,14 +466,12 @@ public class JKS extends KeyStoreSpi
|
||||
byte[] keystream = rand.getSeed(20);
|
||||
System.arraycopy(keystream, 0, encrypted, 0, 20);
|
||||
int count = 0;
|
||||
while (count < k.length)
|
||||
{
|
||||
while (count < k.length) {
|
||||
sha.reset();
|
||||
sha.update(passwd);
|
||||
sha.update(keystream);
|
||||
sha.digest(keystream, 0, keystream.length);
|
||||
for (int i = 0; i < keystream.length && count < k.length; i++)
|
||||
{
|
||||
for (int i = 0; i < keystream.length && count < k.length; i++) {
|
||||
encrypted[count + 20] = (byte) (keystream[i] ^ k[count]);
|
||||
count++;
|
||||
}
|
||||
@ -533,18 +484,14 @@ public class JKS extends KeyStoreSpi
|
||||
// encryption algorithm.
|
||||
return new EncryptedPrivateKeyInfo("1.3.6.1.4.1.42.2.17.1.1",
|
||||
encrypted).getEncoded();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
} catch (Exception x) {
|
||||
throw new KeyStoreException(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] charsToBytes(char[] passwd)
|
||||
{
|
||||
private static byte[] charsToBytes(char[] passwd) {
|
||||
byte[] buf = new byte[passwd.length * 2];
|
||||
for (int i = 0, j = 0; i < passwd.length; i++)
|
||||
{
|
||||
for (int i = 0, j = 0; i < passwd.length; i++) {
|
||||
buf[j++] = (byte) (passwd[i] >>> 8);
|
||||
buf[j++] = (byte) passwd[i];
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
public class KeyNameConflictException extends Exception {
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
|
||||
@ -5,19 +6,28 @@ import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.security.cert.Certificate;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public class KeyStoreFileManager {
|
||||
|
||||
static Provider provider = new BouncyCastleProvider();
|
||||
|
||||
public static Provider getProvider() { return provider; }
|
||||
public static Provider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static void setProvider(Provider provider) {
|
||||
if (KeyStoreFileManager.provider != null) Security.removeProvider(KeyStoreFileManager.provider.getName());
|
||||
@ -48,21 +58,18 @@ public class KeyStoreFileManager {
|
||||
}
|
||||
|
||||
public static KeyStore createKeyStore(String keystorePath, char[] password)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
KeyStore ks = null;
|
||||
if (keystorePath.toLowerCase().endsWith(".bks")) {
|
||||
ks = KeyStore.getInstance("bks", new BouncyCastleProvider());
|
||||
}
|
||||
else ks = new JksKeyStore();
|
||||
} else ks = new JksKeyStore();
|
||||
ks.load(null, password);
|
||||
|
||||
return ks;
|
||||
}
|
||||
|
||||
public static KeyStore loadKeyStore(String keystorePath, char[] password)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
KeyStore ks = null;
|
||||
try {
|
||||
ks = new JksKeyStore();
|
||||
@ -89,8 +96,7 @@ public class KeyStoreFileManager {
|
||||
}
|
||||
|
||||
public static void writeKeyStore(KeyStore ks, String keystorePath, String encodedPassword)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
char password[] = null;
|
||||
try {
|
||||
password = PasswordObfuscator.getInstance().decodeKeystorePassword(keystorePath, encodedPassword);
|
||||
@ -101,8 +107,7 @@ public class KeyStoreFileManager {
|
||||
}
|
||||
|
||||
public static void writeKeyStore(KeyStore ks, String keystorePath, char[] password)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
|
||||
File keystoreFile = new File(keystorePath);
|
||||
try {
|
||||
@ -136,7 +141,8 @@ public class KeyStoreFileManager {
|
||||
x.printStackTrace(pw);
|
||||
pw.flush();
|
||||
pw.close();
|
||||
} catch (Exception y) {}
|
||||
} catch (Exception y) {
|
||||
}
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
@ -159,10 +165,16 @@ public class KeyStoreFileManager {
|
||||
count += n;
|
||||
}
|
||||
} finally {
|
||||
try { output.close(); } catch (IOException x) {} // Ignore
|
||||
try {
|
||||
output.close();
|
||||
} catch (IOException x) {
|
||||
} // Ignore
|
||||
}
|
||||
} finally {
|
||||
try { input.close(); } catch (IOException x) {}
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException x) {
|
||||
}
|
||||
}
|
||||
|
||||
if (srcFile.length() != destFile.length()) {
|
||||
@ -176,23 +188,20 @@ public class KeyStoreFileManager {
|
||||
|
||||
|
||||
public static void renameTo(File fromFile, File toFile)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
copyFile(fromFile, toFile, true);
|
||||
if (!fromFile.delete()) throw new IOException("Failed to delete " + fromFile);
|
||||
}
|
||||
|
||||
public static void deleteKey(String storePath, String storePass, String keyName)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
KeyStore ks = loadKeyStore(storePath, storePass);
|
||||
ks.deleteEntry(keyName);
|
||||
writeKeyStore(ks, storePath, storePass);
|
||||
}
|
||||
|
||||
public static String renameKey(String keystorePath, String storePass, String oldKeyName, String newKeyName, String keyPass)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
char[] keyPw = null;
|
||||
|
||||
try {
|
||||
@ -210,15 +219,13 @@ public class KeyStoreFileManager {
|
||||
|
||||
writeKeyStore(ks, keystorePath, storePass);
|
||||
return newKeyName;
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
PasswordObfuscator.flush(keyPw);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyStore.Entry getKeyEntry(String keystorePath, String storePass, String keyName, String keyPass)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
char[] keyPw = null;
|
||||
KeyStore.PasswordProtection passwordProtection = null;
|
||||
|
||||
@ -227,30 +234,26 @@ public class KeyStoreFileManager {
|
||||
keyPw = PasswordObfuscator.getInstance().decodeAliasPassword(keystorePath, keyName, keyPass);
|
||||
passwordProtection = new KeyStore.PasswordProtection(keyPw);
|
||||
return ks.getEntry(keyName, passwordProtection);
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
if (keyPw != null) PasswordObfuscator.flush(keyPw);
|
||||
if (passwordProtection != null) passwordProtection.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean containsKey(String keystorePath, String storePass, String keyName)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
KeyStore ks = loadKeyStore(keystorePath, storePass);
|
||||
return ks.containsAlias(keyName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param keystorePath
|
||||
* @param encodedPassword
|
||||
* @throws Exception if the password is invalid
|
||||
*/
|
||||
public static void validateKeystorePassword(String keystorePath, String encodedPassword)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
char[] password = null;
|
||||
try {
|
||||
KeyStore ks = KeyStoreFileManager.loadKeyStore(keystorePath, encodedPassword);
|
||||
@ -261,15 +264,13 @@ public class KeyStoreFileManager {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param keystorePath
|
||||
* @param keyName
|
||||
* @param encodedPassword
|
||||
* @throws java.security.UnrecoverableKeyException if the password is invalid
|
||||
*/
|
||||
public static void validateKeyPassword(String keystorePath, String keyName, String encodedPassword)
|
||||
throws Exception
|
||||
{
|
||||
throws Exception {
|
||||
char[] password = null;
|
||||
try {
|
||||
KeyStore ks = KeyStoreFileManager.loadKeyStore(keystorePath, (char[]) null);
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
@ -6,7 +7,12 @@ import kellinwood.security.zipsigner.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
public class PasswordObfuscator {
|
||||
|
||||
|
@ -1,8 +1,13 @@
|
||||
|
||||
package kellinwood.security.zipsigner.optional;
|
||||
|
||||
import kellinwood.security.zipsigner.KeySet;
|
||||
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||
import org.bouncycastle.cms.*;
|
||||
import org.bouncycastle.cms.CMSProcessableByteArray;
|
||||
import org.bouncycastle.cms.CMSSignedData;
|
||||
import org.bouncycastle.cms.CMSSignedDataGenerator;
|
||||
import org.bouncycastle.cms.CMSTypedData;
|
||||
import org.bouncycastle.cms.SignerInfoGenerator;
|
||||
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.DigestCalculatorProvider;
|
||||
|
@ -13,15 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package kellinwood.zipio;
|
||||
|
||||
import java.io.IOException;
|
||||
package kellinwood.zipio;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
public class CentralEnd
|
||||
{
|
||||
import java.io.IOException;
|
||||
|
||||
public class CentralEnd {
|
||||
public int signature = 0x06054b50; // end of central dir signature 4 bytes
|
||||
public short numberThisDisk = 0; // number of this disk 2 bytes
|
||||
public short centralStartDisk = 0; // number of the disk with the start of the central directory 2 bytes
|
||||
@ -34,8 +34,7 @@ public class CentralEnd
|
||||
|
||||
private static LoggerInterface log;
|
||||
|
||||
public static CentralEnd read(ZipInput input) throws IOException
|
||||
{
|
||||
public static CentralEnd read(ZipInput input) throws IOException {
|
||||
|
||||
int signature = input.readInt();
|
||||
if (signature != 0x06054b50) {
|
||||
@ -56,8 +55,7 @@ public class CentralEnd
|
||||
}
|
||||
|
||||
|
||||
private void doRead( ZipInput input) throws IOException
|
||||
{
|
||||
private void doRead(ZipInput input) throws IOException {
|
||||
|
||||
boolean debug = getLogger().isDebugEnabled();
|
||||
|
||||
@ -87,8 +85,7 @@ public class CentralEnd
|
||||
}
|
||||
|
||||
|
||||
public void write( ZipOutput output) throws IOException
|
||||
{
|
||||
public void write(ZipOutput output) throws IOException {
|
||||
|
||||
boolean debug = getLogger().isDebugEnabled();
|
||||
|
||||
|
@ -13,13 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.zipio;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.Date;
|
||||
@ -27,9 +31,6 @@ import java.util.zip.CRC32;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
public class ZioEntry implements Cloneable {
|
||||
|
||||
private ZipInput zipInput;
|
||||
@ -81,8 +82,7 @@ public class ZioEntry implements Cloneable {
|
||||
|
||||
|
||||
public ZioEntry(String name, String sourceDataFile)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
zipInput = new ZipInput(sourceDataFile);
|
||||
filename = name;
|
||||
fileComment = "";
|
||||
@ -116,10 +116,8 @@ public class ZioEntry implements Cloneable {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ZioEntry(String name, String sourceDataFile, short compression, int crc32, int compressedSize, int size)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
zipInput = new ZipInput(sourceDataFile);
|
||||
filename = name;
|
||||
fileComment = "";
|
||||
@ -133,23 +131,19 @@ public class ZioEntry implements Cloneable {
|
||||
}
|
||||
|
||||
// Return a copy with a new name
|
||||
public ZioEntry getClonedEntry( String newName)
|
||||
{
|
||||
public ZioEntry getClonedEntry(String newName) {
|
||||
|
||||
ZioEntry clone;
|
||||
try {
|
||||
clone = (ZioEntry) this.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new IllegalStateException("clone() failed!");
|
||||
}
|
||||
clone.setName(newName);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public void readLocalHeader() throws IOException
|
||||
{
|
||||
public void readLocalHeader() throws IOException {
|
||||
ZipInput input = zipInput;
|
||||
int tmp;
|
||||
boolean debug = getLogger().isDebugEnabled();
|
||||
@ -174,35 +168,43 @@ public class ZioEntry implements Cloneable {
|
||||
short tmpShort;
|
||||
|
||||
// 4 2 Version needed to extract (minimum)
|
||||
/* versionRequired */ tmpShort = input.readShort();
|
||||
/* versionRequired */
|
||||
tmpShort = input.readShort();
|
||||
if (debug) log.debug(String.format("Version required: 0x%04x", tmpShort /*versionRequired*/));
|
||||
|
||||
// 6 2 General purpose bit flag
|
||||
/* generalPurposeBits */ tmpShort = input.readShort();
|
||||
/* generalPurposeBits */
|
||||
tmpShort = input.readShort();
|
||||
if (debug) log.debug(String.format("General purpose bits: 0x%04x", tmpShort /* generalPurposeBits */));
|
||||
|
||||
// 8 2 Compression method
|
||||
/* compression */ tmpShort = input.readShort();
|
||||
/* compression */
|
||||
tmpShort = input.readShort();
|
||||
if (debug) log.debug(String.format("Compression: 0x%04x", tmpShort /* compression */));
|
||||
|
||||
// 10 2 File last modification time
|
||||
/* modificationTime */ tmpShort = input.readShort();
|
||||
/* modificationTime */
|
||||
tmpShort = input.readShort();
|
||||
if (debug) log.debug(String.format("Modification time: 0x%04x", tmpShort /* modificationTime */));
|
||||
|
||||
// 12 2 File last modification date
|
||||
/* modificationDate */ tmpShort = input.readShort();
|
||||
/* modificationDate */
|
||||
tmpShort = input.readShort();
|
||||
if (debug) log.debug(String.format("Modification date: 0x%04x", tmpShort /* modificationDate */));
|
||||
|
||||
// 14 4 CRC-32
|
||||
/* crc32 */ tmpInt = input.readInt();
|
||||
/* crc32 */
|
||||
tmpInt = input.readInt();
|
||||
if (debug) log.debug(String.format("CRC-32: 0x%04x", tmpInt /*crc32*/));
|
||||
|
||||
// 18 4 Compressed size
|
||||
/* compressedSize*/ tmpInt = input.readInt();
|
||||
/* compressedSize*/
|
||||
tmpInt = input.readInt();
|
||||
if (debug) log.debug(String.format("Compressed size: 0x%04x", tmpInt /*compressedSize*/));
|
||||
|
||||
// 22 4 Uncompressed size
|
||||
/* size */ tmpInt = input.readInt();
|
||||
/* size */
|
||||
tmpInt = input.readInt();
|
||||
if (debug) log.debug(String.format("Size: 0x%04x", tmpInt /*size*/));
|
||||
|
||||
// 26 2 File name length (n)
|
||||
@ -226,8 +228,7 @@ public class ZioEntry implements Cloneable {
|
||||
|
||||
}
|
||||
|
||||
public void writeLocalEntry( ZipOutput output) throws IOException
|
||||
{
|
||||
public void writeLocalEntry(ZipOutput output) throws IOException {
|
||||
if (data == null && dataPosition < 0 && zipInput != null) {
|
||||
readLocalHeader();
|
||||
}
|
||||
@ -295,8 +296,7 @@ public class ZioEntry implements Cloneable {
|
||||
if (data != null) {
|
||||
output.writeBytes(data);
|
||||
if (debug) getLogger().debug(String.format("Wrote %d bytes", data.length));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
|
||||
if (debug) getLogger().debug(String.format("Seeking to position 0x%08x", dataPosition));
|
||||
zipInput.seek(dataPosition);
|
||||
@ -311,14 +311,13 @@ public class ZioEntry implements Cloneable {
|
||||
output.writeBytes(buffer, 0, numRead);
|
||||
if (debug) getLogger().debug(String.format("Wrote %d bytes", numRead));
|
||||
totalCount += numRead;
|
||||
}
|
||||
else throw new IllegalStateException(String.format("EOF reached while copying %s with %d bytes left to go", filename, compressedSize - totalCount));
|
||||
} else
|
||||
throw new IllegalStateException(String.format("EOF reached while copying %s with %d bytes left to go", filename, compressedSize - totalCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ZioEntry read(ZipInput input) throws IOException
|
||||
{
|
||||
public static ZioEntry read(ZipInput input) throws IOException {
|
||||
|
||||
// 0 4 Central directory header signature = 0x02014b50
|
||||
int signature = input.readInt();
|
||||
@ -334,8 +333,7 @@ public class ZioEntry implements Cloneable {
|
||||
return entry;
|
||||
}
|
||||
|
||||
private void doRead( ZipInput input) throws IOException
|
||||
{
|
||||
private void doRead(ZipInput input) throws IOException {
|
||||
|
||||
boolean debug = getLogger().isDebugEnabled();
|
||||
|
||||
@ -422,9 +420,10 @@ public class ZioEntry implements Cloneable {
|
||||
|
||||
}
|
||||
|
||||
/** Returns the entry's data. */
|
||||
public byte[] getData() throws IOException
|
||||
{
|
||||
/**
|
||||
* Returns the entry's data.
|
||||
*/
|
||||
public byte[] getData() throws IOException {
|
||||
if (data != null) return data;
|
||||
|
||||
byte[] tmpdata = new byte[size];
|
||||
@ -434,7 +433,8 @@ public class ZioEntry implements Cloneable {
|
||||
|
||||
while (count != size) {
|
||||
int numRead = din.read(tmpdata, count, size - count);
|
||||
if (numRead < 0) throw new IllegalStateException(String.format("Read failed, expecting %d bytes, got %d instead", size, count));
|
||||
if (numRead < 0)
|
||||
throw new IllegalStateException(String.format("Read failed, expecting %d bytes, got %d instead", size, count));
|
||||
count += numRead;
|
||||
}
|
||||
return tmpdata;
|
||||
@ -473,13 +473,11 @@ public class ZioEntry implements Cloneable {
|
||||
// in order to support certain optimizations.
|
||||
dataStream.setReturnDummyByte(true);
|
||||
return new InflaterInputStream(dataStream, new Inflater(true));
|
||||
}
|
||||
else return dataStream;
|
||||
} else return dataStream;
|
||||
}
|
||||
|
||||
// Returns an output stream for writing an entry's data.
|
||||
public OutputStream getOutputStream()
|
||||
{
|
||||
public OutputStream getOutputStream() {
|
||||
entryOut = new ZioEntryOutputStream(compression, new ByteArrayOutputStream());
|
||||
return entryOut;
|
||||
}
|
||||
@ -537,8 +535,7 @@ public class ZioEntry implements Cloneable {
|
||||
int year = d.getYear() + 1900;
|
||||
if (year < 1980) {
|
||||
dtime = (1 << 21) | (1 << 16);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dtime = (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
|
||||
d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
|
||||
d.getSeconds() >> 1;
|
||||
@ -560,7 +557,9 @@ public class ZioEntry implements Cloneable {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
/** Use 0 (STORED), or 8 (DEFLATE). */
|
||||
/**
|
||||
* Use 0 (STORED), or 8 (DEFLATE).
|
||||
*/
|
||||
public void setCompression(int compression) {
|
||||
this.compression = (short) compression;
|
||||
}
|
||||
|
@ -13,18 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.zipio;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
|
||||
/** Input stream used to read just the data from a zip file entry. */
|
||||
/**
|
||||
* Input stream used to read just the data from a zip file entry.
|
||||
*/
|
||||
public class ZioEntryInputStream extends InputStream {
|
||||
|
||||
RandomAccessFile raf;
|
||||
@ -46,8 +49,7 @@ public class ZioEntryInputStream extends InputStream {
|
||||
if (dpos >= 0) {
|
||||
if (debug) log.debug(String.format("Seeking to %d", entry.getDataPosition()));
|
||||
raf.seek(entry.getDataPosition());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// seeks to, then reads, the local header, causing the
|
||||
// file pointer to be positioned at the start of the data.
|
||||
entry.readLocalHeader();
|
||||
@ -87,16 +89,14 @@ public class ZioEntryInputStream extends InputStream {
|
||||
if (returnDummyByte) {
|
||||
returnDummyByte = false;
|
||||
return 0;
|
||||
}
|
||||
else return -1;
|
||||
} else return -1;
|
||||
}
|
||||
int b = raf.read();
|
||||
if (b >= 0) {
|
||||
if (monitor != null) monitor.write(b);
|
||||
if (debug) log.debug("Read 1 byte");
|
||||
offset += 1;
|
||||
}
|
||||
else if (debug) log.debug("Read 0 bytes");
|
||||
} else if (debug) log.debug("Read 0 bytes");
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -111,8 +111,7 @@ public class ZioEntryInputStream extends InputStream {
|
||||
returnDummyByte = false;
|
||||
b[off] = 0;
|
||||
return 1;
|
||||
}
|
||||
else return -1;
|
||||
} else return -1;
|
||||
}
|
||||
int numToRead = Math.min(len, available());
|
||||
int numRead = raf.read(b, off, numToRead);
|
||||
|
@ -13,9 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.zipio;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.CRC32;
|
||||
@ -29,8 +29,7 @@ public class ZioEntryOutputStream extends OutputStream {
|
||||
OutputStream wrapped;
|
||||
OutputStream downstream;
|
||||
|
||||
public ZioEntryOutputStream( int compression, OutputStream wrapped)
|
||||
{
|
||||
public ZioEntryOutputStream(int compression, OutputStream wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
if (compression != 0)
|
||||
downstream = new DeflaterOutputStream(wrapped, new Deflater(Deflater.BEST_COMPRESSION, true));
|
||||
@ -73,8 +72,7 @@ public class ZioEntryOutputStream extends OutputStream {
|
||||
return size;
|
||||
}
|
||||
|
||||
public OutputStream getWrappedStream()
|
||||
{
|
||||
public OutputStream getWrappedStream() {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
|
@ -13,16 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.zipio;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -31,15 +32,10 @@ import java.util.jar.Manifest;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ZipInput implements Closeable
|
||||
{
|
||||
public class ZipInput implements Closeable {
|
||||
static LoggerInterface log;
|
||||
|
||||
public String inputFilename;
|
||||
@ -51,8 +47,7 @@ public class ZipInput implements Closeable
|
||||
CentralEnd centralEnd;
|
||||
Manifest manifest;
|
||||
|
||||
public ZipInput( String filename) throws IOException
|
||||
{
|
||||
public ZipInput(String filename) throws IOException {
|
||||
this.inputFilename = filename;
|
||||
in = new RandomAccessFile(new File(inputFilename), "r");
|
||||
fileLength = in.length();
|
||||
@ -86,12 +81,12 @@ public class ZipInput implements Closeable
|
||||
return zioEntries;
|
||||
}
|
||||
|
||||
/** Returns the names of immediate children in the directory with the given name.
|
||||
/**
|
||||
* Returns the names of immediate children in the directory with the given name.
|
||||
* The path value must end with a "/" character. Use a value of "/"
|
||||
* to get the root entries.
|
||||
*/
|
||||
public Collection<String> list(String path)
|
||||
{
|
||||
public Collection<String> list(String path) {
|
||||
if (!path.endsWith("/")) throw new IllegalArgumentException("Invalid path -- does not end with '/'");
|
||||
|
||||
if (path.startsWith("/")) path = path.substring(1);
|
||||
@ -117,12 +112,14 @@ public class ZipInput implements Closeable
|
||||
return manifest;
|
||||
}
|
||||
|
||||
/** Scan the end of the file for the end of central directory record (EOCDR).
|
||||
Returns the file offset of the EOCD signature. The size parameter is an
|
||||
initial buffer size (e.g., 256).
|
||||
/**
|
||||
* Scan the end of the file for the end of central directory record (EOCDR).
|
||||
* Returns the file offset of the EOCD signature. The size parameter is an
|
||||
* initial buffer size (e.g., 256).
|
||||
*/
|
||||
public long scanForEOCDR(int size) throws IOException {
|
||||
if (size > fileLength || size > 65536) throw new IllegalStateException( "End of central directory not found in " + inputFilename);
|
||||
if (size > fileLength || size > 65536)
|
||||
throw new IllegalStateException("End of central directory not found in " + inputFilename);
|
||||
|
||||
int scanSize = (int) Math.min(fileLength, size);
|
||||
|
||||
@ -143,8 +140,7 @@ public class ZipInput implements Closeable
|
||||
}
|
||||
|
||||
|
||||
private void doRead()
|
||||
{
|
||||
private void doRead() {
|
||||
try {
|
||||
|
||||
long posEOCDR = scanForEOCDR(256);
|
||||
@ -168,15 +164,17 @@ public class ZipInput implements Closeable
|
||||
if (debug) ZipListingHelper.listEntry(getLogger(), entry);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Throwable t) {
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (in != null) try { in.close(); } catch( Throwable t) {}
|
||||
if (in != null) try {
|
||||
in.close();
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
public long getFilePointer() throws IOException {
|
||||
|
@ -13,31 +13,29 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.zipio;
|
||||
|
||||
import java.util.Date;
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ZipListingHelper
|
||||
{
|
||||
public class ZipListingHelper {
|
||||
|
||||
static DateFormat dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm");
|
||||
|
||||
public static void listHeader(LoggerInterface log)
|
||||
{
|
||||
public static void listHeader(LoggerInterface log) {
|
||||
log.debug(" Length Method Size Ratio Date Time CRC-32 Name");
|
||||
log.debug("-------- ------ ------- ----- ---- ---- ------ ----");
|
||||
|
||||
}
|
||||
|
||||
public static void listEntry(LoggerInterface log, ZioEntry entry)
|
||||
{
|
||||
public static void listEntry(LoggerInterface log, ZioEntry entry) {
|
||||
int ratio = 0;
|
||||
if (entry.getSize() > 0) ratio = (100 * (entry.getSize() - entry.getCompressedSize())) / entry.getSize();
|
||||
log.debug(String.format("%8d %6s %8d %4d%% %s %08x %s",
|
||||
|
@ -13,24 +13,25 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kellinwood.zipio;
|
||||
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import kellinwood.logging.LoggerInterface;
|
||||
import kellinwood.logging.LoggerManager;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ZipOutput
|
||||
{
|
||||
public class ZipOutput {
|
||||
|
||||
static LoggerInterface log;
|
||||
|
||||
@ -41,30 +42,26 @@ public class ZipOutput
|
||||
List<ZioEntry> entriesWritten = new LinkedList<ZioEntry>();
|
||||
Set<String> namesWritten = new HashSet<String>();
|
||||
|
||||
public ZipOutput( String filename) throws IOException
|
||||
{
|
||||
public ZipOutput(String filename) throws IOException {
|
||||
this.outputFilename = filename;
|
||||
File ofile = new File(outputFilename);
|
||||
init(ofile);
|
||||
}
|
||||
|
||||
public ZipOutput( File outputFile) throws IOException
|
||||
{
|
||||
public ZipOutput(File outputFile) throws IOException {
|
||||
this.outputFilename = outputFile.getAbsolutePath();
|
||||
File ofile = outputFile;
|
||||
init(ofile);
|
||||
}
|
||||
|
||||
private void init( File ofile) throws IOException
|
||||
{
|
||||
private void init(File ofile) throws IOException {
|
||||
if (ofile.exists()) ofile.delete();
|
||||
out = new FileOutputStream(ofile);
|
||||
if (getLogger().isDebugEnabled()) ZipListingHelper.listHeader(getLogger());
|
||||
|
||||
}
|
||||
|
||||
public ZipOutput( OutputStream os) throws IOException
|
||||
{
|
||||
public ZipOutput(OutputStream os) throws IOException {
|
||||
out = os;
|
||||
}
|
||||
|
||||
@ -87,9 +84,7 @@ public class ZipOutput
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
public void close() throws IOException {
|
||||
CentralEnd centralEnd = new CentralEnd();
|
||||
|
||||
centralEnd.centralStartOffset = (int) getFilePointer();
|
||||
@ -104,7 +99,10 @@ public class ZipOutput
|
||||
|
||||
centralEnd.write(this);
|
||||
|
||||
if (out != null) try { out.close(); } catch( Throwable t) {}
|
||||
if (out != null) try {
|
||||
out.close();
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
public int getFilePointer() throws IOException {
|
||||
|
Loading…
x
Reference in New Issue
Block a user