<PackageReference Include="BouncyCastle.Cryptography" Version="2.7.0-beta.98" />

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