diff options
Diffstat (limited to 'libjava/classpath/gnu/javax/crypto/keyring')
24 files changed, 4380 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java new file mode 100644 index 00000000000..22b42b3ea0b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java @@ -0,0 +1,222 @@ +/* AuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; + +public final class AuthenticatedEntry extends MaskableEnvelopeEntry implements + Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 2; + + // Constructor. + // ------------------------------------------------------------------------ + + public AuthenticatedEntry(String mac, int macLen, Properties properties) + { + super(TYPE, properties); + + if (macLen <= 0) + { + throw new IllegalArgumentException("invalid mac length"); + } + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(macLen)); + setMasked(false); + } + + private AuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static AuthenticatedEntry decode(DataInputStream in) + throws IOException + { + AuthenticatedEntry entry = new AuthenticatedEntry(); + entry.properties.decode(in); + if (!entry.properties.containsKey("mac")) + { + throw new MalformedKeyringException("no mac specified"); + } + if (!entry.properties.containsKey("maclen")) + { + throw new MalformedKeyringException("no mac length specified"); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Computes the mac over this envelope's data. This method <b>must</b> be + * called before this entry in encoded. + * + * @param key The key to authenticate with. + * @throws IOException If encoding fails. + * @throws InvalidKeyException If the supplied key is bad. + */ + public void authenticate(byte[] key) throws IOException, InvalidKeyException + { + if (isMasked()) + { + throw new IllegalStateException("entry is masked"); + } + IMac m = getMac(key); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + /** + * Verifies this entry's payload. This method will unmask this entry, + * thus it must be called before accessing its contents. + * + * @param key The key to use to authenticate. + * @throws InvalidKeyException If the given key is improper. + */ + public void verify(byte[] key) throws InvalidKeyException + { + if (!isMasked() || payload == null) + { + return; + } + IMac m = getMac(key); + + m.update(payload, 0, payload.length - m.macSize()); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (!Arrays.equals(macValue, m.digest())) + { + throw new IllegalArgumentException("MAC verification failed"); + } + try + { + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + payload, + 0, + payload.length + - m.macSize())); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + throw new IllegalStateException("not authenticated"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMac getMac(byte[] key) throws InvalidKeyException + { + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + { + throw new IllegalArgumentException("no such mac: " + + properties.get("mac")); + } + int maclen = 0; + if (!properties.containsKey("maclen")) + { + throw new IllegalArgumentException("no MAC length"); + } + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad MAC length"); + } + + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, key); + macAttr.put(IMac.TRUNCATED_SIZE, new Integer(maclen)); + mac.init(macAttr); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java new file mode 100644 index 00000000000..5fe7dbf4deb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java @@ -0,0 +1,198 @@ +/* BaseKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import gnu.java.security.Registry; + +public abstract class BaseKeyring implements IKeyring +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** + * The top-level keyring data. + */ + protected PasswordAuthenticatedEntry keyring; + + protected CompressedEntry keyring2; + + // Constructors. + // ------------------------------------------------------------------------ + + public BaseKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void load(Map attributes) throws IOException + { + InputStream in = (InputStream) attributes.get(KEYRING_DATA_IN); + if (in == null) + { + throw new IllegalArgumentException("no input stream"); + } + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + { + password = new char[0]; + } + + if (in.read() != Registry.GKR_MAGIC[0] + || in.read() != Registry.GKR_MAGIC[1] + || in.read() != Registry.GKR_MAGIC[2] + || in.read() != Registry.GKR_MAGIC[3]) + { + throw new MalformedKeyringException("magic"); + } + + load(in, password); + + List l = keyring.getEntries(); + if (l.size() == 1 && (l.get(0) instanceof CompressedEntry)) + { + keyring2 = (CompressedEntry) l.get(0); + } + } + + public void store(Map attributes) throws IOException + { + OutputStream out = (OutputStream) attributes.get(KEYRING_DATA_OUT); + if (out == null) + { + throw new IllegalArgumentException("no output stream"); + } + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + { + password = new char[0]; + } + if (keyring == null) + { + throw new IllegalStateException("empty keyring"); + } + + out.write(Registry.GKR_MAGIC); + store(out, password); + } + + public void reset() + { + keyring = null; + } + + public int size() + { + if (keyring == null) + { + throw new IllegalStateException ("keyring not loaded"); + } + return ((StringTokenizer) aliases()).countTokens(); + } + + public Enumeration aliases() + { + if (keyring == null) + { + throw new IllegalStateException ("keyring not loaded"); + } + return new StringTokenizer(keyring.getAliasList(), ";"); + } + + public boolean containsAlias(String alias) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + return keyring.containsAlias(alias); + } + + public List get(String alias) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + return keyring.get(alias); + } + + public void add(Entry entry) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + if (keyring2 != null) + keyring2.add(entry); + else + keyring.add(entry); + } + + public void remove(String alias) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + keyring.remove(alias); + } + + protected String fixAlias(String alias) + { + return alias.replace(';', '_'); + } + + protected abstract void load(InputStream in, char[] password) + throws IOException; + + protected abstract void store(OutputStream out, char[] password) + throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java new file mode 100644 index 00000000000..2dcd5454fb6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java @@ -0,0 +1,128 @@ +/* BinaryDataEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; + +import java.util.Date; + +/** + * A binary data entry is a primitive entry that simply contains some amount + * of arbitrary binary data and an optional content type. + */ +public class BinaryDataEntry extends PrimitiveEntry +{ + + // Fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 9; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Creates a new binary data entry. + * + * @param contentType The content type of this entry. This parameter can + * be <code>null</code> if no content type is needed. + * @param data The data. + * @param creationDate The creation date. + * @param properties This entry's properties. + */ + public BinaryDataEntry(String contentType, byte[] data, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (data == null) + { + throw new IllegalArgumentException("no data"); + } + payload = (byte[]) data.clone(); + if (contentType != null) + { + this.properties.put("content-type", contentType); + } + } + + private BinaryDataEntry() + { + super(TYPE); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static BinaryDataEntry decode(DataInputStream in) throws IOException + { + BinaryDataEntry entry = new BinaryDataEntry(); + entry.defaultDecode(in); + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the content type of this entry, or <code>null</code> if this + * property is not set. + * + * @return The content type. + */ + public String getContentType() + { + return properties.get("content-type"); + } + + /** + * Returns this object's data field. + * + * @return The data. + */ + public byte[] getData() + { + return getPayload(); + } + + protected void encodePayload() + { + // Empty. + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java new file mode 100644 index 00000000000..ef62347ec9d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java @@ -0,0 +1,133 @@ +/* CertPathEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +import java.util.Date; + +/** + * A primitive entry that contains a path of X.509 certificates. + */ +public final class CertPathEntry extends PrimitiveEntry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 8; + + private Certificate[] path; + + // Constructor. + // ------------------------------------------------------------------------ + + public CertPathEntry(Certificate[] path, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (path == null || path.length == 0) + { + throw new IllegalArgumentException("no certificate path"); + } + this.path = (Certificate[]) path.clone(); + } + + private CertPathEntry() + { + super(TYPE); + } + + // Class method. + // ------------------------------------------------------------------------ + + public static CertPathEntry decode(DataInputStream in) throws IOException + { + CertPathEntry entry = new CertPathEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + entry.path = (Certificate[]) fact.generateCertificates(in2).toArray( + new Certificate[0]); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Certificate[] getCertPath() + { + return path; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + byte[] enc = null; + try + { + for (int i = 0; i < path.length; i++) + { + bout.write(path[i].getEncoded()); + } + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + payload = bout.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java new file mode 100644 index 00000000000..95a708ac53f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java @@ -0,0 +1,150 @@ +/* CertificateEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Date; + +/** + * <p>An immutable class representing a trusted certificate entry.</p> + */ +public final class CertificateEntry extends PrimitiveEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 5; + + /** The certificate. */ + private Certificate certificate; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Creates a new certificate entry. + * + * @param certificate The certificate. + * @param creationDate The creation date. + * @param properties The alias. + * @throws IllegalArgumentException If any argument is null, or if the alias + * is empty. + */ + public CertificateEntry(Certificate certificate, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + + if (certificate == null) + { + throw new IllegalArgumentException("no certificate"); + } + this.certificate = certificate; + this.properties.put("type", certificate.getType()); + } + + private CertificateEntry() + { + super(TYPE); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static CertificateEntry decode(DataInputStream in) throws IOException + { + CertificateEntry entry = new CertificateEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + String type = entry.properties.get("type"); + if (type == null) + { + throw new MalformedKeyringException("no certificate type"); + } + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance(type); + entry.certificate = fact.generateCertificate(in2); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + if (!in2.limitReached()) + { + throw new MalformedKeyringException("extra data at end of payload"); + } + return entry; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Returns this entry's certificate. + * + * @return The certificate. + */ + public Certificate getCertificate() + { + return certificate; + } + + protected void encodePayload() throws IOException + { + try + { + payload = certificate.getEncoded(); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java new file mode 100644 index 00000000000..cce930d739d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java @@ -0,0 +1,113 @@ +/* CompressedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.Iterator; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public class CompressedEntry extends EnvelopeEntry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 4; + + // Constructor. + // ------------------------------------------------------------------------ + + public CompressedEntry(Properties properties) + { + super(TYPE, properties); + this.properties.put("algorithm", "DEFLATE"); + } + + private CompressedEntry() + { + this(new Properties()); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static CompressedEntry decode(DataInputStream in) throws IOException + { + CompressedEntry entry = new CompressedEntry(); + entry.properties.decode(in); + String alg = entry.properties.get("algorithm"); + if (alg == null) + { + throw new MalformedKeyringException("no compression algorithm"); + } + if (!alg.equalsIgnoreCase("DEFLATE")) + { + throw new MalformedKeyringException( + "unsupported compression algorithm: " + + alg); + } + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + InflaterInputStream infin = new InflaterInputStream(min); + DataInputStream in2 = new DataInputStream(infin); + entry.decodeEnvelope(in2); + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); + DeflaterOutputStream dout = new DeflaterOutputStream(buf); + DataOutputStream out2 = new DataOutputStream(dout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + ((Entry) it.next()).encode(out2); + } + dout.finish(); + payload = buf.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java new file mode 100644 index 00000000000..fad5f54b236 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java @@ -0,0 +1,235 @@ +/* EncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 0; + + // Constructor. + // ------------------------------------------------------------------------ + + public EncryptedEntry(String cipher, String mode, Properties properties) + { + super(TYPE, properties); + if (cipher == null || mode == null) + { + throw new IllegalArgumentException( + "neither cipher nor mode can be null"); + } + properties.put("cipher", cipher); + properties.put("mode", mode); + setMasked(false); + } + + private EncryptedEntry() + { + super(TYPE, new Properties()); + setMasked(true); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static EncryptedEntry decode(DataInputStream in) throws IOException + { + EncryptedEntry entry = new EncryptedEntry(); + entry.defaultDecode(in); + if (!entry.properties.containsKey("cipher")) + { + throw new MalformedKeyringException("no cipher"); + } + if (!entry.properties.containsKey("cipher")) + { + throw new MalformedKeyringException("no cipher"); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void decrypt(byte[] key, byte[] iv) throws IllegalArgumentException, + WrongPaddingException + { + if (!isMasked() || payload == null) + { + return; + } + IMode mode = getMode(key, iv, IMode.DECRYPTION); + IPad padding = null; + padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + for (int i = 0; i < payload.length; i++) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + buf, + 0, + buf.length + - padlen)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(byte[] key, byte[] iv) throws IOException + { + IMode mode = getMode(key, iv, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + } + + public void encodePayload() throws IOException + { + if (payload == null) + { + throw new IOException("not encrypted"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMode getMode(byte[] key, byte[] iv, int state) + { + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + { + throw new IllegalArgumentException("no such cipher: " + + properties.get("cipher")); + } + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + { + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, + blockSize); + if (mode == null) + { + throw new IllegalArgumentException("no such mode: " + + properties.get("mode")); + } + + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, key); + modeAttr.put(IMode.STATE, new Integer(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Entry.java b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java new file mode 100644 index 00000000000..fa7f496798b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java @@ -0,0 +1,178 @@ +/* Entry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * An immutable class representing a single entry in a keyring. + */ +public abstract class Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** This entry's type identifier. */ + protected int type; + + /** This entry's property set. */ + protected Properties properties; + + /** This entry's payload. */ + protected byte[] payload; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new Entry. + * + * @param type This entry's type. + * @param properties This entry's properties. + * @throws IllegalArgumentException If the properties argument is null, + * or if the type is out of range. + */ + protected Entry(int type, Properties properties) + { + if (type < 0 || type > 255) + { + throw new IllegalArgumentException("invalid packet type"); + } + if (properties == null) + { + throw new IllegalArgumentException("no properties"); + } + this.type = type; + this.properties = (Properties) properties.clone(); + } + + /** + * Constructor for use by subclasses. + */ + protected Entry(final int type) + { + if (type < 0 || type > 255) + { + throw new IllegalArgumentException("invalid packet type"); + } + this.type = type; + properties = new Properties(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns this entry's properties object. The properties are cloned before + * being returned. + * + * @return The properties. + */ + public Properties getProperties() + { + return (Properties) properties.clone(); + } + + /** + * Returns this entry's payload data, or null if + */ + public byte[] getPayload() + { + if (payload == null) + return null; + return (byte[]) payload.clone(); + } + + /** + * This method is called when this entry needs to be written to an + * output stream. + * + * @param out The stream to write to. + * @throws IOException If an I/O exception occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + if (payload == null) + { + encodePayload(); + } + if (out == null) + { + return; + } + out.write(type); + properties.encode(out); + out.writeInt(payload.length); + out.write(payload); + } + + /** + * Generic decoding method, which simply decodes the properties field + * and reads the payload field. + * + * @param in The input data stream. + * @throws IOException If an I/O error occurs. + */ + protected void defaultDecode(DataInputStream in) throws IOException + { + properties = new Properties(); + properties.decode(in); + int len = in.readInt(); + if (len < 0) + { + throw new IOException("corrupt length"); + } + payload = new byte[len]; + in.readFully(payload); + } + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + * This method is called of subclasses when the payload data needs to be + * created. + * + * @throws IOException If an encoding error occurs. + */ + protected abstract void encodePayload() throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java new file mode 100644 index 00000000000..25b1dc2a04d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -0,0 +1,398 @@ +/* EnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * An envelope entry is a generic container for some number of primitive + * and other envelope entries. + */ +public abstract class EnvelopeEntry extends Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The envelope that contains this one (if any). */ + protected EnvelopeEntry containingEnvelope; + + /** The contained entries. */ + protected List entries; + + // Constructor. + // ------------------------------------------------------------------------ + + public EnvelopeEntry(int type, Properties properties) + { + super(type, properties); + entries = new LinkedList(); + if (this.properties.get("alias-list") != null) + { + this.properties.remove("alias-list"); + } + } + + protected EnvelopeEntry(int type) + { + super(type); + entries = new LinkedList(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Adds an entry to this envelope. + * + * @param entry The entry to add. + */ + public void add(Entry entry) + { + if (!containsEntry(entry)) + { + if (entry instanceof EnvelopeEntry) + { + ((EnvelopeEntry) entry).setContainingEnvelope(this); + } + entries.add(entry); + payload = null; + makeAliasList(); + } + } + + /** + * Tests if this envelope contains a primitive entry with the + * given alias. + * + * @param alias The alias to test. + * @return True if this envelope (or one of the contained envelopes) + * contains a primitive entry with the given alias. + */ + public boolean containsAlias(String alias) + { + String aliases = getAliasList(); + if (aliases == null) + { + return false; + } + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + { + if (tok.nextToken().equals(alias)) + { + return true; + } + } + return false; + } + + /** + * Tests if this envelope contains the given entry. + * + * @param entry The entry to test. + * @return True if this envelope contains the given entry. + */ + public boolean containsEntry(Entry entry) + { + if (entry instanceof EnvelopeEntry) + { + return entries.contains(entry); + } + else if (entry instanceof PrimitiveEntry) + { + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e.equals(entry)) + return true; + if ((e instanceof EnvelopeEntry) + && ((EnvelopeEntry) e).containsEntry(entry)) + return true; + } + } + return false; + } + + /** + * Returns a copy of all entries this envelope contains. + * + * @return All contained entries. + */ + public List getEntries() + { + return new ArrayList(entries); + } + + /** + * Gets all primitive entries that have the given alias. If there + * are any masked entries that contain the given alias, they will + * be returned as well. + * + * @param alias The alias of the entries to get. + * @return A list of all primitive entries that have the given alias. + */ + public List get(String alias) + { + List result = new LinkedList(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (!((EnvelopeEntry) e).containsAlias(alias)) + { + continue; + } + if (e instanceof MaskableEnvelopeEntry) + { + if (((MaskableEnvelopeEntry) e).isMasked()) + { + result.add(e); + continue; + } + } + result.addAll(((EnvelopeEntry) e).get(alias)); + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).getAlias().equals(alias)) + { + result.add(e); + } + } + } + return result; + } + + /** + * Returns the list of all aliases contained by this envelope, + * separated by a semicolon (';'). + * + * @return The list of aliases. + */ + public String getAliasList() + { + String list = properties.get("alias-list"); + if (list == null) + { + return ""; + } + else + { + return list; + } + } + + /** + * Removes the specified entry. + * + * @param entry The entry. + * @return True if an entry was removed. + */ + public boolean remove(Entry entry) + { + boolean ret = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (e == entry) + { + it.remove(); + ret = true; + break; + } + if (((EnvelopeEntry) e).remove(entry)) + { + ret = true; + break; + } + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).equals(entry)) + { + it.remove(); + ret = true; + break; + } + } + } + if (ret) + { + payload = null; + makeAliasList(); + } + return ret; + } + + /** + * Removes all primitive entries that have the specified alias. + * + * @param alias The alias of the entries to remove. + */ + public void remove(String alias) + { + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + ((EnvelopeEntry) e).remove(alias); + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).getAlias().equals(alias)) + { + it.remove(); + } + } + } + payload = null; + makeAliasList(); + } + + // Protected methods. + // ------------------------------------------------------------------------ + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + ((Entry) it.next()).encode(out); + } + } + + protected void setContainingEnvelope(EnvelopeEntry e) + { + if (containingEnvelope != null) + { + throw new IllegalArgumentException("envelopes may not be shared"); + } + containingEnvelope = e; + } + + protected void decodeEnvelope(DataInputStream in) throws IOException + { + while (true) + { + int type = in.read(); + switch (type) + { + case EncryptedEntry.TYPE: + add(EncryptedEntry.decode(in)); + break; + case PasswordEncryptedEntry.TYPE: + add(PasswordEncryptedEntry.decode(in)); + break; + case PasswordAuthenticatedEntry.TYPE: + add(PasswordAuthenticatedEntry.decode(in)); + break; + case AuthenticatedEntry.TYPE: + add(AuthenticatedEntry.decode(in)); + break; + case CompressedEntry.TYPE: + add(CompressedEntry.decode(in)); + break; + case CertificateEntry.TYPE: + add(CertificateEntry.decode(in)); + break; + case PublicKeyEntry.TYPE: + add(PublicKeyEntry.decode(in)); + break; + case PrivateKeyEntry.TYPE: + add(PrivateKeyEntry.decode(in)); + break; + case CertPathEntry.TYPE: + add(CertPathEntry.decode(in)); + break; + case BinaryDataEntry.TYPE: + add(BinaryDataEntry.decode(in)); + break; + case -1: + return; + default: + throw new MalformedKeyringException("unknown type " + type); + } + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private void makeAliasList() + { + if (entries.isEmpty()) + return; + StringBuffer buf = new StringBuffer(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (entry instanceof EnvelopeEntry) + { + buf.append(((EnvelopeEntry) entry).getAliasList()); + } + else if (entry instanceof PrimitiveEntry) + { + buf.append(((PrimitiveEntry) entry).getAlias()); + } + if (it.hasNext()) + buf.append(';'); + } + properties.put("alias-list", buf.toString()); + if (containingEnvelope != null) + { + containingEnvelope.makeAliasList(); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java new file mode 100644 index 00000000000..d49bd09636d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -0,0 +1,328 @@ +/* GnuPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +/** + * <p>.</p> + */ +public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int USAGE = Registry.GKR_PRIVATE_KEYS + | Registry.GKR_PUBLIC_CREDENTIALS; + + protected String mac; + + protected int maclen; + + protected String cipher; + + protected String mode; + + protected int keylen; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public GnuPrivateKeyring(String mac, int maclen, String cipher, String mode, + int keylen) + { + keyring = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + this.mac = mac; + this.maclen = maclen; + this.cipher = cipher; + this.mode = mode; + this.keylen = keylen; + } + + public GnuPrivateKeyring() + { + this("HMAC-SHA-1", 20, "AES", "OFB", 16); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean containsPrivateKey(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof PasswordAuthenticatedEntry) + { + return true; + } + } + return false; + } + + public Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + PasswordAuthenticatedEntry e1 = null; + PasswordEncryptedEntry e2 = null; + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordAuthenticatedEntry) + { + e1 = (PasswordAuthenticatedEntry) e; + break; + } + } + if (e1 == null) + { + return null; + } + try + { + e1.verify(password); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("authentication failed"); + } + for (Iterator it = e1.getEntries().iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordEncryptedEntry) + { + e2 = (PasswordEncryptedEntry) e; + break; + } + } + if (e2 == null) + { + return null; + } + try + { + e2.decrypt(password); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("decryption failed"); + } + for (Iterator it = e2.get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PrivateKeyEntry) + { + return ((PrivateKeyEntry) e).getKey(); + } + } + return null; + } + + public void putPrivateKey(String alias, Key key, char[] password) + { + if (containsPrivateKey(alias)) + { + return; + } + alias = fixAlias(alias); + Properties p = new Properties(); + p.put("alias", alias); + PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + PasswordEncryptedEntry enc = new PasswordEncryptedEntry(cipher, mode, + keylen, + new Properties()); + PasswordAuthenticatedEntry auth = new PasswordAuthenticatedEntry( + mac, + maclen, + new Properties()); + enc.add(pke); + auth.add(enc); + try + { + enc.encode(null, password); + auth.encode(null, password); + } + catch (IOException ioe) + { + throw new IllegalArgumentException(ioe.toString()); + } + keyring.add(auth); + } + + public boolean containsPublicKey(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof PublicKeyEntry) + { + return true; + } + } + return false; + } + + public PublicKey getPublicKey(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PublicKeyEntry) + { + return ((PublicKeyEntry) e).getKey(); + } + } + return null; + } + + public void putPublicKey(String alias, PublicKey key) + { + if (containsPublicKey(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new PublicKeyEntry(key, new Date(), p)); + } + + public boolean containsCertPath(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof CertPathEntry) + { + return true; + } + } + return false; + } + + public Certificate[] getCertPath(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertPathEntry) + { + return ((CertPathEntry) e).getCertPath(); + } + } + return null; + } + + public void putCertPath(String alias, Certificate[] path) + { + if (containsCertPath(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertPathEntry(path, new Date(), p)); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (in.read() != USAGE) + { + throw new MalformedKeyringException("incompatible keyring usage"); + } + if (in.read() != PasswordAuthenticatedEntry.TYPE) + { + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + } + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), + password); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java new file mode 100644 index 00000000000..318eb036fc8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -0,0 +1,146 @@ +/* GnuPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import java.security.cert.Certificate; + +import gnu.java.security.Registry; + +public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring +{ + + // Fields. + // ------------------------------------------------------------------------ + + public static final int USAGE = Registry.GKR_CERTIFICATES; + + // Constructors. + // ------------------------------------------------------------------------ + + public GnuPublicKeyring(String mac, int macLen) + { + keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + } + + public GnuPublicKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public boolean containsCertificate(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof CertificateEntry) + { + return true; + } + } + return false; + } + + public Certificate getCertificate(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertificateEntry) + { + return ((CertificateEntry) e).getCertificate(); + } + } + return null; + } + + public void putCertificate(String alias, Certificate cert) + { + if (containsCertificate(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertificateEntry(cert, new Date(), p)); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (in.read() != USAGE) + { + throw new MalformedKeyringException("incompatible keyring usage"); + } + if (in.read() != PasswordAuthenticatedEntry.TYPE) + { + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + } + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), + password); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java new file mode 100644 index 00000000000..56f467df26e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java @@ -0,0 +1,164 @@ +/* IKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +/** + * <p>The top-level interface to a <i>keyring:</i> a file that is used to + * store and protect public and private cryptographic keys.</p> + * + * <p>A <i>keyring</i> is modelled as a mapping of one <i>alias</i> to one or + * more <i>entries</i> (optionally of different types).</p> + * + * <p>See also the sub-interfaces {@link IPublicKeyring} and + * {@link IPrivateKeyring} for special types of <i>keyrings</i> --the difference + * being in the type of entries they contain.</p> + */ +public interface IKeyring +{ + + /** + * <p>Property name for the source of data to load the keyring from. The + * value mapped must be a {@link java.io.InputStream}.</p> + */ + public static final String KEYRING_DATA_IN = "gnu.crypto.keyring.data.in"; + + /** + * <p>Property name for the data sink to store the keyring to. The value + * mapped must be a {@link java.io.OutputStream}.</p> + */ + public static final String KEYRING_DATA_OUT = "gun.crypto.keyring.data.out"; + + /** + * <p>Property name for the keyring's top-level password, used to + * authenticate and/or transform the store itself. The mapped value must be a + * char array.</p> + */ + public static final String KEYRING_PASSWORD = "gnu.crypto.keyring.password"; + + /** + * <p>Loads a keyring into memory.</p> + * + * <p>What happens to the current contents of this keyring? are the new ones + * merged with the current ones or do they simply replace them?</p> + * + * @param attributes The attributes that designate the source where the store + * is to be loaded from. What happens + * @throws IllegalArgumentException If the attributes are inappropriate. + * @throws IOException If the keyring file cannot be read. + * @throws SecurityException If the given password is incorrect, or if the + * top-level authentication or decryption fails. + */ + void load(Map attributes) throws IOException; + + /** + * <p>Stores the contents of this keyring to persistent storage as specified + * by the designated <code>attributes</code>.</p> + * + * @param attributes the attributes that define where the contents of this + * keyring will be stored. + * @throws IOException if an exception occurs during the process. + */ + void store(Map attributes) throws IOException; + + /** + * <p>Resets this keyring, clearing all sensitive data. This method always + * suceeds.</p> + */ + void reset(); + + /** + * <p>Returns the number of entries in this keyring.</p> + * + * @return The number of current entries in this keyring. + */ + int size(); + + /** + * <p>Returns an {@link Enumeration} of all aliases (instances of + * {@link String}) in this keyring.</p> + * + * @return The enumeration of {@link String}s each representing an + * <i>alias</i> found in this keyring. + */ + Enumeration aliases(); + + /** + * Tests whether or not this keyring contains the given alias. + * + * @param alias The alias to check. + * @return true if this keyring contains the alias. + */ + boolean containsAlias(String alias); + + /** + * <p>Returns a {@link List} of entries (instances of {@link Entry}) for the + * given <code>alias</code>, or <code>null</code> if there no such entry + * exists.</p> + * + * @param alias The alias of the entry(ies) to return. + * @return A list of all entries (instances of {@link Entry} that have the + * given <code>alias</code>, or <code>null</code> if no one {@link Entry} can + * be found with the designated <code>alias</code>. + */ + List get(String alias); + + /** + * <p>Adds a designated {@link Entry} to this keyring.</p> + * + * <p>What happens if there is already an entry with the same alias?</p> + * + * @param entry The entry to put in this keyring. + */ + void add(Entry entry); + + /** + * <p>Removes an entry with the designated <code>alias</code> from this + * keyring. Does nothing if there was no such entry.</p> + * + * <p>What happens if there are more than one?</p> + * + * @param alias The alias of the entry to remove. + */ + void remove(String alias); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java new file mode 100644 index 00000000000..66bbd84f568 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java @@ -0,0 +1,142 @@ +/* IPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; + +/** + * <p>An interface to private, or "personal", keyrings, which contain private + * credentials. The contract is that each such entry is known by a unique + * <i>alias</i>.</p> + * + * <p>What about public keys? and certificate-path?</p> + */ +public interface IPrivateKeyring extends IKeyring +{ + + /** + * <p>Tests if this keyring contains a private key entry with the given + * <code>alias</code>.</p> + * + * @param alias The alias to check. + * @return <code>true</code> if this keyring contains a private key with the + * given <code>alias</code>; <code>false</code> otherwise.</p> + */ + boolean containsPrivateKey(String alias); + + /** + * <p>Returns the private key with the given <code>alias</code>.</p> + * + * @param alias The alias of the private key to find. + * @param password The password of the private key. + * @return The private, or secret, key if one is found; <code>null</code> if + * none were found. + * @throws UnrecoverableKeyException If the private key could not be + * recovered, possibly due to a bad password. + */ + Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException; + + /** + * <p>Adds a private key to this keyring.</p> + * + * @param alias The alias of the private key. + * @param key The private key. + * @param password The password used to protect this private key. + */ + void putPrivateKey(String alias, Key key, char[] password); + + /** + * <p>Checks if this keyring contains a public key with the given + * <code>alias</code>.</p> + * + * @param alias The alias to test. + * @return <code>true</code> if this keyring contains a public key entry with + * the given <code>alias</code>; <code>false</code> otherwise. + */ + boolean containsPublicKey(String alias); + + /** + * <p>Returns the public key with the given <code>alias</code>, or + * <code>null</code> if there is no such entry.</p> + * + * @param alias The alias of the public key to find. + * @return The public key; or <code>null</code> if none were found. + */ + PublicKey getPublicKey(String alias); + + /** + * <p>Sets a public key entry.</p> + * + * @param alias The alias for this public key. + * @param key The public key. + */ + void putPublicKey(String alias, PublicKey key); + + /** + * <p>Checks if this keyring contains a certificate path with the given + * <code>alias</code>.</p> + * + * @param alias The alias to check. + * @return <code>true</code> if this keyring contains a certificate path with + * the given <code>alias</code>; <code>false</code> otherwise. + */ + boolean containsCertPath(String alias); + + /** + * <p>Returns the certificate path with the given <code>alias</code>, or + * <code>null</code> if there is no such entry.</p> + * + * @param alias The alias of the certificate path to find. + * @return The certificate path for the designated <code>alias</code>; or + * <code>null</code> if none were found. + */ + Certificate[] getCertPath(String alias); + + /** + * <p>Sets a certificate path entry.</p> + * + * @param alias The alias for this certificate path. + * @param path The certificate path. + */ + void putCertPath(String alias, Certificate[] path); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java new file mode 100644 index 00000000000..ccf9ca73b55 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java @@ -0,0 +1,81 @@ +/* IPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.cert.Certificate; + +/** + * <p>An interface for keyrings that contain trusted (by the owner) public + * credentials (incl. certificates).</p> + * + * @see IKeyring + */ +public interface IPublicKeyring extends IKeyring +{ + + /** + * <p>Tests if this keyring contains a certificate entry with the specified + * <code>alias</code>.</p> + * + * @param alias The alias of the certificate to check. + * @return <code>true</code> if this keyring contains a certificate entry + * that has the given <code>alias</code>; <code>false</code> otherwise. + */ + boolean containsCertificate(String alias); + + /** + * <p>Returns a certificate that has the given <code>alias</code>, or + * <code>null</code> if this keyring has no such entry.</p> + * + * @param alias The alias of the certificate to find. + * @return The certificate with the designated <code>alias</code>, or + * <code>null</code> if none found. + */ + Certificate getCertificate(String alias); + + /** + * <p>Adds a certificate in this keyring, with the given <code>alias</code>.</p> + * + * <p>What happens if there is already a certificate entry with this alias?</p> + * + * @param alias The alias of this certificate entry. + * @param cert The certificate. + */ + void putCertificate(String alias, Certificate cert); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java new file mode 100644 index 00000000000..44c953946d4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java @@ -0,0 +1,58 @@ +/* MalformedKeyringException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; + +public class MalformedKeyringException extends IOException +{ + + // Constructors. + // ------------------------------------------------------------------------ + + public MalformedKeyringException() + { + super(); + } + + public MalformedKeyringException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java new file mode 100644 index 00000000000..7fed7c40c15 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -0,0 +1,148 @@ +/* MaskableEnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.ArrayList; +import java.util.List; + +/** + * An envelope entry that can be "masked" -- placed in a state where the + * envelope's contents cannot be accessed, due to the envelope not being + * fully decoded, for example. + */ +public abstract class MaskableEnvelopeEntry extends EnvelopeEntry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The masked state. */ + protected boolean masked; + + // Constructors. + // ------------------------------------------------------------------------ + + public MaskableEnvelopeEntry(int type, Properties properties) + { + super(type, properties); + } + + protected MaskableEnvelopeEntry(int type) + { + super(type); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Sets the masked state to the specified value. + * + * @param masked The new masked state. + */ + protected final void setMasked(boolean masked) + { + this.masked = masked; + } + + /** + * Gets the masked state of this object. Certain operations on this object + * will fail if it is masked. + * + * @return The current masked state. + */ + public boolean isMasked() + { + return masked; + } + + public void add(Entry entry) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + super.add(entry); + } + + public boolean containsEntry(Entry entry) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return super.containsEntry(entry); + } + + public List getEntries() + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return new ArrayList(entries); + } + + public List get(String alias) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return super.get(alias); + } + + public boolean remove(Entry entry) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return super.remove(entry); + } + + public void remove(String alias) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + super.remove(alias); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java new file mode 100644 index 00000000000..fcf2be746c9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java @@ -0,0 +1,137 @@ +/* MeteredInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +final class MeteredInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------ + + private int count; + + private final int limit; + + // Constructor. + // ------------------------------------------------------------------------ + + MeteredInputStream(InputStream in, int limit) + { + super(in); + if (limit < 0) + throw new IllegalArgumentException("limit must be nonnegative"); + this.limit = limit; + count = 0; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Tests if the number of bytes read has reached the limit. + * + * @return True if the limit has been reached. + */ + public boolean limitReached() + { + return count == limit; + } + + public int available() throws IOException + { + return Math.min(in.available(), limit - count); + } + + public void close() throws IOException + { + in.close(); + } + + public void mark(int readLimit) + { + } + + public boolean markSupported() + { + return false; + } + + public int read() throws IOException + { + if (limitReached()) + return -1; + int i = in.read(); + if (i != -1) + count++; + return i; + } + + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (limitReached()) + return -1; + int i = in.read(buf, off, Math.min(len, limit - count)); + if (i != -1) + count += i; + return i; + } + + public void reset() throws IOException + { + } + + public long skip(long len) throws IOException + { + if (limitReached()) + return 0L; + len = Math.min(len, limit - count); + len = in.skip(len); + count += (int) len; + return len; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java new file mode 100644 index 00000000000..2e3a0d145c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -0,0 +1,285 @@ +/* PasswordAuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Iterator; +import java.util.HashMap; + +/** + * <p>An entry authenticated with a password-based MAC.</p> + */ +public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 3; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PasswordAuthenticatedEntry(String mac, int maclen, + Properties properties) + { + super(TYPE, properties); + + if (mac == null || mac.length() == 0) + { + throw new IllegalArgumentException("no MAC specified"); + } + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(maclen)); + setMasked(false); + } + + private PasswordAuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static PasswordAuthenticatedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.properties.decode(in); + IMac mac = entry.getMac(password); + int len = in.readInt() - mac.macSize(); + MeteredInputStream min = new MeteredInputStream(in, len); + MacInputStream macin = new MacInputStream(min, mac); + DataInputStream in2 = new DataInputStream(macin); + entry.setMasked(false); + entry.decodeEnvelope(in2); + byte[] macValue = new byte[mac.macSize()]; + in.readFully(macValue); + if (!Arrays.equals(macValue, mac.digest())) + { + throw new MalformedKeyringException("MAC verification failed"); + } + return entry; + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.defaultDecode(in); + if (!entry.properties.containsKey("mac")) + { + throw new MalformedKeyringException("no MAC"); + } + if (!entry.properties.containsKey("maclen")) + { + throw new MalformedKeyringException("no MAC length"); + } + if (!entry.properties.containsKey("salt")) + { + throw new MalformedKeyringException("no salt"); + } + return entry; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public void verify(char[] password) + { + if (!isMasked() || payload == null) + { + return; + } + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString()); + } + + m.update(payload, 0, payload.length - m.macSize()); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (!Arrays.equals(macValue, m.digest())) + { + throw new IllegalArgumentException("MAC verification failed"); + } + try + { + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + payload, + 0, + payload.length + - m.macSize())); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + public void authenticate(char[] password) throws IOException + { + if (isMasked()) + { + throw new IllegalStateException("entry is masked"); + } + byte[] salt = new byte[8]; + new SecureRandom ().nextBytes (salt); + properties.put("salt", Util.toString(salt)); + IMac m = getMac(password); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + authenticate(password); + encode(out); + } + + protected void encodePayload(DataOutputStream out) throws IOException + { + if (payload == null) + { + throw new IllegalStateException("mac not computed"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMac getMac(char[] password) throws MalformedKeyringException + { + if (!properties.containsKey("salt")) + { + throw new MalformedKeyringException("no salt"); + } + byte[] salt = Util.toBytesFromString(properties.get("salt")); + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + { + throw new MalformedKeyringException("no such mac: " + + properties.get("mac")); + } + int keylen = mac.macSize(); + int maclen = 0; + if (!properties.containsKey("maclen")) + { + throw new MalformedKeyringException("no MAC length"); + } + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("bad MAC length"); + } + + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + + byte[] dk = new byte[keylen]; + try + { + kdf.nextBytes(dk, 0, keylen); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, dk); + macAttr.put(IMac.TRUNCATED_SIZE, new Integer(maclen)); + try + { + mac.init(macAttr); + } + catch (InvalidKeyException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java new file mode 100644 index 00000000000..26b4032bdfb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -0,0 +1,301 @@ +/* PasswordEncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +/** + * An envelope that is encrypted with a password-derived key. + */ +public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements + PasswordProtectedEntry, Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 1; + + // Constructors. + // ------------------------------------------------------------------------ + + public PasswordEncryptedEntry(String cipher, String mode, int keylen, + Properties properties) + { + super(TYPE, properties); + if ((cipher == null || cipher.length() == 0) + || (mode == null || mode.length() == 0)) + { + throw new IllegalArgumentException("cipher nor mode can be empty"); + } + this.properties.put("cipher", cipher); + this.properties.put("mode", mode); + this.properties.put("keylen", String.valueOf(keylen)); + setMasked(false); + } + + private PasswordEncryptedEntry() + { + super(TYPE); + setMasked(true); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static PasswordEncryptedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordEncryptedEntry entry = decode(in); + try + { + entry.decrypt(password); + } + catch (WrongPaddingException wpe) + { + throw new MalformedKeyringException("wrong padding in decrypted data"); + } + return entry; + } + + public static PasswordEncryptedEntry decode(DataInputStream in) + throws IOException + { + PasswordEncryptedEntry entry = new PasswordEncryptedEntry(); + entry.defaultDecode(in); + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void decrypt(char[] password) throws IllegalArgumentException, + WrongPaddingException + { + if (!isMasked() || payload == null) + { + return; + } + IMode mode = getMode(password, IMode.DECRYPTION); + IPad padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + for (int i = 0; i < payload.length; i++) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + buf, + 0, + buf.length + - padlen)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(char[] password) throws IOException + { + byte[] salt = new byte[8]; + new SecureRandom ().nextBytes (salt); + properties.put("salt", Util.toString(salt)); + IMode mode = getMode(password, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + encrypt(password); + encode(out); + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + throw new IllegalStateException("not encrypted"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMode getMode(char[] password, int state) + { + String s = properties.get("salt"); + if (s == null) + { + throw new IllegalArgumentException("no salt"); + } + byte[] salt = Util.toBytesFromString(s); + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + { + throw new IllegalArgumentException("no such cipher: " + + properties.get("cipher")); + } + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + { + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, + blockSize); + if (mode == null) + { + throw new IllegalArgumentException("no such mode: " + + properties.get("mode")); + } + + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + + int keylen = 0; + if (!properties.containsKey("keylen")) + { + throw new IllegalArgumentException("no key length"); + } + try + { + keylen = Integer.parseInt(properties.get("keylen")); + } + catch (NumberFormatException nfe) + { + } + byte[] dk = new byte[keylen]; + byte[] iv = new byte[blockSize]; + try + { + kdf.nextBytes(dk, 0, keylen); + kdf.nextBytes(iv, 0, blockSize); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, dk); + modeAttr.put(IMode.STATE, new Integer(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java new file mode 100644 index 00000000000..0dcf73eb8d2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java @@ -0,0 +1,66 @@ +/* PasswordProtectedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataOutputStream; +import java.io.IOException; + +public interface PasswordProtectedEntry +{ + + // Constant. + // ------------------------------------------------------------------------ + + /** + * The iteration count for password-based KDFs. + */ + Integer ITERATION_COUNT = new Integer(1000); + + // Method. + // ------------------------------------------------------------------------ + + /** + * Encodes this entry, protected by a password. + * + * @param out The output stream to encode to. + * @param password The password. + * @throws IOException If an I/O error occurs. + */ + void encode(DataOutputStream out, char[] password) throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java new file mode 100644 index 00000000000..4c9ff0ff1d9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -0,0 +1,129 @@ +/* PrimitiveEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.Date; + +/** + * A primitive entry is an entry that contains a single cryptographic entity. + */ +public abstract class PrimitiveEntry extends Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The creation date. */ + protected Date creationDate; + + // Constructor. + // ------------------------------------------------------------------------ + + protected PrimitiveEntry(int type, Date creationDate, Properties properties) + { + super(type, properties); + if (creationDate == null) + { + this.creationDate = new Date(); + } + else + { + this.creationDate = (Date) creationDate.clone(); + } + if (!this.properties.containsKey("alias") + || this.properties.get("alias").length() == 0) + { + throw new IllegalArgumentException( + "primitive entries MUST have an alias"); + } + this.properties.put("creation-date", String.valueOf(creationDate.getTime())); + } + + protected PrimitiveEntry(int type) + { + super(type); + } + + // Instance method. + // ------------------------------------------------------------------------ + + /** + * Returns the alias of this primitive entry. + * + * @return The alias. + */ + public String getAlias() + { + return properties.get("alias"); + } + + /** + * Returns the creation date of this primitive entry. + * + * @return The creation date. + */ + public Date getCreationDate() + { + return (Date) creationDate.clone(); + } + + public boolean equals(Object object) + { + if (!getClass().equals(object.getClass())) + return false; + return getAlias().equals(((PrimitiveEntry) object).getAlias()); + } + + protected final void makeCreationDate() throws MalformedKeyringException + { + String s = properties.get("creation-date"); + if (s == null) + { + throw new MalformedKeyringException("no creation date"); + } + try + { + creationDate = new Date(Long.parseLong(s)); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("invalid creation date"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java new file mode 100644 index 00000000000..30634991570 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -0,0 +1,221 @@ +/* PrivateKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; + +import gnu.javax.crypto.key.GnuSecretKey; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Date; + +/** + * <p>An immutable class representing a private or secret key entry.</p> + * + * @version $Revision: 1.1 $ + */ +public final class PrivateKeyEntry extends PrimitiveEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 7; + + /** The key. */ + private Key key; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Creates a new key entry.</p> + * + * @param key The key. + * @param creationDate The entry creation date. + * @param properties The entry properties. + * @throws IllegalArgumentException If any parameter is null. + */ + public PrivateKeyEntry(Key key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + + if (key == null) + { + throw new IllegalArgumentException("no private key"); + } + if (!(key instanceof PrivateKey) && !(key instanceof GnuSecretKey)) + { + throw new IllegalArgumentException("not a private or secret key"); + } + this.key = key; + } + + private PrivateKeyEntry() + { + super(TYPE); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static PrivateKeyEntry decode(DataInputStream in) throws IOException + { + PrivateKeyEntry entry = new PrivateKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + { + throw new MalformedKeyringException("no key type"); + } + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW")) + { + entry.key = new GnuSecretKey(entry.payload, null); + } + else if (type.equalsIgnoreCase("PKCS8")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + throw new MalformedKeyringException( + "could not decode PKCS#8 key"); + } + } + } + else + { + throw new MalformedKeyringException("unsupported key type " + type); + } + return entry; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns this entry's key.</p> + * + * @return The key. + */ + public Key getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + String format = key.getFormat(); + if (key instanceof DSSPrivateKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuRSAPrivateKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuDHPrivateKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuSecretKey) + { + properties.put("type", "RAW"); + payload = key.getEncoded(); + } + else if (format != null && format.equals("PKCS#8")) + { + properties.put("type", "PKCS8"); + payload = key.getEncoded(); + } + else + { + throw new IllegalArgumentException("unsupported private key"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Properties.java b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java new file mode 100644 index 00000000000..646b5711df2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java @@ -0,0 +1,227 @@ +/* Properties.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A set of <code>(name => value)</code> pairs used in keyring entries. + * Keys and values are simple strings, with the key never being empty and + * always treated case-insensitively. + */ +public class Properties implements Cloneable +{ + + // Field. + // ------------------------------------------------------------------------ + + private HashMap props; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new properties object. + */ + public Properties() + { + props = new HashMap(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Removes all properties from this object. + */ + public void clear() + { + props.clear(); + } + + /** + * Creates a copy of this properties object. + * + * @return The copy. + */ + public Object clone() + { + Properties result = new Properties(); + result.props.putAll(props); + return result; + } + + /** + * Tests if this object contains a given property name. + * + * @param key The key to test. + * @return True if this object contains the given key. + */ + public boolean containsKey(String key) + { + if (key == null || key.length() == 0) + { + return false; + } + return props.containsKey(canonicalize(key)); + } + + /** + * Tests if this object contains a given property value. + * + * @param value The value to test. + * @return True if this object contains the given value. + */ + public boolean containsValue(String value) + { + if (value == null) + { + return false; + } + return props.containsValue(value); + } + + /** + * Adds a new property to this object. + * + * @param key The key, which can neither be null nor empty. + * @param value The value, which cannot be null. + * @return The old value mapped by the key, if any. + * @throws IllegalArgumentException If either the key or value parameter + + * is null, or if the key is empty. + */ + public String put(String key, String value) + { + if (key == null || value == null || key.length() == 0) + { + throw new IllegalArgumentException("key nor value can be null"); + } + return (String) props.put(canonicalize(key), value); + } + + /** + * Returns the value mapped by the given key, or null if there is no + * such mapping. + * + * @param key + */ + public String get(String key) + { + if (key == null || key.length() == 0) + { + return null; + } + return (String) props.get(canonicalize(key)); + } + + /** + * Removes a key and its value from this object. + * + * @param key The key of the property to remove. + * @return The old value mapped by the key, if any. + */ + public String remove(String key) + { + if (key == null || key.length() == 0) + { + return null; + } + return (String) props.remove(canonicalize(key)); + } + + /** + * Decodes a set of properties from the given input stream. + * + * @param in The input stream. + * @throws IOException If an I/O error occurs. + */ + public void decode(DataInputStream in) throws IOException + { + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + DataInputStream in2 = new DataInputStream(min); + while (!min.limitReached()) + { + String name = in2.readUTF(); + String value = in2.readUTF(); + put(name, value); + } + } + + /** + * Encodes this set of properties to the given output stream. + * + * @param out The output stream to encode to. + * @throws IOException If an I/O error occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out2 = new DataOutputStream(buf); + for (Iterator it = props.entrySet().iterator(); it.hasNext();) + { + Map.Entry entry = (Map.Entry) it.next(); + out2.writeUTF((String) entry.getKey()); + out2.writeUTF((String) entry.getValue()); + } + out.writeInt(buf.size()); + buf.writeTo(out); + } + + public String toString() + { + return props.toString(); + } + + // Own methods. + // ------------------------------------------------------------------------ + + private String canonicalize(String key) + { + return key.toLowerCase(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java new file mode 100644 index 00000000000..528e70cc648 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java @@ -0,0 +1,192 @@ +/* PublicKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.PublicKey; +import java.security.KeyFactory; +import java.security.spec.X509EncodedKeySpec; + +import java.util.Date; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +public final class PublicKeyEntry extends PrimitiveEntry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 6; + + private PublicKey key; + + // Constructor. + // ------------------------------------------------------------------------ + + public PublicKeyEntry(PublicKey key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + + if (key == null) + { + throw new IllegalArgumentException("no key specified"); + } + this.key = key; + } + + private PublicKeyEntry() + { + super(TYPE); + } + + // Class method. + // ------------------------------------------------------------------------ + + public static PublicKeyEntry decode(DataInputStream in) throws IOException + { + PublicKeyEntry entry = new PublicKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + { + throw new MalformedKeyringException("no key type"); + } + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("X.509")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + throw new MalformedKeyringException( + "could not decode X.509 key"); + } + } + } + else + { + throw new MalformedKeyringException("unsupported public key type: " + + type); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the public key. + * + * @return The public key. + */ + public PublicKey getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + if (key instanceof DSSPublicKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuRSAPublicKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuDHPublicKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePublicKey(key); + } + else if (key.getFormat() != null && key.getFormat().equals("X.509")) + { + properties.put("type", "X.509"); + payload = key.getEncoded(); + } + else + { + throw new IllegalArgumentException("cannot encode public key"); + } + } +} |

