reformat all zipsigner code with Android Studio Ctrl-Alt-L

This commit is contained in:
Hans-Christoph Steiner 2018-04-19 16:18:24 +02:00
parent a3d9850a42
commit 4e4dd2385b
37 changed files with 1339 additions and 1385 deletions

View File

@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.logging; package kellinwood.logging;
import java.io.PrintStream;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
public abstract class AbstractLogger implements LoggerInterface public abstract class AbstractLogger implements LoggerInterface {
{
protected String category; protected String category;
@ -91,6 +90,4 @@ public abstract class AbstractLogger implements LoggerInterface
public boolean isWarningEnabled() { public boolean isWarningEnabled() {
return true; return true;
} }
} }

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.logging; package kellinwood.logging;
public class ConsoleLoggerFactory implements LoggerFactory { public class ConsoleLoggerFactory implements LoggerFactory {

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.logging; package kellinwood.logging;
public interface LoggerFactory { public interface LoggerFactory {

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.logging; package kellinwood.logging;
public interface LoggerInterface { public interface LoggerInterface {
@ -23,20 +24,28 @@ public interface LoggerInterface {
public static final String DEBUG = "DEBUG"; public static final String DEBUG = "DEBUG";
public boolean isErrorEnabled(); public boolean isErrorEnabled();
public void error(String message); public void error(String message);
public void error(String message, Throwable t); public void error(String message, Throwable t);
public boolean isWarningEnabled(); public boolean isWarningEnabled();
public void warning(String message); public void warning(String message);
public void warning(String message, Throwable t); public void warning(String message, Throwable t);
public boolean isInfoEnabled(); public boolean isInfoEnabled();
public void info(String message); public void info(String message);
public void info(String message, Throwable t); public void info(String message, Throwable t);
public boolean isDebugEnabled(); public boolean isDebugEnabled();
public void debug(String message); public void debug(String message);
public void debug(String message, Throwable t); public void debug(String message, Throwable t);

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.logging; package kellinwood.logging;
import java.util.Map; import java.util.Map;

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.logging; package kellinwood.logging;
public class NullLoggerFactory implements LoggerFactory { public class NullLoggerFactory implements LoggerFactory {

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.logging; package kellinwood.logging;
import java.io.PrintStream; import java.io.PrintStream;
@ -21,8 +22,7 @@ public class StreamLogger extends AbstractLogger {
PrintStream out; PrintStream out;
public StreamLogger( String category, PrintStream out) public StreamLogger(String category, PrintStream out) {
{
super(category); super(category);
this.out = out; this.out = out;
} }

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
public class AutoKeyException extends RuntimeException { public class AutoKeyException extends RuntimeException {

View File

@ -15,15 +15,16 @@
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
/* /*
* This class provides Base64 encoding services using one of several possible * This class provides Base64 encoding services using one of several possible
* implementations available elsewhere in the classpath. Supported implementations * implementations available elsewhere in the classpath. Supported implementations
@ -63,8 +64,8 @@ public class Base64 {
aEncodeMethod = clazz.getMethod("encode", byte[].class, Integer.TYPE); aEncodeMethod = clazz.getMethod("encode", byte[].class, Integer.TYPE);
aDecodeMethod = clazz.getMethod("decode", byte[].class, Integer.TYPE); aDecodeMethod = clazz.getMethod("decode", byte[].class, Integer.TYPE);
logger.info(clazz.getName() + " is available."); logger.info(clazz.getName() + " is available.");
} } catch (ClassNotFoundException x) {
catch (ClassNotFoundException x) {} // Ignore } // Ignore
catch (Exception x) { catch (Exception x) {
logger.error("Failed to initialize use of android.util.Base64", 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) // Looking for decode( byte[] input, int offset, int length, OutputStream output)
bDecodeMethod = clazz.getMethod("decode", byte[].class, Integer.TYPE, Integer.TYPE, OutputStream.class); bDecodeMethod = clazz.getMethod("decode", byte[].class, Integer.TYPE, Integer.TYPE, OutputStream.class);
} } catch (ClassNotFoundException x) {
catch (ClassNotFoundException x) {} // Ignore } // Ignore
catch (Exception x) { catch (Exception x) {
logger.error("Failed to initialize use of org.bouncycastle.util.encoders.Base64Encoder", 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 // Invoking a static method call, using null for the instance value
byte[] encodedBytes = (byte[]) aEncodeMethod.invoke(null, data, 2); byte[] encodedBytes = (byte[]) aEncodeMethod.invoke(null, data, 2);
return new String(encodedBytes); return new String(encodedBytes);
} } else if (bEncodeMethod != null) {
else if (bEncodeMethod != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
bEncodeMethod.invoke(bEncoder, data, 0, data.length, baos); bEncodeMethod.invoke(bEncoder, data, 0, data.length, baos);
return new String(baos.toByteArray()); return new String(baos.toByteArray());
} }
} } catch (Exception x) {
catch (Exception x) {
throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage()); 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 // Invoking a static method call, using null for the instance value
byte[] decodedBytes = (byte[]) aDecodeMethod.invoke(null, data, 2); byte[] decodedBytes = (byte[]) aDecodeMethod.invoke(null, data, 2);
return decodedBytes; return decodedBytes;
} } else if (bDecodeMethod != null) {
else if (bDecodeMethod != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
bDecodeMethod.invoke(bEncoder, data, 0, data.length, baos); bDecodeMethod.invoke(bEncoder, data, 0, data.length, baos);
return baos.toByteArray(); return baos.toByteArray();
} }
} } catch (Exception x) {
catch (Exception x) {
throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage()); throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage());
} }

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
/** /**

View File

@ -15,16 +15,17 @@
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
import java.io.IOException;
import java.io.ByteArrayOutputStream; 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. * section (16 bytes per row) and right-column printable character dislpay.
*/ */
public class HexDumpEncoder public class HexDumpEncoder {
{
static HexEncoder encoder = new HexEncoder(); static HexEncoder encoder = new HexEncoder();
@ -64,8 +65,7 @@ public class HexDumpEncoder
} }
return hexDumpOut.toString(); return hexDumpOut.toString();
} } catch (IOException x) {
catch (IOException x) {
throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage()); throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage());
} }
} }

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner; 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.IOException;
import java.io.OutputStream; import java.io.OutputStream;
public class HexEncoder public class HexEncoder {
{
protected final byte[] encodingTable = protected final byte[] encodingTable =
{ {
(byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (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 final byte[] decodingTable = new byte[128];
protected void initialiseDecodingTable() protected void initialiseDecodingTable() {
{ for (int i = 0; i < encodingTable.length; i++) {
for (int i = 0; i < encodingTable.length; i++)
{
decodingTable[encodingTable[i]] = (byte) i; decodingTable[encodingTable[i]] = (byte) i;
} }
@ -60,8 +58,7 @@ public class HexEncoder
decodingTable['F'] = decodingTable['f']; decodingTable['F'] = decodingTable['f'];
} }
public HexEncoder() public HexEncoder() {
{
initialiseDecodingTable(); initialiseDecodingTable();
} }
@ -75,10 +72,8 @@ public class HexEncoder
int off, int off,
int length, int length,
OutputStream out) OutputStream out)
throws IOException throws IOException {
{ for (int i = off; i < (off + length); i++) {
for (int i = off; i < (off + length); i++)
{
int v = data[i] & 0xff; int v = data[i] & 0xff;
out.write(encodingTable[(v >>> 4)]); out.write(encodingTable[(v >>> 4)]);
@ -89,8 +84,7 @@ public class HexEncoder
} }
private boolean ignore( private boolean ignore(
char c) char c) {
{
return (c == '\n' || c == '\r' || c == '\t' || c == ' '); return (c == '\n' || c == '\r' || c == '\t' || c == ' ');
} }
@ -105,17 +99,14 @@ public class HexEncoder
int off, int off,
int length, int length,
OutputStream out) OutputStream out)
throws IOException throws IOException {
{
byte b1, b2; byte b1, b2;
int outLen = 0; int outLen = 0;
int end = off + length; int end = off + length;
while (end > off) while (end > off) {
{ if (!ignore((char) data[end - 1])) {
if (!ignore((char)data[end - 1]))
{
break; break;
} }
@ -123,17 +114,14 @@ public class HexEncoder
} }
int i = off; int i = off;
while (i < end) while (i < end) {
{ while (i < end && ignore((char) data[i])) {
while (i < end && ignore((char)data[i]))
{
i++; i++;
} }
b1 = decodingTable[data[i++]]; b1 = decodingTable[data[i++]];
while (i < end && ignore((char)data[i])) while (i < end && ignore((char) data[i])) {
{
i++; i++;
} }
@ -156,17 +144,14 @@ public class HexEncoder
public int decode( public int decode(
String data, String data,
OutputStream out) OutputStream out)
throws IOException throws IOException {
{
byte b1, b2; byte b1, b2;
int length = 0; int length = 0;
int end = data.length(); int end = data.length();
while (end > 0) while (end > 0) {
{ if (!ignore(data.charAt(end - 1))) {
if (!ignore(data.charAt(end - 1)))
{
break; break;
} }
@ -174,17 +159,14 @@ public class HexEncoder
} }
int i = 0; int i = 0;
while (i < end) while (i < end) {
{ while (i < end && ignore(data.charAt(i))) {
while (i < end && ignore(data.charAt(i)))
{
i++; i++;
} }
b1 = decodingTable[data.charAt(i++)]; b1 = decodingTable[data.charAt(i++)];
while (i < end && ignore(data.charAt(i))) while (i < end && ignore(data.charAt(i))) {
{
i++; i++;
} }

View File

@ -1,5 +1,3 @@
/* /*
* Copyright (C) 2010 Ken Ellinwood * Copyright (C) 2010 Ken Ellinwood
* *
@ -15,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
import java.security.PrivateKey; import java.security.PrivateKey;
@ -38,16 +37,14 @@ public class KeySet {
public 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.name = name;
this.publicKey = publicKey; this.publicKey = publicKey;
this.privateKey = privateKey; this.privateKey = privateKey;
this.sigBlockTemplate = sigBlockTemplate; 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.name = name;
this.publicKey = publicKey; this.publicKey = publicKey;
this.privateKey = privateKey; this.privateKey = privateKey;

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
public class ProgressEvent { public class ProgressEvent {
@ -27,18 +28,23 @@ public class ProgressEvent {
public String getMessage() { public String getMessage() {
return message; return message;
} }
public void setMessage(String message) { public void setMessage(String message) {
this.message = message; this.message = message;
} }
public int getPercentDone() { public int getPercentDone() {
return percentDone; return percentDone;
} }
public void setPercentDone(int percentDone) { public void setPercentDone(int percentDone) {
this.percentDone = percentDone; this.percentDone = percentDone;
} }
public int getPriority() { public int getPriority() {
return priority; return priority;
} }
public void setPriority(int priority) { public void setPriority(int priority) {
this.priority = priority; this.priority = priority;
} }

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
import java.util.ArrayList; import java.util.ArrayList;
@ -23,8 +24,7 @@ public class ProgressHelper {
private int progressCurrentItem = 0; private int progressCurrentItem = 0;
private ProgressEvent progressEvent = new ProgressEvent(); private ProgressEvent progressEvent = new ProgressEvent();
public void initProgress() public void initProgress() {
{
progressTotalItems = 10000; progressTotalItems = 10000;
progressCurrentItem = 0; progressCurrentItem = 0;
} }
@ -65,16 +65,14 @@ public class ProgressHelper {
private ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>(); private ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public synchronized void addProgressListener( ProgressListener l) public synchronized void addProgressListener(ProgressListener l) {
{
ArrayList<ProgressListener> list = (ArrayList<ProgressListener>) listeners.clone(); ArrayList<ProgressListener> list = (ArrayList<ProgressListener>) listeners.clone();
list.add(l); list.add(l);
listeners = list; listeners = list;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public synchronized void removeProgressListener( ProgressListener l) public synchronized void removeProgressListener(ProgressListener l) {
{
ArrayList<ProgressListener> list = (ArrayList<ProgressListener>) listeners.clone(); ArrayList<ProgressListener> list = (ArrayList<ProgressListener>) listeners.clone();
list.remove(l); list.remove(l);
listeners = list; listeners = list;

View File

@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
public interface ProgressListener { 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); public void onProgress(ProgressEvent event);
} }

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
/** /**
@ -14,7 +15,9 @@ public interface ResourceAdapter {
GENERATING_SIGNATURE_FILE, GENERATING_SIGNATURE_FILE,
GENERATING_SIGNATURE_BLOCK, GENERATING_SIGNATURE_BLOCK,
COPYING_ZIP_ENTRY COPYING_ZIP_ENTRY
}; }
;
public String getString(Item item, Object... args); public String getString(Item item, Object... args);
} }

View File

@ -13,18 +13,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.io.IOException; import java.io.IOException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.PrivateKey; import java.security.PrivateKey;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
@SuppressWarnings("restriction") @SuppressWarnings("restriction")
public class ZipSignature { public class ZipSignature {
@ -41,14 +41,12 @@ public class ZipSignature {
MessageDigest md; MessageDigest md;
public ZipSignature() throws IOException, GeneralSecurityException public ZipSignature() throws IOException, GeneralSecurityException {
{
md = MessageDigest.getInstance("SHA1"); md = MessageDigest.getInstance("SHA1");
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 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); cipher.init(Cipher.ENCRYPT_MODE, privateKey);
} }
@ -60,8 +58,7 @@ public class ZipSignature {
md.update(data, offset, count); md.update(data, offset, count);
} }
public byte[] sign() throws BadPaddingException, IllegalBlockSizeException public byte[] sign() throws BadPaddingException, IllegalBlockSizeException {
{
cipher.update(beforeAlgorithmIdBytes); cipher.update(beforeAlgorithmIdBytes);
cipher.update(algorithmIdBytes); cipher.update(algorithmIdBytes);
cipher.update(afterAlgorithmIdBytes); cipher.update(afterAlgorithmIdBytes);

View File

@ -26,6 +26,7 @@
* using signature block template files. * using signature block template files.
*/ */
package kellinwood.security.zipsigner; package kellinwood.security.zipsigner;
import kellinwood.logging.LoggerInterface; import kellinwood.logging.LoggerInterface;
@ -38,17 +39,40 @@ import javax.crypto.Cipher;
import javax.crypto.EncryptedPrivateKeyInfo; import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec; 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.lang.reflect.Method;
import java.net.URL; 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.Certificate;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec; import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec; 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.Attributes;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.jar.Manifest; 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 * 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 * API to sign JAR files (including APKs and Zip/OTA updates) in
* a way compatible with the mincrypt verifier, using SHA1 and RSA keys. * 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. * 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; private boolean canceled = false;
@ -102,8 +125,7 @@ public class ZipSigner
AutoKeyObservable autoKeyObservable = new AutoKeyObservable(); 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 // 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("aa9852bc5a53272ac8031d49b65e4b0e", "media");
autoKeyDetect.put("e60418c4b638f20d0721e115674ca11f", "platform"); autoKeyDetect.put("e60418c4b638f20d0721e115674ca11f", "platform");
@ -129,14 +151,12 @@ public class ZipSigner
return keymode; 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); if (getLogger().isDebugEnabled()) getLogger().debug("setKeymode: " + km);
keymode = km; keymode = km;
if (keymode.startsWith(MODE_AUTO)) { if (keymode.startsWith(MODE_AUTO)) {
keySet = null; keySet = null;
} } else {
else {
progressHelper.initProgress(); progressHelper.initProgress();
loadKeys(keymode); loadKeys(keymode);
} }
@ -148,8 +168,7 @@ public class ZipSigner
protected String autoDetectKey(String mode, Map<String, ZioEntry> zioEntries) protected String autoDetectKey(String mode, Map<String, ZioEntry> zioEntries)
throws NoSuchAlgorithmException, IOException throws NoSuchAlgorithmException, IOException {
{
boolean debug = getLogger().isDebugEnabled(); boolean debug = getLogger().isDebugEnabled();
if (!mode.startsWith(MODE_AUTO)) return mode; if (!mode.startsWith(MODE_AUTO)) return mode;
@ -197,8 +216,7 @@ public class ZipSigner
if (debug) getLogger().debug("Falling back to key=" + keyName); if (debug) getLogger().debug("Falling back to key=" + keyName);
return KEY_TESTKEY; 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. // 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); if (debug) getLogger().debug("Unable to determine key, returning: " + KEY_NONE);
return KEY_NONE; return KEY_NONE;
@ -213,8 +231,7 @@ public class ZipSigner
// Loads one of the built-in keys (media, platform, shared, testkey) // Loads one of the built-in keys (media, platform, shared, testkey)
public void loadKeys(String name) public void loadKeys(String name)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
keySet = loadedKeys.get(name); keySet = loadedKeys.get(name);
if (keySet != null) return; 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); 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); keySet = new KeySet(name, publicKey, privateKey, signatureAlgorithm, signatureBlockTemplate);
} }
@ -272,8 +287,7 @@ public class ZipSigner
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void loadProvider(String providerClassName) public void loadProvider(String providerClassName)
throws ClassNotFoundException, IllegalAccessException, InstantiationException throws ClassNotFoundException, IllegalAccessException, InstantiationException {
{
Class providerClass = Class.forName(providerClassName); Class providerClass = Class.forName(providerClassName);
Provider provider = (Provider) providerClass.newInstance(); Provider provider = (Provider) providerClass.newInstance();
Security.insertProviderAt(provider, 1); Security.insertProviderAt(provider, 1);
@ -293,7 +307,7 @@ public class ZipSigner
/** /**
* Decrypt an encrypted PKCS 8 format private key. * Decrypt an encrypted PKCS 8 format private key.
* * <p>
* Based on ghstark's post on Aug 6, 2006 at * Based on ghstark's post on Aug 6, 2006 at
* http://forums.sun.com/thread.jspa?threadID=758133&messageID=4330949 * 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()); 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(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[2048]; byte[] buffer = new byte[2048];
@ -349,7 +365,9 @@ public class ZipSigner
return bytes; return bytes;
} }
/** Read a PKCS 8 format private key. */ /**
* Read a PKCS 8 format private key.
*/
public PrivateKey readPrivateKey(URL privateKeyUrl, String keyPassword) public PrivateKey readPrivateKey(URL privateKeyUrl, String keyPassword)
throws IOException, GeneralSecurityException { throws IOException, GeneralSecurityException {
DataInputStream input = new DataInputStream(privateKeyUrl.openStream()); 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) private Manifest addDigestsToManifest(Map<String, ZioEntry> entries)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
Manifest input = null; Manifest input = null;
ZioEntry manifestEntry = entries.get(JarFile.MANIFEST_NAME); ZioEntry manifestEntry = entries.get(JarFile.MANIFEST_NAME);
if (manifestEntry != null) { if (manifestEntry != null) {
@ -411,8 +430,7 @@ public class ZipSigner
if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) && if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
!name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) && !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
(stripPattern == null || (stripPattern == null ||
!stripPattern.matcher(name).matches())) !stripPattern.matcher(name).matches())) {
{
progressHelper.progress(ProgressEvent.PRORITY_NORMAL, resourceAdapter.getString(ResourceAdapter.Item.GENERATING_MANIFEST)); progressHelper.progress(ProgressEvent.PRORITY_NORMAL, resourceAdapter.getString(ResourceAdapter.Item.GENERATING_MANIFEST));
InputStream data = entry.getInputStream(); 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) private void generateSignatureFile(Manifest manifest, OutputStream out)
throws IOException, GeneralSecurityException { throws IOException, GeneralSecurityException {
out.write(("Signature-Version: 1.0\r\n").getBytes()); 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") @SuppressWarnings("unchecked")
private void writeSignatureBlock(KeySet keySet, byte[] signatureFileBytes, OutputStream out) private void writeSignatureBlock(KeySet keySet, byte[] signatureFileBytes, OutputStream out)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
if (keySet.getSigBlockTemplate() != null) { if (keySet.getSigBlockTemplate() != null) {
// Can't use default Signature on Android. Although it generates a signature that can be verified by jarsigner, // 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); byte[] tmpData = cipher.doFinal(signatureBytes);
getLogger().debug("Signature Decrypted: \n" + HexDumpEncoder.encode(tmpData)); getLogger().debug("Signature Decrypted: \n" + HexDumpEncoder.encode(tmpData));
} }
} } else {
else {
try { try {
byte[] sigBlock = null; byte[] sigBlock = null;
// Use reflection to call the optional generator. // Use reflection to call the optional generator.
@ -528,8 +548,7 @@ public class ZipSigner
* more efficient. * more efficient.
*/ */
private void copyFiles(Manifest manifest, Map<String, ZioEntry> input, ZipOutput output, long timestamp) private void copyFiles(Manifest manifest, Map<String, ZioEntry> input, ZipOutput output, long timestamp)
throws IOException throws IOException {
{
Map<String, Attributes> entries = manifest.getEntries(); Map<String, Attributes> entries = manifest.getEntries();
List<String> names = new ArrayList<String>(entries.keySet()); List<String> names = new ArrayList<String>(entries.keySet());
Collections.sort(names); Collections.sort(names);
@ -549,8 +568,7 @@ public class ZipSigner
* Copy all the files from input to output. * Copy all the files from input to output.
*/ */
private void copyFiles(Map<String, ZioEntry> input, ZipOutput output) private void copyFiles(Map<String, ZioEntry> input, ZipOutput output)
throws IOException throws IOException {
{
int i = 1; int i = 1;
for (ZioEntry inEntry : input.values()) { for (ZioEntry inEntry : input.values()) {
if (canceled) break; if (canceled) break;
@ -571,8 +589,7 @@ public class ZipSigner
String inputZipFilename, String inputZipFilename,
String outputZipFilename) String outputZipFilename)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, throws ClassNotFoundException, IllegalAccessException, InstantiationException,
IOException, GeneralSecurityException IOException, GeneralSecurityException {
{
signZip(keystoreURL, keystoreType, keystorePw.toCharArray(), certAlias, certPw.toCharArray(), "SHA1withRSA", inputZipFilename, outputZipFilename); signZip(keystoreURL, keystoreType, keystorePw.toCharArray(), certAlias, certPw.toCharArray(), "SHA1withRSA", inputZipFilename, outputZipFilename);
} }
@ -585,8 +602,7 @@ public class ZipSigner
String inputZipFilename, String inputZipFilename,
String outputZipFilename) String outputZipFilename)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, throws ClassNotFoundException, IllegalAccessException, InstantiationException,
IOException, GeneralSecurityException IOException, GeneralSecurityException {
{
InputStream keystoreStream = null; InputStream keystoreStream = null;
@ -605,34 +621,31 @@ public class ZipSigner
setKeys("custom", publicKey, privateKey, signatureAlgorithm, null); setKeys("custom", publicKey, privateKey, signatureAlgorithm, null);
signZip(inputZipFilename, outputZipFilename); signZip(inputZipFilename, outputZipFilename);
} } finally {
finally {
if (keystoreStream != null) keystoreStream.close(); 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. * Save result to output file.
*/ */
public void signZip(Map<String, ZioEntry> zioEntries, String outputZipFilename) public void signZip(Map<String, ZioEntry> zioEntries, String outputZipFilename)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
progressHelper.initProgress(); progressHelper.initProgress();
signZip(zioEntries, new FileOutputStream(outputZipFilename), outputZipFilename); 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 * and signature block template. The signature block template
* parameter may be null, but if so * parameter may be null, but if so
* android-sun-jarsign-support.jar must be in the classpath. * android-sun-jarsign-support.jar must be in the classpath.
*/ */
public void signZip(String inputZipFilename, String outputZipFilename) public void signZip(String inputZipFilename, String outputZipFilename)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
File inFile = new File(inputZipFilename).getCanonicalFile(); File inFile = new File(inputZipFilename).getCanonicalFile();
File outFile = new File(outputZipFilename).getCanonicalFile(); File outFile = new File(outputZipFilename).getCanonicalFile();
@ -649,21 +662,20 @@ public class ZipSigner
input = ZipInput.read(inputZipFilename); input = ZipInput.read(inputZipFilename);
outStream = new FileOutputStream(outputZipFilename); outStream = new FileOutputStream(outputZipFilename);
signZip(input.getEntries(), outStream, outputZipFilename); signZip(input.getEntries(), outStream, outputZipFilename);
} } finally {
finally {
if (input != null) input.close(); if (input != null) input.close();
if (outStream != null) outStream.close(); if (outStream != null) outStream.close();
} }
} }
/** Sign the /**
* Sign the
* and signature block template. The signature block template * and signature block template. The signature block template
* parameter may be null, but if so * parameter may be null, but if so
* android-sun-jarsign-support.jar must be in the classpath. * android-sun-jarsign-support.jar must be in the classpath.
*/ */
public void signZip(Map<String, ZioEntry> zioEntries, OutputStream outputStream, String outputZipFilename) public void signZip(Map<String, ZioEntry> zioEntries, OutputStream outputStream, String outputZipFilename)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
boolean debug = getLogger().isDebugEnabled(); boolean debug = getLogger().isDebugEnabled();
progressHelper.initProgress(); progressHelper.initProgress();
@ -683,7 +695,6 @@ public class ZipSigner
} }
ZipOutput zipOutput = null; ZipOutput zipOutput = null;
try { try {
@ -705,8 +716,7 @@ public class ZipSigner
if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) && if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
!name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) && !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
(stripPattern == null || (stripPattern == null ||
!stripPattern.matcher(name).matches())) !stripPattern.matcher(name).matches())) {
{
progressTotalItems += 3; // digest for manifest, digest in sig file, copy data progressTotalItems += 3; // digest for manifest, digest in sig file, copy data
} }
} }
@ -754,33 +764,28 @@ public class ZipSigner
copyFiles(manifest, zioEntries, zipOutput, timestamp); copyFiles(manifest, zioEntries, zipOutput, timestamp);
if (canceled) return; if (canceled) return;
} } finally {
finally {
if (zipOutput != null) zipOutput.close(); if (zipOutput != null) zipOutput.close();
if (canceled) { if (canceled) {
try { try {
if (outputZipFilename != null) new File(outputZipFilename).delete(); if (outputZipFilename != null) new File(outputZipFilename).delete();
} } catch (Throwable t) {
catch (Throwable t) {
getLogger().warning(t.getClass().getName() + ":" + t.getMessage()); getLogger().warning(t.getClass().getName() + ":" + t.getMessage());
} }
} }
} }
} }
public void addProgressListener( ProgressListener l) public void addProgressListener(ProgressListener l) {
{
progressHelper.addProgressListener(l); progressHelper.addProgressListener(l);
} }
public synchronized void removeProgressListener( ProgressListener l) public synchronized void removeProgressListener(ProgressListener l) {
{
progressHelper.removeProgressListener(l); progressHelper.removeProgressListener(l);
} }
public static class AutoKeyObservable extends Observable public static class AutoKeyObservable extends Observable {
{
@Override @Override
public void notifyObservers(Object arg) { public void notifyObservers(Object arg) {
super.setChanged(); super.setChanged();

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import kellinwood.security.zipsigner.KeySet; import kellinwood.security.zipsigner.KeySet;
@ -7,7 +8,10 @@ import org.bouncycastle.x509.X509V3CertificateGenerator;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; 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.security.cert.X509Certificate;
import java.util.Date; import java.util.Date;
@ -17,7 +21,8 @@ import java.util.Date;
*/ */
public class CertCreator { 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 * RSA 2048, with the cert signed using SHA1withRSA. The certificate will have a validity of
* 30 years). * 30 years).
* *
@ -27,8 +32,7 @@ public class CertCreator {
* @param distinguishedNameValues - contains Country, State, Locality,...,Common Name, etc. * @param distinguishedNameValues - contains Country, State, Locality,...,Common Name, etc.
*/ */
public static void createKeystoreAndKey(String storePath, char[] password, 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, createKeystoreAndKey(storePath, password, "RSA", 2048, keyName, password, "SHA1withRSA", 30,
distinguishedNameValues); 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, public static KeySet createKey(String storePath, char[] storePass,
String keyAlgorithm, int keySize, String keyName, char[] keyPass, 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, public static KeySet createKey(String keyAlgorithm, int keySize, String keyName,
String certSignatureAlgorithm, int certValidityYears, DistinguishedNameValues distinguishedNameValues) String certSignatureAlgorithm, int certValidityYears, DistinguishedNameValues distinguishedNameValues) {
{
try { try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
keyPairGenerator.initialize(keySize); keyPairGenerator.initialize(keySize);

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import kellinwood.security.zipsigner.ZipSigner; import kellinwood.security.zipsigner.ZipSigner;
@ -12,7 +13,9 @@ import java.security.cert.X509Certificate;
*/ */
public class CustomKeySigner { 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, public static void signZip(ZipSigner zipSigner,
String keystorePath, String keystorePath,
char[] keystorePw, char[] keystorePw,
@ -21,8 +24,7 @@ public class CustomKeySigner {
String signatureAlgorithm, String signatureAlgorithm,
String inputZipFilename, String inputZipFilename,
String outputZipFilename) String outputZipFilename)
throws Exception throws Exception {
{
zipSigner.issueLoadingCertAndKeysProgressEvent(); zipSigner.issueLoadingCertAndKeysProgressEvent();
KeyStore keystore = KeyStoreFileManager.loadKeyStore(keystorePath, keystorePw); KeyStore keystore = KeyStoreFileManager.loadKeyStore(keystorePath, keystorePw);
Certificate cert = keystore.getCertificate(certAlias); Certificate cert = keystore.getCertificate(certAlias);

View File

@ -1,10 +1,10 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.style.BCStyle; import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.jce.X509Principal; import org.bouncycastle.jce.X509Principal;
import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Vector; import java.util.Vector;

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import kellinwood.logging.LoggerInterface; import kellinwood.logging.LoggerInterface;

View File

@ -23,15 +23,17 @@ power to enforce restrictions on reverse-engineering of their software,
and it is irresponsible for them to claim they can. */ and it is irresponsible for them to claim they can. */
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.DigestInputStream; import java.security.DigestInputStream;
import java.security.DigestOutputStream; import java.security.DigestOutputStream;
import java.security.Key; import java.security.Key;
@ -42,29 +44,24 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.UnrecoverableKeyException; import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date; import java.util.Date;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Vector; import java.util.Vector;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.spec.SecretKeySpec;
/** /**
* This is an implementation of Sun's proprietary key store * This is an implementation of Sun's proprietary key store
* algorithm, called "JKS" for "Java Key Store". This implementation was * algorithm, called "JKS" for "Java Key Store". This implementation was
* created entirely through reverse-engineering. * created entirely through reverse-engineering.
* * <p>
* <p>The format of JKS files is, from the start of the file: * <p>The format of JKS files is, from the start of the file:
* * <p>
* <ol> * <ol>
* <li>Magic bytes. This is a four-byte integer, in big-endian byte * <li>Magic bytes. This is a four-byte integer, in big-endian byte
* order, equal to <code>0xFEEDFEED</code>.</li> * 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> * 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, * <li>An eight-byte integer, representing the entry's creation date,
* in milliseconds since the epoch. * in milliseconds since the epoch.
* * <p>
* <p>Then, if the entry is a private key entry: * <p>Then, if the entry is a private key entry:
* <ol> * <ol>
* <li>The size of the encoded key as a four-byte int, then that * <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 * certificates, encoded as described in the trusted certificates
* section.</li> * section.</li>
* </ol> * </ol>
* * <p>
* <p>Otherwise, the entry is a trusted certificate, which is encoded * <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 * 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 * way as alias names. Then, a four-byte integer representing the size
@ -108,12 +105,12 @@ import javax.crypto.spec.SecretKeySpec;
* </ol> * </ol>
* </li> * </li>
* </ol> * </ol>
* * <p>
* <p>(See <a href="genkey.java">this file</a> for some idea of how I * <p>(See <a href="genkey.java">this file</a> for some idea of how I
* was able to figure out these algorithms)</p> * was able to figure out these algorithms)</p>
* * <p>
* <p>Decrypting the key works as follows: * <p>Decrypting the key works as follows:
* * <p>
* <ol> * <ol>
* <li>The key length is the length of the ciphertext minus 40. The * <li>The key length is the length of the ciphertext minus 40. The
* encrypted key, <code>ekey</code>, is the middle bytes of 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, * the last 20 bytes of the ciphertext, output <code>FAIL</code>. Otherwise,
* output <code>key</code>.</li> * output <code>key</code>.</li>
* </ol> * </ol>
* * <p>
* <p>The signature is defined as <code>SHA-1(UTF-16BE(password) + * <p>The signature is defined as <code>SHA-1(UTF-16BE(password) +
* US_ASCII("Mighty Aphrodite") + encoded_keystore)</code> (yup, Sun * US_ASCII("Mighty Aphrodite") + encoded_keystore)</code> (yup, Sun
* engineers are just that clever). * engineers are just that clever).
* * <p>
* <p>(Above, SHA-1 denotes the secure hash algorithm, UTF-16BE the * <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 * big-endian byte representation of a UTF-16 string, and US_ASCII the
* ASCII byte representation of the string.) * ASCII byte representation of the string.)
* * <p>
* <p>The source code of this class should be available in the file <a * <p>The source code of this class should be available in the file <a
* href="http://metastatic.org/source/JKS.java">JKS.java</a>. * href="http://metastatic.org/source/JKS.java">JKS.java</a>.
* *
* @author Casey Marshall (rsdio@metastatic.org) * @author Casey Marshall (rsdio@metastatic.org)
* * <p>
* Changes by Ken Ellinwood: * Changes by Ken Ellinwood:
* ** Fixed a NullPointerException in engineLoad(). This method must return gracefully if the keystore input stream is null. * ** 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. * ** 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. * ** 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. * ** 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. // 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 MAGIC = 0xFEEDFEED;
private static final int PRIVATE_KEY = 1; private static final int PRIVATE_KEY = 1;
@ -170,8 +168,7 @@ public class JKS extends KeyStoreSpi
// Constructor. // Constructor.
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
public JKS() public JKS() {
{
super(); super();
aliases = new Vector(); aliases = new Vector();
trustedCerts = new HashMap(); trustedCerts = new HashMap();
@ -185,8 +182,7 @@ public class JKS extends KeyStoreSpi
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
public Key engineGetKey(String alias, char[] password) public Key engineGetKey(String alias, char[] password)
throws NoSuchAlgorithmException, UnrecoverableKeyException throws NoSuchAlgorithmException, UnrecoverableKeyException {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
if (!privateKeys.containsKey(alias)) if (!privateKeys.containsKey(alias))
@ -194,32 +190,25 @@ public class JKS extends KeyStoreSpi
byte[] key = decryptKey((byte[]) privateKeys.get(alias), byte[] key = decryptKey((byte[]) privateKeys.get(alias),
charsToBytes(password)); charsToBytes(password));
Certificate[] chain = engineGetCertificateChain(alias); Certificate[] chain = engineGetCertificateChain(alias);
if (chain.length > 0) if (chain.length > 0) {
{ try {
try
{
// Private and public keys MUST have the same algorithm. // Private and public keys MUST have the same algorithm.
KeyFactory fact = KeyFactory.getInstance( KeyFactory fact = KeyFactory.getInstance(
chain[0].getPublicKey().getAlgorithm()); chain[0].getPublicKey().getAlgorithm());
return fact.generatePrivate(new PKCS8EncodedKeySpec(key)); return fact.generatePrivate(new PKCS8EncodedKeySpec(key));
} } catch (InvalidKeySpecException x) {
catch (InvalidKeySpecException x)
{
throw new UnrecoverableKeyException(x.getMessage()); throw new UnrecoverableKeyException(x.getMessage());
} }
} } else
else
return new SecretKeySpec(key, alias); return new SecretKeySpec(key, alias);
} }
public Certificate[] engineGetCertificateChain(String alias) public Certificate[] engineGetCertificateChain(String alias) {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
return (Certificate[]) certChains.get(alias); return (Certificate[]) certChains.get(alias);
} }
public Certificate engineGetCertificate(String alias) public Certificate engineGetCertificate(String alias) {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
if (engineIsKeyEntry(alias)) { if (engineIsKeyEntry(alias)) {
Certificate[] certChain = (Certificate[]) certChains.get(alias); Certificate[] certChain = (Certificate[]) certChains.get(alias);
@ -228,8 +217,7 @@ public class JKS extends KeyStoreSpi
return (Certificate) trustedCerts.get(alias); return (Certificate) trustedCerts.get(alias);
} }
public Date engineGetCreationDate(String alias) public Date engineGetCreationDate(String alias) {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
return (Date) dates.get(alias); return (Date) dates.get(alias);
} }
@ -237,8 +225,7 @@ public class JKS extends KeyStoreSpi
// XXX implement writing methods. // XXX implement writing methods.
public void engineSetKeyEntry(String alias, Key key, char[] passwd, Certificate[] certChain) public void engineSetKeyEntry(String alias, Key key, char[] passwd, Certificate[] certChain)
throws KeyStoreException throws KeyStoreException {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
if (trustedCerts.containsKey(alias)) if (trustedCerts.containsKey(alias))
throw new KeyStoreException("\"" + alias + " is a trusted certificate entry"); throw new KeyStoreException("\"" + alias + " is a trusted certificate entry");
@ -247,25 +234,20 @@ public class JKS extends KeyStoreSpi
certChains.put(alias, certChain); certChains.put(alias, certChain);
else else
certChains.put(alias, new Certificate[0]); certChains.put(alias, new Certificate[0]);
if (!aliases.contains(alias)) if (!aliases.contains(alias)) {
{
dates.put(alias, new Date()); dates.put(alias, new Date());
aliases.add(alias); aliases.add(alias);
} }
} }
public void engineSetKeyEntry(String alias, byte[] encodedKey, Certificate[] certChain) public void engineSetKeyEntry(String alias, byte[] encodedKey, Certificate[] certChain)
throws KeyStoreException throws KeyStoreException {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
if (trustedCerts.containsKey(alias)) if (trustedCerts.containsKey(alias))
throw new KeyStoreException("\"" + alias + "\" is a trusted certificate entry"); throw new KeyStoreException("\"" + alias + "\" is a trusted certificate entry");
try try {
{
new EncryptedPrivateKeyInfo(encodedKey); new EncryptedPrivateKeyInfo(encodedKey);
} } catch (IOException ioe) {
catch (IOException ioe)
{
throw new KeyStoreException("encoded key is not an EncryptedPrivateKeyInfo"); throw new KeyStoreException("encoded key is not an EncryptedPrivateKeyInfo");
} }
privateKeys.put(alias, encodedKey); privateKeys.put(alias, encodedKey);
@ -273,67 +255,56 @@ public class JKS extends KeyStoreSpi
certChains.put(alias, certChain); certChains.put(alias, certChain);
else else
certChains.put(alias, new Certificate[0]); certChains.put(alias, new Certificate[0]);
if (!aliases.contains(alias)) if (!aliases.contains(alias)) {
{
dates.put(alias, new Date()); dates.put(alias, new Date());
aliases.add(alias); aliases.add(alias);
} }
} }
public void engineSetCertificateEntry(String alias, Certificate cert) public void engineSetCertificateEntry(String alias, Certificate cert)
throws KeyStoreException throws KeyStoreException {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
if (privateKeys.containsKey(alias)) if (privateKeys.containsKey(alias))
throw new KeyStoreException("\"" + alias + "\" is a private key entry"); throw new KeyStoreException("\"" + alias + "\" is a private key entry");
if (cert == null) if (cert == null)
throw new NullPointerException(); throw new NullPointerException();
trustedCerts.put(alias, cert); trustedCerts.put(alias, cert);
if (!aliases.contains(alias)) if (!aliases.contains(alias)) {
{
dates.put(alias, new Date()); dates.put(alias, new Date());
aliases.add(alias); aliases.add(alias);
} }
} }
public void engineDeleteEntry(String alias) throws KeyStoreException public void engineDeleteEntry(String alias) throws KeyStoreException {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
aliases.remove(alias); aliases.remove(alias);
} }
public Enumeration engineAliases() public Enumeration engineAliases() {
{
return aliases.elements(); return aliases.elements();
} }
public boolean engineContainsAlias(String alias) public boolean engineContainsAlias(String alias) {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
return aliases.contains(alias); return aliases.contains(alias);
} }
public int engineSize() public int engineSize() {
{
return aliases.size(); return aliases.size();
} }
public boolean engineIsKeyEntry(String alias) public boolean engineIsKeyEntry(String alias) {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
return privateKeys.containsKey(alias); return privateKeys.containsKey(alias);
} }
public boolean engineIsCertificateEntry(String alias) public boolean engineIsCertificateEntry(String alias) {
{
alias = alias.toLowerCase(); alias = alias.toLowerCase();
return trustedCerts.containsKey(alias); return trustedCerts.containsKey(alias);
} }
public String engineGetCertificateAlias(Certificate cert) public String engineGetCertificateAlias(Certificate cert) {
{ for (Iterator keys = trustedCerts.keySet().iterator(); keys.hasNext(); ) {
for (Iterator keys = trustedCerts.keySet().iterator(); keys.hasNext(); )
{
String alias = (String) keys.next(); String alias = (String) keys.next();
if (cert.equals(trustedCerts.get(alias))) if (cert.equals(trustedCerts.get(alias)))
return alias; return alias;
@ -342,8 +313,7 @@ public class JKS extends KeyStoreSpi
} }
public void engineStore(OutputStream out, char[] passwd) public void engineStore(OutputStream out, char[] passwd)
throws IOException, NoSuchAlgorithmException, CertificateException throws IOException, NoSuchAlgorithmException, CertificateException {
{
MessageDigest md = MessageDigest.getInstance("SHA1"); MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(charsToBytes(passwd)); md.update(charsToBytes(passwd));
md.update("Mighty Aphrodite".getBytes("UTF-8")); md.update("Mighty Aphrodite".getBytes("UTF-8"));
@ -351,18 +321,14 @@ public class JKS extends KeyStoreSpi
dout.writeInt(MAGIC); dout.writeInt(MAGIC);
dout.writeInt(2); dout.writeInt(2);
dout.writeInt(aliases.size()); dout.writeInt(aliases.size());
for (Enumeration e = aliases.elements(); e.hasMoreElements(); ) for (Enumeration e = aliases.elements(); e.hasMoreElements(); ) {
{
String alias = (String) e.nextElement(); String alias = (String) e.nextElement();
if (trustedCerts.containsKey(alias)) if (trustedCerts.containsKey(alias)) {
{
dout.writeInt(TRUSTED_CERT); dout.writeInt(TRUSTED_CERT);
dout.writeUTF(alias); dout.writeUTF(alias);
dout.writeLong(((Date) dates.get(alias)).getTime()); dout.writeLong(((Date) dates.get(alias)).getTime());
writeCert(dout, (Certificate) trustedCerts.get(alias)); writeCert(dout, (Certificate) trustedCerts.get(alias));
} } else {
else
{
dout.writeInt(PRIVATE_KEY); dout.writeInt(PRIVATE_KEY);
dout.writeUTF(alias); dout.writeUTF(alias);
dout.writeLong(((Date) dates.get(alias)).getTime()); dout.writeLong(((Date) dates.get(alias)).getTime());
@ -380,8 +346,7 @@ public class JKS extends KeyStoreSpi
} }
public void engineLoad(InputStream in, char[] passwd) public void engineLoad(InputStream in, char[] passwd)
throws IOException, NoSuchAlgorithmException, CertificateException throws IOException, NoSuchAlgorithmException, CertificateException {
{
MessageDigest md = MessageDigest.getInstance("SHA"); MessageDigest md = MessageDigest.getInstance("SHA");
if (passwd != null) md.update(charsToBytes(passwd)); if (passwd != null) md.update(charsToBytes(passwd));
md.update("Mighty Aphrodite".getBytes("UTF-8")); // HAR HAR md.update("Mighty Aphrodite".getBytes("UTF-8")); // HAR HAR
@ -399,14 +364,12 @@ public class JKS extends KeyStoreSpi
aliases.ensureCapacity(n); aliases.ensureCapacity(n);
if (n < 0) if (n < 0)
throw new LoadKeystoreException("Malformed key store"); throw new LoadKeystoreException("Malformed key store");
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++) {
{
int type = din.readInt(); int type = din.readInt();
String alias = din.readUTF(); String alias = din.readUTF();
aliases.add(alias); aliases.add(alias);
dates.put(alias, new Date(din.readLong())); dates.put(alias, new Date(din.readLong()));
switch (type) switch (type) {
{
case PRIVATE_KEY: case PRIVATE_KEY:
int len = din.readInt(); int len = din.readInt();
byte[] encoded = new byte[len]; byte[] encoded = new byte[len];
@ -442,8 +405,7 @@ public class JKS extends KeyStoreSpi
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
private static Certificate readCert(DataInputStream in) private static Certificate readCert(DataInputStream in)
throws IOException, CertificateException, NoSuchAlgorithmException throws IOException, CertificateException, NoSuchAlgorithmException {
{
String type = in.readUTF(); String type = in.readUTF();
int len = in.readInt(); int len = in.readInt();
byte[] encoded = new byte[len]; byte[] encoded = new byte[len];
@ -453,8 +415,7 @@ public class JKS extends KeyStoreSpi
} }
private static void writeCert(DataOutputStream dout, Certificate cert) private static void writeCert(DataOutputStream dout, Certificate cert)
throws IOException, CertificateException throws IOException, CertificateException {
{
dout.writeUTF(cert.getType()); dout.writeUTF(cert.getType());
byte[] b = cert.getEncoded(); byte[] b = cert.getEncoded();
dout.writeInt(b.length); dout.writeInt(b.length);
@ -462,10 +423,8 @@ public class JKS extends KeyStoreSpi
} }
private static byte[] decryptKey(byte[] encryptedPKI, byte[] passwd) private static byte[] decryptKey(byte[] encryptedPKI, byte[] passwd)
throws UnrecoverableKeyException throws UnrecoverableKeyException {
{ try {
try
{
EncryptedPrivateKeyInfo epki = EncryptedPrivateKeyInfo epki =
new EncryptedPrivateKeyInfo(encryptedPKI); new EncryptedPrivateKeyInfo(encryptedPKI);
byte[] encr = epki.getEncryptedData(); byte[] encr = epki.getEncryptedData();
@ -476,14 +435,12 @@ public class JKS extends KeyStoreSpi
byte[] key = new byte[encr.length - 40]; byte[] key = new byte[encr.length - 40];
MessageDigest sha = MessageDigest.getInstance("SHA1"); MessageDigest sha = MessageDigest.getInstance("SHA1");
int count = 0; int count = 0;
while (count < key.length) while (count < key.length) {
{
sha.reset(); sha.reset();
sha.update(passwd); sha.update(passwd);
sha.update(keystream); sha.update(keystream);
sha.digest(keystream, 0, keystream.length); 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]); key[count] = (byte) (keystream[i] ^ encr[count + 20]);
count++; count++;
} }
@ -494,18 +451,14 @@ public class JKS extends KeyStoreSpi
if (!MessageDigest.isEqual(check, sha.digest())) if (!MessageDigest.isEqual(check, sha.digest()))
throw new UnrecoverableKeyException("checksum mismatch"); throw new UnrecoverableKeyException("checksum mismatch");
return key; return key;
} } catch (Exception x) {
catch (Exception x)
{
throw new UnrecoverableKeyException(x.getMessage()); throw new UnrecoverableKeyException(x.getMessage());
} }
} }
private static byte[] encryptKey(Key key, byte[] passwd) private static byte[] encryptKey(Key key, byte[] passwd)
throws KeyStoreException throws KeyStoreException {
{ try {
try
{
MessageDigest sha = MessageDigest.getInstance("SHA1"); MessageDigest sha = MessageDigest.getInstance("SHA1");
SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
byte[] k = key.getEncoded(); byte[] k = key.getEncoded();
@ -513,14 +466,12 @@ public class JKS extends KeyStoreSpi
byte[] keystream = rand.getSeed(20); byte[] keystream = rand.getSeed(20);
System.arraycopy(keystream, 0, encrypted, 0, 20); System.arraycopy(keystream, 0, encrypted, 0, 20);
int count = 0; int count = 0;
while (count < k.length) while (count < k.length) {
{
sha.reset(); sha.reset();
sha.update(passwd); sha.update(passwd);
sha.update(keystream); sha.update(keystream);
sha.digest(keystream, 0, keystream.length); 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]); encrypted[count + 20] = (byte) (keystream[i] ^ k[count]);
count++; count++;
} }
@ -533,18 +484,14 @@ public class JKS extends KeyStoreSpi
// encryption algorithm. // encryption algorithm.
return new EncryptedPrivateKeyInfo("1.3.6.1.4.1.42.2.17.1.1", return new EncryptedPrivateKeyInfo("1.3.6.1.4.1.42.2.17.1.1",
encrypted).getEncoded(); encrypted).getEncoded();
} } catch (Exception x) {
catch (Exception x)
{
throw new KeyStoreException(x.getMessage()); throw new KeyStoreException(x.getMessage());
} }
} }
private static byte[] charsToBytes(char[] passwd) private static byte[] charsToBytes(char[] passwd) {
{
byte[] buf = new byte[passwd.length * 2]; 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] >>> 8);
buf[j++] = (byte) passwd[i]; buf[j++] = (byte) passwd[i];
} }

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
public class KeyNameConflictException extends Exception { public class KeyNameConflictException extends Exception {

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
@ -5,19 +6,28 @@ import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager; import kellinwood.logging.LoggerManager;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.*; import java.io.File;
import java.security.*; 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; import java.security.cert.Certificate;
/** /**
*/ */
public class KeyStoreFileManager { public class KeyStoreFileManager {
static Provider provider = new BouncyCastleProvider(); static Provider provider = new BouncyCastleProvider();
public static Provider getProvider() { return provider; } public static Provider getProvider() {
return provider;
}
public static void setProvider(Provider provider) { public static void setProvider(Provider provider) {
if (KeyStoreFileManager.provider != null) Security.removeProvider(KeyStoreFileManager.provider.getName()); if (KeyStoreFileManager.provider != null) Security.removeProvider(KeyStoreFileManager.provider.getName());
@ -48,21 +58,18 @@ public class KeyStoreFileManager {
} }
public static KeyStore createKeyStore(String keystorePath, char[] password) public static KeyStore createKeyStore(String keystorePath, char[] password)
throws Exception throws Exception {
{
KeyStore ks = null; KeyStore ks = null;
if (keystorePath.toLowerCase().endsWith(".bks")) { if (keystorePath.toLowerCase().endsWith(".bks")) {
ks = KeyStore.getInstance("bks", new BouncyCastleProvider()); ks = KeyStore.getInstance("bks", new BouncyCastleProvider());
} } else ks = new JksKeyStore();
else ks = new JksKeyStore();
ks.load(null, password); ks.load(null, password);
return ks; return ks;
} }
public static KeyStore loadKeyStore(String keystorePath, char[] password) public static KeyStore loadKeyStore(String keystorePath, char[] password)
throws Exception throws Exception {
{
KeyStore ks = null; KeyStore ks = null;
try { try {
ks = new JksKeyStore(); ks = new JksKeyStore();
@ -89,8 +96,7 @@ public class KeyStoreFileManager {
} }
public static void writeKeyStore(KeyStore ks, String keystorePath, String encodedPassword) public static void writeKeyStore(KeyStore ks, String keystorePath, String encodedPassword)
throws Exception throws Exception {
{
char password[] = null; char password[] = null;
try { try {
password = PasswordObfuscator.getInstance().decodeKeystorePassword(keystorePath, encodedPassword); password = PasswordObfuscator.getInstance().decodeKeystorePassword(keystorePath, encodedPassword);
@ -101,8 +107,7 @@ public class KeyStoreFileManager {
} }
public static void writeKeyStore(KeyStore ks, String keystorePath, char[] password) public static void writeKeyStore(KeyStore ks, String keystorePath, char[] password)
throws Exception throws Exception {
{
File keystoreFile = new File(keystorePath); File keystoreFile = new File(keystorePath);
try { try {
@ -136,7 +141,8 @@ public class KeyStoreFileManager {
x.printStackTrace(pw); x.printStackTrace(pw);
pw.flush(); pw.flush();
pw.close(); pw.close();
} catch (Exception y) {} } catch (Exception y) {
}
throw x; throw x;
} }
} }
@ -159,10 +165,16 @@ public class KeyStoreFileManager {
count += n; count += n;
} }
} finally { } finally {
try { output.close(); } catch (IOException x) {} // Ignore try {
output.close();
} catch (IOException x) {
} // Ignore
} }
} finally { } finally {
try { input.close(); } catch (IOException x) {} try {
input.close();
} catch (IOException x) {
}
} }
if (srcFile.length() != destFile.length()) { if (srcFile.length() != destFile.length()) {
@ -176,23 +188,20 @@ public class KeyStoreFileManager {
public static void renameTo(File fromFile, File toFile) public static void renameTo(File fromFile, File toFile)
throws IOException throws IOException {
{
copyFile(fromFile, toFile, true); copyFile(fromFile, toFile, true);
if (!fromFile.delete()) throw new IOException("Failed to delete " + fromFile); if (!fromFile.delete()) throw new IOException("Failed to delete " + fromFile);
} }
public static void deleteKey(String storePath, String storePass, String keyName) public static void deleteKey(String storePath, String storePass, String keyName)
throws Exception throws Exception {
{
KeyStore ks = loadKeyStore(storePath, storePass); KeyStore ks = loadKeyStore(storePath, storePass);
ks.deleteEntry(keyName); ks.deleteEntry(keyName);
writeKeyStore(ks, storePath, storePass); writeKeyStore(ks, storePath, storePass);
} }
public static String renameKey(String keystorePath, String storePass, String oldKeyName, String newKeyName, String keyPass) public static String renameKey(String keystorePath, String storePass, String oldKeyName, String newKeyName, String keyPass)
throws Exception throws Exception {
{
char[] keyPw = null; char[] keyPw = null;
try { try {
@ -210,15 +219,13 @@ public class KeyStoreFileManager {
writeKeyStore(ks, keystorePath, storePass); writeKeyStore(ks, keystorePath, storePass);
return newKeyName; return newKeyName;
} } finally {
finally {
PasswordObfuscator.flush(keyPw); PasswordObfuscator.flush(keyPw);
} }
} }
public static KeyStore.Entry getKeyEntry(String keystorePath, String storePass, String keyName, String keyPass) public static KeyStore.Entry getKeyEntry(String keystorePath, String storePass, String keyName, String keyPass)
throws Exception throws Exception {
{
char[] keyPw = null; char[] keyPw = null;
KeyStore.PasswordProtection passwordProtection = null; KeyStore.PasswordProtection passwordProtection = null;
@ -227,30 +234,26 @@ public class KeyStoreFileManager {
keyPw = PasswordObfuscator.getInstance().decodeAliasPassword(keystorePath, keyName, keyPass); keyPw = PasswordObfuscator.getInstance().decodeAliasPassword(keystorePath, keyName, keyPass);
passwordProtection = new KeyStore.PasswordProtection(keyPw); passwordProtection = new KeyStore.PasswordProtection(keyPw);
return ks.getEntry(keyName, passwordProtection); return ks.getEntry(keyName, passwordProtection);
} } finally {
finally {
if (keyPw != null) PasswordObfuscator.flush(keyPw); if (keyPw != null) PasswordObfuscator.flush(keyPw);
if (passwordProtection != null) passwordProtection.destroy(); if (passwordProtection != null) passwordProtection.destroy();
} }
} }
public static boolean containsKey(String keystorePath, String storePass, String keyName) public static boolean containsKey(String keystorePath, String storePass, String keyName)
throws Exception throws Exception {
{
KeyStore ks = loadKeyStore(keystorePath, storePass); KeyStore ks = loadKeyStore(keystorePath, storePass);
return ks.containsAlias(keyName); return ks.containsAlias(keyName);
} }
/** /**
*
* @param keystorePath * @param keystorePath
* @param encodedPassword * @param encodedPassword
* @throws Exception if the password is invalid * @throws Exception if the password is invalid
*/ */
public static void validateKeystorePassword(String keystorePath, String encodedPassword) public static void validateKeystorePassword(String keystorePath, String encodedPassword)
throws Exception throws Exception {
{
char[] password = null; char[] password = null;
try { try {
KeyStore ks = KeyStoreFileManager.loadKeyStore(keystorePath, encodedPassword); KeyStore ks = KeyStoreFileManager.loadKeyStore(keystorePath, encodedPassword);
@ -261,15 +264,13 @@ public class KeyStoreFileManager {
} }
/** /**
*
* @param keystorePath * @param keystorePath
* @param keyName * @param keyName
* @param encodedPassword * @param encodedPassword
* @throws java.security.UnrecoverableKeyException if the password is invalid * @throws java.security.UnrecoverableKeyException if the password is invalid
*/ */
public static void validateKeyPassword(String keystorePath, String keyName, String encodedPassword) public static void validateKeyPassword(String keystorePath, String keyName, String encodedPassword)
throws Exception throws Exception {
{
char[] password = null; char[] password = null;
try { try {
KeyStore ks = KeyStoreFileManager.loadKeyStore(keystorePath, (char[]) null); KeyStore ks = KeyStoreFileManager.loadKeyStore(keystorePath, (char[]) null);

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import java.io.IOException; import java.io.IOException;

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import kellinwood.logging.LoggerInterface; import kellinwood.logging.LoggerInterface;
@ -6,7 +7,12 @@ import kellinwood.security.zipsigner.Base64;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; 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 { public class PasswordObfuscator {

View File

@ -1,8 +1,13 @@
package kellinwood.security.zipsigner.optional; package kellinwood.security.zipsigner.optional;
import kellinwood.security.zipsigner.KeySet; import kellinwood.security.zipsigner.KeySet;
import org.bouncycastle.cert.jcajce.JcaCertStore; 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.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DigestCalculatorProvider; import org.bouncycastle.operator.DigestCalculatorProvider;

View File

@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.zipio;
import java.io.IOException; package kellinwood.zipio;
import kellinwood.logging.LoggerInterface; import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager; 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 int signature = 0x06054b50; // end of central dir signature 4 bytes
public short numberThisDisk = 0; // number of this disk 2 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 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; private static LoggerInterface log;
public static CentralEnd read(ZipInput input) throws IOException public static CentralEnd read(ZipInput input) throws IOException {
{
int signature = input.readInt(); int signature = input.readInt();
if (signature != 0x06054b50) { 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(); 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(); boolean debug = getLogger().isDebugEnabled();

View File

@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.zipio; package kellinwood.zipio;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.File;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.SequenceInputStream; import java.io.SequenceInputStream;
import java.util.Date; import java.util.Date;
@ -27,9 +31,6 @@ import java.util.zip.CRC32;
import java.util.zip.Inflater; import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
public class ZioEntry implements Cloneable { public class ZioEntry implements Cloneable {
private ZipInput zipInput; private ZipInput zipInput;
@ -81,8 +82,7 @@ public class ZioEntry implements Cloneable {
public ZioEntry(String name, String sourceDataFile) public ZioEntry(String name, String sourceDataFile)
throws IOException throws IOException {
{
zipInput = new ZipInput(sourceDataFile); zipInput = new ZipInput(sourceDataFile);
filename = name; filename = name;
fileComment = ""; fileComment = "";
@ -116,10 +116,8 @@ public class ZioEntry implements Cloneable {
} }
public ZioEntry(String name, String sourceDataFile, short compression, int crc32, int compressedSize, int size) public ZioEntry(String name, String sourceDataFile, short compression, int crc32, int compressedSize, int size)
throws IOException throws IOException {
{
zipInput = new ZipInput(sourceDataFile); zipInput = new ZipInput(sourceDataFile);
filename = name; filename = name;
fileComment = ""; fileComment = "";
@ -133,23 +131,19 @@ public class ZioEntry implements Cloneable {
} }
// Return a copy with a new name // Return a copy with a new name
public ZioEntry getClonedEntry( String newName) public ZioEntry getClonedEntry(String newName) {
{
ZioEntry clone; ZioEntry clone;
try { try {
clone = (ZioEntry) this.clone(); clone = (ZioEntry) this.clone();
} } catch (CloneNotSupportedException e) {
catch (CloneNotSupportedException e)
{
throw new IllegalStateException("clone() failed!"); throw new IllegalStateException("clone() failed!");
} }
clone.setName(newName); clone.setName(newName);
return clone; return clone;
} }
public void readLocalHeader() throws IOException public void readLocalHeader() throws IOException {
{
ZipInput input = zipInput; ZipInput input = zipInput;
int tmp; int tmp;
boolean debug = getLogger().isDebugEnabled(); boolean debug = getLogger().isDebugEnabled();
@ -174,35 +168,43 @@ public class ZioEntry implements Cloneable {
short tmpShort; short tmpShort;
// 4 2 Version needed to extract (minimum) // 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*/)); if (debug) log.debug(String.format("Version required: 0x%04x", tmpShort /*versionRequired*/));
// 6 2 General purpose bit flag // 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 */)); if (debug) log.debug(String.format("General purpose bits: 0x%04x", tmpShort /* generalPurposeBits */));
// 8 2 Compression method // 8 2 Compression method
/* compression */ tmpShort = input.readShort(); /* compression */
tmpShort = input.readShort();
if (debug) log.debug(String.format("Compression: 0x%04x", tmpShort /* compression */)); if (debug) log.debug(String.format("Compression: 0x%04x", tmpShort /* compression */));
// 10 2 File last modification time // 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 */)); if (debug) log.debug(String.format("Modification time: 0x%04x", tmpShort /* modificationTime */));
// 12 2 File last modification date // 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 */)); if (debug) log.debug(String.format("Modification date: 0x%04x", tmpShort /* modificationDate */));
// 14 4 CRC-32 // 14 4 CRC-32
/* crc32 */ tmpInt = input.readInt(); /* crc32 */
tmpInt = input.readInt();
if (debug) log.debug(String.format("CRC-32: 0x%04x", tmpInt /*crc32*/)); if (debug) log.debug(String.format("CRC-32: 0x%04x", tmpInt /*crc32*/));
// 18 4 Compressed size // 18 4 Compressed size
/* compressedSize*/ tmpInt = input.readInt(); /* compressedSize*/
tmpInt = input.readInt();
if (debug) log.debug(String.format("Compressed size: 0x%04x", tmpInt /*compressedSize*/)); if (debug) log.debug(String.format("Compressed size: 0x%04x", tmpInt /*compressedSize*/));
// 22 4 Uncompressed size // 22 4 Uncompressed size
/* size */ tmpInt = input.readInt(); /* size */
tmpInt = input.readInt();
if (debug) log.debug(String.format("Size: 0x%04x", tmpInt /*size*/)); if (debug) log.debug(String.format("Size: 0x%04x", tmpInt /*size*/));
// 26 2 File name length (n) // 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) { if (data == null && dataPosition < 0 && zipInput != null) {
readLocalHeader(); readLocalHeader();
} }
@ -295,8 +296,7 @@ public class ZioEntry implements Cloneable {
if (data != null) { if (data != null) {
output.writeBytes(data); output.writeBytes(data);
if (debug) getLogger().debug(String.format("Wrote %d bytes", data.length)); 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)); if (debug) getLogger().debug(String.format("Seeking to position 0x%08x", dataPosition));
zipInput.seek(dataPosition); zipInput.seek(dataPosition);
@ -311,14 +311,13 @@ public class ZioEntry implements Cloneable {
output.writeBytes(buffer, 0, numRead); output.writeBytes(buffer, 0, numRead);
if (debug) getLogger().debug(String.format("Wrote %d bytes", numRead)); if (debug) getLogger().debug(String.format("Wrote %d bytes", numRead));
totalCount += numRead; totalCount += numRead;
} } else
else throw new IllegalStateException(String.format("EOF reached while copying %s with %d bytes left to go", filename, compressedSize - totalCount)); 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 // 0 4 Central directory header signature = 0x02014b50
int signature = input.readInt(); int signature = input.readInt();
@ -334,8 +333,7 @@ public class ZioEntry implements Cloneable {
return entry; return entry;
} }
private void doRead( ZipInput input) throws IOException private void doRead(ZipInput input) throws IOException {
{
boolean debug = getLogger().isDebugEnabled(); 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; if (data != null) return data;
byte[] tmpdata = new byte[size]; byte[] tmpdata = new byte[size];
@ -434,7 +433,8 @@ public class ZioEntry implements Cloneable {
while (count != size) { while (count != size) {
int numRead = din.read(tmpdata, count, size - count); 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; count += numRead;
} }
return tmpdata; return tmpdata;
@ -473,13 +473,11 @@ public class ZioEntry implements Cloneable {
// in order to support certain optimizations. // in order to support certain optimizations.
dataStream.setReturnDummyByte(true); dataStream.setReturnDummyByte(true);
return new InflaterInputStream(dataStream, new Inflater(true)); return new InflaterInputStream(dataStream, new Inflater(true));
} } else return dataStream;
else return dataStream;
} }
// Returns an output stream for writing an entry's data. // Returns an output stream for writing an entry's data.
public OutputStream getOutputStream() public OutputStream getOutputStream() {
{
entryOut = new ZioEntryOutputStream(compression, new ByteArrayOutputStream()); entryOut = new ZioEntryOutputStream(compression, new ByteArrayOutputStream());
return entryOut; return entryOut;
} }
@ -537,8 +535,7 @@ public class ZioEntry implements Cloneable {
int year = d.getYear() + 1900; int year = d.getYear() + 1900;
if (year < 1980) { if (year < 1980) {
dtime = (1 << 21) | (1 << 16); dtime = (1 << 21) | (1 << 16);
} } else {
else {
dtime = (year - 1980) << 25 | (d.getMonth() + 1) << 21 | dtime = (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 | d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
d.getSeconds() >> 1; d.getSeconds() >> 1;
@ -560,7 +557,9 @@ public class ZioEntry implements Cloneable {
this.filename = filename; this.filename = filename;
} }
/** Use 0 (STORED), or 8 (DEFLATE). */ /**
* Use 0 (STORED), or 8 (DEFLATE).
*/
public void setCompression(int compression) { public void setCompression(int compression) {
this.compression = (short) compression; this.compression = (short) compression;
} }

View File

@ -13,18 +13,21 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.zipio; package kellinwood.zipio;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.RandomAccessFile; 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 { public class ZioEntryInputStream extends InputStream {
RandomAccessFile raf; RandomAccessFile raf;
@ -46,8 +49,7 @@ public class ZioEntryInputStream extends InputStream {
if (dpos >= 0) { if (dpos >= 0) {
if (debug) log.debug(String.format("Seeking to %d", entry.getDataPosition())); if (debug) log.debug(String.format("Seeking to %d", entry.getDataPosition()));
raf.seek(entry.getDataPosition()); raf.seek(entry.getDataPosition());
} } else {
else {
// seeks to, then reads, the local header, causing the // seeks to, then reads, the local header, causing the
// file pointer to be positioned at the start of the data. // file pointer to be positioned at the start of the data.
entry.readLocalHeader(); entry.readLocalHeader();
@ -87,16 +89,14 @@ public class ZioEntryInputStream extends InputStream {
if (returnDummyByte) { if (returnDummyByte) {
returnDummyByte = false; returnDummyByte = false;
return 0; return 0;
} } else return -1;
else return -1;
} }
int b = raf.read(); int b = raf.read();
if (b >= 0) { if (b >= 0) {
if (monitor != null) monitor.write(b); if (monitor != null) monitor.write(b);
if (debug) log.debug("Read 1 byte"); if (debug) log.debug("Read 1 byte");
offset += 1; offset += 1;
} } else if (debug) log.debug("Read 0 bytes");
else if (debug) log.debug("Read 0 bytes");
return b; return b;
} }
@ -111,8 +111,7 @@ public class ZioEntryInputStream extends InputStream {
returnDummyByte = false; returnDummyByte = false;
b[off] = 0; b[off] = 0;
return 1; return 1;
} } else return -1;
else return -1;
} }
int numToRead = Math.min(len, available()); int numToRead = Math.min(len, available());
int numRead = raf.read(b, off, numToRead); int numRead = raf.read(b, off, numToRead);

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.zipio; package kellinwood.zipio;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.zip.CRC32; import java.util.zip.CRC32;
@ -29,8 +29,7 @@ public class ZioEntryOutputStream extends OutputStream {
OutputStream wrapped; OutputStream wrapped;
OutputStream downstream; OutputStream downstream;
public ZioEntryOutputStream( int compression, OutputStream wrapped) public ZioEntryOutputStream(int compression, OutputStream wrapped) {
{
this.wrapped = wrapped; this.wrapped = wrapped;
if (compression != 0) if (compression != 0)
downstream = new DeflaterOutputStream(wrapped, new Deflater(Deflater.BEST_COMPRESSION, true)); downstream = new DeflaterOutputStream(wrapped, new Deflater(Deflater.BEST_COMPRESSION, true));
@ -73,8 +72,7 @@ public class ZioEntryOutputStream extends OutputStream {
return size; return size;
} }
public OutputStream getWrappedStream() public OutputStream getWrappedStream() {
{
return wrapped; return wrapped;
} }

View File

@ -13,16 +13,17 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.zipio; package kellinwood.zipio;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -31,15 +32,10 @@ import java.util.jar.Manifest;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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; static LoggerInterface log;
public String inputFilename; public String inputFilename;
@ -51,8 +47,7 @@ public class ZipInput implements Closeable
CentralEnd centralEnd; CentralEnd centralEnd;
Manifest manifest; Manifest manifest;
public ZipInput( String filename) throws IOException public ZipInput(String filename) throws IOException {
{
this.inputFilename = filename; this.inputFilename = filename;
in = new RandomAccessFile(new File(inputFilename), "r"); in = new RandomAccessFile(new File(inputFilename), "r");
fileLength = in.length(); fileLength = in.length();
@ -86,12 +81,12 @@ public class ZipInput implements Closeable
return zioEntries; 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 "/" * The path value must end with a "/" character. Use a value of "/"
* to get the root entries. * 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.endsWith("/")) throw new IllegalArgumentException("Invalid path -- does not end with '/'");
if (path.startsWith("/")) path = path.substring(1); if (path.startsWith("/")) path = path.substring(1);
@ -117,12 +112,14 @@ public class ZipInput implements Closeable
return manifest; 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 * Scan the end of the file for the end of central directory record (EOCDR).
initial buffer size (e.g., 256). * 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 { 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); int scanSize = (int) Math.min(fileLength, size);
@ -143,8 +140,7 @@ public class ZipInput implements Closeable
} }
private void doRead() private void doRead() {
{
try { try {
long posEOCDR = scanForEOCDR(256); long posEOCDR = scanForEOCDR(256);
@ -168,15 +164,17 @@ public class ZipInput implements Closeable
if (debug) ZipListingHelper.listEntry(getLogger(), entry); if (debug) ZipListingHelper.listEntry(getLogger(), entry);
} }
} } catch (Throwable t) {
catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
} }
} }
@Override @Override
public void close() { 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 { public long getFilePointer() throws IOException {

View File

@ -13,31 +13,29 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.zipio; package kellinwood.zipio;
import java.util.Date; import kellinwood.logging.LoggerInterface;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import kellinwood.logging.LoggerInterface; import java.util.Date;
import kellinwood.logging.LoggerManager;
/** /**
* *
*/ */
public class ZipListingHelper public class ZipListingHelper {
{
static DateFormat dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm"); 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(" Length Method Size Ratio Date Time CRC-32 Name");
log.debug("-------- ------ ------- ----- ---- ---- ------ ----"); log.debug("-------- ------ ------- ----- ---- ---- ------ ----");
} }
public static void listEntry(LoggerInterface log, ZioEntry entry) public static void listEntry(LoggerInterface log, ZioEntry entry) {
{
int ratio = 0; int ratio = 0;
if (entry.getSize() > 0) ratio = (100 * (entry.getSize() - entry.getCompressedSize())) / entry.getSize(); if (entry.getSize() > 0) ratio = (100 * (entry.getSize() - entry.getCompressedSize())) / entry.getSize();
log.debug(String.format("%8d %6s %8d %4d%% %s %08x %s", log.debug(String.format("%8d %6s %8d %4d%% %s %08x %s",

View File

@ -13,24 +13,25 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package kellinwood.zipio; package kellinwood.zipio;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List;
import java.util.LinkedList;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set; import java.util.Set;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
/** /**
* *
*/ */
public class ZipOutput public class ZipOutput {
{
static LoggerInterface log; static LoggerInterface log;
@ -41,30 +42,26 @@ public class ZipOutput
List<ZioEntry> entriesWritten = new LinkedList<ZioEntry>(); List<ZioEntry> entriesWritten = new LinkedList<ZioEntry>();
Set<String> namesWritten = new HashSet<String>(); Set<String> namesWritten = new HashSet<String>();
public ZipOutput( String filename) throws IOException public ZipOutput(String filename) throws IOException {
{
this.outputFilename = filename; this.outputFilename = filename;
File ofile = new File(outputFilename); File ofile = new File(outputFilename);
init(ofile); init(ofile);
} }
public ZipOutput( File outputFile) throws IOException public ZipOutput(File outputFile) throws IOException {
{
this.outputFilename = outputFile.getAbsolutePath(); this.outputFilename = outputFile.getAbsolutePath();
File ofile = outputFile; File ofile = outputFile;
init(ofile); init(ofile);
} }
private void init( File ofile) throws IOException private void init(File ofile) throws IOException {
{
if (ofile.exists()) ofile.delete(); if (ofile.exists()) ofile.delete();
out = new FileOutputStream(ofile); out = new FileOutputStream(ofile);
if (getLogger().isDebugEnabled()) ZipListingHelper.listHeader(getLogger()); if (getLogger().isDebugEnabled()) ZipListingHelper.listHeader(getLogger());
} }
public ZipOutput( OutputStream os) throws IOException public ZipOutput(OutputStream os) throws IOException {
{
out = os; out = os;
} }
@ -87,9 +84,7 @@ public class ZipOutput
} }
public void close() throws IOException {
public void close() throws IOException
{
CentralEnd centralEnd = new CentralEnd(); CentralEnd centralEnd = new CentralEnd();
centralEnd.centralStartOffset = (int) getFilePointer(); centralEnd.centralStartOffset = (int) getFilePointer();
@ -104,7 +99,10 @@ public class ZipOutput
centralEnd.write(this); 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 { public int getFilePointer() throws IOException {