Пример #1
0
        /// <summary>
        /// Adds padding to the input data and returns the padded data.
        /// </summary>
        /// <param name="dataBytes">Data to be padded prior to encryption</param>
        /// <param name="params">RSA Parameters used for padding computation</param>
        /// <returns>Padded message</returns>
        public byte[] EncodeMessage(byte[] dataBytes, RSAParameters @params)
        {
            //Determine if we can add padding.
            if (dataBytes.Length > GetMaxMessageLength(@params))
            {
                throw new CryptographicException("Data length is too long.  Increase your key size or consider encrypting less data.");
            }

            int padLength = @params.N.Length - dataBytes.Length - 3;
            BigInteger biRnd = new BigInteger();
            biRnd.genRandomBits(padLength * 8, new Random(DateTime.Now.Millisecond));

            byte[] bytRandom = null;
            bytRandom = biRnd.getBytes();

            int z1 = bytRandom.Length;

            //Make sure the bytes are all > 0.
            for (int i = 0; i <= bytRandom.Length - 1; i++)
            {
                if (bytRandom[i] == 0x00)
                {
                    bytRandom[i] = 0x01;
                }
            }

            byte[] result = new byte[@params.N.Length];


            //Add the starting 0x00 byte
            result[0] = 0x00;

            //Add the version code 0x02 byte
            result[1] = 0x02;

            for (int i = 0; i <= bytRandom.Length - 1; i++)
            {
                z1 = i + 2;
                result[z1] = bytRandom[i];
            }

            //Add the trailing 0 byte after the padding.
            result[bytRandom.Length + 2] = 0x00;

            //This starting index for the unpadded data.
            int idx = bytRandom.Length + 3;

            //Copy the unpadded data to the padded byte array.
            dataBytes.CopyTo(result, idx);

            return result;
        }
Пример #2
0
        /// <summary>
        /// Create and initialize structure from RSAParameters
        /// </summary>
        /// <returns>Initialized structure</returns>
        /// <note>http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsaparameters.aspx</note>
        public static PublicKeyBlob FromRSAParameters(RSAParameters @params)
        {
            var publicKeyBlob = new PublicKeyBlob
            {
                Header = BlobHeader.FromRSAParameters(KeyBlobType.PublicKeyBlob),
                RSAPubKey = RSAPubKey.FromRSAParameters(@params, false),

                Modulus = new byte[@params.N.Length],
            };

            for (int i = 0; i < publicKeyBlob.Modulus.Length; i++)
            {
                publicKeyBlob.Modulus[i] = @params.N[@params.N.Length - i - 1];
            }

            return publicKeyBlob;
        }
Пример #3
0
        /// <summary>
        /// Create and initialize structure from RSAParameters
        /// </summary>
        /// <returns>Initialized structure</returns>
        /// <note>http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsaparameters.aspx</note>
        public static PrivateKeyBlob FromRSAParameters(RSAParameters @params)
        {
            var privateKeyBlob = new PrivateKeyBlob
            {
                Header = BlobHeader.FromRSAParameters(KeyBlobType.PrivateKeyBlob),
                RSAPubKey = RSAPubKey.FromRSAParameters(@params, true),
            };

            privateKeyBlob.Modulus = new byte[@params.N.Length];
            for (int i = 0; i < privateKeyBlob.Modulus.Length; i++)
            {
                privateKeyBlob.Modulus[i] = @params.N[@params.N.Length - i - 1];
            }

            privateKeyBlob.Prime1 = new byte[@params.P.Length];
            for (int i = 0; i < privateKeyBlob.Prime1.Length; i++)
            {
                privateKeyBlob.Prime1[i] = @params.P[@params.P.Length - i - 1];
            }

            privateKeyBlob.Prime2 = new byte[@params.Q.Length];
            for (int i = 0; i < privateKeyBlob.Prime2.Length; i++)
            {
                privateKeyBlob.Prime2[i] = @params.Q[@params.Q.Length - i - 1];
            }

            privateKeyBlob.Exponent1 = new byte[@params.DP.Length];
            for (int i = 0; i < privateKeyBlob.Exponent1.Length; i++)
            {
                privateKeyBlob.Exponent1[i] = @params.DP[@params.DP.Length - i - 1];
            }

            privateKeyBlob.Exponent2 = new byte[@params.DQ.Length];
            for (int i = 0; i < privateKeyBlob.Exponent2.Length; i++)
            {
                privateKeyBlob.Exponent2[i] = @params.DQ[@params.DQ.Length - i - 1];
            }

            privateKeyBlob.Coefficient = new byte[@params.IQ.Length];
            for (int i = 0; i < privateKeyBlob.Coefficient.Length; i++)
            {
                privateKeyBlob.Coefficient[i] = @params.IQ[@params.IQ.Length - i - 1];
            }

            privateKeyBlob.PrivateExponent = new byte[@params.D.Length];
            for (int i = 0; i < privateKeyBlob.PrivateExponent.Length; i++)
            {
                privateKeyBlob.PrivateExponent[i] = @params.D[@params.D.Length - i - 1];
            }

            return privateKeyBlob;
        }
Пример #4
0
        /// <summary>
        /// Create and initialize RSAParameters structure
        /// </summary>
        /// <returns>Initialized structure</returns>
        /// <note>http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsaparameters.aspx</note>
        public RSAParameters ToRSAParameters()
        {
            var bytes = BitConverter.GetBytes(PublicExponent);

            var @params = new RSAParameters
            {
                E = new byte[bytes[sizeof(uint) - 1] == 0 ? sizeof(uint) - 1 : sizeof(uint)]
            };

            for (int i = 0; i < @params.E.Length; i++)
            {
                @params.E[i] = bytes[@params.E.Length - i - 1];
            }

            return @params;
        }
Пример #5
0
        /// <summary>
        /// Create and initialize structure from RSAParameters
        /// </summary>
        /// <returns>Initialized structure</returns>
        public static RSAPubKey FromRSAParameters(RSAParameters @params, bool includePrivateParameters)
        {
            var rsaPubKey = new RSAPubKey
            {
                Magic = (uint)(includePrivateParameters ? 0x32415352 : 0x31415352),
                BitLength = (uint)(@params.N.Length << 3),
            };

            var bytes = new byte[sizeof(uint)];
            bytes[sizeof(uint) - 1] = 0;

            for (int i = 0; i < @params.E.Length; i++)
            {
                bytes[i] = @params.E[@params.E.Length - i - 1];
            }

            rsaPubKey.PublicExponent = BitConverter.ToUInt32(bytes, 0);

            return rsaPubKey;
        }
Пример #6
0
        /// <summary>
        /// Verifies the signed data against the unsigned data after decryption.
        /// </summary>
        /// <param name="dataBytes">Unsigned data</param>
        /// <param name="signedDataBytes">Signed data (after decryption)</param>
        /// <param name="params">RSAParameters used for signature computation</param>
        /// <returns>Boolean representing whether the input data matches the signed data</returns>
        bool ISignatureProvider.VerifySignature(byte[] dataBytes, byte[] signedDataBytes, RSAParameters @params)
        {
            byte[] EM2 = EncodeSignature(dataBytes, @params);

            if (!(EM2.Length == signedDataBytes.Length))
            {
                return false;
            }

            bool isValid = true;

            for (int i = 0; i <= EM2.Length - 1; i++)
            {
                if (!(EM2[i] == signedDataBytes[i]))
                {
                    isValid = false;
                    break;
                }
            }

            return isValid;
        }
Пример #7
0
 /// <summary>
 /// Gets the maximum message length for this padding provider.
 /// </summary>
 /// <param name="params">RSA Parameters used for padding computation</param>
 /// <returns>Max message length</returns>
 public int GetMaxMessageLength(RSAParameters @params)
 {
     return @params.N.Length - 11;
 }
Пример #8
0
        /// <summary>
        /// Returns an RSAParameters object that contains the key data for the currently loaded key.  
        /// </summary>
        /// <returns>Instance of the currently loaded RSAParameters object or null if no key is loaded</returns>
        /// <remarks></remarks>
        public RSAParameters ExportParameters(bool exportPrivate=true)
        {
            RSAParameters result = new RSAParameters();

            if (m_KeyLoaded == true)
            {
                result = m_RSAParams;
            }
            else
            {
                result = null;
            }

            return result;
        }
