2016-07-14 47 views
0

使用下面的代碼 - 我通常能夠解密一個令牌,我被傳遞。當解碼JSON令牌字符串如下所示:C#Bouncy Castle AES Decryption + GZ Decompression - 變長數據失敗

\"id\":\"9efef759-15a3-4cd0-b1f1-fceab7ad0a6e\", 
\"exp\":\"2016-07-23T15:27:50.758+12:00\", 
\"iv\":\"OOqNpy9puM5jPjTwrWHSNb+d5NYDEwIq2pZFqx6mraI14Kkh0bzEWADoU2d/KGu6cp9/FrVt4epheIP5Fw9qUFrdVcNYjLO5HWdJ0V5GhpdLJlFbMnFy4vS1rJ+4X1qTNZrqPwZh2deLceoHmxnqw7ml8JVFeIaz9H8BQXkgcNo=\", 
\"ver\":\"1\", 
\"iat\":\"2016-07-13T15:27:50.758+12:00\", 
\"key\":\"d7R9blmqBYMywOEdYpRbd+gvKPfOqmxsRQMlDipkuGoWZobJ0dnK0MGBFAXq4wOdHbHVbfisjqm+6HoRSZ2w0KcfY+enPoKL5yptvlULkwpDtATEP8pnRmCh6ycWntbanL1gJI7RoNWTkomItBp/yODdL5kSMue76xAtIzc9+no=\", 
\"sig\":\"X6A58tRDSUC5HJEP1VVmQjo17Qk2rJC9pYZiV5ccIjdcLmz7HPIkpm0ZCsFcQX4ps1k32asSojqOyegYFIdDqHypdrV9c5sHchIrp6Ak8MOjNTpy+SweTGPzkjlEHCMkWLVHjrkBq9mmoMk2o0sYyZes+/ARuYB8IjtAINtbAQE=\", 
\"enc\":\"n+exbDhicBLuUtbYPXrrKESIktgyaidSreD5FWAxErGJeOyjTWv9QOqCGfEou5yJq2njCddf0mu0JOEP9i1mlhe1MUUa1hE4J+qnqxre+tSxWRNszHQL8Pk+0FV6cZ1nqk+aCfw9VOjlOLYXYmNF0NSZBqQIqzpobM3twHIf5u7pvJkvbnfP8Db0S83ZchNgMWyH1t+UEb+jbpcg1Um3U7Yb8Q==\" 

的IV和密鑰是從令牌拉,非對稱解密然後將它們傳遞到一個gzip壓縮前的ENC文本對稱解密。

internal virtual UserObj decrypt(string jsonToken, UserObj cls, System.Security.Cryptography.AsymmetricAlgorithm certPrivateKey) 
{ 

    Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair bcPrivateKey; 
    try 
    { 
     //Make a bouncyCastle private key for feeding to the rsa Engine. 
     bcPrivateKey = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(certPrivateKey); 
     // Attempt to unmarshal the JSON token 
     Token token = encoder.unmarshalJsonString<Token>(jsonToken); 

     // Asymmetrically encrypt the symmetric encryption iv 
     Org.BouncyCastle.Crypto.Engines.RsaEngine rsaCipher = new Org.BouncyCastle.Crypto.Engines.RsaEngine(); 
     Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding rsaEncoder = new Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding(rsaCipher); 

     rsaEncoder.Init(false, bcPrivateKey.Private); 

     // Asymmetrically decrypt the symmetric encryption key 
     byte[] encryptedAesKeyBytes = encoder.fromBase64String(token.Get(Token.ENCRYPTED_KEY)); 
     byte[] aesKeyBytes = rsaEncoder.ProcessBlock(encryptedAesKeyBytes, 0, encryptedAesKeyBytes.Length); 

     // Asymmetrically decrypt the symmetric encryption IV 
     byte[] encryptedAesIvBytes = encoder.fromBase64String(token.Get(Token.IV)); 
     byte[] aesIvBytes = rsaEncoder.ProcessBlock(encryptedAesIvBytes, 0, encryptedAesIvBytes.Length); 

     //Setting equivalent excyption to "AES/CTR/NoPadding" 
     Org.BouncyCastle.Crypto.Engines.AesEngine aes = new Org.BouncyCastle.Crypto.Engines.AesEngine(); 
     Org.BouncyCastle.Crypto.Modes.SicBlockCipher blockCipher = new Org.BouncyCastle.Crypto.Modes.SicBlockCipher(aes); 
     Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher aesCipher = new Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher(blockCipher, new Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding()); 

     Org.BouncyCastle.Crypto.Parameters.KeyParameter keyParam2 = new Org.BouncyCastle.Crypto.Parameters.KeyParameter(aesKeyBytes); 

     // Symmetrically decrypt the data 
     Org.BouncyCastle.Crypto.Parameters.ParametersWithIV keyParamWithIv = new Org.BouncyCastle.Crypto.Parameters.ParametersWithIV(keyParam2, aesIvBytes, 0, TokenEncryptor.IV_SIZE_BYTES); 
     // 
     // Symmetrically decrypt the data 
     aesCipher.Init(false, keyParamWithIv); 
     string encryptedData = token.Get(Token.ENCRYPTED_DATA); 
     byte[] inputBytes = encoder.fromBase64String(encryptedData); 
     byte[] compressedJsonBytes = new byte[aesCipher.GetOutputSize(inputBytes.Length)]; 
     //Do the decryption. length is the proper size of the compressed data, compressedJsonBytes will 
     //contain extra nulls at the end. 
     int length = aesCipher.ProcessBytes(inputBytes, compressedJsonBytes, 0); 

     //String to look at the compressed data (debug) 
     string compressed = encoder.toBase64String(compressedJsonBytes); 
     byte[] compressedJsonBytesProperSize = new byte[length]; 
     Array.Copy(compressedJsonBytes, compressedJsonBytesProperSize, length); 

     //String to look at the compressed data (debug) 
     compressed = encoder.toBase64String(compressedJsonBytesProperSize); 
     byte[] jsonBytes = null; 
     try 
     { 
       jsonBytes = encoder.decompress(compressedJsonBytesProperSize); 
     } 
     catch (Exception) 
     { 
       jsonBytes = encoder.decompress(compressedJsonBytes); 
     } 
     string tmep = System.Text.Encoding.UTF8.GetString(jsonBytes, 0, jsonBytes.Length); 
     UserObj dataObj = encoder.fromJsonBytes<UserObj>(jsonBytes); 

     return dataObj; 

    } 
    catch (Exception e) 
    { 
     throw new Exceptions.TokenDecryptionException(e); 
    } 
} 

