简体   繁体   English

cryptico.js加密消息,必须在C#中解密

[英]cryptico.js encrypted message, must decrypt in C#

I need to be able to decrypt a string on the server using C#, but the string was encrypted using public key encryption with cryptico.js on the client. 我需要能够使用C#解密服务器上的字符串,但是使用客户端上的cryptico.js使用公钥加密对字符串进行加密。 For details, see context at the end. 有关详细信息,请参阅最后的上下文。

Cryptico gives me a private RSA key like this (note - 'like' this - I created a new one for this question): Cryptico给我一个像这样的私人RSA密钥(注意 - '喜欢'这个 - 我为这个问题创建了一个新的密钥):

Array ( [n] => 8029845567507477803775928519657066509146751167600087041355508603090505634905205233922950527978886894355290423984597739819216469551137046641801207199138209 [e] => 3 [d] => 5353230378338318535850619013104711006097834111733391360903672402060337089936682996269976597251251223844095913209399106464214877696419418951728015128013411 [p] => 102067954277225510613941189336789903269738979633396754230261162567549753196947 [q] => 78671563708406591396117399809764267229341143260756252277657051641634753921147 [dmp1] => 68045302851483673742627459557859935513159319755597836153507441711699835464631 [dmq1] => 52447709138937727597411599873176178152894095507170834851771367761089835947431 [coeff] => 26458340158787140383846156526777567128582042036682248240414722856369310516021 

...plus a bunch of methods. ......加上一堆方法。

I am trying to decrypt it thusly: 我试图解密它:

                RSAParameters parameters = new RSAParameters();

            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();

            parameters.Exponent = encoding.GetBytes("3");

            //dmp1
            parameters.DP =
                encoding.GetBytes("68045302851483673742627459557859935513159319755597836153507441711699835464631");

            //dmq1
            parameters.DQ =
                encoding.GetBytes("52447709138937727597411599873176178152894095507170834851771367761089835947431");

            //d
            parameters.D =
                encoding.GetBytes(
                    "5353230378338318535850619013104711006097834111733391360903672402060337089936682996269976597251251223844095913209399106464214877696419418951728015128013411");

            //p
            parameters.P =
                encoding.GetBytes("102067954277225510613941189336789903269738979633396754230261162567549753196947");

            //q
            parameters.Q =
                encoding.GetBytes("78671563708406591396117399809764267229341143260756252277657051641634753921147");

            //n
            parameters.InverseQ =
                encoding.GetBytes(
                    "8029845567507477803775928519657066509146751167600087041355508603090505634905205233922950527978886894355290423984597739819216469551137046641801207199138209");

            //coeff
            parameters.Modulus =
                encoding.GetBytes("26458340158787140383846156526777567128582042036682248240414722856369310516021");

            RSA rsa = new RSACryptoServiceProvider();
            rsa.ImportParameters(parameters);

            var decryptThis = encoding.GetBytes(ciphertext);

            var result = rsa.DecryptValue(decryptThis);

            resultString = encoding.GetString(result);

But this chucks the Exception 'Bad data'. 但是这会让异常“糟糕的数据”丢掉。

Has anyone more experienced with C# got any ideas where I'm going wrong? 有没有更多有经验的C#有任何想法,我出错了?

Thanks, 谢谢,

G G


Details of context: I am attempting to implement a password strength checking function on both the client and server side of an app, but using only code on the server side. 上下文详细信息:我试图在应用程序的客户端和服务器端实现密码强度检查功能,但仅使用服务器端的代码。 To achieve this on the client side, I want to send the putative password to the server, judge its strength, and then return a score which is displayed on the client. 为了在客户端实现这一点,我想将假定的密码发送到服务器,判断其强度,然后返回客户端上显示的分数。 This means I only have to maintain password strength checking code on the server. 这意味着我只需要在服务器上维护密码强度检查代码。 As an extra security measure, I am encrypting the putative password using the cryptico.js library before sending it to the server to be judged. 作为额外的安全措施,我在使用cryptico.js库加密推定的密码,然后将其发送到服务器进行判断。

BigInteger and RSAParameter classes store numbers in different format. BigInteger和RSAParameter类以不同的格式存储数字。

BigInteger stores numbers as little-endian - this means that if you create a BigInteger to hold hex number 0xABCD (43981) - ToByteArray will return bytes { 0xCD, 0xAB, 0x00 } (more on extra zero later). BigInteger将数字存储为little-endian - 这意味着如果你创建一个BigInteger来保存十六进制数0xABCD (43981) - ToByteArray将返回字节{ 0xCD,0xAB,0x00 }(稍后会有更多的额外零)。

RSAParameter was designed to store numbers in big-endian format. RSAParameter旨在以big-endian格式存储数字。 It means that bytes { 0xCD, 0xAB, 0x00 } written into, for example, Exponent property, will be interpreted by RSA implementation as number 0xCDAB00 (13478656). 这意味着写入例如Exponent属性的字节{ 0xCD,0xAB,0x00 }将被RSA实现解释为数字0xCDAB00 (13478656)。

To make matters more complicated - RSAParameters are always positive numbers, while BigInteger supports sign. 更复杂的是 - RSAParameters总是正数,而BigInteger支持sign。 and same number, 0xFF - will be interpreted differently. 和相同的数字,0xFF - 将被不同地解释。 For RSA, it is decimal 255. for BigInteger it means -1, since it is interpreting most significant bit as a sign. 对于RSA,它是十进制255.对于BigInteger,它表示-1,因为它将最高有效位解释为符号。 This is why zero is added - at construction time, BigInteger is aware that we are passing positive value, 43981. But storing this value as two bytes would produce negative number (-21555), since highest bit is set for byte 0xCD (11001101 in binary). 这就是为什么添加零 - 在构造时,BigInteger意识到我们正在传递正值43981.但是将此值存储为两个字节将产生负数(-21555),因为最高位设置为字节0xCD (11001101 in二进制)。 So BigInteger adds zero to indicate positive number. 所以BigInteger加零表示正数。 Try it yourself: 亲自尝试一下:

Console.WriteLine(new BigInteger(new byte[]{0xCD,0xAB}));
Console.WriteLine(BitConverter.ToString(new BigInteger(0xABCD).ToByteArray()));

So, we have large integer passed to us as a decimal string "1234567...", and we want to convert it to representation used by RSA. 因此,我们将大整数作为十进制字符串“1234567 ...”传递给我们,我们希望将其转换为RSA使用的表示形式。 In order to do this, we would need: 为此,我们需要:

  1. Parse string to BigInteger. 将字符串解析为BigInteger。
  2. Extract BigInteger bytes. 提取BigInteger字节。
  3. Make sure BigInteger did not add any leading zeros to compensate sign. 确保BigInteger没有添加任何前导零来补偿符号。
  4. Reverse array back to big endian form, and feed to RSA. 将数组反转回大端格式,并提供给RSA。

Code (using your parameters): 代码(使用您的参数):

using System;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;

class App
{
    static void Main()
    {
      var parameters = new RSAParameters();
      parameters.Exponent=B("3"); 
      parameters.Modulus=B("8029845567507477803775928519657066509146751167600087041355508603090505634905205233922950527978886894355290423984597739819216469551137046641801207199138209"); 
      parameters.D=B("5353230378338318535850619013104711006097834111733391360903672402060337089936682996269976597251251223844095913209399106464214877696419418951728015128013411");
      parameters.P=B("102067954277225510613941189336789903269738979633396754230261162567549753196947");
      parameters.Q=B("78671563708406591396117399809764267229341143260756252277657051641634753921147");
      parameters.DP=B("68045302851483673742627459557859935513159319755597836153507441711699835464631");
      parameters.DQ=B("52447709138937727597411599873176178152894095507170834851771367761089835947431");
      parameters.InverseQ=B("26458340158787140383846156526777567128582042036682248240414722856369310516021");

      var rsa = new RSACryptoServiceProvider();
      rsa.ImportParameters(parameters);
      var ciphertext = rsa.Encrypt(Encoding.ASCII.GetBytes("Hello"), false);
      Console.WriteLine(Encoding.ASCII.GetString(rsa.Decrypt(ciphertext, false)));
    }

    static byte[] B(string s)
    {
      var b = BigInteger.Parse(s);
      var ret = b.ToByteArray();
      if (ret[ret.Length - 1] == 0) 
      {
        Array.Resize(ref ret, ret.Length - 1);
      }
      Array.Reverse(ret);
      return ret;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM