Fwd: ClearSign signatures and required carriage return at the end

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Fwd: ClearSign signatures and required carriage return at the end

cdgendron
 --------------------------------------------------------------
From: Dominic Gendron <[hidden email][hidden email]>
To: [hidden email]
Subject: ClearSign signatures and required carriage return at the end

Hello,

I try to create to apply a ClearSign signature on a text file using the ClearSignedFileProcessor example included with the .Net BouncyCastle source code.

If I try to sign a text file containing the value "Hello World" and it generates the following content at the end of my message. The problem I live is that the "BEGIN PGP SIGNED MESSAGE" label is on the same line as the text content I try to sign.

When I try to verify the signature using the VerifyFile() method, a null value is returned on the following line of the ClearSignedFileProcessor/VerifyFile(). The null problem is simply caused by the bad structure of the file generated by the Sign() method.

PgpSignatureList p3 = (PgpSignatureList) pgpFact.NextPgpObject();
Caused by --> Hello World-----BEGIN PGP SIGNATURE-----

Actually I have 2 "solutions" to avoid this problem :

1. Always have a \r\n at the end of every file I want to sign : "Hello World\r\n".
2. Inside the Sign() method, adding manually the \r\n to always ensure it will be present
            ProcessLine(armoredOutputStream, pgpSignatureGenerator, new byte[] { 13, 10 });
            armoredOutputStream.EndClearText();

The problem about each of these solutions is that it alters the original content to sign...

We actually have to respect a government quality test where they expect to get from us the precise text "Hello World" signed, then encrypted. After that they verify if they obtain the same result on their side by decrypting/unsigning using Symantec PGP.

If I use the 2 proposed solutions I the 2 results will be different because of the new \r\n added and I suppose we will fail the goverrnment test. (different checksum)

Message to send : "Hello Word"
Message they will receive : Hello World\r\n"

I unit tested the ClearSignedFileProcessor and even if the message is similar ... they are not equals.

Hope you can help me ... could it be an improvement to make to the BouncyCastle library ?

Regards.

Dominic

Note :

I searched on the Net before posting here and found out interesting past answers on this forum, but even if it gave me more information, it did not completly solved by problem.




Sample behavior I encounter :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello World-----BEGIN PGP SIGNATURE-----
Version: BCPG C# v1.8.3.0

iKYEAQECABAFAlu0xTkJHHVzZXJuYW1lAAoJEP13OYhS4wamzVsD/jdNYCWrpaE1
G4N50OA0rLxjYV5//8VbR7s9gtEVADrPM+wSLXVbLct2MY3ZLBrgBJ1rJs6WkdJB
k33qE+dXbzwfR+o9AXP7tGRgKGO6hifllpRQxSJifjQ6ukZKPSwmopm0PwmOPHib
rYuUwBHuu7MSoKvVosk28USHS/7IlNa0
=LPnd
-----END PGP SIGNATURE-----
 --------------------------------------------------------------  
Reply | Threaded
Open this post in threaded view
|

RE: Fwd: ClearSign signatures and required carriage return at the end

Eckenfels. Bernd
Hello,

you Must add the linefeed, but according to the RFC it will not be part of the checksum:


 As with binary signatures on text documents, a cleartext signature is
   calculated on the text using canonical <CR><LF> line endings.  The
   line ending (i.e., the <CR><LF>) before the '-----BEGIN PGP
   SIGNATURE-----' line that terminates the signed text is not
   considered part of the signed text.

--
http://www.seeburger.com
________________________________________
From: Dominic Gendron [[hidden email]]
Sent: Wednesday, October 03, 2018 18:45
To: [hidden email]
Subject: [dev-crypto] Fwd: ClearSign signatures and required carriage return at the end

 --------------------------------------------------------------
From: Dominic Gendron <c<mailto:[hidden email]>[hidden email]<mailto:[hidden email]>>
To: [hidden email]<mailto:[hidden email]>
Subject: ClearSign signatures and required carriage return at the end

