#![allow(
dead_code,
unused_imports,
unused_qualifications,
unreachable_patterns,
unsafe_code,
clippy::mem_forget,
clippy::ptr_as_ptr,
let_underscore_drop
)]
use super::convert::key_name;
use super::export::export_public_key;
use super::provider::{open_provider, NcryptHandle};
use super::ui_policy::set_ui_policy;
use crate::internal::core::{AccessPolicy, Error, Result};
use windows::core::PCWSTR;
use windows::Win32::Security::Cryptography::*;
pub fn create_key(
provider: &NcryptHandle,
app_name: &str,
label: &str,
algorithm: &str,
policy: AccessPolicy,
) -> Result<(NcryptHandle, Vec<u8>)> {
create_key_with_flags(
provider,
app_name,
label,
algorithm,
policy,
NCRYPT_FLAGS::default(),
)
}
pub fn create_key_silent(
provider: &NcryptHandle,
app_name: &str,
label: &str,
algorithm: &str,
policy: AccessPolicy,
) -> Result<(NcryptHandle, Vec<u8>)> {
create_key_with_flags(
provider,
app_name,
label,
algorithm,
policy,
NCRYPT_SILENT_FLAG,
)
}
fn create_key_with_flags(
provider: &NcryptHandle,
app_name: &str,
label: &str,
algorithm: &str,
policy: AccessPolicy,
flags: NCRYPT_FLAGS,
) -> Result<(NcryptHandle, Vec<u8>)> {
let name = key_name(app_name, label);
let name_wide: Vec<u16> = name.encode_utf16().chain(std::iter::once(0)).collect();
let algo_wide: Vec<u16> = algorithm.encode_utf16().chain(std::iter::once(0)).collect();
let mut key_handle = NCRYPT_KEY_HANDLE::default();
unsafe {
NCryptCreatePersistedKey(
provider.as_prov(),
&mut key_handle,
PCWSTR(algo_wide.as_ptr()),
PCWSTR(name_wide.as_ptr()),
CERT_KEY_SPEC::default(),
flags,
)
.map_err(|e| Error::GenerateFailed {
detail: format!("NCryptCreatePersistedKey: {e}"),
})?;
}
let key = NcryptHandle(NCRYPT_HANDLE(key_handle.0));
if policy != AccessPolicy::None {
set_ui_policy(&key, policy)?;
}
unsafe {
NCryptFinalizeKey(key.as_key(), flags).map_err(|e| Error::GenerateFailed {
detail: format!("NCryptFinalizeKey: {e}"),
})?;
}
let pub_key = export_public_key(&key)?;
Ok((key, pub_key))
}
pub fn open_key(provider: &NcryptHandle, app_name: &str, label: &str) -> Result<NcryptHandle> {
open_key_with_flags(provider, app_name, label, NCRYPT_FLAGS::default())
}
pub fn open_key_silent(
provider: &NcryptHandle,
app_name: &str,
label: &str,
) -> Result<NcryptHandle> {
open_key_with_flags(provider, app_name, label, NCRYPT_SILENT_FLAG)
}
fn open_key_with_flags(
provider: &NcryptHandle,
app_name: &str,
label: &str,
flags: NCRYPT_FLAGS,
) -> Result<NcryptHandle> {
let name = key_name(app_name, label);
let name_wide: Vec<u16> = name.encode_utf16().chain(std::iter::once(0)).collect();
let mut key_handle = NCRYPT_KEY_HANDLE::default();
unsafe {
NCryptOpenKey(
provider.as_prov(),
&mut key_handle,
PCWSTR(name_wide.as_ptr()),
CERT_KEY_SPEC::default(),
flags,
)
.map_err(|_| Error::KeyNotFound {
label: label.to_string(),
})?;
}
Ok(NcryptHandle(NCRYPT_HANDLE(key_handle.0)))
}
pub fn delete_key(app_name: &str, label: &str) -> Result<()> {
let provider = open_provider()?;
let key = open_key(&provider, app_name, label)?;
let raw_handle = key.as_key();
std::mem::forget(key);
unsafe {
NCryptDeleteKey(raw_handle, 0).map_err(|e| Error::KeyOperation {
operation: "delete_key".into(),
detail: format!("NCryptDeleteKey: {e}"),
})?;
}
Ok(())
}
pub fn enumerate_keys(provider: &NcryptHandle, app_name: &str) -> Result<Vec<String>> {
let prefix = format!("{app_name}-");
let mut labels = Vec::new();
let mut enum_state: *mut std::ffi::c_void = std::ptr::null_mut();
loop {
let mut key_name: *mut NCryptKeyName = std::ptr::null_mut();
let result = unsafe {
NCryptEnumKeys(
provider.as_prov(),
PCWSTR::null(),
&mut key_name,
&mut enum_state,
NCRYPT_FLAGS::default(),
)
};
if result.is_err() {
break;
}
if !key_name.is_null() {
let key_info = unsafe { &*key_name };
let name = unsafe { key_info.pszName.to_string() };
if let Ok(name_str) = name {
if let Some(stripped) = name_str.strip_prefix(&prefix) {
labels.push(stripped.to_string());
}
}
unsafe {
let _ = NCryptFreeBuffer(key_name as *mut _);
}
}
}
if !enum_state.is_null() {
unsafe {
let _ = NCryptFreeBuffer(enum_state);
}
}
labels.sort();
Ok(labels)
}