C#Bouncy Castle AES解密+ GZ解压缩-可变长度数据失败 - java

使用以下代码-通常,我可以解密正在传递的令牌。令牌字符串解码为json时将如下所示:

\"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和密钥并进行非对称解密,然后对enc文本进行对称解密,然后再将它们传递给gzip解压缩。

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数组(末尾为null),它会抱怨CRC错误(为什么要在解压缩周围进行try / catch),因此,我将修剪后的字节数组传递给它。但是对于其他具有更多组的令牌,它将使用全字节数组解压缩。

我有一个可比较的加密例程,发现如果警报的用户名从17到19个字符,则其他所有条件都是相同的,因此我需要使用未修饰的字节数组进行解压缩。但是从那以后发现问题更加严重了。

任何帮助,将不胜感激。我希望这是一个解压缩问题,但是我怀疑解密中的某些内容可能会混淆输出字节数组的末尾。

我无法更改解密类型,因为它来自外部实体,并且它们的侧面是用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);
            }
        }

参考方案

您正在使用ZeroBytePadding,而CTR模式根本不需要任何填充,您也可以直接使用SicCipher实例。

零字节填充会从数据末尾剥离所有零值字节,这就是为什么您可能会得到受损数据的原因。

零字节填充不是确定性的,除非以下两种情况之一,否则不应使用:

确保数据不以零字节或零结尾;
能够以其他方式确定明文长度。

45码