scram-rs

Crates.ioscram-rs
lib.rsscram-rs
version0.18.3
created_at2021-03-27 00:31:52.7745+00
updated_at2025-09-15 23:00:58.635026+00
descriptionSalted Challenge Response Authentication Mechanism (SCRAM) SASL mechanism, a library which implements SCRAM logic for Rust and C languages.
homepage
repositoryhttps://codeberg.org/4neko/scram-rs
max_upload_size
id374018
size507,299
Aleksandr Morozov (eesekaj)

documentation

README

scram-rs

Dual licensed crate.

Policy
  • This crate i.e code is NOT an Open Source software. This is a FREE (gratis) software and follows the principle of Sources Available/Disclosed software which must be fairly used.
  • It is published under FSF/OSI approved licenses however author does not follow/share/respect OSI and FSF principles and phylosophy.
  • License is subject to be changed in further versions without warning.
  • If you are using code in non-free (in terms of gratis) software you MUST NEVER demand a development of any features which are missing and needed for your business if you are not sponsoring/contributing those changes.
  • Access to the code can be limited by author/platform to specific entities due to the local laws (not my bad or fault)(despite what is said in the license).
AI policy
  • AI generated sloppy code is prohibited. AI generates slop "a priori" (anyway).
  • Licenses (thank you OSS sectarians ) do not anyhow limit AI training, but f^ck you all - ChatGPT, CockPilot, especially Claude and rest unidentified cr@p.
  • It is strongly discouraged from using the AI based tools to write or enhance the code. AI slope would 100% violate the license by introducing the 3rd party licensed code.
Pull requests

The pull requests are now supported because the repository was moved to Codeberg. The alternative way is to send patches over the email to patch[at]4neko.org.

In case if you would like to contribute the code, please use pull request. Your pull request should include:

  • Description of changes and why it is needed.

  • Test the pull request.

    In case of you prefer email and patch files please consider the following:

  • For each feature or fix, please send patches separatly.

  • Please write what your patch is implementing or fixing.

  • I can read the code and I am able to understand it, so don't write a poem or essay in the description to the patches.

  • Please test your patch.

Questions about license MPL-2.0
  • Can I use the MPL-2.0 licensed code (crate) in larger project licensed with more permissive license like BSD or MIT.

I want to distribute (outside my organization) executable programs or libraries that I have compiled from someone else's unchanged MPL-licensed source code, either standalone or part of a larger work. What do I have to do?

You must inform the recipients where they can get the source for the MPLed code in the executable program or library you are distributing (i.e., you must comply with Section 3.2). You may distribute any executables you create under a license of your choosing, as long as that license does not interfere with the recipients' rights to the source under the terms of the MPL.

MPL2.0 FAQ