Пример #9
0
 /// <summary>
 /// Gets the maximum message length for this padding provider.
 /// </summary>
 /// <param name="params">RSA Parameters used for padding computation</param>
 /// <returns>Max message length</returns>
 public int GetMaxMessageLength(RSAParameters @params)
 {
     return m_OAEP.GetMaxMessageLength(@params);
 }
Пример #10
0
 /// <summary>
 /// Removes padding that was added to the unencrypted data prior to encryption.
 /// </summary>
 /// <param name="dataBytes">Data to have padding removed</param>
 /// <param name="params">RSA Parameters used for padding computation</param>
 /// <returns>Unpadded message</returns>
 public byte[] DecodeMessage(byte[] dataBytes, RSAParameters @params)
 {
     return m_OAEP.DecodeMessage(dataBytes, @params);
 }
Пример #11
0
 /// <summary>
 /// Gets the maximum message length for this padding provider.
 /// </summary>
 /// <param name="params">RSA Parameters used for padding computation</param>
 /// <returns>Max message length</returns>
 public int GetMaxMessageLength(RSAParameters @params)
 {
     return @params.N.Length - (2 * m_hLen) - 2;
 }
Пример #12
0
        /// <summary>
        /// Removes padding that was added to the unencrypted data prior to encryption.
        /// </summary>
        /// <param name="dataBytes">Data to have padding removed</param>
        /// <param name="params">RSA Parameters used for padding computation</param>
        /// <returns>Unpadded message</returns>
        public byte[] DecodeMessage(byte[] dataBytes, RSAParameters @params)
        {
            m_k = @params.D.Length;
            if (!(m_k == dataBytes.Length))
            {
                throw new CryptographicException("Bad Data.");
            }

            //Length of the datablock
            int iDBLen = dataBytes.Length - m_hLen - 1;

            //Starting index for the data block.  This will be equal to m_hLen + 1.  The 
            //index is zero based, and the dataBytes should start with a single leading byte, 
            //plus the maskedSeed (equal to hash length m_hLen).
            int iDBidx = m_hLen + 1;

            //Single byte for leading byte
            byte bytY = 0;

            //Byte array matching the length of the hashing algorithm.
            //This array will hold the masked seed.
            byte[] maskedSeed = new byte[m_hLen];

            //Byte array matching the length of the following:
            //Private Exponent D minus Hash Length, minus 1 (for the leading byte)
            byte[] maskedDB = new byte[iDBLen];

            //Copy the leading byte
            bytY = dataBytes[0];

            //Copy the mask
            Array.Copy(dataBytes, 1, maskedSeed, 0, m_hLen);

            //Copy the data block
            Array.Copy(dataBytes, iDBidx, maskedDB, 0, iDBLen);

            //Reproduce the seed mask from the masked data block using the mask generation function
            byte[] seedMask = Mathematics.OAEPMGF(maskedDB, m_hLen, m_hLen, m_hashProvider);

            //Reproduce the Seed from the Seed Mask.
            byte[] seed = Mathematics.BitwiseXOR(maskedSeed, seedMask);

            //Reproduce the data block bask from the seed using the mask generation function
            byte[] dbMask = Mathematics.OAEPMGF(seed, m_k - m_hLen - 1, m_hLen, m_hashProvider);

            //Reproduce the data block from the masked data block and the seed
            byte[] dataBlock = Mathematics.BitwiseXOR(maskedDB, dbMask);

            //Pull the message from the data block.  First m_hLen bytes are the lHash, 
            //followed by padding of 0x00's, followed by a single 0x01, then the message.
            //So we're going to start and index m_hLen and work forward.
            if (!(dataBlock[m_hLen] == 0x00))
            {
                throw new CryptographicException("Decryption Error.  Bad Data.");
            }

            //If we passed the 0x00 first byte test, iterate through the 
            //data block and find the terminating character.
            int iDataIdx = 0;


            for (int i = m_hLen; i <= dataBlock.Length - 1; i++)
            {
                if (dataBlock[i] == 0x01)
                {
                    iDataIdx = i + 1;
                    break;
                }
            }

            //Now find the length of the data and copy it to a byte array.
            int iDataLen = dataBlock.Length - iDataIdx;
            byte[] result = new byte[iDataLen];
            Array.Copy(dataBlock, iDataIdx, result, 0, iDataLen);

            return result;
        }
