Initial Commit
This commit is contained in:
393
iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs
Normal file
393
iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs
Normal file
@@ -0,0 +1,393 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Generator for PGP signatures.</remarks>
|
||||
// TODO Should be able to implement ISigner?
|
||||
public class PgpSignatureGenerator
|
||||
{
|
||||
private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
|
||||
|
||||
private PublicKeyAlgorithmTag keyAlgorithm;
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
private PgpPrivateKey privKey;
|
||||
private ISigner sig;
|
||||
private IDigest dig;
|
||||
private int signatureType;
|
||||
private byte lastb;
|
||||
|
||||
private SignatureSubpacket[] unhashed = EmptySignatureSubpackets;
|
||||
private SignatureSubpacket[] hashed = EmptySignatureSubpackets;
|
||||
|
||||
/// <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
|
||||
public PgpSignatureGenerator(
|
||||
PublicKeyAlgorithmTag keyAlgorithm,
|
||||
HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
this.keyAlgorithm = keyAlgorithm;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
|
||||
dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
|
||||
}
|
||||
|
||||
/// <summary>Initialise the generator for signing.</summary>
|
||||
public void InitSign(
|
||||
int sigType,
|
||||
PgpPrivateKey key)
|
||||
{
|
||||
InitSign(sigType, key, null);
|
||||
}
|
||||
|
||||
/// <summary>Initialise the generator for signing.</summary>
|
||||
public void InitSign(
|
||||
int sigType,
|
||||
PgpPrivateKey key,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.privKey = key;
|
||||
this.signatureType = sigType;
|
||||
|
||||
try
|
||||
{
|
||||
ICipherParameters cp = key.Key;
|
||||
if (random != null)
|
||||
{
|
||||
cp = new ParametersWithRandom(key.Key, random);
|
||||
}
|
||||
|
||||
sig.Init(true, cp);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new PgpException("invalid key.", e);
|
||||
}
|
||||
|
||||
dig.Reset();
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte b)
|
||||
{
|
||||
if (signatureType == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(
|
||||
byte b)
|
||||
{
|
||||
if (b == '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
else if (b == '\n')
|
||||
{
|
||||
if (lastb != '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
doUpdateByte((byte)'\r');
|
||||
doUpdateByte((byte)'\n');
|
||||
}
|
||||
|
||||
private void doUpdateByte(
|
||||
byte b)
|
||||
{
|
||||
sig.Update(b);
|
||||
dig.Update(b);
|
||||
}
|
||||
|
||||
public void Update(
|
||||
params byte[] b)
|
||||
{
|
||||
Update(b, 0, b.Length);
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte[] b,
|
||||
int off,
|
||||
int len)
|
||||
{
|
||||
if (signatureType == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
int finish = off + len;
|
||||
|
||||
for (int i = off; i != finish; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, off, len);
|
||||
dig.BlockUpdate(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHashedSubpackets(
|
||||
PgpSignatureSubpacketVector hashedPackets)
|
||||
{
|
||||
hashed = hashedPackets == null
|
||||
? EmptySignatureSubpackets
|
||||
: hashedPackets.ToSubpacketArray();
|
||||
}
|
||||
|
||||
public void SetUnhashedSubpackets(
|
||||
PgpSignatureSubpacketVector unhashedPackets)
|
||||
{
|
||||
unhashed = unhashedPackets == null
|
||||
? EmptySignatureSubpackets
|
||||
: unhashedPackets.ToSubpacketArray();
|
||||
}
|
||||
|
||||
/// <summary>Return the one pass header associated with the current signature.</summary>
|
||||
public PgpOnePassSignature GenerateOnePassVersion(
|
||||
bool isNested)
|
||||
{
|
||||
return new PgpOnePassSignature(
|
||||
new OnePassSignaturePacket(
|
||||
signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
|
||||
}
|
||||
|
||||
/// <summary>Return a signature object containing the current signature state.</summary>
|
||||
public PgpSignature Generate()
|
||||
{
|
||||
SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed;
|
||||
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
|
||||
{
|
||||
hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow));
|
||||
}
|
||||
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId)
|
||||
&& !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
|
||||
{
|
||||
unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId));
|
||||
}
|
||||
|
||||
int version = 4;
|
||||
byte[] hData;
|
||||
|
||||
try
|
||||
{
|
||||
MemoryStream hOut = new MemoryStream();
|
||||
|
||||
for (int i = 0; i != hPkts.Length; i++)
|
||||
{
|
||||
hPkts[i].Encode(hOut);
|
||||
}
|
||||
|
||||
byte[] data = hOut.ToArray();
|
||||
|
||||
MemoryStream sOut = new MemoryStream(data.Length + 6);
|
||||
sOut.WriteByte((byte)version);
|
||||
sOut.WriteByte((byte)signatureType);
|
||||
sOut.WriteByte((byte)keyAlgorithm);
|
||||
sOut.WriteByte((byte)hashAlgorithm);
|
||||
sOut.WriteByte((byte)(data.Length >> 8));
|
||||
sOut.WriteByte((byte)data.Length);
|
||||
sOut.Write(data, 0, data.Length);
|
||||
|
||||
hData = sOut.ToArray();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception encoding hashed data.", e);
|
||||
}
|
||||
|
||||
sig.BlockUpdate(hData, 0, hData.Length);
|
||||
dig.BlockUpdate(hData, 0, hData.Length);
|
||||
|
||||
hData = new byte[]
|
||||
{
|
||||
(byte) version,
|
||||
0xff,
|
||||
(byte)(hData.Length >> 24),
|
||||
(byte)(hData.Length >> 16),
|
||||
(byte)(hData.Length >> 8),
|
||||
(byte) hData.Length
|
||||
};
|
||||
|
||||
sig.BlockUpdate(hData, 0, hData.Length);
|
||||
dig.BlockUpdate(hData, 0, hData.Length);
|
||||
|
||||
byte[] sigBytes = sig.GenerateSignature();
|
||||
byte[] digest = DigestUtilities.DoFinal(dig);
|
||||
byte[] fingerPrint = new byte[] { digest[0], digest[1] };
|
||||
|
||||
// an RSA signature
|
||||
bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
|
||||
|| keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
|
||||
|
||||
MPInteger[] sigValues = isRsa
|
||||
? PgpUtilities.RsaSigToMpi(sigBytes)
|
||||
: PgpUtilities.DsaSigToMpi(sigBytes);
|
||||
|
||||
return new PgpSignature(
|
||||
new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm,
|
||||
hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues));
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification for the passed in ID and key.</summary>
|
||||
/// <param name="id">The ID we are certifying against the public key.</param>
|
||||
/// <param name="pubKey">The key we are certifying against the ID.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
string id,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
//
|
||||
// hash in the id
|
||||
//
|
||||
UpdateWithIdData(0xb4, Strings.ToByteArray(id));
|
||||
|
||||
return Generate();
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification for the passed in userAttributes.</summary>
|
||||
/// <param name="userAttributes">The ID we are certifying against the public key.</param>
|
||||
/// <param name="pubKey">The key we are certifying against the ID.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
PgpUserAttributeSubpacketVector userAttributes,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
//
|
||||
// hash in the attributes
|
||||
//
|
||||
try
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
|
||||
{
|
||||
packet.Encode(bOut);
|
||||
}
|
||||
UpdateWithIdData(0xd1, bOut.ToArray());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("cannot encode subpacket array", e);
|
||||
}
|
||||
|
||||
return this.Generate();
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification for the passed in key against the passed in master key.</summary>
|
||||
/// <param name="masterKey">The key we are certifying against.</param>
|
||||
/// <param name="pubKey">The key we are certifying.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
PgpPublicKey masterKey,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(masterKey);
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
return Generate();
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification, such as a revocation, for the passed in key.</summary>
|
||||
/// <param name="pubKey">The key we are certifying.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
return Generate();
|
||||
}
|
||||
|
||||
private byte[] GetEncodedPublicKey(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
return pubKey.publicPk.GetEncodedContents();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception preparing key.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private bool packetPresent(
|
||||
SignatureSubpacket[] packets,
|
||||
SignatureSubpacketTag type)
|
||||
{
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private SignatureSubpacket[] insertSubpacket(
|
||||
SignatureSubpacket[] packets,
|
||||
SignatureSubpacket subpacket)
|
||||
{
|
||||
SignatureSubpacket[] tmp = new SignatureSubpacket[packets.Length + 1];
|
||||
tmp[0] = subpacket;
|
||||
packets.CopyTo(tmp, 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void UpdateWithIdData(
|
||||
int header,
|
||||
byte[] idBytes)
|
||||
{
|
||||
this.Update(
|
||||
(byte) header,
|
||||
(byte)(idBytes.Length >> 24),
|
||||
(byte)(idBytes.Length >> 16),
|
||||
(byte)(idBytes.Length >> 8),
|
||||
(byte)(idBytes.Length));
|
||||
this.Update(idBytes);
|
||||
}
|
||||
|
||||
private void UpdateWithPublicKey(
|
||||
PgpPublicKey key)
|
||||
{
|
||||
byte[] keyBytes = GetEncodedPublicKey(key);
|
||||
|
||||
this.Update(
|
||||
(byte) 0x99,
|
||||
(byte)(keyBytes.Length >> 8),
|
||||
(byte)(keyBytes.Length));
|
||||
this.Update(keyBytes);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user