Package org.bouncycastle.openpgp

Source Code of org.bouncycastle.openpgp.PGPSecretKeyRing

package org.bouncycastle.openpgp;

import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.PacketTags;
import org.bouncycastle.bcpg.SecretKeyPacket;
import org.bouncycastle.bcpg.SecretSubkeyPacket;
import org.bouncycastle.bcpg.TrustPacket;
import org.bouncycastle.bcpg.PublicSubkeyPacket;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.security.SecureRandom;
import java.security.NoSuchProviderException;
import java.security.Provider;

/**
* 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)
        throws IOException, PGPException
    {
        this(new ByteArrayInputStream(encoding));
    }
   
    public PGPSecretKeyRing(
        InputStream    in)
        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)));


        // 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)));
            }
            else
            {
                PublicSubkeyPacket sub = (PublicSubkeyPacket)pIn.readPacket();

                TrustPacket subTrust = readOptionalTrustPacket(pIn);
                List        sigList = readSignaturesAndTrust(pIn);

                extraPubKeys.add(new PGPPublicKey(sub, subTrust, sigList));
            }
        }
    }

    /**
     * Return the public key for the master key.
     *
     * @return PGPPublicKey
     */
    public PGPPublicKey getPublicKey()
    {
        return ((PGPSecretKey)keys.get(0)).getPublicKey();
    }

    /**
     * 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 = null;
            try
            {
                pk = publicRing.getPublicKey(sk.getKeyID());
            }
            catch (PGPException e)
            {
                throw new IllegalStateException(e.toString());
            }

            newList.add(PGPSecretKey.replacePublicKey(sk, pk));
        }

        return new PGPSecretKeyRing(newList);
    }

    /**
     * Return a copy of the passed in secret key ring, with the master key and sub keys encrypted
     * using a new password and the passed in algorithm.
     *
     * @param ring the PGPSecretKeyRing to be copied.
     * @param oldPassPhrase the current password for key.
     * @param newPassPhrase the new password for the key.
     * @param newEncAlgorithm the algorithm to be used for the encryption.
     * @param rand source of randomness.
     * @param provider name of the provider to use
     */
    public static PGPSecretKeyRing copyWithNewPassword(
        PGPSecretKeyRing ring,
        char[]           oldPassPhrase,
        char[]           newPassPhrase,
        int              newEncAlgorithm,
        SecureRandom     rand,
        String           provider)
        throws PGPException, NoSuchProviderException
    {
        return copyWithNewPassword(ring, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand, PGPUtil.getProvider(provider));
    }

    /**
     * Return a copy of the passed in secret key ring, with the master key and sub keys encrypted
     * using a new password and the passed in algorithm.
     *
     * @param ring the PGPSecretKeyRing to be copied.
     * @param oldPassPhrase the current password for key.
     * @param newPassPhrase the new password for the key.
     * @param newEncAlgorithm the algorithm to be used for the encryption.
     * @param rand source of randomness.
     * @param provider provider to use
     */
    public static PGPSecretKeyRing copyWithNewPassword(
        PGPSecretKeyRing ring,
        char[]           oldPassPhrase,
        char[]           newPassPhrase,
        int              newEncAlgorithm,
        SecureRandom     rand,
        Provider         provider)
        throws PGPException
    {
        List newKeys = new ArrayList(ring.keys.size());

        for (Iterator keys = ring.getSecretKeys(); keys.hasNext();)
        {
            newKeys.add(PGPSecretKey.copyWithNewPassword((PGPSecretKey)keys.next(), oldPassPhrase, newPassPhrase, newEncAlgorithm, rand, provider));
        }

        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);
    }
}
TOP

Related Classes of org.bouncycastle.openpgp.PGPSecretKeyRing

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.