Пример #13
0
        /// <summary>
        /// Adds padding to the input data and returns the padded data.
        /// </summary>
        /// <param name="dataBytes">Data to be padded prior to encryption</param>
        /// <param name="params">RSA Parameters used for padding computation</param>
        /// <returns>Padded message</returns>
        public byte[] EncodeMessage(byte[] dataBytes, RSAParameters @params)
        {
            //Iterator
            int i = 0;

            //Get the size of the data to be encrypted
            m_mLen = dataBytes.Length;

            //Get the size of the public modulus (will serve as max length for cipher text)
            m_k = @params.N.Length;

            if (m_mLen > GetMaxMessageLength(@params))
            {
                throw new CryptographicException("Bad Data.");
            }

            //Generate the random octet seed (same length as hash)
            BigInteger biSeed = new BigInteger();
            biSeed.genRandomBits(m_hLen * 8, new Random());
            byte[] bytSeed = biSeed.getBytesRaw();

            //Make sure all of the bytes are greater than 0.
            for (i = 0; i <= bytSeed.Length - 1; i++)
            {
                if (bytSeed[i] == 0x00)
                {
                    //Replacing with the prime byte 17, no real reason...just picked at random.
                    bytSeed[i] = 0x17;
                }
            }

            //Mask the seed with MFG Function(SHA1 Hash)
            //This is the mask to be XOR'd with the DataBlock below.
            byte[] dbMask = Mathematics.OAEPMGF(bytSeed, m_k - m_hLen - 1, m_hLen, m_hashProvider);

            //Compute the length needed for PS (zero padding) and 
            //fill a byte array to the computed length
            int psLen = GetMaxMessageLength(@params) - m_mLen;

            //Generate the SHA1 hash of an empty L (Label).  Label is not used for this 
            //application of padding in the RSA specification.
            byte[] lHash = m_hashProvider.ComputeHash(System.Text.Encoding.UTF8.GetBytes(string.Empty.ToCharArray()));

            //Create a dataBlock which will later be masked.  The 
            //data block includes the concatenated hash(L), PS, 
            //a 0x01 byte, and the message.
            int dbLen = m_hLen + psLen + 1 + m_mLen;
            byte[] dataBlock = new byte[dbLen];

            int cPos = 0;
            //Current position

            //Add the L Hash to the data blcok
            for (i = 0; i <= lHash.Length - 1; i++)
            {
                dataBlock[cPos] = lHash[i];
                cPos += 1;
            }

            //Add the zero padding
            for (i = 0; i <= psLen - 1; i++)
            {
                dataBlock[cPos] = 0x00;
                cPos += 1;
            }

            //Add the 0x01 byte
            dataBlock[cPos] = 0x01;
            cPos += 1;

            //Add the message
            for (i = 0; i <= dataBytes.Length - 1; i++)
            {
                dataBlock[cPos] = dataBytes[i];
                cPos += 1;
            }

            //Create the masked data block.
            byte[] maskedDB = Mathematics.BitwiseXOR(dbMask, dataBlock);

            //Create the seed mask
            byte[] seedMask = Mathematics.OAEPMGF(maskedDB, m_hLen, m_hLen, m_hashProvider);

            //Create the masked seed
            byte[] maskedSeed = Mathematics.BitwiseXOR(bytSeed, seedMask);

            //Create the resulting cipher - starting with a 0 byte.
            byte[] result = new byte[@params.N.Length];
            result[0] = 0x00;

            //Add the masked seed
            maskedSeed.CopyTo(result, 1);

            //Add the masked data block
            maskedDB.CopyTo(result, maskedSeed.Length + 1);

            return result;
        }
Пример #14
0
 /// <summary>
 /// Gets the maximum message length for this padding provider.
 /// </summary>
 /// <param name="params">RSA Parameters used for padding computation</param>
 /// <returns>Max message length</returns>
 public int GetMaxMessageLength(RSAParameters @params)
 {
     return int.MaxValue;
 }
