Tuesday, September 8, 2015

C# Bouncy Castle File Decryption

I had a hard time finding a good sample of decrypting a PGP-encrypted file in C# so I decided to write this post.

Bouncy Castle works with streams for the most part.  So first you need to open the file as a stream, then get a special decoder stream using PgpUtilities:

// Comment
using (FileStream fsEncryptedFile = File.Open(ENCRYPTED_FILENAME, FileMode.Open)) {
 using (Stream decoderStream = PgpUtilities.GetDecoderStream(fsEncryptedFile))
 {
Next we have to create a PgpObjectFactory using that stream which will provide us with PgpObjects. We're looking for a PgpEncryptedDataList so we might have to skip the first object which could be a marker:
PgpObjectFactory factory = new PgpObjectFactory(decoderStream);
PgpObject obj = factory.NextPgpObject();
if (!(obj is PgpEncryptedDataList))
{
 obj = factory.NextPgpObject(); // first object might be a PGP marker packet
}
PgpEncryptedDataList edl = obj as PgpEncryptedDataList;
With our PgpEncryptedDataList we find PgpPublicKeyEncryptedData, and find the key. Here we open a secret keyring file and find the key based on the KeyId in the data and decrypt it using a passphrase:
PgpEncryptedDataList edl = obj as PgpEncryptedDataList;
foreach (PgpPublicKeyEncryptedData data in edl.GetEncryptedDataObjects())
{
    PgpPrivateKey privateKey = null;
    using (FileStream fsKeyring = File.Open(KEYRING_FILENAME, FileMode.Open))
    {
     PgpSecretKeyRingBundle bundle = new PgpSecretKeyRingBundle(fsKeyring );
     PgpSecretKey secretKey = bundle.GetSecretKey(data.KeyId);
     privateKey = secretKey.ExtractPrivateKey(PASSPHRASE.ToCharArray());
    }
Next we use GetDataStream on our PgpPublicKeyEncryptedData and pass it our private key and create a PgpObjectFactory that will give us our data. If the object is compressed, we uncompress it:
PgpObjectFactory plainFactory = new PgpObjectFactory(data.GetDataStream(privateKey));
PgpObject message = plainFactory.NextPgpObject();
if (message is PgpCompressedData) {
 message = new PgpObjectFactory(((PgpCompressedData)message).GetDataStream()).NextPgpObject();
}
Hopefully that will give us a PgpLiteralData which is what we need to get a stream containing the plain, unencrypted data and write that to a new file:
if (message is PgpLiteralData) {
 PgpLiteralData ld = (PgpLiteralData)message;
 using (FileStream outStream = File.Create(OUTPUT_FILENAME)) {
  Stream inStream = ld.GetInputStream();
  byte [] buffer = new byte[0x100000];
  int count = inStream.Read(buffer, 0, buffer.Length);
  while (count > 0) {
   outStream.Write(buffer, 0, count);
   count = inStream.Read(buffer, 0, buffer.Length);
  }
  outStream.Close();
 }
} else {
 Console.WriteLine("ERROR: Unknown type of message in PGP file: {0}", message.GetType().FullName);
}

Thursday, August 11, 2011

Near Miss Pedantry

"Near miss" is a correct term to describe something that comes close to hitting something else.  I hate it when people say that "near miss" would really be a collision.  The most common meaning of near means close, usually in space.  If I am shooting at a target and I got close to it but didn't quite hit it, that would both be a miss and it would be near the target, therefore it would be a "near miss".  If I had missed way off to the side, it would be a "far miss".  You could say "The miss was near the target", so why can't you call it a "near miss"?

If you have a low ceiling you might say "The ceiling is near".  You could say it was a "near ceiling".  It would be a stretch to interpret this as meaning "It is almost a ceiling, but not quite."

Why do so many pedants skip to the fifth definition when complaining about this term?


Tuesday, July 19, 2011

Intellisense for Google Closure Library in VS 2010 (MVC)

Visual Studio examines your javascript to provide intellisense, and lets you add references to other javascript files to pull info from.  To get closure classes to show up I created a plovr config and did a grep of the whole closure library to find goog.provide calls and converted them to goog.require calls.  Then I did a build to include all the code for closure, resulting in Test.7z (534kb).  It contains the following files:

  • Test\test-config.js: plovr config file, uncomment the module you want to build and run through plovr
  • Test\test.js: goog.require for entire closure library
  • Test\test2.js: missing requires for gears, crypt, test, and some others I'll never use
  • Test\test3.js: also missing goog.ui.editor
  • Test\closure_complete.js: built from test.js, 4.1mb
  • Test\closure_mostly.js: built from test2.js, 2.6mb
  • Test\closure_noeditor.js: built from test3.js, 2.4mb
The easiest way to use them would be to unpack in your Content directory and add this line to the top of your javascript files (has to be the first thing):
/// <reference path="~/Content/Test/closure_mostly.js">

Note: you don't have to add the files to your project, but it uses the same url pathing as if they were part of your web site.

You could also just build your project in WHITESPACE mode and use the generated file.  If you use SIMPLE mode, the closure compiler will shorten your parameter names.  If you use ADVANCED mode the closure compiler would shorten all the names and wouldn't even include code you didn't use.



Monday, July 4, 2011

Building PLOVR on Windows

I wanted to add options to plovr, specifically the ability to output a property map to use for interacting with my server using JSON.

First I installed Mercurial which is needed to get the plovr source code.  I installed it to I:\Programs\Mercurial and added that to my path.

Next I got the plovr source code:
I:\plovr\SRC>hg clone https://plovr.googlecode.com/hg/ plovr

I saw it had a build.xml file so I downloaded apache ant and unzipped it to I:\Programs\apache-ant-1.8.2, adding I:\Programs\apache-ant-1.8.2\bin to my path also.

Building produced an error that bash wasn't found, so I downloaded MSYS (MinGW not needed) and installed it to I:\Programs\msys\1.0.

Then I just started an msys shell and did:
$ cd /i/plovr/src/plovr
$ ant


And voila - /i/plovr/SRC/plovr/build/plovr.jar (i:\plovr\SRC\plovr\build\plovr.jar) is now there!

Friday, June 17, 2011

MiniProfiler with PetaPoco

Integrating PetaPoco with Mvc Mini Profiler can be done by changing a few lines in PetaPoco.cs to wrap the connection with a MvcMiniProfiler.Data.ProfiledDbConnection and by changing a line that gets a command using the factory to use the connection. I've written a simple DbProviderFactory that acts as a proxy to the SQL Server factory so you don't have to make any changes to PetaPoco. You register it by adding a system.data element under the root configuration element in your web.config to register the factory and change your connect strings to use the new provider:

<configuration>
  <system.data>
    <DbProviderFactories>
      <add name="MiniProfiler Data Provider"
           invariant="MiniProfilerSql"
           description="SqlServer wrapper for MiniProfiler"
           type="WebSupport.Code.MiniProfilerSqlProviderFactory, WebSupport"
      />
    </DbProviderFactories>
  </system.data>
  <connectionStrings>
    <add name="Test" providerName="MiniProfilerSql" connectionString="xxxx" />
  </connectionStrings>

Notice in the type attribute that my class is in the WebSupport.Code namespace, the value after the comma shows that it is in the WebSupport assembly I have referenced in my MVC project. If you want to stop using MiniProfiler you can just change your connect strings back to using System.Data.SqlClient as the provider.

Here's the code, you should be able to change it for other providers by changing the provider name in the constructor:

public class MiniProfilerSqlProviderFactory : DbProviderFactory
    {
        public static MiniProfilerSqlProviderFactory Instance = new MiniProfilerSqlProviderFactory();

        DbProviderFactory _factory;

        public override bool CanCreateDataSourceEnumerator
        {
            get
            {
                return _factory.CanCreateDataSourceEnumerator;
            }
        }

        public override DbCommand CreateCommand()
        {
            return _factory.CreateCommand();
        }

        public override DbCommandBuilder CreateCommandBuilder()
        {
            return _factory.CreateCommandBuilder();
        }

        public override DbConnection CreateConnection()
        {
            DbConnection cnn = _factory.CreateConnection();
            return MvcMiniProfiler.Data.ProfiledDbConnection.Get(cnn);
        }

        public override DbConnectionStringBuilder CreateConnectionStringBuilder()
        {
            return _factory.CreateConnectionStringBuilder();
        }

        public override DbDataAdapter CreateDataAdapter()
        {
            return _factory.CreateDataAdapter();
        }

        public override DbDataSourceEnumerator CreateDataSourceEnumerator()
        {
            return _factory.CreateDataSourceEnumerator();
        }

        public override DbParameter CreateParameter()
        {
            return _factory.CreateParameter();
        }

        public override CodeAccessPermission CreatePermission(PermissionState state)
        {
            return _factory.CreatePermission(state);
        }

        public MiniProfilerSqlProviderFactory()
        {
            _factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        }
    }