6 releases (3 breaking)

0.4.1 Sep 12, 2024
0.4.0 Jan 9, 2024
0.3.0 Mar 29, 2022
0.2.2 Feb 16, 2022
0.1.0 Dec 31, 2021

#158 in Cryptography

Download history 227/week @ 2024-08-24 271/week @ 2024-08-31 366/week @ 2024-09-07 488/week @ 2024-09-14 356/week @ 2024-09-21 537/week @ 2024-09-28 409/week @ 2024-10-05 502/week @ 2024-10-12 624/week @ 2024-10-19 481/week @ 2024-10-26 544/week @ 2024-11-02 453/week @ 2024-11-09 435/week @ 2024-11-16 377/week @ 2024-11-23 659/week @ 2024-11-30 575/week @ 2024-12-07

2,124 downloads per month
Used in 24 crates (5 directly)

MIT license

49KB
1K SLoC

Cross Platform Kerberos 5 Interface

cross-krb5 is a safe interface for Kerberos 5 services on Windows and Unix. It provides most of the flexibility of using gssapi and sspi directly with a unified cross platform api.

As well as providing a uniform API, services using cross-krb5 should interoperate across all the supported OSes transparently, and should interoperate with other services assuming they are not platform specific.

Example

use bytes::Bytes;
use cross_krb5::{AcceptFlags, ClientCtx, InitiateFlags, K5Ctx, Step, ServerCtx};
use std::{env::args, process::exit, sync::mpsc, thread};

enum Msg {
    Token(Bytes),
    Msg(Bytes),
}

fn server(spn: String, input: mpsc::Receiver<Msg>, output: mpsc::Sender<Msg>) {
    let mut server = ServerCtx::new(AcceptFlags::empty(), Some(&spn)).expect("new");
    let mut server = loop {
        let token = match input.recv().expect("expected data") {
            Msg::Msg(_) => panic!("server not finished initializing"),
            Msg::Token(t) => t,
        };
        match server.step(&*token).expect("step") {
            Step::Finished((ctx, token)) => {
                if let Some(token) = token {
                    output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send");
                }
                break ctx
            },
            Step::Continue((ctx, token)) => {
                output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send");
                server = ctx;
            }
        }
    };
    match input.recv().expect("expected data msg") {
        Msg::Token(_) => panic!("unexpected extra token"),
        Msg::Msg(secret_msg) => println!(
            "{}",
            String::from_utf8_lossy(&server.unwrap(&*secret_msg).expect("unwrap"))
        ),
    }
}

fn client(spn: &str, input: mpsc::Receiver<Msg>, output: mpsc::Sender<Msg>) {
    let (mut client, token) =
        ClientCtx::new(InitiateFlags::empty(), None, spn, None).expect("new");
    output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send");
    let mut client = loop {
        let token = match input.recv().expect("expected data") {
            Msg::Msg(_) => panic!("client not finished initializing"),
            Msg::Token(t) => t,
        };
        match client.step(&*token).expect("step") {
            Step::Finished((ctx, token)) => {
                if let Some(token) = token {
                    output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send");
                }
                break ctx
            },
            Step::Continue((ctx, token)) => {
                output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send");
                client = ctx;
            }
        }
    };
    let msg = client.wrap(true, b"super secret message").expect("wrap");
    output.send(Msg::Msg(Bytes::copy_from_slice(&*msg))).expect("send");
}

fn main() {
    let args = args().collect::<Vec<_>>();
    if args.len() != 2 {
        println!("usage: {}: <service/host@REALM>", args[0]);
        exit(1);
    }
    let spn = String::from(&args[1]);
    let (server_snd, server_recv) = mpsc::channel();
    let (client_snd, client_recv) = mpsc::channel();
    thread::spawn(move || server(spn, server_recv, client_snd));
    client(&args[1], client_recv, server_snd);
}

Dependencies

~0.6–38MB
~583K SLoC