PgpSignatureGenerator
using Org.BouncyCastle.Bcpg.Sig;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC.Rfc8032;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
public class PgpSignatureGenerator
{
private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
private readonly PublicKeyAlgorithmTag keyAlgorithm;
private readonly 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;
public PgpSignatureGenerator(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
{
this.keyAlgorithm = keyAlgorithm;
this.hashAlgorithm = hashAlgorithm;
dig = PgpUtilities.CreateDigest(hashAlgorithm);
}
public void InitSign(int sigType, PgpPrivateKey privKey)
{
InitSign(sigType, privKey, null);
}
public void InitSign(int sigType, PgpPrivateKey privKey, SecureRandom random)
{
this.privKey = privKey;
signatureType = sigType;
AsymmetricKeyParameter key = privKey.Key;
sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
try {
ICipherParameters cipherParameters = key;
if (keyAlgorithm != PublicKeyAlgorithmTag.EdDsa)
cipherParameters = ParameterUtilities.WithRandom(cipherParameters, random);
sig.Init(true, cipherParameters);
} catch (InvalidKeyException innerException) {
throw new PgpException("invalid key.", innerException);
}
dig.Reset();
lastb = 0;
}
public void Update(byte b)
{
if (signatureType == 1)
DoCanonicalUpdateByte(b);
else
DoUpdateByte(b);
}
private void DoCanonicalUpdateByte(byte b)
{
switch (b) {
case 13:
DoUpdateCRLF();
break;
case 10:
if (lastb != 13)
DoUpdateCRLF();
break;
default:
DoUpdateByte(b);
break;
}
lastb = b;
}
private void DoUpdateCRLF()
{
DoUpdateByte(13);
DoUpdateByte(10);
}
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)
{
Update(b.AsSpan(off, len));
}
public void Update(ReadOnlySpan<byte> input)
{
if (signatureType == 1) {
for (int i = 0; i < input.Length; i++) {
DoCanonicalUpdateByte(input[i]);
}
} else {
sig.BlockUpdate(input);
dig.BlockUpdate(input);
}
}
public void SetHashedSubpackets(PgpSignatureSubpacketVector hashedPackets)
{
hashed = ((hashedPackets == null) ? EmptySignatureSubpackets : hashedPackets.ToSubpacketArray());
}
public void SetUnhashedSubpackets(PgpSignatureSubpacketVector unhashedPackets)
{
unhashed = ((unhashedPackets == null) ? EmptySignatureSubpackets : unhashedPackets.ToSubpacketArray());
}
public PgpOnePassSignature GenerateOnePassVersion(bool isNested)
{
return new PgpOnePassSignature(new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
}
public PgpSignature Generate()
{
SignatureSubpacket[] array = hashed;
SignatureSubpacket[] array2 = unhashed;
if (!IsPacketPresent(hashed, SignatureSubpacketTag.CreationTime))
array = InsertSubpacket(array, new SignatureCreationTime(false, DateTime.UtcNow));
if (!IsPacketPresent(hashed, SignatureSubpacketTag.IssuerKeyId) && !IsPacketPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
array2 = InsertSubpacket(array2, new IssuerKeyId(false, privKey.KeyId));
int num = 4;
byte[] array4;
try {
MemoryStream memoryStream = new MemoryStream();
for (int i = 0; i != array.Length; i++) {
array[i].Encode(memoryStream);
}
byte[] array3 = memoryStream.ToArray();
MemoryStream memoryStream2 = new MemoryStream(array3.Length + 6);
memoryStream2.WriteByte((byte)num);
memoryStream2.WriteByte((byte)signatureType);
memoryStream2.WriteByte((byte)keyAlgorithm);
memoryStream2.WriteByte((byte)hashAlgorithm);
memoryStream2.WriteByte((byte)(array3.Length >> 8));
memoryStream2.WriteByte((byte)array3.Length);
memoryStream2.Write(array3, 0, array3.Length);
array4 = memoryStream2.ToArray();
} catch (IOException innerException) {
throw new PgpException("exception encoding hashed data.", innerException);
}
sig.BlockUpdate(array4, 0, array4.Length);
dig.BlockUpdate(array4, 0, array4.Length);
array4 = new byte[6] {
(byte)num,
byte.MaxValue,
(byte)(array4.Length >> 24),
(byte)(array4.Length >> 16),
(byte)(array4.Length >> 8),
(byte)array4.Length
};
sig.BlockUpdate(array4, 0, array4.Length);
dig.BlockUpdate(array4, 0, array4.Length);
byte[] array5 = sig.GenerateSignature();
byte[] array6 = DigestUtilities.DoFinal(dig);
byte[] fingerprint = new byte[2] {
array6[0],
array6[1]
};
MPInteger[] signature;
if (keyAlgorithm != PublicKeyAlgorithmTag.EdDsa)
signature = ((keyAlgorithm != PublicKeyAlgorithmTag.RsaSign && keyAlgorithm != PublicKeyAlgorithmTag.RsaGeneral) ? PgpUtilities.DsaSigToMpi(array5) : PgpUtilities.RsaSigToMpi(array5));
else {
int num2 = array5.Length;
if (num2 == Ed25519.SignatureSize)
signature = new MPInteger[2] {
new MPInteger(new BigInteger(1, array5, 0, 32)),
new MPInteger(new BigInteger(1, array5, 32, 32))
};
else {
if (num2 != Ed448.SignatureSize)
throw new InvalidOperationException();
signature = new MPInteger[2] {
new MPInteger(new BigInteger(1, Arrays.Prepend(array5, 64))),
new MPInteger(BigInteger.Zero)
};
}
}
return new PgpSignature(new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm, hashAlgorithm, array, array2, fingerprint, signature));
}
public PgpSignature GenerateCertification(string id, PgpPublicKey pubKey)
{
UpdateWithPublicKey(pubKey);
UpdateWithIdData(180, Strings.ToUtf8ByteArray(id));
return Generate();
}
public PgpSignature GenerateCertification(PgpUserAttributeSubpacketVector userAttributes, PgpPublicKey pubKey)
{
UpdateWithPublicKey(pubKey);
try {
MemoryStream memoryStream = new MemoryStream();
UserAttributeSubpacket[] array = userAttributes.ToSubpacketArray();
for (int i = 0; i < array.Length; i++) {
array[i].Encode(memoryStream);
}
UpdateWithIdData(209, memoryStream.ToArray());
} catch (IOException innerException) {
throw new PgpException("cannot encode subpacket array", innerException);
}
return Generate();
}
public PgpSignature GenerateCertification(PgpPublicKey masterKey, PgpPublicKey pubKey)
{
UpdateWithPublicKey(masterKey);
UpdateWithPublicKey(pubKey);
return Generate();
}
public PgpSignature GenerateCertification(PgpPublicKey pubKey)
{
UpdateWithPublicKey(pubKey);
return Generate();
}
private static byte[] GetEncodedPublicKey(PgpPublicKey pubKey)
{
try {
return pubKey.publicPk.GetEncodedContents();
} catch (IOException innerException) {
throw new PgpException("exception preparing key.", innerException);
}
}
private static bool IsPacketPresent(SignatureSubpacket[] packets, SignatureSubpacketTag type)
{
for (int i = 0; i != packets.Length; i++) {
if (packets[i].SubpacketType == type)
return true;
}
return false;
}
private static SignatureSubpacket[] InsertSubpacket(SignatureSubpacket[] packets, SignatureSubpacket subpacket)
{
return Arrays.Prepend(packets, subpacket);
}
private void UpdateWithIdData(int header, byte[] idBytes)
{
Update((byte)header, (byte)(idBytes.Length >> 24), (byte)(idBytes.Length >> 16), (byte)(idBytes.Length >> 8), (byte)idBytes.Length);
Update(idBytes);
}
private void UpdateWithPublicKey(PgpPublicKey key)
{
byte[] encodedPublicKey = GetEncodedPublicKey(key);
Update(153, (byte)(encodedPublicKey.Length >> 8), (byte)encodedPublicKey.Length);
Update(encodedPublicKey);
}
}
}