/// <summary>
        /// Initializes an instance of <see cref="EnvelopedSignatureWriter"/>. The returned writer can be directly used
        /// to write the envelope. The signature will be automatically generated when
        /// the envelope is completed.
        /// </summary>
        /// <param name="innerWriter">Writer to wrap/</param>
        /// <param name="signingCredentials">SigningCredentials to be used to generate the signature.</param>
        /// <param name="referenceId">The reference Id of the envelope.</param>
        /// <param name="securityTokenSerializer">SecurityTokenSerializer to serialize the signature KeyInfo.</param>
        /// <exception cref="ArgumentNullException">One of he input parameter is null.</exception>
        /// <exception cref="ArgumentException">The string 'referenceId' is either null or empty.</exception>
        public EnvelopedSignatureWriter(XmlWriter innerWriter, SigningCredentials signingCredentials, string referenceId, SecurityTokenSerializer securityTokenSerializer)
        {
            if (innerWriter == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("innerWriter");
            }

            if (signingCredentials == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("signingCredentials");
            }

            if (string.IsNullOrEmpty(referenceId))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.ID0006), "referenceId"));
            }

            if (securityTokenSerializer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenSerializer");
            }

            // Remember the user's writer here. We need to finally write out the signed XML
            // into this writer.
            _dictionaryManager = new DictionaryManager();
            _innerWriter       = innerWriter;
            _signingCreds      = signingCredentials;
            _referenceId       = referenceId;
            _tokenSerializer   = securityTokenSerializer;

            _signatureFragment = new MemoryStream();
            _endFragment       = new MemoryStream();
            _writerStream      = new MemoryStream();

            XmlDictionaryWriter effectiveWriter = XmlDictionaryWriter.CreateTextWriter(_writerStream, Encoding.UTF8, false);

            // Initialize the base writer to the newly created writer. The user should write the XML
            // to this.
            base.InitializeInnerWriter(effectiveWriter);
            _hashAlgorithm = CryptoHelper.CreateHashAlgorithm(_signingCreds.DigestAlgorithm);
            _hashStream    = new HashStream(_hashAlgorithm);
            base.InnerWriter.StartCanonicalization(_hashStream, false, null);

            //
            // Add tracing for the un-canonicalized bytes
            //
            if (DiagnosticUtility.ShouldTraceVerbose)
            {
                _preCanonicalTracingStream = new MemoryStream();
                base.InitializeTracingWriter(new XmlTextWriter(_preCanonicalTracingStream, Encoding.UTF8));
            }
        }
 public HashAlgorithm TakeHashAlgorithm(string algorithm)
 {
     if (this.hashAlgorithm == null)
     {
         if (string.IsNullOrEmpty(algorithm))
         {
             throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, System.IdentityModel.SR.GetString("EmptyOrNullArgumentString", new object[] { "algorithm" }));
         }
         this.hashAlgorithm = CryptoHelper.CreateHashAlgorithm(algorithm);
     }
     else
     {
         this.hashAlgorithm.Initialize();
     }
     return(this.hashAlgorithm);
 }
        public HashAlgorithm TakeHashAlgorithm(string algorithm)
        {
            if (this.hashAlgorithm == null)
            {
                if (string.IsNullOrEmpty(algorithm))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.GetString(SR.EmptyOrNullArgumentString, "algorithm"));
                }

                this.hashAlgorithm = CryptoHelper.CreateHashAlgorithm(algorithm);
            }
            else
            {
                this.hashAlgorithm.Initialize();
            }

            return(this.hashAlgorithm);
        }
        private HashAlgorithm TakeHashAlgorithm(string algorithm)
        {
            if (_hashAlgorithm == null)
            {
                if (string.IsNullOrEmpty(algorithm))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.Format(SR.EmptyOrNullArgumentString, nameof(algorithm)));
                }

                _hashAlgorithm = CryptoHelper.CreateHashAlgorithm(algorithm);
            }
            else
            {
                _hashAlgorithm.Initialize();
            }

            return(_hashAlgorithm);
        }
        /// <summary>
        /// Signs data.
        /// </summary>
        /// <param name="value">Data to be signed.</param>
        /// <returns>Signed data.</returns>
        /// <exception cref="ArgumentNullException">The argument 'value' is null.</exception>
        /// <exception cref="ArgumentException">The argument 'value' contains zero bytes.</exception>
        /// <exception cref="InvalidOperationException">The SigningKey is null.</exception>
        /// <exception cref="NotSupportedException">The platform does not support the requested algorithm.</exception>
        /// <exception cref="InvalidOperationException">The SigningKey is null, is not an RSACryptoServiceProvider, or does not contain a private key.</exception>
        /// <remarks>The SigningKey must include the private key in order to sign.</remarks>
        public override byte[] Encode(byte[] value)
        {
            if (null == value)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
            }

            if (0 == value.Length)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString(SR.ID6044));
            }

            RSA signingKey = SigningKey;

            RSACryptoServiceProvider rsaCryptoServiceProvider = signingKey as RSACryptoServiceProvider;

            if (null == signingKey || null == rsaCryptoServiceProvider)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6042));
            }

            if (rsaCryptoServiceProvider.PublicOnly)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6046));
            }

            // Compute the signature
            byte[] signature;
            using (HashAlgorithm hash = CryptoHelper.CreateHashAlgorithm(HashName))
            {
                try
                {
                    hash.ComputeHash(value);
                    AsymmetricSignatureFormatter signer = GetSignatureFormatter(signingKey);

                    if (isSha256())
                    {
                        signature = CryptoHelper.CreateSignatureForSha256(signer, hash);
                    }
                    else
                    {
                        signature = signer.CreateSignature(hash);
                    }
                }
                // Not all algorithms are supported on all OS
                catch (CryptographicException e)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ID6035, HashName, signingKey.GetType().FullName), e));
                }
            }

            // Get the signature length as a big-endian integer
            byte[] signatureLength = BitConverter.GetBytes(signature.Length);

            // Assemble the message ...
            int currentIndex = 0;

            byte[] message = new byte[signatureLength.Length + signature.Length + value.Length];

            // SignatureLength : 4-byte big endian integer
            Array.Copy(signatureLength, 0, message, currentIndex, signatureLength.Length);
            currentIndex += signatureLength.Length;

            // Signature       : Octet stream, length is SignatureLength
            Array.Copy(signature, 0, message, currentIndex, signature.Length);
            currentIndex += signature.Length;

            // CookieValue     : Octet stream, remainder of message
            Array.Copy(value, 0, message, currentIndex, value.Length);

            return(message);
        }
        // Format:
        //   SignatureLength : 4-byte big-endian integer
        //   Signature       : Octet stream, length is SignatureLength
        //   CookieValue     : Octet stream, remainder of message

        /// <summary>
        /// Verifies the signature.  All keys in the collection VerificationKeys will be attempted.
        /// </summary>
        /// <param name="encoded">Data previously returned from <see cref="Encode"/></param>
        /// <returns>The originally signed data.</returns>
        /// <exception cref="ArgumentNullException">The argument 'encoded' is null.</exception>
        /// <exception cref="ArgumentException">The argument 'encoded' contains zero bytes.</exception>
        /// <exception cref="FormatException">The data is in the wrong format.</exception>
        /// <exception cref="CryptographicException">The signature is invalid.</exception>
        /// <exception cref="NotSupportedException">The platform does not support the requested algorithm.</exception>
        /// <exception cref="InvalidOperationException">There are no verification keys.</exception>
        public override byte[] Decode(byte[] encoded)
        {
            if (null == encoded)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encoded");
            }

            if (0 == encoded.Length)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("encoded", SR.GetString(SR.ID6045));
            }

            ReadOnlyCollection <RSA> verificationKeys = VerificationKeys;

            if (0 == verificationKeys.Count)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6036));
            }

            // Decode the message ...
            int currentIndex = 0;

            // SignatureLength : 4-byte big-endian integer
            if (encoded.Length < sizeof(Int32))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1012)));
            }
            Int32 signatureLength = BitConverter.ToInt32(encoded, currentIndex);

            if (signatureLength < 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1005, signatureLength)));
            }

            if (signatureLength >= encoded.Length - sizeof(Int32))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1013)));
            }
            currentIndex += sizeof(Int32);

            // Signature        : Octet stream, length is SignatureLength
            byte[] signature = new byte[signatureLength];
            Array.Copy(encoded, currentIndex, signature, 0, signature.Length);
            currentIndex += signature.Length;

            // CookieValue      : Octet stream, remainder of message
            byte[] cookieValue = new byte[encoded.Length - currentIndex];
            Array.Copy(encoded, currentIndex, cookieValue, 0, cookieValue.Length);

            bool verified = false;

            try
            {
                // Verify the signature
                using (HashAlgorithm hash = CryptoHelper.CreateHashAlgorithm(HashName))
                {
                    hash.ComputeHash(cookieValue);

                    foreach (RSA rsa in verificationKeys)
                    {
                        AsymmetricSignatureDeformatter verifier = GetSignatureDeformatter(rsa);
                        if ((isSha256() && CryptoHelper.VerifySignatureForSha256(verifier, hash, signature)) ||
                            verifier.VerifySignature(hash, signature))
                        {
                            verified = true;
                            break;
                        }
                    }
                }
            }

            // Not all algorithms are supported on all OS
            catch (CryptographicException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ID6035, HashName, verificationKeys[0].GetType().FullName), e));
            }

            if (!verified)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.ID1014)));
            }

            return(cookieValue);
        }
