Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Cryptographic Interoperability: Digital Signatures

, 20 Oct 2009
Sign and verify messages using Crypto++, Java, and C#.
cryptoppinteropkeys.zip
CryptoPPInteropKeys
CryptoPPInteropKeys
cryptoppinteropsign.zip
CryptoPPInteropSign
CryptoPPInteropSign
csinteropkeys.zip
CSInteropKeys
CSInteropKeys
Properties
csinteropsign.zip
CSInteropSign
CSInteropSign
Properties
javainteropkeys.zip
JavaInteropKeys
manifest.mf
nbproject
genfiles.properties
private
private.properties
project.properties
src
JavaInteropKeys
test
javainteropsign.zip
JavaInteropSign
build
classes
JavaInteropSign
test
classes
results
manifest.mf
nbproject
genfiles.properties
private
private.properties
project.properties
src
JavaInteropSign
test
using System;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Cryptography;

class AsnKeyParser
{
  private AsnParser parser;

  internal AsnKeyParser(String pathname)
  {
    using (BinaryReader reader = new BinaryReader(
        new FileStream(pathname, FileMode.Open, FileAccess.Read)))
    {
      FileInfo info = new FileInfo(pathname);

      parser = new AsnParser(reader.ReadBytes((int)info.Length));

    }
  }

  internal byte[] TrimLeadingZero(byte[] values)
  {
    byte[] r = null;
    if ( (0x00 == values[0]) && (values.Length > 1) )
    {
      r = new byte[values.Length - 1];
      Array.Copy(values, 1, r, 0, values.Length - 1);
    }
    else
    {
      r = new byte[values.Length];
      Array.Copy(values, r, values.Length);
    }

    return r;
  }

  internal static bool EqualOid(byte[] first, byte[] second)
  {
    if (first.Length != second.Length)
    { return false; }

    for (int i = 0; i < first.Length; i++)
    {
      if (first[i] != second[i])
      { return false; }
    }

    return true;
  }

  internal RSAParameters ParseRSAPublicKey()
  {
    RSAParameters parameters = new RSAParameters();

    // Current value
    byte[] value = null;

    // Current Position
    int position = parser.CurrentPosition();

    // Ignore Sequence - PublicKeyInfo
    parser.NextSequence();

    // Ignore Sequence - AlgorithmIdentifier
    parser.NextSequence();

    // Current position
    position = parser.CurrentPosition();
    // Grab the OID
    value = parser.NextOID();
    byte[] oid = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
    if (!EqualOid(value, oid))
    { throw new BERDecodeException("Expected OID 1.2.840.113549.1.1.1", position); }

    // Optional Parameters
    if (parser.IsNextNull())
    {
      parser.NextNull();
    }
    else
    {
      // Gracefully skip the optional data
      // hopefully, it is a sequence
      int size = parser.NextSequence();
      value = parser.GetOctets(size);
    }

    // Ignore BitString - PublicKey
    parser.NextBitString();

    // Ignore Sequence - RSAPublicKey
    parser.NextSequence();

    parameters.Modulus = TrimLeadingZero(parser.NextInteger());
    parameters.Exponent = TrimLeadingZero(parser.NextInteger());

    Debug.Assert(0 == parser.RemainingBytes());

    return parameters;
  }

