【问题标题】:How do I decrypt an AES key using C# Bouncy Castle that was encrypted using Libgcrypt raw flag如何使用 C# Bouncy Castle 解密使用 Libgcrypt 原始标志加密的 AES 密钥
【发布时间】:2013-07-10 17:16:17
【问题描述】:

总结: 我正在尝试解密(并最终加密并返回)AES128 加密的文件。 AES 密钥使用 libcrypt 的 RSA 提供程序进行加密。当我尝试使用 C# 和 BouncyCastle 在 Windows 7 上解密 AESKey 时,当我调用“ProcessBlock”时会引发“块截断”错误。我尝试将数据转换为 BigEndian,当我尝试创建 RsaKeyParameters 时,我会得到“不是有效的 RSA 指数”。

加密是在 Linux 系统上使用 libgcrypt 1.2x 完成的。我认为这是一个填充问题,因为这个 sn-p 代码表明没有使用填充。 gcry_sexp_build(&PlainKeyExp, NULL, "(data (flags raw) (value %s))", AESKey );

很遗憾,我无法更改原始系统。我在下面包含代码示例和键以提供帮助。在过去的 3 天里,这一直让我发疯。我已经搜索了 interwebz 并没有找到解决方案。 提前感谢您的帮助。

源代码sn-p

static const char RSAPrivateKey[] =
"(private-key"
" (rsa"
"  (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa"
"      2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291"
"      ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7"
"      891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)"
"  (e #010001#)"
"  (d #046129f2489d71579be0a75fe029bd6cdb574ebf57ea8a5b0fda942cab943b11"
"      7d7bb95e5d28875e0f9fc5fcc06a72f6d502464dabded78ef6b716177b83d5bd"
"      c543dc5d3fed932e59f5897e92e6f58a0f33424106a3b6fa2cbf877510e4ac21"
"      c3ee47851e97d12996222ac3566d4ccb0b83d164074abf7de655fc2446da1781#)"
"  (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213"
"      fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)"
"  (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9"
"      35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)"
"  (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e"
"      ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)))";

Error = gcry_sexp_sscan(&PublicKey, NULL, RSAPublicKey, strlen(RSAPublicKey));
if ( Error ) { goto Return; }

Error = gcry_sexp_sscan(&PrivateKey, NULL, RSAPrivateKey, strlen(RSAPrivateKey));
if ( Error ) { goto Return; }

Error = gcry_sexp_build(&PlainKeyExp, NULL, "(data (flags raw) (value %s))", AESKey );
gpg_strerror_r(Error, Output, 500);
if ( Error ) { goto Return; }

Error = gcry_pk_encrypt(&Encrypted, PlainKeyExp, PublicKey);
if ( Error ) { goto Return; }

if ( gcry_sexp_sprint(Encrypted, GCRYSEXP_FMT_CANON, Output, 500) <= 0 ) { Error = TRUE; goto Return; }
Encrypted = gcry_sexp_find_token(Encrypted, "a", 0);
if ( Encrypted == NULL ) { Error = TRUE; goto Return; }

if ( gcry_sexp_sprint(Encrypted, GCRYSEXP_FMT_ADVANCED, Output, 500) <= 0 ) { Error = TRUE; goto Return; }
if ( strtok(Output, "#") != NULL ) {
    Output2 = strtok(NULL, "#");
    if ( Output2 != NULL ) { sprintf(EncryptedKey,"%s", Output2); }
    else { Error = TRUE; }
} else { Error = TRUE; }

解码码sn-p

var modulus ="00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251";

var privateExponent ="046129f2489d71579be0a75fe029bd6cdb574ebf57ea8a5b0fda942cab943b117d7bb95e5d28875e0f9fc5fcc06a72f6d502464dabded78ef6b716177b83d5bdc543dc5d3fed932e59f5897e92e6f58a0f33424106a3b6fa2cbf877510e4ac21c3ee47851e97d12996222ac3566d4ccb0b83d164074abf7de655fc2446da1781";

var encryptedAesKey ="77FD84196959DDE3C367952B3C25B34582B489A705FB3C61D69D04DDA16B011F6358F32834DD76BF81A1DF28106F377FF1125F91CA39BB92D293B8F5134C15C17DE1157390723301A01B938489E04DA1D8D4A70511F0FF2508984710CEB3F18D4BA929C18487A0977011BDE169DBBF3047646FBFBC50ED5A02FC40E53E59B8CD";

try
{
  // Convert to biginteger
  var bcMod = new Org.BouncyCastle.Math.BigInteger(Hex.Decode(modulus));
  var bcPrivateExponent = new Org.BouncyCastle.Math.BigInteger(Hex.Decode(privateExponent));
  byte[] decodedAesKey = Hex.Decode(encryptedAesKey);

  // Init bouncyCastle
  var privParameters = new RsaKeyParameters(true, bcMod, bcPrivateExponent);
  var eng = new Pkcs1Encoding(new RsaEngine());
  eng.Init(false, privParameters);

  var ret = eng.ProcessBlock(decodedAesKey, 0, 128);
}
catch (Exception e)
{
  Console.WriteLine(e);
}

【问题讨论】:

    标签: cryptography aes rsa bouncycastle libgcrypt


    【解决方案1】:

    答案就是去掉new Pkcs1Encoding()构造函数调用,直接使用RsaEngine。如果没有填充,则无需删除或验证它。

    请注意,填充是创建基于 RSA 的安全密文的必要条件。所以这可以解决兼容性问题,但应该立即更换系统。

    【讨论】:

    • 另请注意,PKCS#1v1.5 填充不安全 - 您应该使用 OAEP。
    • @ntoskrnl 是的,PKCS#1 1.5 不像 OAEP 填充那样安全。与 no padding 相比,PKSC#1 v1.5 padding 非常安全 :)
    • 谢谢@owlstead!答案就在我的眼皮底下!我同意并理解这“不是最理想的”,但事实就是如此。
    • 还要注意.. 有时加密的 AESKey 有前导零,需要在解密之前删除。
    • 原则上 RSA 加密传递一个数字作为密文。通常,这被编码为与密钥长度相同的字节数组(答案当然总是适合模数)。对于填充加密方法,这意味着答案总是大约模数的大小。它比 192 小 1 字节的机会大约是 1 比 192,比 256 小 2 字节的机会大约是 1 比 192 乘以 256。同样对于解密,密文被视为一个数字。前导零应该不是问题。如果你有超过两/三个前导零,那么你就有麻烦了。
    猜你喜欢
    • 1970-01-01
    • 2012-05-10
    • 2011-08-20
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 2018-01-13
    • 2021-12-19
    相关资源
    最近更新 更多