/// <summary> /// Initializes a new instance of the SymmetricKey class. /// </summary> /// <param name="provider">One of the <see cref="CryptoProvider"/> values.</param> /// <param name="algorithm">One of the <see cref="CryptoAlgorithm"/> values.</param> /// <exception cref="SecurityException">An error occurs when generating a new key.</exception> public SymmetricKey(CryptoProvider provider, CryptoAlgorithm algorithm) : this(provider) { m_Handle = 0; if (SspiProvider.CryptGenKey(m_Provider, new IntPtr((int)algorithm), SecurityConstants.CRYPT_EXPORTABLE, ref m_Handle) == 0) { throw new SecurityException("Cannot generate session key."); } }
/// <summary> /// Dynamically creates an exponent-of-one key. /// </summary> /// <returns>The handle of a exponent-of-one key.</returns> /// <exception cref="SecurityException">An error occurs while creating the key.</exception> private int CreateDynamicExponentOfOneKey() { int hPrivateKey = 0; int dwKeyBlob = 0; IntPtr keyblob = IntPtr.Zero; int dwBitLen; try { if (SspiProvider.CryptGenKey(m_Provider, new IntPtr(SecurityConstants.AT_KEYEXCHANGE), SecurityConstants.CRYPT_EXPORTABLE, ref hPrivateKey) == 0) { throw new SecurityException("Cannot generate key pair."); } // Export the private key, we'll convert it to a private // exponent of one key if (SspiProvider.CryptExportKey(hPrivateKey, 0, SecurityConstants.PRIVATEKEYBLOB, 0, IntPtr.Zero, ref dwKeyBlob) == 0) { throw new SecurityException("Cannot export generated key."); } keyblob = Marshal.AllocHGlobal(dwKeyBlob); if (SspiProvider.CryptExportKey(hPrivateKey, 0, SecurityConstants.PRIVATEKEYBLOB, 0, keyblob, ref dwKeyBlob) == 0) { throw new SecurityException("Cannot export generated key."); } SspiProvider.CryptDestroyKey(hPrivateKey); hPrivateKey = 0; // Get the bit length of the key dwBitLen = Marshal.ReadInt32(keyblob, 12); /* Modify the Exponent in Key BLOB format [Key BLOB format is documented in SDK] */ // Convert pubexp in rsapubkey to 1 int offset = 16; for (int i = 0; i < 4; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Skip pubexp offset += 4; // Skip modulus, prime1, prime2 offset += dwBitLen / 8; offset += dwBitLen / 16; offset += dwBitLen / 16; // Convert exponent1 to 1 for (int i = 0; i < dwBitLen / 16; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Skip exponent1 offset += dwBitLen / 16; // Convert exponent2 to 1 for (int i = 0; i < dwBitLen / 16; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Skip exponent2, coefficient offset += dwBitLen / 16; offset += dwBitLen / 16; // Convert privateExponent to 1 for (int i = 0; i < dwBitLen / 8; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Import the exponent-of-one private key. if (SspiProvider.CryptImportKey(m_Provider, keyblob, dwKeyBlob, 0, SecurityConstants.CRYPT_EXPORTABLE, ref hPrivateKey) == 0) { throw new SecurityException("Could not import modified key."); } } catch (Exception e) { if (hPrivateKey != 0) { SspiProvider.CryptDestroyKey(hPrivateKey); } throw e; } finally { if (keyblob != IntPtr.Zero) { Marshal.FreeHGlobal(keyblob); } } return(hPrivateKey); }
/// <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); }