RSA加密处理无效问题

时间:2018-04-02 03:15:09

标签: c# cryptography rsa public-key-encryption private-key

我正在尝试加密文本并使用公共私钥对对其进行解密。我需要将键作为字符串处理。所以我将这些键从字符串转换为RSAParameters。但是当我尝试加密文本时,它会抛出一个错误,因为“句柄无效”。

static RSAParameters _publicKey = new RSAParameters();
static RSAParameters _privateKey = new RSAParameters();
static string _strPublicKey = "-----BEGIN PUBLIC KEY-----\r\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsG5sBbnH7gXkrExzNOeK\r\nEjoRDHUH5uU+crH52Z1uXCEx8LiFow8RwrvZGqjYXgBwxzqOQwHJt3utoNVY0niP\r\nHjfPXwKTk79PkeET/mtRar1gEcCOr0/hgHxT3YGlQLw2ugVIulMzlUBRY4rceNv3\r\nEiSZ+4cnO04hJ6UiftrCfwTe6q9Hadp6B6SX+N9hgcHhRX4iR/VYUf/6cvN+NAgb\r\ntuF0Dk61C6ulh2Gvdj2TBCLaq1LPF5H+ghrRxjK/Zn6MG9BW2ju9g8zYKuufaaaM\r\ndbTmN+Z4f27nEOxFq5wWqeaWl53yrMia6xnOi7vtU8zcwBL7jSLgwrkyO8LabCdz\r\neQIDAQAB\r\n-----END PUBLIC KEY-----";
static string _strPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\nMIIEogIBAAKCAQEAsG5sBbnH7gXkrExzNOeKEjoRDHUH5uU+crH52Z1uXCEx8LiF\r\now8RwrvZGqjYXgBwxzqOQwHJt3utoNVY0niPHjfPXwKTk79PkeET/mtRar1gEcCO\r\nr0/hgHxT3YGlQLw2ugVIulMzlUBRY4rceNv3EiSZ+4cnO04hJ6UiftrCfwTe6q9H\r\nadp6B6SX+N9hgcHhRX4iR/VYUf/6cvN+NAgbtuF0Dk61C6ulh2Gvdj2TBCLaq1LP\r\nF5H+ghrRxjK/Zn6MG9BW2ju9g8zYKuufaaaMdbTmN+Z4f27nEOxFq5wWqeaWl53y\r\nrMia6xnOi7vtU8zcwBL7jSLgwrkyO8LabCdzeQIDAQABAoIBAA2z5cvkC/UenA4N\r\nufzn5r9Xpy9Sf5SdRWZfEEqogYPCSECr9CUf7H81W71IU9WpLxkqIRZvMx1/C5Ms\r\nPsPJ/UOZjg+RAak9+I4Z7xWZfC9QGgAG9o4DJD54aYMQqKcIdy+nbWibQaxb3HZg\r\nuJLicqQEF7mDW7atcMHFf5JepzB6LO7u9mfgR03uHQh6r6ym27BTGwssSmEeOeiA\r\n+tOPEhCsbZMSs5+8aGMoV08OqjscytQCWDY8rwA8ZE/qis+cNxKo0OluRTde68mH\r\nbr42CZpNJNulhg4mZyxtrtC+D13VcRpFeKW7WbMBwEUJ8/liUBDvAPLB3Np46FsG\r\njcZfFmkCgYEAtSk5HGEk+y8dyl+l62u7oir5IEZf8vNsMJ+CrpF1C8e6qShRe9uy\r\nJ5pN/4dBb2thknOLsaw6K2qYGNkH3TYSpHusW7v4Iuy6ONmzXHCxcgconzCWJ0HI\r\nLWnYRZAHv8PdOxdFqukjLqFOz6fEyIJ5Ayp+7qxg3QRmE7bwnEwWYK8CgYEA+VEC\r\nBUVUd8tHLqMyaYuv7HXQlQ3J01fobts98k+xqQtKsMUu4SZQ/5uQF8Wk3P6AAKiU\r\ngeD81Fpu4PINrRH97R0twnlWru1fHNSHNenuLASW+3I4l975PhZJc5AeV7VpRcnY\r\nyZCMAKO/XRpfgTEsv5HNfidUsYuJ/9epQzVy6FcCgYAs1V3f6x621ys9OTybrZbL\r\nBG2REjmOq7V7tw4lW7QmzTAhyuuXhoBpkqN4+KU2CNIl51iMCP6AXin0BEoQ8d/d\r\nOwolzbgUFJfll+LunqkbejAQbXrLjlkW/Bnc5U81oyhuBk1khbwCP0N82p01rix6\r\nnxq4wIpcSElm2aBkXeQv2wKBgCvewUhEJtTdhC0Esn44AkDNimJwBq+VrGS1V3Un\r\n6M8iGYZ5bAJaR65ypSxJrvTkI4n6IAeqm1KShyg174ogvFnY5JBv4Xzub+oWy6QF\r\nAc/lDtw4ARVYOutd6JbZKT2twlRxbCAruzbxmV68oUmOaZ1b/pjQOury7tmCDVqy\r\nMQIJAoGAIqUiIAnKLBrXhfN0nqGt2iOnRl31Ef3p/pTNwhUBdJphi/zlE9JHTI2Q\r\nCiLCGyJTpr3FoPjIJZ2P+fRrB3FmVuGNVZw5s8g4ouuDWNyCL/upVwU84eAWMu7P\r\nDsUL5Ia5W7/Cm7d0/nqchUCkRslIsH+bfGj0NZ7qcE5H1D8Ee0A=\r\n-----END RSA PRIVATE KEY-----";
static void Main(string[] args)
{
  var message = "Hello World!";
  var data = Encrypt(message);
  var res = Decrypt(data);
}

