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
* limitations under the License.
*/
package kellinwood.logging;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public abstract class AbstractLogger implements LoggerInterface
{
public abstract class AbstractLogger implements LoggerInterface {
protected String category;
@ -91,6 +90,4 @@ public abstract class AbstractLogger implements LoggerInterface
public boolean isWarningEnabled() {
return true;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,16 +15,17 @@
*/
package kellinwood.security.zipsigner;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/** Produces the classic hex dump with an address column, hex data
/**
* Produces the classic hex dump with an address column, hex data
* section (16 bytes per row) and right-column printable character dislpay.
*/
public class HexDumpEncoder
{
public class HexDumpEncoder {
static HexEncoder encoder = new HexEncoder();
@ -64,8 +65,7 @@ public class HexDumpEncoder
}
return hexDumpOut.toString();
}
catch (IOException x) {
} catch (IOException x) {
throw new IllegalStateException(x.getClass().getName() + ": " + x.getMessage());
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kellinwood.security.zipsigner;
public interface ProgressListener {
/** Called to notify the listener that progress has been made during
the zip signing operation.
/**
* Called to notify the listener that progress has been made during
* the zip signing operation.
*/
public void onProgress(ProgressEvent event);
}

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional;
import kellinwood.security.zipsigner.KeySet;
@ -7,7 +8,10 @@ import org.bouncycastle.x509.X509V3CertificateGenerator;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Date;
@ -17,7 +21,8 @@ import java.util.Date;
*/
public class CertCreator {
/** Creates a new keystore and self-signed key. The key will have the same password as the key, and will be
/**
* Creates a new keystore and self-signed key. The key will have the same password as the key, and will be
* RSA 2048, with the cert signed using SHA1withRSA. The certificate will have a validity of
* 30 years).
*
@ -27,8 +32,7 @@ public class CertCreator {
* @param distinguishedNameValues - contains Country, State, Locality,...,Common Name, etc.
*/
public static void createKeystoreAndKey(String storePath, char[] password,
String keyName, DistinguishedNameValues distinguishedNameValues)
{
String keyName, DistinguishedNameValues distinguishedNameValues) {
createKeystoreAndKey(storePath, password, "RSA", 2048, keyName, password, "SHA1withRSA", 30,
distinguishedNameValues);
}
@ -63,8 +67,8 @@ public class CertCreator {
}
}
/** Create a new key and store it in an existing keystore.
*
/**
* Create a new key and store it in an existing keystore.
*/
public static KeySet createKey(String storePath, char[] storePass,
String keyAlgorithm, int keySize, String keyName, char[] keyPass,
@ -93,8 +97,7 @@ public class CertCreator {
}
public static KeySet createKey(String keyAlgorithm, int keySize, String keyName,
String certSignatureAlgorithm, int certValidityYears, DistinguishedNameValues distinguishedNameValues)
{
String certSignatureAlgorithm, int certValidityYears, DistinguishedNameValues distinguishedNameValues) {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
keyPairGenerator.initialize(keySize);

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional;
import kellinwood.security.zipsigner.ZipSigner;
@ -12,7 +13,9 @@ import java.security.cert.X509Certificate;
*/
public class CustomKeySigner {
/** KeyStore-type agnostic. This method will sign the zip file, automatically handling JKS or BKS keystores. */
/**
* KeyStore-type agnostic. This method will sign the zip file, automatically handling JKS or BKS keystores.
*/
public static void signZip(ZipSigner zipSigner,
String keystorePath,
char[] keystorePw,
@ -21,8 +24,7 @@ public class CustomKeySigner {
String signatureAlgorithm,
String inputZipFilename,
String outputZipFilename)
throws Exception
{
throws Exception {
zipSigner.issueLoadingCertAndKeysProgressEvent();
KeyStore keystore = KeyStoreFileManager.loadKeyStore(keystorePath, keystorePw);
Certificate cert = keystore.getCertificate(certAlias);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
package kellinwood.security.zipsigner.optional;
import kellinwood.logging.LoggerInterface;
@ -6,7 +7,12 @@ import kellinwood.security.zipsigner.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class PasswordObfuscator {

View File

@ -1,8 +1,13 @@
package kellinwood.security.zipsigner.optional;
import kellinwood.security.zipsigner.KeySet;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DigestCalculatorProvider;

View File

@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kellinwood.zipio;
import java.io.IOException;
package kellinwood.zipio;
import kellinwood.logging.LoggerInterface;
import kellinwood.logging.LoggerManager;
public class CentralEnd
{
import java.io.IOException;
public class CentralEnd {
public int signature = 0x06054b50; // end of central dir signature 4 bytes
public short numberThisDisk = 0; // number of this disk 2 bytes
public short centralStartDisk = 0; // number of the disk with the start of the central directory 2 bytes
@ -34,8 +34,7 @@ public class CentralEnd
private static LoggerInterface log;
public static CentralEnd read(ZipInput input) throws IOException
{
public static CentralEnd read(ZipInput input) throws IOException {
int signature = input.readInt();
if (signature != 0x06054b50) {
@ -56,8 +55,7 @@ public class CentralEnd
}
private void doRead( ZipInput input) throws IOException
{
private void doRead(ZipInput input) throws IOException {
boolean debug = getLogger().isDebugEnabled();
@ -87,8 +85,7 @@ public class CentralEnd
}
public void write( ZipOutput output) throws IOException
{
public void write(ZipOutput output) throws IOException {
boolean debug = getLogger().isDebugEnabled();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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