0

Summary: I am attempting to decrypt (and eventually encrypt and return) files that are AES128 encrypted. The AES key is encrypted using libcrypt's RSA provider. When I attempt to decrypt the AESKey on Windows 7 using C# & BouncyCastle a "block truncated" error is thrown when I call "ProcessBlock". I have tried converting the data to BigEndian and I'll get a "Not a valid RSA exponent" when I try to create the RsaKeyParameters.

The encryption was done using libgcrypt 1.2x on a linux system. I think it's a padding issue since this snippet of code indicates that no padding is used. gcry_sexp_build(&PlainKeyExp, NULL, "(data (flags raw) (value %s))", AESKey );

Unfortunately I cannot change the originating system. I'm including code samples & keys below to help. This has been driving me insane for the past 3 days. I've scoured the interwebz and have not found a solution. Thank you in advance for your help.

Originating code snippet

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

Decoding code snippet

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);
}
TheBrian
  • 148
  • 1
  • 8

1 Answers1

4

The answer is simply to remove the new Pkcs1Encoding() constructor call and directly use RsaEngine. If there is no padding, then there is no need to remove or validate it.

Note that padding is a requirement to create a secure RSA based ciphertext. So this is OK to overcome compatibility issues, but the system should be replaced right away.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • 2
    Also note that PKCS#1v1.5 padding is not secure – you should use OAEP. – ntoskrnl Jul 11 '13 at 08:58
  • 2
    @ntoskrnl Yep, PKCS#1 1.5 is not *as* secure as OAEP padding. Compared to *no padding* PKSC#1 v1.5 padding is however very secure :) – Maarten Bodewes Jul 11 '13 at 12:40
  • Thank you @owlstead! The answer was right there under my nose! I agree and understand that this is 'less than optimal' but it is what it is. – TheBrian Jul 11 '13 at 15:13
  • Also to note.. sometimes the encrypted AESKey has leading zeros which need to be removed before decrypting. – TheBrian Jul 11 '13 at 15:14
  • In principle RSA encryption delivers a number as ciphertext. Normally this is encoded as a byte array with the same length as the key (the answer of course always fits inside the modulus). For a *padded* encryption method this means that the answer is always *about* the size of the modulus. The chances of it being one byte smaller is about 1 over 192, the chances of it being two bytes smaller is about 1 over 192 times 256. Again for decryption, the ciphertext is treated as a number. Leading zero's should not be a problem. If you have got over two/three leading zero's then you are in trouble. – Maarten Bodewes Jul 11 '13 at 17:13