private static RSAParameters GetRSAParameters(string pPublicKey)
{
  byte[] lDer;

  //Set RSAKeyInfo to the public key values. 
  int lBeginStart = "-----BEGIN PUBLIC KEY-----".Length;
  int lEndLenght = "-----END PUBLIC KEY-----".Length;
  string KeyString = pPublicKey.Substring(lBeginStart, (pPublicKey.Length - lBeginStart - lEndLenght));
  lDer = Convert.FromBase64String(KeyString);


  //Create a new instance of the RSAParameters structure.
  RSAParameters lRSAKeyInfo = new RSAParameters();

  lRSAKeyInfo.Modulus = GetModulus(lDer);
  lRSAKeyInfo.Exponent = GetExponent(lDer);

  return lRSAKeyInfo;
}

private static byte[] GetModulus(byte[] pDer)
{
  //Size header is 29 bits
  //The key size modulus is 128 bits, but in hexa string the size is 2 digits => 256 
  string lModulus = BitConverter.ToString(pDer).Replace("-", "").Substring(58, 256);

  return StringHexToByteArray(lModulus);
}

private static byte[] GetExponent(byte[] pDer)
{
  int lExponentLenght = pDer[pDer.Length - 3];
  string lExponent = BitConverter.ToString(pDer).Replace("-", "").Substring((pDer.Length * 2) - lExponentLenght * 2, lExponentLenght * 2);

  return StringHexToByteArray(lExponent);
}

public static byte[] StringHexToByteArray(string hex)
{
  return Enumerable.Range(0, hex.Length)
                   .Where(x => x % 2 == 0)
                   .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                   .ToArray();
}

public static string Encrypt(string mess)
{
  string response = "";
  var input = Encoding.UTF8.GetBytes(mess);
  using (var rsa = new RSACryptoServiceProvider(1024))
  {
    rsa.PersistKeyInCsp = false;
    rsa.ImportParameters(GetRSAParameters(_strPublicKey));
    var decrypt = rsa.Encrypt(input, true);
    response = Convert.ToBase64String(decrypt);
  }
  return response;
}

public static string Decrypt(string mess)
{
  string response = "";
  var input = Convert.FromBase64String(mess);
  using (var rsa = new RSACryptoServiceProvider(2048))
  {
    rsa.PersistKeyInCsp = false;
    rsa.ImportParameters(GetRSAParameters(_strPublicKey));
    var decrypt = rsa.Decrypt(input, false);
    response = Encoding.UTF8.GetString(decrypt);
  }
  return response;
}

以上是我用来加密和解密的代码。转换后,我将它们转换为字符串并将其传递给decrypt函数。请建议

1 个答案:

答案 0 :(得分:0)

您尝试阅读DER绝对缺乏。可能是因为你有一个2048位的密钥而你的“解析器”最好只能用于1024位密钥(尽管我在确定它可以合法读取的密钥时遇到问题)。

您的公钥十六进制是

30820122300D06092A864886F70D01010105000382010F003082010A02820101
00B06E6C05B9C7EE05E4AC4C7334E78A123A110C7507E6E53E72B1F9D99D6E5C
2131F0B885A30F11C2BBD91AA8D85E0070C73A8E4301C9B77BADA0D558D2788F
1E37CF5F029393BF4F91E113FE6B516ABD6011C08EAF4FE1807C53DD81A540BC
36BA0548BA5333954051638ADC78DBF7122499FB87273B4E2127A5227EDAC27F
04DEEAAF4769DA7A07A497F8DF6181C1E1457E2247F55851FFFA72F37E34081B
B6E1740E4EB50BABA58761AF763D930422DAAB52CF1791FE821AD1C632BF667E
8C1BD056DA3BBD83CCD82AEB9F69A68C75B4E637E6787F6EE710EC45AB9C16A9
E696979DF2ACC89AEB19CE8BBBED53CCDCC012FB8D22E0C2B9323BC2DA6C2773
790203010001

DER分解(因为我无法自助)

 30 82 01 22
    30 0D
       06 09 2A 86 48 86 F7 0D 01 01 01
       05 00
    03
       82 01 0F
          00
          30 82 01 0A
             02 82 01 01
                00B06E6C05B9C7EE05E4AC4C7334E78A123A110C7507E6E53E72B1F9D99D6E5C
                2131F0B885A30F11C2BBD91AA8D85E0070C73A8E4301C9B77BADA0D558D2788F
                1E37CF5F029393BF4F91E113FE6B516ABD6011C08EAF4FE1807C53DD81A540BC
                36BA0548BA5333954051638ADC78DBF7122499FB87273B4E2127A5227EDAC27F
                04DEEAAF4769DA7A07A497F8DF6181C1E1457E2247F55851FFFA72F37E34081B
                B6E1740E4EB50BABA58761AF763D930422DAAB52CF1791FE821AD1C632BF667E
                8C1BD056DA3BBD83CCD82AEB9F69A68C75B4E637E6787F6EE710EC45AB9C16A9
                E696979DF2ACC89AEB19CE8BBBED53CCDCC012FB8D22E0C2B9323BC2DA6C2773
                79
             02 03
                010001

哪个是ASN.1等同于

SEQUENCE
  SEQUENCE
    OBJECT IDENTIFIER id-rsaEncryption
    NULL
  BIT STRING (0 bits unused) (wrapping)
    SEQUENCE
      INTEGER (positive) 0xB06E...7379
      INTEGER 0x010001

你的模数提取器跳过29个字节并读取下一个128个字节。(为什么它的byte [] => hex => substring => byte []而不是new byte[size]Buffer.BlockCopy超越我)。问题是,你的密钥是一个2048位的密钥(模数长度是0x0101,一旦我们删除符号填充字节,它的长度为0x0100字节,高位设置,所以256 * 8 = 2048位模数)。所以你需要读取256个字节。而且,更糟糕的是,因为有效载荷大于预期,它不会从您认为的偏移量开始。因此,在最终使用B0 6E 6C ... 27 73 79(跳过填充字节后)的情况下,最终会得到82 01 01 00 *B0 6E 6C ... A5 22 7E(星号标记所需的有效负载启动)。所以,这很糟糕,你绝对不会加密你认为你是什么。 (A5 22 7E序列出现在以36BA开头的行上,最后还剩下3个字节就行了)

更糟糕的是GetExponent方法。它似乎试图将实际的DER读数与预设的价值结合起来。它应该以{{1​​}}结束,但它将有效负载的第一个01 00 01读取为长度,然后使用该长度从末尾开始计数。所以指数值最终只是01。 RSA算法不适用于01,并且发生的事情可能是加密后自检确定结果是垃圾,Win32加密库得出的结论是问题是调用者给了它一些东西这不是一个有效的键句柄,而是一个无效键的有效句柄。除了不理解byte [] => hex => substring => byte [] pattern这里我不明白为什么这段代码决定pDer [-3](使用另一种语言的语法)是长度值。 DER只能从“从左到右”读取,如果它知道“指数总是0x010001”,则a)在pDer [-4] b进行长度编码)只读取最后三个字节是可以原谅的c)假设这个代码有多少假设,那么盲目地假设0x010001会更有意义。

所以,你需要a)用正确的解析器替换你的解析器,或者至少是一个在你想要的密钥大小上运行的专用解析器和b)永远不要使用那个私钥来解决任何重要问题,因为你刚刚将它发布到了Internet上(并且在这个问题中甚至没有使用私钥变量)。