views:

337

answers:

4

I am trying to mimic the results of some C code that uses the OpenSSL library using the system.security.crytography library in the .net 3.5 world, and I can't seem to get it right. I need some help... part of the issue is my understanding of crytography in general.

Here's what is supposed to happen:

  1. I send a request for authentication to a device.
  2. It returns a challenge digest, which I then need to sign with a known key and return
  3. The device returns a "success" or "Fail" message.

I have the following code snippet that I am trying to "copy":

  //Seed the PRNG
  //Cheating here - the PRNG will be seeded when we create a key pair
  //The key pair is discarded only doing this to seed the PRNG.
  DSA *temp_dsa = DSA_new();
  if(!temp_dsa)
  {
     printf("Error:  The client had an error with the DSA API\n");
     exit(0);
  }

  unsigned char seed[20] = "Our Super Secret Key";
  temp_dsa = DSA_generate_parameters(128, seed, sizeof(seed), NULL, NULL, NULL, NULL);
  DSA_free(temp_dsa);


  //A pointer to the private key.
  p = (unsigned char *)&priv_key;

  //Create and allocate a DSA structure from the private key.
  DSA *priv_dsa = NULL;
  priv_dsa = d2i_DSAPrivateKey(NULL, &p, sizeof(priv_key));
  if(!priv_dsa)
  {
     printf("Error:  The client had an error with the DSA API\n");
     exit(0);
  }


  //Allocate memory for the to be computed signature.
  sigret = OPENSSL_malloc(DSA_size(priv_dsa));

  //Sign the challenge digest recieved from the ISC.
  retval = DSA_sign(0, pResp->data, pResp->data_length, sigret, &siglen, priv_dsa);

A few more bits of information:

  1. priv_key is a 252 element character array of hex characters that is included.

  2. The end result is a 512 (or less) array of characters to send back for validation to the device.

Rasmus asked to see the key array. Here it is:

unsigned char priv_key[] = {0x30, 0x81, 0xf9, 0x02, 0x01, 0x00,
0x02, 0x41, 0x00, 0xfe, 0xca, 
0x97, 0x55, 0x1f, 0xc0, 0xb7, 
0x1f, 0xad, 0xf0, 0x93, 0xec, 
0x4b, 0x31, 0x94, 0x78, 0x86, 
0x82, 0x1b, 0xab, 0xc4, 0x9e, 
0x5c, 0x40, 0xd9, 0x89, 0x7d, 
0xde, 0x43, 0x38, 0x06, 0x4f, 
0x1b, 0x2b, 0xef, 0x5c, 0xb7, 
0xff, 0x21, 0xb1, 0x11, 0xe6, 
0x9a, 0x81, 0x9a, 0x2b, 0xef, 
0x3a, 0xbb, 0x5c, 0xea, 0x76, 
0xae, 0x3a, 0x8b, 0x92, 0xd2, 
0x7c, 0xf1, 0x89, 0x8e, 0x4d, 
0x3f, 0x0d, 0x02, 0x15, 0x00, 
0x88, 0x16, 0x1b, 0xf5, 0xda, 
0x43, 0xee, 0x4b, 0x58, 0xbb, 
0x93, 0xea, 0x4e, 0x2b, 0xda, 
0xb9, 0x17, 0xd1, 0xff, 0x21, 
0x02, 0x41, 0x00, 0xf6, 0xbb, 
0x45, 0xea, 0xda, 0x72, 0x39, 
0x4f, 0xc1, 0xdd, 0x02, 0xb4, 
0xf3, 0xaa, 0xe5, 0xe2, 0x76, 
0xc7, 0xdc, 0x34, 0xb2, 0x0a, 
0xd8, 0x69, 0x63, 0xc3, 0x40, 
0x2c, 0x58, 0xea, 0xa6, 0xbd, 
0x24, 0x8b, 0x6b, 0xaa, 0x4b, 
0x41, 0xfc, 0x5f, 0x21, 0x02, 
0x3c, 0x27, 0xa9, 0xc7, 0x7a, 
0xc8, 0x59, 0xcd, 0x5b, 0xdd, 
0x6c, 0x44, 0x48, 0x86, 0xd1, 
0x34, 0x46, 0xb0, 0x89, 0x55, 
0x50, 0x87, 0x02, 0x41, 0x00, 
0x80, 0x29, 0xc6, 0x4a, 0x08, 
0x3e, 0x30, 0x54, 0x71, 0x9b, 
0x95, 0x49, 0x55, 0x17, 0x70, 
0xc7, 0x96, 0x65, 0xc8, 0xc2, 
0xe2, 0x8a, 0xe0, 0x5d, 0x9f, 
0xe4, 0xb2, 0x1f, 0x20, 0x83, 
0x70, 0xbc, 0x88, 0x36, 0x03, 
0x29, 0x59, 0xcd, 0xc7, 0xcd, 
0xd9, 0x4a, 0xa8, 0x65, 0x24, 
0x6a, 0x77, 0x8a, 0x10, 0x88, 
0x0d, 0x2f, 0x15, 0x4b, 0xbe, 
0xba, 0x13, 0x23, 0xa1, 0x73, 
0xa3, 0x04, 0x37, 0xc9, 0x02, 
0x14, 0x06, 0x8e, 0xc1, 0x41, 
0x40, 0xf1, 0xf6, 0xe1, 0xfa, 
0xfb, 0x64, 0x28, 0x02, 0x15, 
0xce, 0x47, 0xaa, 0xce, 0x6e, 
0xfe};