Hello,

I try to create to apply a ClearSign signature on a text file using the ClearSignedFileProcessor example included with the .Net BouncyCastle source code.

If I try to sign a text file containing the value "Hello World" and it generates the following content at the end of my message. The problem I live is that the "BEGIN PGP SIGNED MESSAGE" label is on the same line as the text content I try to sign.

When I try to verify the signature using the VerifyFile() method, a null value is returned on the following line of the ClearSignedFileProcessor/VerifyFile(). The null problem is simply caused by the bad structure of the file generated by the Sign() method.

PgpSignatureList p3 = (PgpSignatureList) pgpFact.NextPgpObject();
Caused by --> Hello World-----BEGIN PGP SIGNATURE-----

Actually I have 2 "solutions" to avoid this problem :

1. Always have a \r\n at the end of every file I want to sign : "Hello World\r\n".
2. Inside the Sign() method, adding manually the \r\n to always ensure it will be present
            ProcessLine(armoredOutputStream, pgpSignatureGenerator, new byte[] { 13, 10 });
            armoredOutputStream.EndClearText();

The problem about each of these solutions is that it alters the original content to sign...

We actually have to respect a government quality test where they expect to get from us the precise text "Hello World" signed, then encrypted. After that they verify if they obtain the same result on their side by decrypting/unsigning using Symantec PGP.

If I use the 2 proposed solutions I the 2 results will be different because of the new \r\n added and I suppose we will fail the goverrnment test. (different checksum)

Message to send : "Hello Word"
Message they will receive : Hello World\r\n"

I unit tested the ClearSignedFileProcessor and even if the message is similar ... they are not equals.

Hope you can help me ... could it be an improvement to make to the BouncyCastle library ?

Regards.

Dominic

Note :

I searched on the Net before posting here and found out interesting past answers on this forum, but even if it gave me more information, it did not completly solved by problem.

http://bouncy-castle.1462172.n4.nabble.com/Problem-with-openpgp-examples-ClearSignedFileProcessor-td4656903.html

http://bouncy-castle.1462172.n4.nabble.com/problems-with-BEGIN-and-END-signature-td4450682.html


Sample behavior I encounter :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello World-----BEGIN PGP SIGNATURE-----
Version: BCPG C# v1.8.3.0

iKYEAQECABAFAlu0xTkJHHVzZXJuYW1lAAoJEP13OYhS4wamzVsD/jdNYCWrpaE1
G4N50OA0rLxjYV5//8VbR7s9gtEVADrPM+wSLXVbLct2MY3ZLBrgBJ1rJs6WkdJB
k33qE+dXbzwfR+o9AXP7tGRgKGO6hifllpRQxSJifjQ6ukZKPSwmopm0PwmOPHib
rYuUwBHuu7MSoKvVosk28USHS/7IlNa0
=LPnd
-----END PGP SIGNATURE-----
 --------------------------------------------------------------








SEEBURGER AG            Vorstand/SEEBURGER Executive Board:
Sitz der Gesellschaft/Registered Office:                Axel Haas, Michael Kleeberg, Axel Otto, Dr. Martin Kuntz, Matthias Feßenbecker
Edisonstr. 1
D-75015 Bretten         Vorsitzende des Aufsichtsrats/Chairperson of the SEEBURGER Supervisory Board:
Tel.: 07252 / 96 - 0            Prof. Dr. Simone Zeuchner
Fax: 07252 / 96 - 2222
Internet: http://www.seeburger.de               Registergericht/Commercial Register:
e-mail: [hidden email]               HRB 240708 Mannheim