Example #7
0
 internal static HashAlgorithm NewSha1HashAlgorithm()
 {
     return(CryptoHelper.CreateHashAlgorithm("http://www.w3.org/2000/09/xmldsig#sha1"));
 }
Example #8
0
        /// <summary>
        /// Encode the data.  The data is encrypted using the default encryption algorithm (AES-256),
        /// then the AES key is encrypted using RSA and the RSA public key is appended.
        /// </summary>
        /// <param name="value">The data to encode</param>
        /// <exception cref="ArgumentNullException">The argument 'value' is null.</exception>
        /// <exception cref="ArgumentException">The argument 'value' contains zero bytes.</exception>
        /// <exception cref="InvalidOperationException">The EncryptionKey is null.</exception>
        /// <returns>Encoded data</returns>
        public override byte[] Encode(byte[] value)
        {
            if (null == value)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
            }

            if (0 == value.Length)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString(SR.ID6044));
            }

            RSA encryptionKey = EncryptionKey;

            if (null == encryptionKey)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6043));
            }

            byte[] rsaHash;
            byte[] encryptedKeyAndIV;
            byte[] encryptedData;

            using (HashAlgorithm hash = CryptoHelper.CreateHashAlgorithm(_hashName))
            {
                rsaHash = hash.ComputeHash(Encoding.UTF8.GetBytes(encryptionKey.ToXmlString(false)));
            }

            using (SymmetricAlgorithm encryptionAlgorithm = CryptoHelper.NewDefaultEncryption())
            {
                encryptionAlgorithm.GenerateIV();
                encryptionAlgorithm.GenerateKey();

                using (ICryptoTransform encryptor = encryptionAlgorithm.CreateEncryptor())
                {
                    encryptedData = encryptor.TransformFinalBlock(value, 0, value.Length);
                }

                RSACryptoServiceProvider provider = encryptionKey as RSACryptoServiceProvider;

                if (provider == null)
                {
                    throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6041));
                }

                //
                // Concatenate the Key and IV in an attempt to avoid two minimum block lengths in the cookie
                //
                byte[] keyAndIV = new byte[encryptionAlgorithm.Key.Length + encryptionAlgorithm.IV.Length];
                Array.Copy(encryptionAlgorithm.Key, keyAndIV, encryptionAlgorithm.Key.Length);
                Array.Copy(encryptionAlgorithm.IV, 0, keyAndIV, encryptionAlgorithm.Key.Length, encryptionAlgorithm.IV.Length);

                encryptedKeyAndIV = CngLightup.OaepSha1Encrypt(encryptionKey, keyAndIV);
            }

            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter bw = new BinaryWriter(ms))
                {
                    bw.Write(rsaHash);
                    bw.Write(encryptedKeyAndIV.Length);
                    bw.Write(encryptedKeyAndIV);
                    bw.Write(encryptedData.Length);
                    bw.Write(encryptedData);
                    bw.Flush();
                }

                return(ms.ToArray());
            }
        }