Пример #15
0
 /// <summary>
 /// Removes padding that was added to the unencrypted data prior to encryption.
 /// </summary>
 /// <param name="dataBytes">Data to have padding removed</param>
 /// <param name="params">RSA Parameters used for padding computation</param>
 /// <returns>Unpadded message</returns>
 byte[] IPaddingProvider.DecodeMessage(byte[] dataBytes, RSAParameters @params)
 {
     return dataBytes;
 }
Пример #16
0
        /// <summary>
        /// Sets the current class internal variables based on the supplied XML. 
        /// Attempts to validate the XML prior to setting.
        /// </summary>
        /// <param name="xmlString">XML String containing key info</param>
        /// <remarks></remarks>
        public void FromXmlString(string xmlString)
        {
            RSAParameters oParams = new RSAParameters();

            using (System.Xml.XmlReader reader = System.Xml.XmlReader.Create(new StringReader(xmlString)))
            {
                int iNode = 0;

                while (reader.Read())
                {
                    if (reader.Value.Trim().Length > 0)
                    {
                        switch (iNode)
                        {
                            case 1:
                                oParams.N = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                            case 2:
                                oParams.E = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                            case 3:
                                oParams.P = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                            case 4:
                                oParams.Q = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                            case 5:
                                oParams.DP = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                            case 6:
                                oParams.DQ = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                            case 7:
                                oParams.IQ = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                            case 8:
                                oParams.D = Convert.FromBase64String(reader.Value);
                                iNode = 0;
                                break;
                        }
                    }

                    switch (reader.NodeType)
                    {
                        case System.Xml.XmlNodeType.Element:
                            switch (reader.Name.ToUpper())
                            {
                                case "MODULUS":
                                    iNode = 1;
                                    break;
                                case "EXPONENT":
                                    iNode = 2;
                                    break;
                                case "P":
                                    iNode = 3;
                                    break;
                                case "Q":
                                    iNode = 4;
                                    break;
                                case "DP":
                                    iNode = 5;
                                    break;
                                case "DQ":
                                    iNode = 6;
                                    break;
                                case "INVERSEQ":
                                    iNode = 7;
                                    break;
                                case "D":
                                    iNode = 8;
                                    break;
                            }
                            break;
                    }
                }
            }

            //If P and Q are set, set Phi
            if (oParams.P.Length > 0 && oParams.Q.Length > 0)
            {
                oParams.Phi = new BigInteger((new BigInteger(oParams.P) - 1) * (new BigInteger(oParams.Q) - 1)).getBytes();
            }

            if (Validate_Key_Data(oParams))
            {
                m_RSAParams = oParams;
                m_KeyLoaded = true;
            }
        }
Пример #17
0
        /// <summary>
        /// Import an existing set of RSA Parameters.  If only the public key is to be loaded, 
        /// Do not set the P, Q, DP, DQ, IQ or D values.  If P, Q or D are set, the parameters 
        /// will automatically be validated for existence of private key.
        /// </summary>
        /// <param name="params">RSAParameters object containing key data.</param>
        public void ImportParameters(RSAParameters @params)
        {
            if (Validate_Key_Data(@params))
            {
                m_RSAParams.D = @params.D;
                m_RSAParams.N = @params.N;
                m_RSAParams.DP = @params.DP;
                m_RSAParams.DQ = @params.DQ;
                m_RSAParams.E = @params.E;
                m_RSAParams.IQ = @params.IQ;
                m_RSAParams.P = @params.P;
                m_RSAParams.Q = @params.Q;
                //Phi can only be set internally and is always calculated
                m_RSAParams.Phi = new BigInteger((new BigInteger(@params.P) - 1) * (new BigInteger(@params.Q) - 1)).getBytes();

                m_KeyLoaded = true;
            }

        }