Dieses E-Mail ist nur für den Empfänger bestimmt, an den es gerichtet ist und kann vertrauliches bzw. unter das Berufsgeheimnis fallendes Material enthalten. Jegliche darin enthaltene Ansicht oder Meinungsäußerung ist die des Autors und stellt nicht notwendigerweise die Ansicht oder Meinung der SEEBURGER AG dar. Sind Sie nicht der Empfänger, so haben Sie diese E-Mail irrtümlich erhalten und jegliche Verwendung, Veröffentlichung, Weiterleitung, Abschrift oder jeglicher Druck dieser E-Mail ist strengstens untersagt. Weder die SEEBURGER AG noch der Absender (Eckenfels. Bernd) übernehmen die Haftung für Viren; es obliegt Ihrer Verantwortung, die E-Mail und deren Anhänge auf Viren zu prüfen.


This email is intended only for the recipient(s) to whom it is addressed. This email may contain confidential material that may be protected by professional secrecy. Any fact or opinion contained, or expression of the material herein, does not necessarily reflect that of SEEBURGER AG. If you are not the addressee or if you have received this email in error, any use, publication or distribution including forwarding, copying or printing is strictly prohibited. Neither SEEBURGER AG, nor the sender (Eckenfels. Bernd) accept liability for viruses; it is your responsibility to check this email and its attachments for viruses.

Reply | Threaded
Open this post in threaded view
|

RE: Fwd: ClearSign signatures and required carriage return at the end

cdgendron
Thanks for your answer.

I now realize using the \r\n was the right thing to do to generate the
clearsigned file, but it caused me problems because I absolutly wanted to
unit test it using the outStr content coming from the VerifyFile() method.

I integrated the \r\n behavior in both methods so I can now auto-add the
\r\n in SignFile() and auto-remove the \r\n from the VerifyFile() original
value I return from it. (Used in unit tests to validate)

Thanks !

