diff options
Diffstat (limited to 'libraries/spongycastle/pg/src/main/j2me/org/spongycastle/openpgp/PGPSecretKeyRing.java')
-rw-r--r-- | libraries/spongycastle/pg/src/main/j2me/org/spongycastle/openpgp/PGPSecretKeyRing.java | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/libraries/spongycastle/pg/src/main/j2me/org/spongycastle/openpgp/PGPSecretKeyRing.java b/libraries/spongycastle/pg/src/main/j2me/org/spongycastle/openpgp/PGPSecretKeyRing.java new file mode 100644 index 000000000..b54f34084 --- /dev/null +++ b/libraries/spongycastle/pg/src/main/j2me/org/spongycastle/openpgp/PGPSecretKeyRing.java @@ -0,0 +1,402 @@ +package org.spongycastle.openpgp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.bcpg.BCPGInputStream; +import org.spongycastle.bcpg.PacketTags; +import org.spongycastle.bcpg.PublicSubkeyPacket; +import org.spongycastle.bcpg.SecretKeyPacket; +import org.spongycastle.bcpg.SecretSubkeyPacket; +import org.spongycastle.bcpg.TrustPacket; +import org.spongycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; + +/** + * Class to hold a single master secret key and its subkeys. + * <p> + * Often PGP keyring files consist of multiple master keys, if you are trying to process + * or construct one of these you should use the PGPSecretKeyRingCollection class. + */ +public class PGPSecretKeyRing + extends PGPKeyRing +{ + List keys; + List extraPubKeys; + + PGPSecretKeyRing(List keys) + { + this(keys, new ArrayList()); + } + + private PGPSecretKeyRing(List keys, List extraPubKeys) + { + this.keys = keys; + this.extraPubKeys = extraPubKeys; + } + + public PGPSecretKeyRing( + byte[] encoding, + KeyFingerPrintCalculator fingerPrintCalculator) + throws IOException, PGPException + { + this(new ByteArrayInputStream(encoding), fingerPrintCalculator); + } + + public PGPSecretKeyRing( + InputStream in, + KeyFingerPrintCalculator fingerPrintCalculator) + throws IOException, PGPException + { + this.keys = new ArrayList(); + this.extraPubKeys = new ArrayList(); + + BCPGInputStream pIn = wrap(in); + + int initialTag = pIn.nextPacketTag(); + if (initialTag != PacketTags.SECRET_KEY && initialTag != PacketTags.SECRET_SUBKEY) + { + throw new IOException( + "secret key ring doesn't start with secret key tag: " + + "tag 0x" + Integer.toHexString(initialTag)); + } + + SecretKeyPacket secret = (SecretKeyPacket)pIn.readPacket(); + + // + // ignore GPG comment packets if found. + // + while (pIn.nextPacketTag() == PacketTags.EXPERIMENTAL_2) + { + pIn.readPacket(); + } + + TrustPacket trust = readOptionalTrustPacket(pIn); + + // revocation and direct signatures + List keySigs = readSignaturesAndTrust(pIn); + + List ids = new ArrayList(); + List idTrusts = new ArrayList(); + List idSigs = new ArrayList(); + readUserIDs(pIn, ids, idTrusts, idSigs); + + keys.add(new PGPSecretKey(secret, new PGPPublicKey(secret.getPublicKeyPacket(), trust, keySigs, ids, idTrusts, idSigs, fingerPrintCalculator))); + + + // Read subkeys + while (pIn.nextPacketTag() == PacketTags.SECRET_SUBKEY + || pIn.nextPacketTag() == PacketTags.PUBLIC_SUBKEY) + { + if (pIn.nextPacketTag() == PacketTags.SECRET_SUBKEY) + { + SecretSubkeyPacket sub = (SecretSubkeyPacket)pIn.readPacket(); + + // + // ignore GPG comment packets if found. + // + while (pIn.nextPacketTag() == PacketTags.EXPERIMENTAL_2) + { + pIn.readPacket(); + } + + TrustPacket subTrust = readOptionalTrustPacket(pIn); + List sigList = readSignaturesAndTrust(pIn); + + keys.add(new PGPSecretKey(sub, new PGPPublicKey(sub.getPublicKeyPacket(), subTrust, sigList, fingerPrintCalculator))); + } + else + { + PublicSubkeyPacket sub = (PublicSubkeyPacket)pIn.readPacket(); + + TrustPacket subTrust = readOptionalTrustPacket(pIn); + List sigList = readSignaturesAndTrust(pIn); + + extraPubKeys.add(new PGPPublicKey(sub, subTrust, sigList, fingerPrintCalculator)); + } + } + } + + /** + * Return the public key for the master key. + * + * @return PGPPublicKey + */ + public PGPPublicKey getPublicKey() + { + return ((PGPSecretKey)keys.get(0)).getPublicKey(); + } + + /** + * Return the public key referred to by the passed in keyID if it + * is present. + * + * @param keyID + * @return PGPPublicKey + */ + public PGPPublicKey getPublicKey( + long keyID) + { + PGPSecretKey key = getSecretKey(keyID); + if (key != null) + { + return key.getPublicKey(); + } + + for (int i = 0; i != extraPubKeys.size(); i++) + { + PGPPublicKey k = (PGPPublicKey)keys.get(i); + + if (keyID == k.getKeyID()) + { + return k; + } + } + + return null; + } + + /** + * Return an iterator containing all the public keys. + * + * @return Iterator + */ + public Iterator getPublicKeys() + { + List pubKeys = new ArrayList(); + + for (Iterator it = getSecretKeys(); it.hasNext();) + { + pubKeys.add(((PGPSecretKey)it.next()).getPublicKey()); + } + + pubKeys.addAll(extraPubKeys); + + return Collections.unmodifiableList(pubKeys).iterator(); + } + + /** + * Return the master private key. + * + * @return PGPSecretKey + */ + public PGPSecretKey getSecretKey() + { + return ((PGPSecretKey)keys.get(0)); + } + + /** + * Return an iterator containing all the secret keys. + * + * @return Iterator + */ + public Iterator getSecretKeys() + { + return Collections.unmodifiableList(keys).iterator(); + } + + public PGPSecretKey getSecretKey( + long keyId) + { + for (int i = 0; i != keys.size(); i++) + { + PGPSecretKey k = (PGPSecretKey)keys.get(i); + + if (keyId == k.getKeyID()) + { + return k; + } + } + + return null; + } + + /** + * Return an iterator of the public keys in the secret key ring that + * have no matching private key. At the moment only personal certificate data + * appears in this fashion. + * + * @return iterator of unattached, or extra, public keys. + */ + public Iterator getExtraPublicKeys() + { + return extraPubKeys.iterator(); + } + + public byte[] getEncoded() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + this.encode(bOut); + + return bOut.toByteArray(); + } + + public void encode( + OutputStream outStream) + throws IOException + { + for (int i = 0; i != keys.size(); i++) + { + PGPSecretKey k = (PGPSecretKey)keys.get(i); + + k.encode(outStream); + } + for (int i = 0; i != extraPubKeys.size(); i++) + { + PGPPublicKey k = (PGPPublicKey)extraPubKeys.get(i); + + k.encode(outStream); + } + } + + /** + * Replace the public key set on the secret ring with the corresponding key off the public ring. + * + * @param secretRing secret ring to be changed. + * @param publicRing public ring containing the new public key set. + */ + public static PGPSecretKeyRing replacePublicKeys(PGPSecretKeyRing secretRing, PGPPublicKeyRing publicRing) + { + List newList = new ArrayList(secretRing.keys.size()); + + for (Iterator it = secretRing.keys.iterator(); it.hasNext();) + { + PGPSecretKey sk = (PGPSecretKey)it.next(); + PGPPublicKey pk = publicRing.getPublicKey(sk.getKeyID()); + + newList.add(PGPSecretKey.replacePublicKey(sk, pk)); + } + + return new PGPSecretKeyRing(newList); + } + + /** + * Return a copy of the passed in secret key ring, with the private keys (where present) associated with the master key and sub keys + * are encrypted using a new password and the passed in algorithm. + * + * @param ring the PGPSecretKeyRing to be copied. + * @param oldKeyDecryptor the current decryptor based on the current password for key. + * @param newKeyEncryptor a new encryptor based on a new password for encrypting the secret key material. + * @return the updated key ring. + */ + public static PGPSecretKeyRing copyWithNewPassword( + PGPSecretKeyRing ring, + PBESecretKeyDecryptor oldKeyDecryptor, + PBESecretKeyEncryptor newKeyEncryptor) + throws PGPException + { + List newKeys = new ArrayList(ring.keys.size()); + + for (Iterator keys = ring.getSecretKeys(); keys.hasNext();) + { + PGPSecretKey key = (PGPSecretKey)keys.next(); + + if (key.isPrivateKeyEmpty()) + { + newKeys.add(key); + } + else + { + newKeys.add(PGPSecretKey.copyWithNewPassword(key, oldKeyDecryptor, newKeyEncryptor)); + } + } + + return new PGPSecretKeyRing(newKeys, ring.extraPubKeys); + } + + /** + * Returns a new key ring with the secret key passed in either added or + * replacing an existing one with the same key ID. + * + * @param secRing the secret key ring to be modified. + * @param secKey the secret key to be added. + * @return a new secret key ring. + */ + public static PGPSecretKeyRing insertSecretKey( + PGPSecretKeyRing secRing, + PGPSecretKey secKey) + { + List keys = new ArrayList(secRing.keys); + boolean found = false; + boolean masterFound = false; + + for (int i = 0; i != keys.size();i++) + { + PGPSecretKey key = (PGPSecretKey)keys.get(i); + + if (key.getKeyID() == secKey.getKeyID()) + { + found = true; + keys.set(i, secKey); + } + if (key.isMasterKey()) + { + masterFound = true; + } + } + + if (!found) + { + if (secKey.isMasterKey()) + { + if (masterFound) + { + throw new IllegalArgumentException("cannot add a master key to a ring that already has one"); + } + + keys.add(0, secKey); + } + else + { + keys.add(secKey); + } + } + + return new PGPSecretKeyRing(keys, secRing.extraPubKeys); + } + + /** + * Returns a new key ring with the secret key passed in removed from the + * key ring. + * + * @param secRing the secret key ring to be modified. + * @param secKey the secret key to be removed. + * @return a new secret key ring, or null if secKey is not found. + */ + public static PGPSecretKeyRing removeSecretKey( + PGPSecretKeyRing secRing, + PGPSecretKey secKey) + { + List keys = new ArrayList(secRing.keys); + boolean found = false; + + for (int i = 0; i < keys.size();i++) + { + PGPSecretKey key = (PGPSecretKey)keys.get(i); + + if (key.getKeyID() == secKey.getKeyID()) + { + found = true; + keys.remove(i); + } + } + + if (!found) + { + return null; + } + + return new PGPSecretKeyRing(keys, secRing.extraPubKeys); + } +} |