You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

168 lines
5.8 KiB

using System;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
/// <remarks>
/// General class for reading a PGP object stream.
/// <p>
/// Note: if this class finds a PgpPublicKey or a PgpSecretKey it
/// will create a PgpPublicKeyRing, or a PgpSecretKeyRing for each
/// key found. If all you are trying to do is read a key ring file use
/// either PgpPublicKeyRingBundle or PgpSecretKeyRingBundle.</p>
/// </remarks>
public class PgpObjectFactory
{
private readonly BcpgInputStream bcpgIn;
public PgpObjectFactory(
Stream inputStream)
{
this.bcpgIn = BcpgInputStream.Wrap(inputStream);
}
public PgpObjectFactory(
byte[] bytes)
: this(new MemoryStream(bytes, false))
{
}
/// <summary>Return the next object in the stream, or null if the end is reached.</summary>
/// <exception cref="IOException">On a parse error</exception>
public PgpObject NextPgpObject()
{
PacketTag tag = bcpgIn.NextPacketTag();
if ((int) tag == -1) return null;
switch (tag)
{
case PacketTag.Signature:
{
IList l = Platform.CreateArrayList();
while (bcpgIn.NextPacketTag() == PacketTag.Signature)
{
try
{
l.Add(new PgpSignature(bcpgIn));
}
catch (UnsupportedPacketVersionException)
{
// Signatures of unsupported version MUST BE ignored
// see: https://tests.sequoia-pgp.org/#Detached_signatures_with_unknown_packets
continue;
}
catch (PgpException e)
{
throw new IOException("can't create signature object: " + e);
}
}
PgpSignature[] sigs = new PgpSignature[l.Count];
for (int i = 0; i < l.Count; ++i)
{
sigs[i] = (PgpSignature)l[i];
}
return new PgpSignatureList(sigs);
}
case PacketTag.SecretKey:
try
{
return new PgpSecretKeyRing(bcpgIn);
}
catch (PgpException e)
{
throw new IOException("can't create secret key object: " + e);
}
case PacketTag.PublicKey:
return new PgpPublicKeyRing(bcpgIn);
// TODO Make PgpPublicKey a PgpObject or return a PgpPublicKeyRing
// case PacketTag.PublicSubkey:
// return PgpPublicKeyRing.ReadSubkey(bcpgIn);
case PacketTag.CompressedData:
return new PgpCompressedData(bcpgIn);
case PacketTag.LiteralData:
return new PgpLiteralData(bcpgIn);
case PacketTag.PublicKeyEncryptedSession:
case PacketTag.SymmetricKeyEncryptedSessionKey:
return new PgpEncryptedDataList(bcpgIn);
case PacketTag.OnePassSignature:
{
IList l = Platform.CreateArrayList();
while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature)
{
try
{
l.Add(new PgpOnePassSignature(bcpgIn));
}
catch (PgpException e)
{
throw new IOException("can't create one pass signature object: " + e);
}
}
PgpOnePassSignature[] sigs = new PgpOnePassSignature[l.Count];
for (int i = 0; i < l.Count; ++i)
{
sigs[i] = (PgpOnePassSignature)l[i];
}
return new PgpOnePassSignatureList(sigs);
}
case PacketTag.Marker:
return new PgpMarker(bcpgIn);
case PacketTag.Experimental1:
case PacketTag.Experimental2:
case PacketTag.Experimental3:
case PacketTag.Experimental4:
return new PgpExperimental(bcpgIn);
}
throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag());
}
[Obsolete("Use NextPgpObject() instead")]
public object NextObject()
{
return NextPgpObject();
}
/// <summary>
/// Return all available objects in a list.
/// </summary>
/// <returns>An <c>IList</c> containing all objects from this factory, in order.</returns>
public IList AllPgpObjects()
{
IList result = Platform.CreateArrayList();
PgpObject pgpObject;
while ((pgpObject = NextPgpObject()) != null)
{
result.Add(pgpObject);
}
return result;
}
/// <summary>
/// Read all available objects, returning only those that are assignable to the specified type.
/// </summary>
/// <param name="type">The type of objects to return. All other objects are ignored.</param>
/// <returns>An <c>IList</c> containing the filtered objects from this factory, in order.</returns>
public IList FilterPgpObjects(Type type)
{
IList result = Platform.CreateArrayList();
PgpObject pgpObject;
while ((pgpObject = NextPgpObject()) != null)
{
if (type.IsInstanceOfType(pgpObject))
{
result.Add(pgpObject);
}
}
return result;
}
}
}