Can anyone help me translate this code to it's VB.net crypto equivalent?

TIA,

Glenn

+1  A: 

Are you dying to code your own solution? If not, check out SharpSsh or the .NET samples.

DaveParillo
+1  A: 

Sorry, the code below does not work. .NET requires additional values in the DSAParameters. I added a comment with another suggestion about BouncyCastle.NET.


Sorry, I can't write VB.NET, but you can probably translate the following C# code:

DSAParameters keyValue = new DSAParameters();
keyValue.P = new byte[]{0xfe, 0xca, 0x97, 0x55, 0x1f, 0xc0, 0xb7, 0x1f, 0xad, 0xf0, 0x93, 0xec, 0x4b, 0x31, 0x94, 0x78, 0x86, 0x82, 0x1b, 0xab, 0xc4, 0x9e, 0x5c, 0x40, 0xd9, 0x89, 0x7d, 0xde, 0x43, 0x38, 0x06, 0x4f, 0x1b, 0x2b, 0xef, 0x5c, 0xb7, 0xff, 0x21, 0xb1, 0x11, 0xe6, 0x9a, 0x81, 0x9a, 0x2b, 0xef, 0x3a, 0xbb, 0x5c, 0xea, 0x76, 0xae, 0x3a, 0x8b, 0x92, 0xd2, 0x7c, 0xf1, 0x89, 0x8e, 0x4d, 0x3f, 0x0d};
keyValue.Q = new byte[]{0x88, 0x16, 0x1b, 0xf5, 0xda, 0x43, 0xee, 0x4b, 0x58, 0xbb, 0x93, 0xea, 0x4e, 0x2b, 0xda, 0xb9, 0x17, 0xd1, 0xff, 0x21};
keyValue.G = new byte[]{0xf6, 0xbb, 0x45, 0xea, 0xda, 0x72, 0x39, 0x4f, 0xc1, 0xdd, 0x02, 0xb4, 0xf3, 0xaa, 0xe5, 0xe2, 0x76, 0xc7, 0xdc, 0x34, 0xb2, 0x0a, 0xd8, 0x69, 0x63, 0xc3, 0x40, 0x2c, 0x58, 0xea, 0xa6, 0xbd, 0x24, 0x8b, 0x6b, 0xaa, 0x4b, 0x41, 0xfc, 0x5f, 0x21, 0x02, 0x3c, 0x27, 0xa9, 0xc7, 0x7a, 0xc8, 0x59, 0xcd, 0x5b, 0xdd, 0x6c, 0x44, 0x48, 0x86, 0xd1, 0x34, 0x46, 0xb0, 0x89, 0x55, 0x50, 0x87};
keyValue.X = new byte[]{0x80, 0x29, 0xc6, 0x4a, 0x08, 0x3e, 0x30, 0x54, 0x71, 0x9b, 0x95, 0x49, 0x55, 0x17, 0x70, 0xc7, 0x96, 0x65, 0xc8, 0xc2, 0xe2, 0x8a, 0xe0, 0x5d, 0x9f, 0xe4, 0xb2, 0x1f, 0x20, 0x83, 0x70, 0xbc, 0x88, 0x36, 0x03, 0x29, 0x59, 0xcd, 0xc7, 0xcd, 0xd9, 0x4a, 0xa8, 0x65, 0x24, 0x6a, 0x77, 0x8a, 0x10, 0x88, 0x0d, 0x2f, 0x15, 0x4b, 0xbe, 0xba, 0x13, 0x23, 0xa1, 0x73, 0xa3, 0x04, 0x37, 0xc9};
keyValue.Y = new byte[]{0x06, 0x8e, 0xc1, 0x41, 0x40, 0xf1, 0xf6, 0xe1, 0xfa, 0xfb, 0x64, 0x28, 0x02, 0x15, 0xce, 0x47, 0xaa, 0xce, 0x6e, 0xfe};

using (DSACryptoServiceProvider key = new DSACryptoServiceProvider())
{
  key.ImportParameters(keyValue);
  byte[] res = key.SignData(data);
}

