/// <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; }