  internal RSAParameters ParseRSAPrivateKey()
  {
    RSAParameters parameters = new RSAParameters();

    // Current value
    byte[] value = null;

    // Current position
    int position = parser.CurrentPosition();

    // Ignore Sequence - PrivateKeyInfo
    parser.NextSequence();

    // Current position
    position = parser.CurrentPosition();
    // Version
    value = parser.NextInteger();
    if (0x00 != value[0])
    {
      throw new BERDecodeException("Incorrect PrivateKeyInfo Version", position);
    }

    // Ignore Sequence - AlgorithmIdentifier
    parser.NextSequence();

    // Current position
    position = parser.CurrentPosition();
    // Grab the OID
    value = parser.NextOID();
    byte[] oid = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
    if (!EqualOid(value, oid))
    { throw new BERDecodeException("Expected OID 1.2.840.113549.1.1.1", position); }

    // Optional Parameters
    if (parser.IsNextNull())
    {
      parser.NextNull();
    }
    else
    {
      // Gracefully skip the optional data
      // hopefully, it is a sequence
      int size = parser.NextSequence();
      value = parser.GetOctets(size);
    }

    // Ignore OctetString - PrivateKey
    parser.NextOctetString();

    // Ignore Sequence - RSAPrivateKey
    parser.NextSequence();

    // Current position
    position = parser.CurrentPosition();
    // Version
    value = parser.NextInteger();
    if (0x00 != value[0])
    {
      throw new BERDecodeException("Incorrect RSAPrivateKey Version", position);
    }

    parameters.Modulus = TrimLeadingZero(parser.NextInteger());
    parameters.Exponent = TrimLeadingZero(parser.NextInteger());
    parameters.D = TrimLeadingZero(parser.NextInteger());
    parameters.P = TrimLeadingZero(parser.NextInteger());
    parameters.Q = TrimLeadingZero(parser.NextInteger());
    parameters.DP = TrimLeadingZero(parser.NextInteger());
    parameters.DQ = TrimLeadingZero(parser.NextInteger());
    parameters.InverseQ = TrimLeadingZero(parser.NextInteger());

    Debug.Assert(0 == parser.RemainingBytes());

    return parameters;
  }

  internal DSAParameters ParseDSAPublicKey()
  {
    DSAParameters parameters = new DSAParameters();

    // Current value
    byte[] value = null;

    // Current Position
    int position = parser.CurrentPosition();

    // Ignore Sequence - PublicKeyInfo
    parser.NextSequence();

    // Ignore Sequence - AlgorithmIdentifier
    parser.NextSequence();

    // Current position
    position = parser.CurrentPosition();
    // Grab the OID
    value = parser.NextOID();
    byte[] oid = { 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01 };
    if (!EqualOid(value, oid))
    { throw new BERDecodeException("Expected OID 1.2.840.10040.4.1", position); }


    // Ignore Sequence - DSS-Params
    parser.NextSequence();

    // Next three are curve parameters
    parameters.P = TrimLeadingZero(parser.NextInteger());
    parameters.Q = TrimLeadingZero(parser.NextInteger());
    parameters.G = TrimLeadingZero(parser.NextInteger());

    // Ignore BitString - PrivateKey
    parser.NextBitString();

    // Public Key
    parameters.Y = TrimLeadingZero(parser.NextInteger());

    Debug.Assert(0 == parser.RemainingBytes());

    return parameters;
  }

  internal DSAParameters ParseDSAPrivateKey()
  {
    DSAParameters parameters = new DSAParameters();

    // Current value
    byte[] value = null;

    // Current Position
    int position = parser.CurrentPosition();

    // Ignore Sequence - PrivateKeyInfo
    parser.NextSequence();

    // Current position
    position = parser.CurrentPosition();
    // Version
    value = parser.NextInteger();
    if (0x00 != value[0])
    {
      throw new BERDecodeException("Incorrect PrivateKeyInfo Version", position);
    }

    // Ignore Sequence - AlgorithmIdentifier
    parser.NextSequence();

    // Current position
    position = parser.CurrentPosition();
    // Grab the OID
    value = parser.NextOID();
    byte[] oid = { 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01 };
    if (!EqualOid(value, oid))
    { throw new BERDecodeException("Expected OID 1.2.840.10040.4.1", position); }

    // Ignore Sequence - DSS-Params
    parser.NextSequence();

    // Next three are curve parameters
    parameters.P = TrimLeadingZero(parser.NextInteger());
    parameters.Q = TrimLeadingZero(parser.NextInteger());
    parameters.G = TrimLeadingZero(parser.NextInteger());

    // Ignore OctetString - PrivateKey
    parser.NextOctetString();

    // Private Key
    parameters.X = TrimLeadingZero(parser.NextInteger());

    Debug.Assert(0 == parser.RemainingBytes());

    return parameters;
  }
}