Your priv_key array of hex-characters is an ASN.1 DER encoded DSA private key (in OpenSSL's non-standard format). Here is a dump, you can probably see where I got the values from:

   0 30  249: SEQUENCE {
   3 02    1:   INTEGER 0
   6 02   65:   INTEGER
            :     00 FE CA 97 55 1F C0 B7 1F AD F0 93 EC 4B 31 94
            :     78 86 82 1B AB C4 9E 5C 40 D9 89 7D DE 43 38 06
            :     4F 1B 2B EF 5C B7 FF 21 B1 11 E6 9A 81 9A 2B EF
            :     3A BB 5C EA 76 AE 3A 8B 92 D2 7C F1 89 8E 4D 3F
            :     0D
  73 02   21:   INTEGER
            :     00 88 16 1B F5 DA 43 EE 4B 58 BB 93 EA 4E 2B DA
            :     B9 17 D1 FF 21
  96 02   65:   INTEGER
            :     00 F6 BB 45 EA DA 72 39 4F C1 DD 02 B4 F3 AA E5
            :     E2 76 C7 DC 34 B2 0A D8 69 63 C3 40 2C 58 EA A6
            :     BD 24 8B 6B AA 4B 41 FC 5F 21 02 3C 27 A9 C7 7A
            :     C8 59 CD 5B DD 6C 44 48 86 D1 34 46 B0 89 55 50
            :     87
 163 02   65:   INTEGER
            :     00 80 29 C6 4A 08 3E 30 54 71 9B 95 49 55 17 70
            :     C7 96 65 C8 C2 E2 8A E0 5D 9F E4 B2 1F 20 83 70
            :     BC 88 36 03 29 59 CD C7 CD D9 4A A8 65 24 6A 77
            :     8A 10 88 0D 2F 15 4B BE BA 13 23 A1 73 A3 04 37
            :     C9
 230 02   20:   INTEGER
            :     06 8E C1 41 40 F1 F6 E1 FA FB 64 28 02 15 CE 47
            :     AA CE 6E FE
            :   }

Likewise the output from SignData might not be in the format you expect. I think OpenSSL puts the result in an ASN.1 DER-container. It will look like this:

3082[2 bytes for length of remaining data]
  0281[1 byte for length of this data][some bytes with first half of signature]
  0281[1 byte for length of this data][some bytes with second half of signature]

.NET just concatenates the two halves of the signature.

Rasmus Faber
I added the key array to the inital posting, as it was too large for a comment. Thanks for the help!
Glenn Sullivan
I tried showing how to import the key.
Rasmus Faber
Well, I've tried what you suggested (both in VB and C#, thinking I was performing the conversion wrong) and it is not working correctly. I get an exception during ImportParameters that says nothing more than "Bad Data".I have asked the originating company if they can provide the ey in standard ASN.1 format, but do you have any other suggestions?Thanks,Glenn
Glenn Sullivan
It looks like .NET requires the Seed, J and Counter values, which are not included in the OpenSSL-code. You could try using BouncyCastle.Net instead. You want to create a DsaKeyParameters with a DsaPrivateKeyParameters inside, then feed that to a DsaSigner.
Rasmus Faber
A: 

I managed to get something working... here's what I ended up doing.

I added a few lines to the original C program:

  //Create and allocate a DSA structure from the private key.
  DSA *priv_dsa = NULL;
  priv_dsa = d2i_DSAPrivateKey(NULL, &p, sizeof(priv_key));
  if(!priv_dsa)
  {
     printf("Error:  The client had an error with the DSA API\n");
     exit(0);
  }

  printf("create file pointer\n");
  FILE *fp1 = NULL;
  printf("Open file pointer\n");
  if((fp1 = fopen("PrivateKey.pem", "w+"))== NULL)
  {
    printf("opening %s \n", 's', "test failed\n");
  }
  printf("Ready to save\n");
  int i = PEM_write_DSAPrivateKey(fp1, priv_dsa, NULL, NULL, 0, 0, NULL);
  printf("Closing the file\n");
  int j = fclose(fp1);

This saved the key in PEM format.

In my .net application, I used OpenSSL.Net to try to get as close to the library that was used in the original program as I could without having to Marshall data back and forth to C functions:

'Set up the DSA object to sign the digest
Dim myDSA As New DSA(128, System.Text.Encoding.ASCII.GetBytes("Our Super Secret Key"), 20, Nothing, Nothing)
Dim objReader As New StreamReader("SNMPUnlock.pem")

Dim strKey As String = objReader.ReadToEnd

objReader.Close()
myDSA = DSA.FromPrivateKey(strKey)

'Create the second Request packet with the signed digest
myRequestPacket = New dcISCValidatePacket
With myRequestPacket
    .ResponseID = dcISCValidatePacket.dcCommandResponseID.ISCValidateGUI
    .Data = myDSA.Sign(myResponsePacket.Data)
End With

It is all working correctly now. Thank you for your help... it pointed me in the right direction...

Thanks again,

Glenn

Glenn Sullivan
A: 

conditional compilation

pmrnt