Skip to content

Commit

Permalink
feat(dpapi): implement basic RPC structures encoding/decoding (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheBestTvarynka authored Jan 15, 2025
1 parent a8272f7 commit 1bcff60
Show file tree
Hide file tree
Showing 18 changed files with 1,632 additions and 120 deletions.
305 changes: 196 additions & 109 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ members = [
"ffi/symbol-rename-macro",
"crates/winscard",
"crates/ffi-types",
"crates/dpapi",
]
exclude = [
"tools/wasm-testcompile",
Expand All @@ -35,9 +36,11 @@ time = { version = "0.3", default-features = false }
sha1 = { version = "0.10", default-features = false }
num-derive = "0.4"
num-traits = { version = "0.2", default-features = false }
picky = { version = "7.0.0-rc.11", default-features = false }
picky = "7.0.0-rc.11"
picky-asn1 = "0.10"
picky-asn1-der = "0.5"
picky-asn1-x509 = "0.14"
picky-krb = "0.9"
tokio = "1.42"
ffi-types = { path = "crates/ffi-types" }
winscard = { version = "0.2", path = "crates/winscard" }
Expand All @@ -47,6 +50,8 @@ base64 = "0.22"
whoami = "1.5"
tracing-subscriber = "0.3"
proptest = "1.6"
serde = "1"
byteorder = "1.5"

[features]
default = ["aws-lc-rs"]
Expand Down Expand Up @@ -87,22 +92,21 @@ tokio = { workspace = true, optional = true, features = ["time", "rt", "rt-multi
winscard = { workspace = true, optional = true }
rsa = { workspace = true, features = ["sha1"] }
tracing = { workspace = true, default-features = true }
serde.workspace = true
picky-krb.workspace = true
picky-asn1 = { workspace = true, features = ["time_conversion"] }
byteorder.workspace = true

byteorder = "1.5"
md-5 = "0.10"
md4 = "0.10"
sha2 = "0.10"
hmac = "0.12"
crypto-mac = "0.11"
lazy_static = "1.5"
serde = "1"
serde_derive = "1"
url = "2.5"
oid = "0.2"

picky-krb = "0.9"
picky-asn1 = { version = "0.10", features = ["time_conversion"] }

reqwest = { version = "0.12", optional = true, default-features = false, features = ["blocking", "rustls-tls-no-provider"] }
hickory-resolver = { version = "0.24", optional = true }
portpicker = { version = "0.1", optional = true }
Expand Down
25 changes: 25 additions & 0 deletions crates/dpapi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "dpapi"
version = "0.1.0"
edition = "2021"
readme = "README.md"
license = "MIT/Apache-2.0"
homepage = "https://github.com/devolutions/sspi-rs"
repository = "https://github.com/devolutions/sspi-rs"
authors = ["Devolutions Inc. <[email protected]>"]
description = "A Rust implementation of Windows DPAPI"

[lib]
name = "dpapi"

[dependencies]
bitflags.workspace = true
byteorder.workspace = true
num-derive.workspace = true
num-traits = { workspace = true, default-features = true }
uuid = { workspace = true, features = ["std"] }

thiserror = "2.0"

[dev-dependencies]
paste = "1.0"
9 changes: 9 additions & 0 deletions crates/dpapi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# dpapi-rs

This crate contains a Windows [DPAPI](https://learn.microsoft.com/en-us/windows/win32/seccng/cng-dpapi) implementation. It can encrypt the data/decrypt DPAPI blobs using the domain's root key.

It automatically makes RPC calls to obtain the root key. The user must provide credentials to authenticate in the DC.

It implements the [MS-GKDI Group Key Distribution Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a).

The original DPAPI supports many [protection descriptors](https://learn.microsoft.com/en-us/windows/win32/seccng/protection-descriptors). This library implements only SID protection descriptor.
51 changes: 51 additions & 0 deletions crates/dpapi/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use thiserror::Error;

#[derive(Debug, Error)]
pub enum Error {
#[error("IO error")]
Io(#[from] std::io::Error),

#[error("UUID error: {0}")]
Uuid(#[from] uuid::Error),

#[error(transparent)]
IntConversion(#[from] std::num::TryFromIntError),

#[error("provided buf contains invalid UTF-8 data")]
Utf8(#[from] std::string::FromUtf8Error),

#[error("invalid context result code value: {0}")]
InvalidContextResultCode(u16),

#[error("invalid integer representation value: {0}")]
InvalidIntRepr(u8),

#[error("invalid character representation value: {0}")]
InvalidCharacterRepr(u8),

#[error("invalid floating point representation value: {0}")]
InvalidFloatingPointRepr(u8),

#[error("invalid packet type value: {0}")]
InvalidPacketType(u8),

#[error("invalid packet flags value: {0}")]
InvalidPacketFlags(u8),

#[error("invalid security provider value: {0}")]
InvalidSecurityProvider(u8),

#[error("invalid authentication level value: {0}")]
InvalidAuthenticationLevel(u8),

#[error("invalid fault flags value: {0}")]
InvalidFaultFlags(u8),

#[error("{0:?} PDU is not supported")]
PduNotSupported(crate::rpc::pdu::PacketType),

#[error("invalid fragment (PDU) length: {0}")]
InvalidFragLength(u16),
}

pub type DpapiResult<T> = Result<T, Error>;
8 changes: 8 additions & 0 deletions crates/dpapi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// #![warn(missing_docs)]
#![doc = include_str!("../README.md")]
#![allow(dead_code)]

mod error;
pub mod rpc;

pub use error::*;
Loading

0 comments on commit 1bcff60

Please sign in to comment.