最終解密令牌看起來像這樣:取決於組中的項目數量時,會發生

\"domain\":\"GLOBAL\", 
\"user\":\"someuser\", 
\"groups\":[\"GROUP1\",\"GROUP2\",\"GROUP3\"], 
\"branchId\":\"0000\" 

我的問題,GZ減壓將失敗。在一些令牌中,如果我傳遞完整的compressedJsonByte數組(在最後有空),它會抱怨CRC錯誤(爲什麼我有解壓縮的try/catch),所以然後我將它傳遞給trimmed字節數組。但對於具有更多組的其他令牌,它將使用完整的字節數組進行解壓縮。

我有一個可比較的加密程序,發現如果提醒用戶名從17到19個字符,其他所有內容都相等,我需要使用未修剪的字節數組進行解壓縮。但從那時起,問題就越來越深入。

任何幫助,將不勝感激。我希望它是一個解壓縮的問題,但我懷疑可能是在解密的東西fudging輸出字節數組的末尾。

我無法更改解密類型,因爲它來自外部實體,而它們的一面是用Java編寫的。

,以供參考解壓縮程序是:

 public virtual byte[] decompress(byte[] compressedData) 
     { 
      try 
      { 
       //Push to a file for debug 
       System.IO.FileStream fs = new System.IO.FileStream(@"C:\temp\file.gz", System.IO.FileMode.OpenOrCreate); 
       fs.Write(compressedData,0,compressedData.Length); 
       fs.Flush(); 
       fs.Close(); 

       byte[] outputBytes = new byte[4096]; 
       byte[] buffer = new byte[4096]; 
        using (System.IO.MemoryStream msInput = new System.IO.MemoryStream(compressedData)) 
        { 
         System.IO.MemoryStream msOutput = new System.IO.MemoryStream(); 
         //using (System.IO.Compression.GZipStream gzs = new System.IO.Compression.GZipStream(msInput, System.IO.Compression.CompressionMode.Decompress)) 
         using (ZLibNet.GZipStream gzs = new ZLibNet.GZipStream(msInput, ZLibNet.CompressionMode.Decompress)) 
         { 

          int nRead; 

          bool canR = gzs.CanRead; 
          while ((nRead = gzs.Read(buffer, 0, buffer.Length)) > 0) 
          { 
           msOutput.Write(buffer, 0, nRead); 

          } 
         } 
         outputBytes = msOutput.ToArray(); 
         if (outputBytes.Length == 0) 
          throw new Exception("Could not decompress"); 
        } 
       return outputBytes; 
      } 
      catch (Exception e) 
      { 
       throw new Exceptions.ServiceException(e); 
      } 
     } 

回答

2

您使用ZeroBytePadding而CTR模式不需要任何填充可言,你還不如直接使用SicCipher實例。

零字節填充將從數據末尾剝離所有零值字節,這就是爲什麼最終可能會泄露數據。

零字節填充是不確定性的,不應該被使用,除非你要麼:

  • 肯定不是一個零字節或位結束的數據;
  • 能夠以其他方式確定明文長度。
+0

所以我想了解一下使用SicBlockCipher。這是否意味着,而不是aesCipher.ProcessBytes我需要輸入一個循環與blockCipher.ProcessBlock爲inputBytes的長度? – dcole

+0

我也試過PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(blockCipher); 並進行了,但展示了壓縮解密數據無效的同樣的問題。 – dcole

-1

我可能剛剛破解它。對於更大的有效負載令牌,ProcessBytes將一次工作。

對於較小的那些,我花了很長時間才注意到從ProcessBytes報告的長度小於inputBytes數組的長度。

我試過DoFinal過程字節之後:

int length = aesCipher.ProcessBytes(inputBytes, compressedJsonBytes, 0); 
int length2= aesCipher.DoFinal(compressedJsonBytes, length); 

而對於令牌我編碼它的工作...但對於給定的那些我有,它發佈了Org.BouncyCastle.Crypto。DataLengthException:最後一個塊解密

完全,所以最後我想

int length2 = aesCipher.ProcessBytes(inputBytes,length,inputBytes.Length-length,compressedJsonBytes,length); 

要處理的數據保留 - 這工作。 所以我最終的代碼現在看起來如下 - 更換一行:

int length = aesCipher.ProcessBytes(inputBytes, compressedJsonBytes, 0); 

有了:

int length = 0; 
while (length < inputBytes.Length) 
{ 
    length += aesCipher.ProcessBytes(inputBytes, length, inputBytes.Length-length, compressedJsonBytes, length); 
} 

而且這似乎已經刪除了需要採取全長壓縮字節數組。 UncompressedProperSize字節數組現在正常工作。

相關問題