Yes, MPL- and Apache-licensed code can be used with an MIT codebase (so in that sense, they are "compatible"). However, the MPL- / Apache-licensed code remains under its original license. (So although compatible, you cannot relicense someone else's MPL or Apache code into the MIT license.) This means that your final codebase will contain a mix of MPL, Apache, and MIT licensed code. As an example, MPL has weak copyleft, so if you modified an MPL file, that file (including your changes) must remain under the MPL license.

Answer1

Questions about license EUPL-1.2

You should use this license if you are located in the EU which gives you more advantages over GPL because in case of any disputes, the license allows you to defend your rights in a European Union country, in this case it will be Spain. It has also been translated into all languages of the EU member states.

Matrix of EUPL compatible open source licences

EUPL-1.2 is incompatiable with GPL according to GNU ORG

This is a free software license. By itself, it has a copyleft comparable to the GPL's, and incompatible with it.

Version

v 0.18 Rust edition 2024

A SCRAM-SHA1, SCRAM-SHA256, SCRAM-SHA512, SCRAM-SHA256-PLUS client and server and C language bindings.

License:

Sources are available under: MPL-2.0 OR EUPL-1.2

Issues tracker:

The project has moved to Codeberg.

Supports:

  • SHA-1 hasher
  • SHA-256 hasher (tested with Postfix Dovecot SASL)
  • SHA-512 hasher
  • Client/Server sync
  • Server Channel Binding 256 untested (user must implement the trait to provide necessary data)
  • Client Channel Binding 256 untested
  • A support of async which allows to integrate it in async code or use with async
  • Client/Server key (custom)
  • Error handling server-error RFC5802 (e=server-error-value)
  • Dynamic server instance i.e store the instance as dyn object instead of the generic struct
  • Initialize the Scram Client/Server with borrowed or consumed instances.
  • NO_STD support (untested)
  • C language bindings

Does not support:

  • Channel binding SHA-1 which is unsafe.

What is not implemented by design

This crate does not open a remote connection to host for you. It does not contain a code to open a connection to any remote target. This crate contains only a SCRAM-SHA logic. Your program manages the connection itself, reception of the data itself and transmitting it back to client/server on its own. This crated performs only logical operaions on received data and retrns the result to your program. This appreoach inreases a flexibility. This crate also implements a signalling so there is no need to implement a special error handling.

Based on crates:

  • pbkdf2
  • sha2
  • sha-1
  • hmac
  • md-5
  • base64
  • getrandom
  • ring

Features:

By default the following crates: [pbkdf2], [hmac], [sha2], [sha1] are included with this crate and a trait objects are available.

  • use_ring - adds crate: [ring] to the crate and a trait objects becomes available, also the ring dependency is added automatically.
  • exclude_sha1 - excludes the sha1 alg.
  • without_async - excludes/masks the async code
  • std - use std lib
  • without_capi - prevents adding a C API for static lib
  • xor_without_u128 - prevents using u128 while XOR-ing the arrays.

Warnings:

  • This crate does not open network connection to anywhere. And must never!
  • This crate has never been audited, only static tests proofs the correctness of its operation.
  • This crate uses unverified cryptography crates. There is no warranty that the operaion of those crates is correct all the time.

Author of this crate is not responsible for anything which may happen.

Issues tracker:

Issues tracket is here

Usage:

see ./examples/ there

Test based benchmarks:

scram_sha256_server() sync tests (DEBUG) on AMD Ryzen 5 7600X 6-Core Processor 5453 MHz

iteration rust-native use_ring
1 30.481112ms 7.813466ms

scram_sha256_works() async tests (DEBUG)

iteration rust-native use_ring
1 30.935835ms 7.913466ms

For usage see ./examples/ For C usage see ./tests/

Examples:

Init:

Generic struct (borrow intances):

  let authdb = AuthDB::new();
  let scramtype = SCRAM_TYPES.get_scramtype("SCRAM-SHA-256").unwrap();

  let mut server = 
      SyncScramServer::<ScramSha256RustNative, &AuthDB, &AuthDB>::new(&authdb, &authdb, ScramNonce::none(), scramtype).unwrap();

Dynamic:

  let authdb = AuthDB::new();
  let authdbcb = AuthDBCb{};
  let scramtype = SCRAM_TYPES.get_scramtype("SCRAM-SHA-256").unwrap();

  let server = 
      SyncScramServer
          ::<ScramSha256RustNative, AuthDB, AuthDBCb>
          ::new(authdb, authdbcb, ScramNonce::none(), scramtype).unwrap();


  let mut server_dyn = server.make_dyn();

Custom (consume the instances):

  let authdb = AuthDB::new();
  let conninst = ConnectionInst::new();
  let scramtype = SCRAM_TYPES.get_scramtype("SCRAM-SHA-256").unwrap();

  let mut server = 
      SyncScramServer
          ::<ScramSha256RustNative, AuthDB, ConnectionInst>
          ::new(authdb, conninst, ScramNonce::none(), scramtype).unwrap();

          .unwrap();

C language bindigns:

gcc test1.c ../../target/debug/libscram_rs.a -o test1
int init_client(const char * usename, const char * password, CApiScramClient ** o_scram_client)
{
    ScramKey * scram_key = NULL;
    CApiScramRuntimeError * err = NULL;

    int32_t res = 
        capi_scram_key(NULL, 0, NULL, 0, &scram_key, &err);

    if (res > 0)
    {
        const char * err_text_dest = capi_scram_error_get_descr(err);

        printf("nonce err text: %s", err_text_dest);

        capi_scram_error_free(err);

        return -1;
    }
    else if (res < 0)
    {
        printf("argument %d is invalid", -res);

        return -1;
    }

    CApiNonce * scram_nonce = NULL;

    res = capi_scram_nonce_none(&scram_nonce, &err);
    
    if (res > 0)
    {
        const char * err_text_dest = capi_scram_error_get_descr(err);

        printf("nonce err text: %s", err_text_dest);

        capi_scram_error_free(err);

        return -1;
    }
    else if (res < 0)
    {
        printf("argument %d is invalid", -res);

        return -1;
    }
    CApiScramClient * scram_client = NULL;

    // init the instance
    res = 
        capi_scram_client_init(RUST_NATIVE, "SCRAM-SHA-256", usename, password, scram_key, scram_nonce, &scram_client, &err);

    if ( res < 0 )
    {
        printf("capi_scram_client_consume() argument %d is invalid", res);
        return -1;
    }
    else if ( res > 0 )
    {
        enum ScramErrorCode err_code = capi_scram_error_get_code(err);
        const char * err_text_dest = capi_scram_error_get_descr(err);

        printf("client init error: err code %i, err text: %s", err_code, err_text_dest);

        capi_scram_error_free(err);

        return -1;
    }    

    *o_scram_client = scram_client;

    return 0;
}

int init_server(struct AuthDBData * some_auth_data, CApiScramServer **o_server)
{
    int res = 0;
    CApiNonce * scram_nonce = NULL;
    CApiScramRuntimeError * err = NULL;

    res = capi_scram_nonce_none(&scram_nonce, &err);
    
    if (res > 0)
    {
        const char * err_text_dest = capi_scram_error_get_descr(err);

        printf("nonce err text: %s", err_text_dest);

        capi_scram_error_free(err);

        return -1;
    }
    else if (res < 0)
    {
        printf("argument %d is invalid", -res);

        return -1;
    }

    CApiScramServer *server = NULL;

    // server instance
    res = 
        capi_scram_server_init(RUST_NATIVE, scram_nonce, (void *)some_auth_data, password_for_user_callback, "SCRAM-SHA-256", &server, &err);

    if ( res < 0 )
    {
        printf("capi_scram_server_init() argument %d is invalid", res);
        return -1;
    }
    else if ( res > 0 )
    {
        const char * err_text_dest = capi_scram_error_get_descr(err);

        printf("response err text: %s", err_text_dest);

        capi_scram_error_free(err);

        return -1;
    }

    *o_server = server;

    return 0;
}
Commit count: 0

cargo fmt