Example #1
0
        /// <summary>
        /// Imports a specified key.
        /// </summary>
        /// <param name="provider">The handle of the CSP.</param>
        /// <param name="algorithm">One of the <see cref="CryptoAlgorithm"/> values.</param>
        /// <param name="key">The key to import.</param>
        /// <returns>The handle of the symmetric key.</returns>
        /// <exception cref="SecurityException">An error occurs while importing the specified key.</exception>
        private int KeyFromBytes(int provider, CryptoAlgorithm algorithm, byte[] key)
        {
            int    dwFlags = SecurityConstants.CRYPT_FIRST, dwSize, dwProvSessionKeySize = 0, dwPublicKeySize = 0, dwSessionBlob, offset = 0, hTempKey = 0, hSessionKey = 0;
            IntPtr algo = new IntPtr((int)algorithm), dwPrivKeyAlg = IntPtr.Zero, pbSessionBlob = IntPtr.Zero;
            IntPtr provEnum = IntPtr.Zero;

            try {
                // Double check to see if this provider supports this algorithm
                // and key size
                bool found = false;
                provEnum = Marshal.AllocHGlobal(84 + IntPtr.Size);
                do
                {
                    dwSize = 84 + IntPtr.Size;
                    if (SspiProvider.CryptGetProvParam(provider, SecurityConstants.PP_ENUMALGS_EX, provEnum, ref dwSize, dwFlags) == 0)
                    {
                        break;
                    }
                    dwFlags = 0;
                    if (Marshal.ReadIntPtr(provEnum) == algo)
                    {
                        found = true;
                    }
                } while (!found);
                if (!found)
                {
                    throw new SecurityException("CSP does not support selected algorithm.");
                }
                // We have to get the key size(including padding)
                // from an HCRYPTKEY handle.  PP_ENUMALGS_EX contains
                // the key size without the padding so we can't use it.
                if (SspiProvider.CryptGenKey(provider, algo, 0, ref hTempKey) == 0)
                {
                    throw new SecurityException("Cannot generate temporary key.");
                }
                dwSize = 4;                 // sizeof(int)
                if (SspiProvider.CryptGetKeyParam(hTempKey, SecurityConstants.KP_KEYLEN, ref dwProvSessionKeySize, ref dwSize, 0) == 0)
                {
                    throw new SecurityException("Cannot retrieve key parameters.");
                }
                // Our key is too big, leave
                if ((key.Length * 8) > dwProvSessionKeySize)
                {
                    throw new SecurityException("Key too big.");
                }
                // Get private key's algorithm
                dwSize = IntPtr.Size;                 //sizeof(ALG_ID)
                if (SspiProvider.CryptGetKeyParam(m_ExponentOfOne, SecurityConstants.KP_ALGID, ref dwPrivKeyAlg, ref dwSize, 0) == 0)
                {
                    throw new SecurityException("Unable to get the private key's algorithm.");
                }
                // Get private key's length in bits
                dwSize = 4;                 // sizeof(DWORD)
                if (SspiProvider.CryptGetKeyParam(m_ExponentOfOne, SecurityConstants.KP_KEYLEN, ref dwPublicKeySize, ref dwSize, 0) == 0)
                {
                    throw new SecurityException("Unable to get the key length.");
                }
                // calculate Simple blob's length
                dwSessionBlob = (dwPublicKeySize / 8) + IntPtr.Size /*sizeof(ALG_ID)*/ + 4 + IntPtr.Size /*sizeof(BLOBHEADER)*/;
                // allocate simple blob buffer
                pbSessionBlob = Marshal.AllocHGlobal(dwSessionBlob);
                // SIMPLEBLOB Format is documented in SDK
                // Copy header to buffer
                PUBLICKEYSTRUC pks = new PUBLICKEYSTRUC();
                pks.bType    = SecurityConstants.SIMPLEBLOB;
                pks.bVersion = 2;
                pks.reserved = 0;
                pks.aiKeyAlg = algo;
                Marshal.StructureToPtr(pks, pbSessionBlob, false);
                Marshal.WriteIntPtr(pbSessionBlob, offset = Marshal.SizeOf(pks), dwPrivKeyAlg);
                offset += IntPtr.Size;                 // sizeof(ALG_ID)
                // Place the key material in reverse order
                for (int i = 0; i < key.Length; i++)
                {
                    Marshal.WriteByte(pbSessionBlob, offset + key.Length - i - 1, key[i]);
                }
                // 3 is for the first reserved byte after the key material + the 2 reserved bytes at the end.
                dwSize  = dwSessionBlob - (IntPtr.Size /*sizeof(ALG_ID)*/ + IntPtr.Size + 4 /*sizeof(BLOBHEADER)*/ + key.Length + 3);
                offset += key.Length + 1;
                // Generate random data for the rest of the buffer
                // (except that last two bytes)
                if (SspiProvider.CryptGenRandom(provider, dwSize, new IntPtr(pbSessionBlob.ToInt64() + offset)) == 0)
                {
                    throw new SecurityException("Could not generate random data.");
                }
                for (int i = 0; i < dwSize; i++)
                {
                    if (Marshal.ReadByte(pbSessionBlob, offset) == 0)
                    {
                        Marshal.WriteByte(pbSessionBlob, offset, 1);
                    }
                    offset++;
                }
                Marshal.WriteByte(pbSessionBlob, dwSessionBlob - 2, 2);
                if (SspiProvider.CryptImportKey(provider, pbSessionBlob, dwSessionBlob, m_ExponentOfOne, SecurityConstants.CRYPT_EXPORTABLE, ref hSessionKey) == 0)
                {
                    throw new SecurityException("Cannot import key [key has right size?].");
                }
            } finally {
                if (provEnum != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(provEnum);
                }
                if (hTempKey != 0)
                {
                    SspiProvider.CryptDestroyKey(hTempKey);
                }
                if (pbSessionBlob != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pbSessionBlob);
                }
            }
            return(hSessionKey);
        }
		/// <summary>
		/// Imports a specified key.
		/// </summary>
		/// <param name="provider">The handle of the CSP.</param>
		/// <param name="algorithm">One of the <see cref="CryptoAlgorithm"/> values.</param>
		/// <param name="key">The key to import.</param>
		/// <returns>The handle of the symmetric key.</returns>
		/// <exception cref="SecurityException">An error occurs while importing the specified key.</exception>
		private int KeyFromBytes(int provider, CryptoAlgorithm algorithm, byte[] key) {
			int dwFlags = SecurityConstants.CRYPT_FIRST, dwSize, dwProvSessionKeySize = 0, dwPublicKeySize = 0, dwSessionBlob, offset = 0, hTempKey = 0, hSessionKey = 0;
			IntPtr algo = new IntPtr((int)algorithm), dwPrivKeyAlg = IntPtr.Zero, pbSessionBlob = IntPtr.Zero;
			IntPtr provEnum = IntPtr.Zero;
			try {
				// Double check to see if this provider supports this algorithm
				// and key size
				bool found = false;
				provEnum = Marshal.AllocHGlobal(84 + IntPtr.Size);
				do {
					dwSize = 84 + IntPtr.Size;
					if (SspiProvider.CryptGetProvParam(provider, SecurityConstants.PP_ENUMALGS_EX, provEnum, ref dwSize, dwFlags) == 0)
						break;
					dwFlags = 0;
					if (Marshal.ReadIntPtr(provEnum) == algo)
						found = true;
				} while (!found);
				if (!found)
					throw new SecurityException("CSP does not support selected algorithm.");
				// We have to get the key size(including padding)
				// from an HCRYPTKEY handle.  PP_ENUMALGS_EX contains
				// the key size without the padding so we can't use it.
				if (SspiProvider.CryptGenKey(provider, algo, 0, ref hTempKey) == 0)
					throw new SecurityException("Cannot generate temporary key.");
				dwSize = 4; // sizeof(int)
				if (SspiProvider.CryptGetKeyParam(hTempKey, SecurityConstants.KP_KEYLEN, ref dwProvSessionKeySize, ref dwSize, 0) == 0)
					throw new SecurityException("Cannot retrieve key parameters.");
				// Our key is too big, leave
				if ((key.Length * 8) > dwProvSessionKeySize)
					throw new SecurityException("Key too big.");
				// Get private key's algorithm
				dwSize = IntPtr.Size; //sizeof(ALG_ID)
				if (SspiProvider.CryptGetKeyParam(m_ExponentOfOne, SecurityConstants.KP_ALGID, ref dwPrivKeyAlg, ref dwSize, 0) == 0)
					throw new SecurityException("Unable to get the private key's algorithm.");
				// Get private key's length in bits
				dwSize = 4; // sizeof(DWORD)
				if (SspiProvider.CryptGetKeyParam(m_ExponentOfOne, SecurityConstants.KP_KEYLEN, ref dwPublicKeySize, ref dwSize, 0) == 0)
					throw new SecurityException("Unable to get the key length.");
				// calculate Simple blob's length
				dwSessionBlob = (dwPublicKeySize / 8) + IntPtr.Size /*sizeof(ALG_ID)*/ + 4 + IntPtr.Size /*sizeof(BLOBHEADER)*/;
				// allocate simple blob buffer
				pbSessionBlob = Marshal.AllocHGlobal(dwSessionBlob);
				// SIMPLEBLOB Format is documented in SDK
				// Copy header to buffer
				PUBLICKEYSTRUC pks = new PUBLICKEYSTRUC();
				pks.bType = SecurityConstants.SIMPLEBLOB;
				pks.bVersion = 2;
				pks.reserved = 0;
				pks.aiKeyAlg = algo;
				Marshal.StructureToPtr(pks, pbSessionBlob, false);
				Marshal.WriteIntPtr(pbSessionBlob, offset = Marshal.SizeOf(pks), dwPrivKeyAlg);
				offset += IntPtr.Size; // sizeof(ALG_ID)
				// Place the key material in reverse order
				for (int i = 0; i < key.Length; i++) {
					Marshal.WriteByte(pbSessionBlob, offset + key.Length - i - 1, key[i]);
				}
				// 3 is for the first reserved byte after the key material + the 2 reserved bytes at the end.
				dwSize = dwSessionBlob - (IntPtr.Size /*sizeof(ALG_ID)*/ + IntPtr.Size + 4 /*sizeof(BLOBHEADER)*/ + key.Length + 3);
				offset += key.Length + 1;
				// Generate random data for the rest of the buffer
				// (except that last two bytes)
				if (SspiProvider.CryptGenRandom(provider, dwSize, new IntPtr(pbSessionBlob.ToInt64() + offset)) == 0)
					throw new SecurityException("Could not generate random data.");
				for (int i = 0; i < dwSize; i++) {
					if (Marshal.ReadByte(pbSessionBlob, offset) == 0)
						Marshal.WriteByte(pbSessionBlob, offset, 1);
					offset++;
				}
				Marshal.WriteByte(pbSessionBlob, dwSessionBlob - 2, 2);
				if (SspiProvider.CryptImportKey( provider, pbSessionBlob, dwSessionBlob, m_ExponentOfOne, SecurityConstants.CRYPT_EXPORTABLE, ref hSessionKey) == 0)
					throw new SecurityException("Cannot import key [key has right size?].");
			} finally {
				if (provEnum != IntPtr.Zero)
					Marshal.FreeHGlobal(provEnum);
				if (hTempKey != 0)
					SspiProvider.CryptDestroyKey(hTempKey);
				if (pbSessionBlob != IntPtr.Zero)
					Marshal.FreeHGlobal(pbSessionBlob);
			}
			return hSessionKey;
		}