// Encrypts the given element with the certificate specified. The certificate is added as
        // an X509Data KeyInfo to an EncryptedKey (AES session key) generated randomly.
        public EncryptedData Encrypt(XmlElement inputElement, X509Certificate2 certificate)
        {
            if (inputElement == null)
            {
                throw new ArgumentNullException("inputElement");
            }
            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }

            if (X509Utils.OidToAlgId(certificate.PublicKey.Oid.Value) != CAPI.CALG_RSA_KEYX)
            {
                throw new NotSupportedException(SecurityResources.GetResourceString("NotSupported_KeyAlgorithm"));
            }

            // Create the EncryptedData object, using an AES-256 session key by default.
            EncryptedData ed = new EncryptedData();

            ed.Type             = EncryptedXml.XmlEncElementUrl;
            ed.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);

            // Include the certificate in the EncryptedKey KeyInfo.
            EncryptedKey ek = new EncryptedKey();

            ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
            ek.KeyInfo.AddClause(new KeyInfoX509Data(certificate));

            // Create a random AES session key and encrypt it with the public key associated with the certificate.
            RijndaelManaged rijn = new RijndaelManaged();

            ek.CipherData.CipherValue = EncryptedXml.EncryptKey(rijn.Key, certificate.PublicKey.Key as RSA, false);

            // Encrypt the input element with the random session key that we've created above.
            KeyInfoEncryptedKey kek = new KeyInfoEncryptedKey(ek);

            ed.KeyInfo.AddClause(kek);
            ed.CipherData.CipherValue = EncryptData(inputElement, rijn, false);

            return(ed);
        }