class AsnParser
{
  private List<byte> octets;
  private int initialCount;

  internal AsnParser(byte[] values)
  {
    octets = new List<byte>(values.Length);
    octets.AddRange(values);

    initialCount = values.Length;
  }

  internal int CurrentPosition()
  {
    return initialCount - octets.Count;
  }

  internal int RemainingBytes()
  {
    return octets.Count;
  }

  private int GetLength()
  {
    int length = 0;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      if (b < 0x80) { return b; }
      int i = b & 0x7f;

      while (0 != i--)
      {
        // shift left
        length <<= 8;

        length |= octets[0];
        octets.RemoveAt(0);
      }
    }
    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - 1, ex); }

    return length;
  }

  internal byte[] Next()
  {
    int count = octets.Count;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      int length = GetLength();

      return null;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }

  internal byte[] GetOctets(int octetCount)
  {
    int count = octets.Count;
    byte[] values = new byte[octetCount];

    try
    {
      for (int i = 0; i < octetCount; i++)
      {
        values[i] = octets[0];
        octets.RemoveAt(0);
      }
      return values;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }

  internal bool IsNextNull()
  {
    return 0x05 == octets[0];
  }

  internal int NextNull()
  {
    int count = octets.Count;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      if (0x05 != b)
      { throw new BERDecodeException("Expected Null", initialCount - count); }

      // Next octet must be 0
      octets.RemoveAt(0);

      return 0;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }

  internal bool IsNextSequence()
  {
    return 0x30 == octets[0];
  }

  internal int NextSequence()
  {
    int count = octets.Count;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      if (0x30 != b)
      { throw new BERDecodeException("Expected Sequence", initialCount - count); }

      int length = GetLength();

      return length;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }

  internal bool IsNextOctetString()
  {
    return 0x04 == octets[0];
  }

  internal int NextOctetString()
  {
    int count = octets.Count;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      if (0x04 != b)
      { throw new BERDecodeException("Expected OctetString", initialCount - count); }

      int length = GetLength();

      return length;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }

  internal bool IsNextBitString()
  {
    return 0x03 == octets[0];
  }

  internal int NextBitString()
  {
    int count = octets.Count;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      if (0x03 != b)
      { throw new BERDecodeException("Expected BitString", initialCount - count); }

      int length = GetLength();

      // We need to consume unused bits
      b = octets[0];
      octets.RemoveAt(0);

      if (0x00 != b)
      { throw new BERDecodeException("Null must have a zero length", initialCount - count); }

      return length;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }

  internal bool IsNextInteger()
  {
    return 0x02 == octets[0];
  }

  internal byte[] NextInteger()
  {
    int count = octets.Count;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      if (0x02 != b)
      { throw new BERDecodeException("Expected Integer", initialCount - count); }

      int length = GetLength();
      byte[] values = new byte[length];

      for (int i = 0; i < length; i++)
      {
        values[i] = octets[0];
        octets.RemoveAt(0);
      }

      return values;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }

  internal byte[] NextOID()
  {
    int count = octets.Count;

    try
    {
      byte b = octets[0];
      octets.RemoveAt(0);

      if (0x06 != b)
      { throw new BERDecodeException("Expected ObjectIdentifier", initialCount - count); }

      int length = GetLength();
      byte[] values = new byte[length];

      for (int i = 0; i < length; i++)
      {
        values[i] = octets[0];
        octets.RemoveAt(0);
      }

      return values;
    }

    catch (ArgumentOutOfRangeException ex)
    { throw new BERDecodeException(initialCount - count, ex); }
  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Jeffrey Walton
Systems / Hardware Administrator
United States United States
No Biography provided

| Advertise | Privacy | Mobile
Web01 | 2.8.140905.1 | Last Updated 20 Oct 2009
Article Copyright 2008 by Jeffrey Walton
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid