【问题标题】:RSA Encrypt Handle invalid issueRSA 加密处理无效问题
【发布时间】:2018-04-02 03:15:09
【问题描述】:

我正在尝试加密文本并使用公钥对对其进行解密。我需要将密钥作为字符串处理。所以我将这些密钥从字符串转换为 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;
}

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

【问题讨论】:

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


    【解决方案1】:

    您肯定缺乏阅读 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 读取与预设值相结合。它应该结束01 00 01,但它读取有效负载的第一个01 作为长度,然后使用该长度从末尾开始计数。所以指数值最终只是01。 RSA 算法不适用于e=1,发生的情况可能是加密后自检确定结果是垃圾,Win32 加密库得出的结论是,问题在于调用者给它的东西不是'不是有效的密钥句柄,而不是无效密钥的有效句柄。除了在这里不理解 byte[] => hex => substring => byte[] 模式之外,我不明白为什么这段代码决定 pDer[-3] (使用另一种语言的语法)是长度值。 DER 只能“从左到右”读取,如果它知道“指数始终为 0x010001”,那么 a) 将在 pDer[-4] 处进行长度编码 b) 仅读取最后三个字节是可以原谅的,并且c) 考虑到这段代码做了多少假设,盲目地假设 0x010001 会更有意义。

    因此,您需要 a) 将您的解析器替换为正确的解析器,或者至少是一个在您想要的密钥大小下运行的专用解析器,并且 b) 永远不要将该私钥用于任何重要的事情,因为您只是将它发布到 Internet (在这个问题中甚至没有使用私钥变量)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-10
      • 2011-01-29
      • 2011-04-11
      相关资源
      最近更新 更多