Example #9
0
        /// <summary>
        /// Decrypts data using the provided RSA key(s) to decrypt an AES key, which decrypts the cookie.
        /// </summary>
        /// <param name="encoded">The encoded data</param>
        /// <returns>The decoded data</returns>
        /// <exception cref="ArgumentNullException">The argument 'encoded' is null.</exception>
        /// <exception cref="ArgumentException">The argument 'encoded' contains zero bytes.</exception>
        /// <exception cref="NotSupportedException">The platform does not support the requested algorithm.</exception>
        /// <exception cref="InvalidOperationException">There are no decryption keys or none of the keys match.</exception>
        public override byte[] Decode(byte[] encoded)
        {
            if (null == encoded)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encoded");
            }

            if (0 == encoded.Length)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("encoded", SR.GetString(SR.ID6045));
            }

            ReadOnlyCollection <RSA> decryptionKeys = DecryptionKeys;

            if (0 == decryptionKeys.Count)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6039));
            }

            byte[] encryptedKeyAndIV;
            byte[] encryptedData;
            byte[] rsaHash;
            RSA    rsaDecryptionKey = null;

            using (HashAlgorithm hash = CryptoHelper.CreateHashAlgorithm(_hashName))
            {
                int hashSizeInBytes = hash.HashSize / 8;
                using (BinaryReader br = new BinaryReader(new MemoryStream(encoded)))
                {
                    rsaHash = br.ReadBytes(hashSizeInBytes);
                    int encryptedKeyAndIVSize = br.ReadInt32();
                    if (encryptedKeyAndIVSize < 0)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1006, encryptedKeyAndIVSize)));
                    }
                    //
                    // Enforce upper limit on key size to prevent large buffer allocation in br.ReadBytes()
                    //

                    if (encryptedKeyAndIVSize > encoded.Length)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1007)));
                    }
                    encryptedKeyAndIV = br.ReadBytes(encryptedKeyAndIVSize);

                    int encryptedDataSize = br.ReadInt32();
                    if (encryptedDataSize < 0)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1008, encryptedDataSize)));
                    }
                    //
                    // Enforce upper limit on data size to prevent large buffer allocation in br.ReadBytes()
                    //
                    if (encryptedDataSize > encoded.Length)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1009)));
                    }

                    encryptedData = br.ReadBytes(encryptedDataSize);
                }

                //
                // Find the decryption key matching the one in XML
                //
                foreach (RSA key in decryptionKeys)
                {
                    byte[] hashedKey = hash.ComputeHash(Encoding.UTF8.GetBytes(key.ToXmlString(false)));
                    if (CryptoHelper.IsEqual(hashedKey, rsaHash))
                    {
                        rsaDecryptionKey = key;
                        break;
                    }
                }
            }

            if (rsaDecryptionKey == null)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6040));
            }

            byte[] decryptedKeyAndIV = CngLightup.OaepSha1Decrypt(rsaDecryptionKey, encryptedKeyAndIV);

            using (SymmetricAlgorithm symmetricAlgorithm = CryptoHelper.NewDefaultEncryption())
            {
                byte[] decryptionKey = new byte[symmetricAlgorithm.KeySize / 8];

                //
                // Ensure there is sufficient length in the descrypted key and IV buffer for an IV.
                //
                if (decryptedKeyAndIV.Length < decryptionKey.Length)
                {
                    throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6047, decryptedKeyAndIV.Length, decryptionKey.Length));
                }

                byte[] decryptionIV = new byte[decryptedKeyAndIV.Length - decryptionKey.Length];

                //
                // Copy key into its own buffer.
                // The remaining bytes are the IV copy those into a buffer as well.
                //
                Array.Copy(decryptedKeyAndIV, decryptionKey, decryptionKey.Length);
                Array.Copy(decryptedKeyAndIV, decryptionKey.Length, decryptionIV, 0, decryptionIV.Length);

                using (ICryptoTransform decryptor = symmetricAlgorithm.CreateDecryptor(decryptionKey, decryptionIV))
                {
                    return(decryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length));
                }
            }
        }