Example #2
0
        internal AlgorithmIdentifier(CAPI.CRYPT_ALGORITHM_IDENTIFIER algorithmIdentifier)
        {
            int  keyLength    = 0;
            uint cbParameters = 0;
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle;

            byte[] parameters = new byte[0];

            uint algId = X509Utils.OidToAlgId(algorithmIdentifier.pszObjId);

            if (algId == CAPI.CALG_RC2)
            {
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS_RC2_CBC_PARAMETERS),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters,
                                           out cbParameters))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    CAPI.CRYPT_RC2_CBC_PARAMETERS rc2Parameters = (CAPI.CRYPT_RC2_CBC_PARAMETERS)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPT_RC2_CBC_PARAMETERS));
                    switch (rc2Parameters.dwVersion)
                    {
                    case CAPI.CRYPT_RC2_40BIT_VERSION:
                        keyLength = 40;
                        break;

                    case CAPI.CRYPT_RC2_56BIT_VERSION:
                        keyLength = 56;
                        break;

                    case CAPI.CRYPT_RC2_128BIT_VERSION:
                        keyLength = 128;
                        break;
                    }
                    // Retrieve IV if available.
                    if (rc2Parameters.fIV)
                    {
                        parameters = (byte[])rc2Parameters.rgbIV.Clone();
                    }
                }
            }
            else if (algId == CAPI.CALG_RC4 || algId == CAPI.CALG_DES || algId == CAPI.CALG_3DES)
            {
                // Retrieve the IV if available. For non RC2, the parameter contains the IV
                // (for RC4 the IV is really the salt). There are (128 - KeyLength) / 8
                // bytes of RC4 salt.
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_OCTET_STRING),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters,
                                           out cbParameters))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    if (cbParameters > Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)))
                    {
                        CAPI.CRYPTOAPI_BLOB blob = (CAPI.CRYPTOAPI_BLOB)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));

                        if (algId == CAPI.CALG_RC4)
                        {
                            if (blob.cbData > 0)
                            {
                                parameters = new byte[blob.cbData];
                                Marshal.Copy(blob.pbData, parameters, 0, parameters.Length);
                            }
                        }
                        else
                        {
                            // This should be the same as the RC4 code, but for compatibility
                            // * Allocate an array as big as the CRYPTOAPI_BLOB
                            // * Copy in the cbData value
                            // * Copy in the (pbData) value
                            //
                            // But don't copy in the pbData pointer value (or, rather, clear it out),
                            // among other things it makes decoding the same contents into two
                            // different EnvelopedCms objects say the parameters were different.
                            parameters = new byte[cbParameters];
                            Marshal.Copy(pbParameters.DangerousGetHandle(), parameters, 0, parameters.Length);
                            Array.Clear(parameters, sizeof(uint), (int)(parameters.Length - blob.cbData - sizeof(uint)));
                        }
                    }
                }

                // Determine key length.
                if (algId == CAPI.CALG_RC4)
                {
                    // For RC4, keyLength = 128 - (salt length * 8).
                    keyLength = 128 - ((int)parameters.Length * 8);
                }
                else if (algId == CAPI.CALG_DES)
                {
                    // DES key length is fixed at 64 (or 56 without the parity bits).
                    keyLength = 64;
                }
                else
                {
                    // 3DES key length is fixed at 192 (or 168 without the parity bits).
                    keyLength = 192;
                }
            }
            else
            {
                // Everything else, don't decode it as CAPI may not expose or know how.
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    parameters = new byte[algorithmIdentifier.Parameters.cbData];
                    Marshal.Copy(algorithmIdentifier.Parameters.pbData, parameters, 0, parameters.Length);
                }
            }

            Reset(Oid.FromOidValue(algorithmIdentifier.pszObjId, OidGroup.All), keyLength, parameters);
            pbParameters.Dispose();
        }
        internal AlgorithmIdentifier(CAPI.CRYPT_ALGORITHM_IDENTIFIER algorithmIdentifier)
        {
            int  keyLength    = 0;
            uint cbParameters = 0;
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle;

            byte[] parameters = new byte[0];

            uint algId = X509Utils.OidToAlgId(algorithmIdentifier.pszObjId);

            if (algId == CAPI.CALG_RC2)
            {
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS_RC2_CBC_PARAMETERS),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters,
                                           out cbParameters))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    CAPI.CRYPT_RC2_CBC_PARAMETERS rc2Parameters = (CAPI.CRYPT_RC2_CBC_PARAMETERS)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPT_RC2_CBC_PARAMETERS));
                    switch (rc2Parameters.dwVersion)
                    {
                    case CAPI.CRYPT_RC2_40BIT_VERSION:
                        keyLength = 40;
                        break;

                    case CAPI.CRYPT_RC2_56BIT_VERSION:
                        keyLength = 56;
                        break;

                    case CAPI.CRYPT_RC2_128BIT_VERSION:
                        keyLength = 128;
                        break;
                    }
                    // Retrieve IV if available.
                    if (rc2Parameters.fIV)
                    {
                        parameters = (byte[])rc2Parameters.rgbIV.Clone();
                    }
                }
            }
            else if (algId == CAPI.CALG_RC4 || algId == CAPI.CALG_DES || algId == CAPI.CALG_3DES)
            {
                // Retrieve the IV if available. For non RC2, the parameter contains the IV
                // (for RC4 the IV is really the salt). There are (128 - KeyLength) / 8
                // bytes of RC4 salt.
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_OCTET_STRING),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters,
                                           out cbParameters))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    if (cbParameters > 0)
                    {
                        if (algId == CAPI.CALG_RC4)
                        {
                            CAPI.CRYPTOAPI_BLOB saltBlob = (CAPI.CRYPTOAPI_BLOB)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
                            if (saltBlob.cbData > 0)
                            {
                                parameters = new byte[saltBlob.cbData];
                                Marshal.Copy(saltBlob.pbData, parameters, 0, parameters.Length);
                            }
                        }
                        else
                        {
                            parameters = new byte[cbParameters];
                            Marshal.Copy(pbParameters.DangerousGetHandle(), parameters, 0, parameters.Length);
                        }
                    }
                }

                // Determine key length.
                if (algId == CAPI.CALG_RC4)
                {
                    // For RC4, keyLength = 128 - (salt length * 8).
                    keyLength = 128 - ((int)parameters.Length * 8);
                }
                else if (algId == CAPI.CALG_DES)
                {
                    // DES key length is fixed at 64 (or 56 without the parity bits).
                    keyLength = 64;
                }
                else
                {
                    // 3DES key length is fixed at 192 (or 168 without the parity bits).
                    keyLength = 192;
                }
            }
            else
            {
                // Everything else, don't decode it as CAPI may not expose or know how.
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    parameters = new byte[algorithmIdentifier.Parameters.cbData];
                    Marshal.Copy(algorithmIdentifier.Parameters.pbData, parameters, 0, parameters.Length);
                }
            }

            Reset(Oid.FromOidValue(algorithmIdentifier.pszObjId, OidGroup.All), keyLength, parameters);
            pbParameters.Dispose();
        }