Skip to content

Commit b9491d1

Browse files
feat(dpapi): implement basic RPC structures encoding/decoding (#342)
1 parent fc0cb61 commit b9491d1

File tree

16 files changed

+1556
-124
lines changed

16 files changed

+1556
-124
lines changed

Cargo.lock

Lines changed: 125 additions & 116 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ members = [
1717
"ffi/symbol-rename-macro",
1818
"crates/winscard",
1919
"crates/ffi-types",
20+
"crates/dpapi",
2021
]
2122
exclude = [
2223
"tools/wasm-testcompile",
@@ -36,8 +37,10 @@ sha1 = { version = "0.10", default-features = false }
3637
num-derive = "0.4"
3738
num-traits = { version = "0.2", default-features = false }
3839
picky = { version = "7.0.0-rc.12", default-features = false }
40+
picky-asn1 = "0.10"
3941
picky-asn1-der = "0.5"
4042
picky-asn1-x509 = "0.14"
43+
picky-krb = "0.9"
4144
tokio = "1.43"
4245
ffi-types = { path = "crates/ffi-types" }
4346
winscard = { version = "0.2", path = "crates/winscard" }
@@ -47,6 +50,8 @@ base64 = "0.22"
4750
whoami = "1.5"
4851
tracing-subscriber = "0.3"
4952
proptest = "1.6"
53+
serde = "1"
54+
byteorder = "1.5"
5055

5156
[features]
5257
default = ["aws-lc-rs"]
@@ -87,22 +92,21 @@ tokio = { workspace = true, optional = true, features = ["time", "rt", "rt-multi
8792
winscard = { workspace = true, optional = true }
8893
rsa = { workspace = true, features = ["sha1"] }
8994
tracing = { workspace = true, default-features = true }
95+
serde.workspace = true
96+
picky-krb.workspace = true
97+
picky-asn1 = { workspace = true, features = ["time_conversion"] }
98+
byteorder.workspace = true
9099

91-
byteorder = "1.5"
92100
md-5 = "0.10"
93101
md4 = "0.10"
94102
sha2 = "0.10"
95103
hmac = "0.12"
96104
crypto-mac = "0.11"
97105
lazy_static = "1.5"
98-
serde = "1"
99106
serde_derive = "1"
100107
url = "2.5"
101108
oid = "0.2"
102109

103-
picky-krb = "0.9"
104-
picky-asn1 = { version = "0.10", features = ["time_conversion"] }
105-
106110
reqwest = { version = "0.12", optional = true, default-features = false, features = ["blocking", "rustls-tls-no-provider"] }
107111
hickory-resolver = { version = "0.24", optional = true }
108112
portpicker = { version = "0.1", optional = true }

crates/dpapi/Cargo.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "dpapi"
3+
version = "0.1.0"
4+
edition = "2021"
5+
readme = "README.md"
6+
license = "MIT/Apache-2.0"
7+
homepage = "https://github.com/devolutions/sspi-rs"
8+
repository = "https://github.com/devolutions/sspi-rs"
9+
authors = ["Devolutions Inc. <[email protected]>"]
10+
description = "A Rust implementation of Windows DPAPI"
11+
12+
[lib]
13+
name = "dpapi"
14+
15+
[dependencies]
16+
bitflags.workspace = true
17+
byteorder.workspace = true
18+
num-derive.workspace = true
19+
num-traits = { workspace = true, default-features = true }
20+
uuid = { workspace = true, features = ["std"] }
21+
22+
thiserror = "2.0"
23+
24+
[dev-dependencies]
25+
paste = "1.0"

crates/dpapi/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# dpapi-rs
2+
3+
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.
4+
5+
It automatically makes RPC calls to obtain the root key. The user must provide credentials to authenticate in the DC.
6+
7+
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).
8+
9+
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.

crates/dpapi/src/error.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use thiserror::Error;
2+
3+
#[derive(Debug, Error)]
4+
pub enum Error {
5+
#[error("IO error")]
6+
Io(#[from] std::io::Error),
7+
8+
#[error("UUID error: {0}")]
9+
Uuid(#[from] uuid::Error),
10+
11+
#[error(transparent)]
12+
IntConversion(#[from] std::num::TryFromIntError),
13+
14+
#[error("provided buf contains invalid UTF-8 data")]
15+
Utf8(#[from] std::string::FromUtf8Error),
16+
17+
#[error("invalid context result code value: {0}")]
18+
InvalidContextResultCode(u16),
19+
20+
#[error("invalid integer representation value: {0}")]
21+
InvalidIntRepr(u8),
22+
23+
#[error("invalid character representation value: {0}")]
24+
InvalidCharacterRepr(u8),
25+
26+
#[error("invalid floating point representation value: {0}")]
27+
InvalidFloatingPointRepr(u8),
28+
29+
#[error("invalid packet type value: {0}")]
30+
InvalidPacketType(u8),
31+
32+
#[error("invalid packet flags value: {0}")]
33+
InvalidPacketFlags(u8),
34+
35+
#[error("invalid security provider value: {0}")]
36+
InvalidSecurityProvider(u8),
37+
38+
#[error("invalid authentication level value: {0}")]
39+
InvalidAuthenticationLevel(u8),
40+
41+
#[error("invalid fault flags value: {0}")]
42+
InvalidFaultFlags(u8),
43+
44+
#[error("{0:?} PDU is not supported")]
45+
PduNotSupported(crate::rpc::pdu::PacketType),
46+
47+
#[error("invalid fragment (PDU) length: {0}")]
48+
InvalidFragLength(u16),
49+
}
50+
51+
pub type DpapiResult<T> = Result<T, Error>;

crates/dpapi/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// #![warn(missing_docs)]
2+
#![doc = include_str!("../README.md")]
3+
#![allow(dead_code)]
4+
5+
mod error;
6+
pub mod rpc;
7+
8+
pub use error::*;

0 commit comments

Comments
 (0)