使用OpenSSL将C代码转换为使用system.security.cryptography进行公钥验证到VisualBasic.NET?

时间:2009-10-20 19:13:11

标签: c vb.net cryptography

我试图模仿使用.net 3.5世界中的system.security.crytography库使用OpenSSL库的一些C代码的结果,我似乎无法做到正确。我需要一些帮助......问题的一部分是我对一般的密码学的理解。

这是应该发生的事情:

  1. 我向设备发送身份验证请求。
  2. 返回挑战摘要,然后我需要使用已知密钥签名并返回
  3. 设备返回“成功”或“失败”消息。
  4. 我有以下代码片段,我试图“复制”:

      //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);
    

    更多信息:

    1. priv_key是包含的十六进制字符的252个元素字符数组。

    2. 最终结果是将512(或更少)字符数组发送回设备进行验证。

    3. Rasmus要求查看关键数组。这是:

      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};
      

      任何人都可以帮我翻译这个代码到它的VB.net加密等效吗?

3 个答案:

答案 0 :(得分:1)

您是否想要编写自己的解决方案?如果没有,请查看SharpSsh.NET samples

答案 1 :(得分:1)

抱歉,以下代码不起作用。 .NET需要DSAParameters中的其他值。我在另一条关于BouncyCastle.NET的建议中添加了评论。


抱歉,我不能编写VB.NET,但您可以翻译以下C#代码:

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);
}

您的priv_key十六进制字符数组是ASN.1 DER编码的DSA私钥(采用OpenSSL的非标准格式)。这是一个转储,您可以看到我从哪里获得值:

   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
            :   }

同样,SignData的输出可能不是您期望的格式。我认为OpenSSL将结果放在ASN.1 DER容器中。它看起来像这样:

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只是连接签名的两半。

答案 2 :(得分:0)

我设法让事情变得有效......这就是我最终做的事情。

我在原始C程序中添加了几行:

  //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);

这以PEM格式保存了密钥。

在我的.net应用程序中,我使用OpenSSL.Net尝试尽可能接近原始程序中使用的库,而不必将数据来回传递给C函数:

'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

现在一切正常。谢谢你的帮助......它指出了我正确的方向......

再次感谢,

格伦