Here is my code based on the example

        internal void Sign(
            Stream contentToSignInputStream,
            Stream privateKeyInputStream,
            Stream signedContentOutputStream,
            string password)
        {
           
contentToSignInputStream.ThrowIfNull(nameof(contentToSignInputStream));
           
privateKeyInputStream.ThrowIfNull(nameof(privateKeyInputStream));
           
signedContentOutputStream.ThrowIfNull(nameof(signedContentOutputStream));
            password.ThrowIfNull(nameof(password));

            var pgpSecretKey =
_internalUtilities.ReadSecretKey(privateKeyInputStream);
            var pgpPrivateKey =
pgpSecretKey.ExtractPrivateKey(password.ToCharArray());
            var pgpSignatureGenerator =
_internalUtilities.InitializeSignatureGenerator(pgpSecretKey,
pgpPrivateKey);
            var armoredOutputStream = new
ArmoredOutputStream(signedContentOutputStream);

            armoredOutputStream.BeginClearText(HashAlgorithmTag.Sha512);

            //
            // note the last \n/\r/\r\n in the file is ignored
            //
            var lineOut = new MemoryStream();
            var lookAhead = ReadInputLine(lineOut,
contentToSignInputStream);
            ProcessLine(armoredOutputStream, pgpSignatureGenerator,
lineOut.ToArray());

            if (lookAhead != -1)
            {
                do
                {
                    lookAhead = ReadInputLine(lineOut, lookAhead,
contentToSignInputStream);

                    pgpSignatureGenerator.Update((byte)'\r');
                    pgpSignatureGenerator.Update((byte)'\n');

                    ProcessLine(armoredOutputStream, pgpSignatureGenerator,
lineOut.ToArray());
                }
                while (lookAhead != -1);
            }

            //We add \r\n manually to ensure we respect the PGP clearsign
canonical standard
            ProcessLine(armoredOutputStream, pgpSignatureGenerator, new
byte[] { 13, 10 });
            armoredOutputStream.EndClearText();

            var bcpgOutputStream = new
BcpgOutputStream(armoredOutputStream);
            pgpSignatureGenerator.Generate().Encode(bcpgOutputStream);
            armoredOutputStream.Close();
        }

        internal bool VerifySignature(Stream contentToVerifyInputStream,
Stream publicKeyStream, Stream originalMessageOutputStream = null)
        {
           
contentToVerifyInputStream.ThrowIfNull(nameof(contentToVerifyInputStream));
            publicKeyStream.ThrowIfNull(nameof(publicKeyStream));

            var armoredInputStream = new
ArmoredInputStream(contentToVerifyInputStream);

            var lineOutput = new MemoryStream();
            int lookAhead = ReadInputLine(lineOutput, armoredInputStream);
            var lineSeparator = LineSeparator();

            var innerOriginalMessageOutputStream = new MemoryStream();

            if (lookAhead != -1 && armoredInputStream.IsClearText())
            {
                byte[] line = lineOutput.ToArray();
                innerOriginalMessageOutputStream.Write(line, 0,
GetLengthWithoutSeparatorOrTrailingWhitespace(line));
                innerOriginalMessageOutputStream.Write(lineSeparator, 0,
lineSeparator.Length);

                while (lookAhead != -1 && armoredInputStream.IsClearText())
                {
                    lookAhead = ReadInputLine(lineOutput, lookAhead,
armoredInputStream);

                    line = lineOutput.ToArray();
                    innerOriginalMessageOutputStream.Write(line, 0,
GetLengthWithoutSeparatorOrTrailingWhitespace(line));
                    innerOriginalMessageOutputStream.Write(lineSeparator, 0,
lineSeparator.Length);
                }
            }
            else
            {
                if (lookAhead != -1)
                {
                    byte[] line = lineOutput.ToArray();
                    innerOriginalMessageOutputStream.Write(line, 0,
GetLengthWithoutSeparatorOrTrailingWhitespace(line));
                    innerOriginalMessageOutputStream.Write(lineSeparator, 0,
lineSeparator.Length);
                }
            }

            publicKeyStream =
PgpUtilities.GetDecoderStream(publicKeyStream);
            var pgpPublicKeyRingBundle = new
PgpPublicKeyRingBundle(publicKeyStream);

            var pgpObjectFactory = new PgpObjectFactory(armoredInputStream);
            var pgpSignatureList =
(PgpSignatureList)pgpObjectFactory.NextPgpObject();
            var pgpSignature = pgpSignatureList[0];

           
pgpSignature.InitVerify(pgpPublicKeyRingBundle.GetPublicKey(pgpSignature.KeyId));

            innerOriginalMessageOutputStream.Seek(0, SeekOrigin.Begin);
            lookAhead = ReadInputLine(lineOutput,
innerOriginalMessageOutputStream);
            ProcessLine(pgpSignature, lineOutput.ToArray());

            if (lookAhead != -1)
            {
                do
                {
                    lookAhead = ReadInputLine(lineOutput, lookAhead,
originalMessageOutputStream);

                    pgpSignature.Update((byte)'\r');
                    pgpSignature.Update((byte)'\n');

                    ProcessLine(pgpSignature, lineOutput.ToArray());
                }
                while (lookAhead != -1);
            }

            if (originalMessageOutputStream != null)
            {
                //To remove the \r\n added in the signature method for the
canonical standard
                innerOriginalMessageOutputStream =
RemoveLastStringCharactersBytes(innerOriginalMessageOutputStream, 2);
                innerOriginalMessageOutputStream.Seek(0, SeekOrigin.Begin);
               
innerOriginalMessageOutputStream.CopyTo(originalMessageOutputStream);
            }

            innerOriginalMessageOutputStream.Close();

            return pgpSignature.Verify();
        }

        private MemoryStream RemoveLastStringCharactersBytes(MemoryStream
stream, int numberOfBytesToRemove)
        {
            byte[] buf = stream.GetBuffer();
            Buffer.BlockCopy(buf, numberOfBytesToRemove, buf,
numberOfBytesToRemove, (int)stream.Length);
            stream.SetLength(stream.Length - numberOfBytesToRemove);
            return stream;
        }



--
Sent from: http://bouncy-castle.1462172.n4.nabble.com/Bouncy-Castle-Dev-f1462173.html