diff options
Diffstat (limited to 'crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs')
-rw-r--r-- | crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs b/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs new file mode 100644 index 000000000..14fa37269 --- /dev/null +++ b/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs @@ -0,0 +1,375 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Bcpg.OpenPgp; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples +{ + /** + * A simple utility class that creates clear signed files and verifies them. + * <p> + * To sign a file: ClearSignedFileProcessor -s fileName secretKey passPhrase. + * </p> + * <p> + * To decrypt: ClearSignedFileProcessor -v fileName signatureFile publicKeyFile. + * </p> + */ + public sealed class ClearSignedFileProcessor + { + private ClearSignedFileProcessor() + { + } + + private static int ReadInputLine( + MemoryStream bOut, + Stream fIn) + { + bOut.SetLength(0); + + int lookAhead = -1; + int ch; + + while ((ch = fIn.ReadByte()) >= 0) + { + bOut.WriteByte((byte) ch); + if (ch == '\r' || ch == '\n') + { + lookAhead = ReadPassedEol(bOut, ch, fIn); + break; + } + } + + return lookAhead; + } + + private static int ReadInputLine( + MemoryStream bOut, + int lookAhead, + Stream fIn) + { + bOut.SetLength(0); + + int ch = lookAhead; + + do + { + bOut.WriteByte((byte) ch); + if (ch == '\r' || ch == '\n') + { + lookAhead = ReadPassedEol(bOut, ch, fIn); + break; + } + } + while ((ch = fIn.ReadByte()) >= 0); + + if (ch < 0) + { + lookAhead = -1; + } + + return lookAhead; + } + + private static int ReadPassedEol( + MemoryStream bOut, + int lastCh, + Stream fIn) + { + int lookAhead = fIn.ReadByte(); + + if (lastCh == '\r' && lookAhead == '\n') + { + bOut.WriteByte((byte) lookAhead); + lookAhead = fIn.ReadByte(); + } + + return lookAhead; + } + + /* + * verify a clear text signed file + */ + private static void VerifyFile( + Stream inputStream, + Stream keyIn, + string resultName) + { + ArmoredInputStream aIn = new ArmoredInputStream(inputStream); + Stream outStr = File.Create(resultName); + + // + // write out signed section using the local line separator. + // note: trailing white space needs to be removed from the end of + // each line RFC 4880 Section 7.1 + // + MemoryStream lineOut = new MemoryStream(); + int lookAhead = ReadInputLine(lineOut, aIn); + byte[] lineSep = LineSeparator; + + if (lookAhead != -1 && aIn.IsClearText()) + { + byte[] line = lineOut.ToArray(); + outStr.Write(line, 0, GetLengthWithoutSeparatorOrTrailingWhitespace(line)); + outStr.Write(lineSep, 0, lineSep.Length); + + while (lookAhead != -1 && aIn.IsClearText()) + { + lookAhead = ReadInputLine(lineOut, lookAhead, aIn); + + line = lineOut.ToArray(); + outStr.Write(line, 0, GetLengthWithoutSeparatorOrTrailingWhitespace(line)); + outStr.Write(lineSep, 0, lineSep.Length); + } + } + + outStr.Close(); + + PgpPublicKeyRingBundle pgpRings = new PgpPublicKeyRingBundle(keyIn); + + PgpObjectFactory pgpFact = new PgpObjectFactory(aIn); + PgpSignatureList p3 = (PgpSignatureList) pgpFact.NextPgpObject(); + PgpSignature sig = p3[0]; + + sig.InitVerify(pgpRings.GetPublicKey(sig.KeyId)); + + // + // read the input, making sure we ignore the last newline. + // + Stream sigIn = File.OpenRead(resultName); + + lookAhead = ReadInputLine(lineOut, sigIn); + + ProcessLine(sig, lineOut.ToArray()); + + if (lookAhead != -1) + { + do + { + lookAhead = ReadInputLine(lineOut, lookAhead, sigIn); + + sig.Update((byte) '\r'); + sig.Update((byte) '\n'); + + ProcessLine(sig, lineOut.ToArray()); + } + while (lookAhead != -1); + } + + sigIn.Close(); + + if (sig.Verify()) + { + Console.WriteLine("signature verified."); + } + else + { + Console.WriteLine("signature verification failed."); + } + } + + private static byte[] LineSeparator + { + get { return Encoding.ASCII.GetBytes(SimpleTest.NewLine); } + } + + /* + * create a clear text signed file. + */ + private static void SignFile( + string fileName, + Stream keyIn, + Stream outputStream, + char[] pass, + string digestName) + { + HashAlgorithmTag digest; + + if (digestName.Equals("SHA256")) + { + digest = HashAlgorithmTag.Sha256; + } + else if (digestName.Equals("SHA384")) + { + digest = HashAlgorithmTag.Sha384; + } + else if (digestName.Equals("SHA512")) + { + digest = HashAlgorithmTag.Sha512; + } + else if (digestName.Equals("MD5")) + { + digest = HashAlgorithmTag.MD5; + } + else if (digestName.Equals("RIPEMD160")) + { + digest = HashAlgorithmTag.RipeMD160; + } + else + { + digest = HashAlgorithmTag.Sha1; + } + + PgpSecretKey pgpSecKey = PgpExampleUtilities.ReadSecretKey(keyIn); + PgpPrivateKey pgpPrivKey = pgpSecKey.ExtractPrivateKey(pass); + PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSecKey.PublicKey.Algorithm, digest); + PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator(); + + sGen.InitSign(PgpSignature.CanonicalTextDocument, pgpPrivKey); + + IEnumerator enumerator = pgpSecKey.PublicKey.GetUserIds().GetEnumerator(); + if (enumerator.MoveNext()) + { + spGen.SetSignerUserId(false, (string) enumerator.Current); + sGen.SetHashedSubpackets(spGen.Generate()); + } + + Stream fIn = File.OpenRead(fileName); + ArmoredOutputStream aOut = new ArmoredOutputStream(outputStream); + + aOut.BeginClearText(digest); + + // + // note the last \n/\r/\r\n in the file is ignored + // + MemoryStream lineOut = new MemoryStream(); + int lookAhead = ReadInputLine(lineOut, fIn); + + ProcessLine(aOut, sGen, lineOut.ToArray()); + + if (lookAhead != -1) + { + do + { + lookAhead = ReadInputLine(lineOut, lookAhead, fIn); + + sGen.Update((byte) '\r'); + sGen.Update((byte) '\n'); + + ProcessLine(aOut, sGen, lineOut.ToArray()); + } + while (lookAhead != -1); + } + + fIn.Close(); + + aOut.EndClearText(); + + BcpgOutputStream bOut = new BcpgOutputStream(aOut); + + sGen.Generate().Encode(bOut); + + aOut.Close(); + } + + private static void ProcessLine( + PgpSignature sig, + byte[] line) + { + // note: trailing white space needs to be removed from the end of + // each line for signature calculation RFC 4880 Section 7.1 + int length = GetLengthWithoutWhiteSpace(line); + if (length > 0) + { + sig.Update(line, 0, length); + } + } + + private static void ProcessLine( + Stream aOut, + PgpSignatureGenerator sGen, + byte[] line) + { + int length = GetLengthWithoutWhiteSpace(line); + if (length > 0) + { + sGen.Update(line, 0, length); + } + + aOut.Write(line, 0, line.Length); + } + + private static int GetLengthWithoutSeparatorOrTrailingWhitespace(byte[] line) + { + int end = line.Length - 1; + + while (end >= 0 && IsWhiteSpace(line[end])) + { + end--; + } + + return end + 1; + } + + private static bool IsLineEnding( + byte b) + { + return b == '\r' || b == '\n'; + } + + private static int GetLengthWithoutWhiteSpace( + byte[] line) + { + int end = line.Length - 1; + + while (end >= 0 && IsWhiteSpace(line[end])) + { + end--; + } + + return end + 1; + } + + private static bool IsWhiteSpace( + byte b) + { + return IsLineEnding(b) || b == '\t' || b == ' '; + } + + public static int Main( + string[] args) + { + if (args[0].Equals("-s")) + { + Stream fis = File.OpenRead(args[2]); + Stream fos = File.Create(args[1] + ".asc"); + + Stream keyIn = PgpUtilities.GetDecoderStream(fis); + + string digestName = (args.Length == 4) + ? "SHA1" + : args[4]; + + SignFile(args[1], keyIn, fos, args[3].ToCharArray(), digestName); + + fis.Close(); + fos.Close(); + } + else if (args[0].Equals("-v")) + { + if (args[1].IndexOf(".asc") < 0) + { + Console.Error.WriteLine("file needs to end in \".asc\""); + return 1; + } + + Stream fin = File.OpenRead(args[1]); + Stream fis = File.OpenRead(args[2]); + + Stream keyIn = PgpUtilities.GetDecoderStream(fis); + + VerifyFile(fin, keyIn, args[1].Substring(0, args[1].Length - 4)); + + fin.Close(); + fis.Close(); + } + else + { + Console.Error.WriteLine("usage: ClearSignedFileProcessor [-s file keyfile passPhrase]|[-v sigFile keyFile]"); + } + return 0; + } + } +} |