001: package org.bouncycastle.openpgp;
002:
003: import org.bouncycastle.bcpg.BCPGOutputStream;
004:
005: import java.io.ByteArrayInputStream;
006: import java.io.ByteArrayOutputStream;
007: import java.io.IOException;
008: import java.io.InputStream;
009: import java.io.OutputStream;
010: import java.util.ArrayList;
011: import java.util.Collection;
012: import java.util.HashMap;
013: import java.util.Iterator;
014: import java.util.List;
015: import java.util.Map;
016:
017: /**
018: * Often a PGP key ring file is made up of a succession of master/sub-key key rings.
019: * If you want to read an entire secret key file in one hit this is the class for you.
020: */
021: public class PGPSecretKeyRingCollection {
022: private Map secretRings = new HashMap();
023: private List order = new ArrayList();
024:
025: private PGPSecretKeyRingCollection(Map secretRings, List order) {
026: this .secretRings = secretRings;
027: this .order = order;
028: }
029:
030: public PGPSecretKeyRingCollection(byte[] encoding)
031: throws IOException, PGPException {
032: this (new ByteArrayInputStream(encoding));
033: }
034:
035: /**
036: * Build a PGPSecretKeyRingCollection from the passed in input stream.
037: *
038: * @param in input stream containing data
039: * @throws IOException if a problem parsinh the base stream occurs
040: * @throws PGPException if an object is encountered which isn't a PGPSecretKeyRing
041: */
042: public PGPSecretKeyRingCollection(InputStream in)
043: throws IOException, PGPException {
044: PGPObjectFactory pgpFact = new PGPObjectFactory(in);
045: Object obj;
046:
047: while ((obj = pgpFact.nextObject()) != null) {
048: if (!(obj instanceof PGPSecretKeyRing)) {
049: throw new PGPException(obj.getClass().getName()
050: + " found where PGPSecretKeyRing expected");
051: }
052:
053: PGPSecretKeyRing pgpSecret = (PGPSecretKeyRing) obj;
054: Long key = new Long(pgpSecret.getPublicKey().getKeyID());
055:
056: secretRings.put(key, pgpSecret);
057: order.add(key);
058: }
059: }
060:
061: public PGPSecretKeyRingCollection(Collection collection)
062: throws IOException, PGPException {
063: Iterator it = collection.iterator();
064:
065: while (it.hasNext()) {
066: PGPSecretKeyRing pgpSecret = (PGPSecretKeyRing) it.next();
067: Long key = new Long(pgpSecret.getPublicKey().getKeyID());
068:
069: secretRings.put(key, pgpSecret);
070: order.add(key);
071: }
072: }
073:
074: /**
075: * Return the number of rings in this collection.
076: *
077: * @return size of the collection
078: */
079: public int size() {
080: return order.size();
081: }
082:
083: /**
084: * return the secret key rings making up this collection.
085: */
086: public Iterator getKeyRings() {
087: return secretRings.values().iterator();
088: }
089:
090: /**
091: * Return an iterator of the key rings associated with the passed in userID.
092: * <p>
093: *
094: * @param userID the user ID to be matched.
095: * @param matchPartial if true userID need only be a substring of an actual ID string to match.
096: * @return an iterator (possibly empty) of key rings which matched.
097: * @throws PGPException
098: */
099: public Iterator getKeyRings(String userID, boolean matchPartial)
100: throws PGPException {
101: Iterator it = this .getKeyRings();
102: List rings = new ArrayList();
103:
104: while (it.hasNext()) {
105: PGPSecretKeyRing secRing = (PGPSecretKeyRing) it.next();
106: Iterator uIt = secRing.getSecretKey().getUserIDs();
107:
108: while (uIt.hasNext()) {
109: if (matchPartial) {
110: if (((String) uIt.next()).indexOf(userID) > -1) {
111: rings.add(secRing);
112: }
113: } else {
114: if (uIt.next().equals(userID)) {
115: rings.add(secRing);
116: }
117: }
118: }
119: }
120:
121: return rings.iterator();
122: }
123:
124: /**
125: * Return an iterator of the key rings associated with the passed in userID.
126: *
127: * @param userID the user ID to be matched.
128: * @return an iterator (possibly empty) of key rings which matched.
129: * @throws PGPException
130: */
131: public Iterator getKeyRings(String userID) throws PGPException {
132: return getKeyRings(userID, false);
133: }
134:
135: /**
136: * Return the PGP secret key associated with the given key id.
137: *
138: * @param keyID
139: * @return the secret key
140: * @throws PGPException
141: */
142: public PGPSecretKey getSecretKey(long keyID) throws PGPException {
143: Iterator it = this .getKeyRings();
144:
145: while (it.hasNext()) {
146: PGPSecretKeyRing secRing = (PGPSecretKeyRing) it.next();
147: PGPSecretKey sec = secRing.getSecretKey(keyID);
148:
149: if (sec != null) {
150: return sec;
151: }
152: }
153:
154: return null;
155: }
156:
157: /**
158: * Return the secret key ring which contains the key referred to by keyID.
159: *
160: * @param keyID
161: * @return the secret key ring
162: * @throws PGPException
163: */
164: public PGPSecretKeyRing getSecretKeyRing(long keyID)
165: throws PGPException {
166: Long id = new Long(keyID);
167:
168: if (secretRings.containsKey(id)) {
169: return (PGPSecretKeyRing) secretRings.get(id);
170: }
171:
172: Iterator it = this .getKeyRings();
173:
174: while (it.hasNext()) {
175: PGPSecretKeyRing secretRing = (PGPSecretKeyRing) it.next();
176: PGPSecretKey secret = secretRing.getSecretKey(keyID);
177:
178: if (secret != null) {
179: return secretRing;
180: }
181: }
182:
183: return null;
184: }
185:
186: public byte[] getEncoded() throws IOException {
187: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
188:
189: this .encode(bOut);
190:
191: return bOut.toByteArray();
192: }
193:
194: public void encode(OutputStream outStream) throws IOException {
195: BCPGOutputStream out;
196:
197: if (outStream instanceof BCPGOutputStream) {
198: out = (BCPGOutputStream) outStream;
199: } else {
200: out = new BCPGOutputStream(outStream);
201: }
202:
203: Iterator it = order.iterator();
204: while (it.hasNext()) {
205: PGPSecretKeyRing sr = (PGPSecretKeyRing) secretRings.get(it
206: .next());
207:
208: sr.encode(out);
209: }
210: }
211:
212: /**
213: * Return a new collection object containing the contents of the passed in collection and
214: * the passed in secret key ring.
215: *
216: * @param ringCollection the collection the ring to be added to.
217: * @param secretKeyRing the key ring to be added.
218: * @return a new collection merging the current one with the passed in ring.
219: * @exception IllegalArgumentException if the keyID for the passed in ring is already present.
220: */
221: public static PGPSecretKeyRingCollection addSecretKeyRing(
222: PGPSecretKeyRingCollection ringCollection,
223: PGPSecretKeyRing secretKeyRing) {
224: Long key = new Long(secretKeyRing.getPublicKey().getKeyID());
225:
226: if (ringCollection.secretRings.containsKey(key)) {
227: throw new IllegalArgumentException(
228: "Collection already contains a key with a keyID for the passed in ring.");
229: }
230:
231: Map newSecretRings = new HashMap(ringCollection.secretRings);
232: List newOrder = new ArrayList(ringCollection.order);
233:
234: newSecretRings.put(key, secretKeyRing);
235: newOrder.add(key);
236:
237: return new PGPSecretKeyRingCollection(newSecretRings, newOrder);
238: }
239:
240: /**
241: * Return a new collection object containing the contents of this collection with
242: * the passed in secret key ring removed.
243: *
244: * @param ringCollection the collection the ring to be removed from.
245: * @param secretKeyRing the key ring to be removed.
246: * @return a new collection merging the current one with the passed in ring.
247: * @exception IllegalArgumentException if the keyID for the passed in ring is not present.
248: */
249: public static PGPSecretKeyRingCollection removeSecretKeyRing(
250: PGPSecretKeyRingCollection ringCollection,
251: PGPSecretKeyRing secretKeyRing) {
252: Long key = new Long(secretKeyRing.getPublicKey().getKeyID());
253:
254: if (!ringCollection.secretRings.containsKey(key)) {
255: throw new IllegalArgumentException(
256: "Collection does not contain a key with a keyID for the passed in ring.");
257: }
258:
259: Map newSecretRings = new HashMap(ringCollection.secretRings);
260: List newOrder = new ArrayList(ringCollection.order);
261:
262: newSecretRings.remove(key);
263:
264: for (int i = 0; i < newOrder.size(); i++) {
265: Long r = (Long) newOrder.get(i);
266:
267: if (r.longValue() == key.longValue()) {
268: newOrder.remove(i);
269: break;
270: }
271: }
272:
273: return new PGPSecretKeyRingCollection(newSecretRings, newOrder);
274: }
275: }
|