Пример #18
0
        /// <summary>
        /// Hashes and encodes the signature for encryption.  Uses the DER (Distinguished Encoding Rules) 
        /// and the SHA256 hash provider for encoding generation.
        /// </summary>
        /// <param name="dataBytes">Data to be signed</param>
        /// <param name="params">RSA Parameters used for signature calculation</param>
        /// <returns>Computed signature (pre-encryption)</returns>
        public byte[] EncodeSignature(byte[] dataBytes, RSAParameters @params)
        {
            //Set the intended message length (key length)
            int emLen = @params.N.Length;

            //Compute the hash of the data
            byte[] H = m_hashProvider.ComputeHash(dataBytes);
            //Get the digest encoding information for the hash being used.
            byte[] bytDigestEncoding = DigestEncoding.SHA256();

            //Create the hashed message including the digest info
            byte[] T = new byte[(bytDigestEncoding.Length + m_hLen)];
            bytDigestEncoding.CopyTo(T, 0);
            H.CopyTo(T, bytDigestEncoding.Length);

            H = null;
            bytDigestEncoding = null;

            if (emLen < T.Length + 11)
            {
                throw new CryptographicException("Message too short.");
            }

            //Create the padding string, octet string of 0xff
            byte[] PS = new byte[(emLen - T.Length - 3)];
            for (int i = 0; i <= PS.Length - 1; i++)
            {
                PS[i] = 0xff;
            }

            byte[] result = new byte[emLen];

            //Add the leading identifier bytes
            result[0] = 0x00;
            result[1] = 0x01;

            //Copy the padding string to the result
            PS.CopyTo(result, 2);

            //Add the separator byte
            result[PS.Length + 2] = 0x00;

            //Copy the digest info
            T.CopyTo(result, PS.Length + 3);
            PS = null;
            T = null;

            return result;
        }
Пример #19
0
        private bool Validate_Key_Data(RSAParameters @params)
        {
            bool result = true;

            //Make sure the public bits have been set
            if (!(@params.N.Length > 0))
            {
                throw new CryptographicException("Value for Modulus (N) is missing or invalid.");
            }

            if (!(@params.E.Length > 0))
            {
                throw new CryptographicException("Value for Public Exponent (E) is missing or invalid.");
            }

            //If any of the private key data (D, P or Q) were supplied, validating private
            //key info.
            if (@params.D.Length > 0 || @params.P.Length > 0 || @params.Q.Length > 0)
            {
                if (!(@params.P.Length > 0))
                {
                    throw new CryptographicException("Value for P is missing or invalid.");
                }

                if (!(@params.Q.Length > 0))
                {
                    throw new CryptographicException("Value for Q is missing or invalid.");
                }

                if (!(@params.D.Length > 0))
                {
                    throw new CryptographicException("Value for Private Exponent (D) is missing or invalid.");
                }

                //Validate the key
                if (@params.P.Length != @params.N.Length / 2 || @params.Q.Length != @params.N.Length / 2)
                {
                    throw new CryptographicException("Invalid Key.");

                }

                BigInteger biN = new BigInteger(@params.N);
                BigInteger biP = new BigInteger(@params.P);
                BigInteger biQ = new BigInteger(@params.Q);

                BigInteger tmpMod = new BigInteger(biP * biQ);

                if (!(tmpMod == biN))
                {
                    throw new CryptographicException("Invalid Key.");
                }

                tmpMod = null;

            }

            return result;
        }
Пример #20
0
        /// <summary>
        /// Removes padding that was added to the unencrypted data prior to encryption.
        /// </summary>
        /// <param name="dataBytes">Data to have padding removed</param>
        /// <param name="params">RSA Parameters used for padding computation</param>
        /// <returns>Unpadded message</returns>
        public byte[] DecodeMessage(byte[] dataBytes, RSAParameters @params)
        {
            byte[] bytDec = new byte[@params.N.Length];

            int lenDiff = 0;

            dataBytes.CopyTo(bytDec, lenDiff);

            if ((bytDec[0] != 0x0) && (bytDec[1] != 0x02))
            {
                throw new CryptographicException("Invalid padding.  Supplied data does not contain valid PKCS#1 v1.5 padding.  Padding could not be removed.");
            }

            //Find out where the padding ends.
            int idxEnd = 0;
            int dataLength = 0;

            for (int i = 2; i < bytDec.Length; i++)
            {
                if (bytDec[i] == 0x00)
                {
                    idxEnd = i;
                    break;
                }
            }

            //Calculate the length of the unpadded data
            dataLength = bytDec.Length - idxEnd - 2;

            byte[] result = new byte[dataLength + 1];

            int idxRslt = 0;

            //Put the unpadded data into the result array
            for (int i = idxEnd + 1; i <= bytDec.Length - 1; i++)
            {
                result[idxRslt] = bytDec[i];
                idxRslt += 1;
            }

            return result;
        }