PgpV3SignatureGenerator
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Date;
using System;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
public class PgpV3SignatureGenerator
{
private readonly PublicKeyAlgorithmTag m_keyAlgorithm;
private readonly HashAlgorithmTag m_hashAlgorithm;
private PgpPrivateKey privKey;
private ISigner sig;
private IDigest dig;
private int signatureType;
private byte lastb;
public PgpV3SignatureGenerator(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
{
if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa)
throw new ArgumentException("Invalid algorithm for V3 signature", "keyAlgorithm");
m_keyAlgorithm = keyAlgorithm;
m_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(m_keyAlgorithm, m_hashAlgorithm, key);
try {
sig.Init(true, ParameterUtilities.WithRandom(key, random));
} 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 PgpOnePassSignature GenerateOnePassVersion(bool isNested)
{
return new PgpOnePassSignature(new OnePassSignaturePacket(signatureType, m_hashAlgorithm, m_keyAlgorithm, privKey.KeyId, isNested));
}
public unsafe PgpSignature Generate()
{
long num = DateTimeUtilities.CurrentUnixMs() / 1000;
Span<byte> span = new Span<byte>(stackalloc byte[5], 5);
span[0] = (byte)signatureType;
Pack.UInt32_To_BE((uint)num, span, 1);
sig.BlockUpdate(span);
dig.BlockUpdate(span);
byte[] encoding = sig.GenerateSignature();
byte[] array = DigestUtilities.DoFinal(dig);
byte[] fingerprint = new byte[2] {
array[0],
array[1]
};
MPInteger[] signature = (m_keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || m_keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral) ? PgpUtilities.RsaSigToMpi(encoding) : PgpUtilities.DsaSigToMpi(encoding);
return new PgpSignature(new SignaturePacket(3, signatureType, privKey.KeyId, m_keyAlgorithm, m_hashAlgorithm, num * 1000, fingerprint, signature));
}
}
}