mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-04 20:03:45 +00:00
rust ffi
This commit is contained in:
parent
20a8263d42
commit
8e4ebfec1a
8 changed files with 255 additions and 2 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,8 +1,11 @@
|
||||||
/target
|
**/target
|
||||||
/Cargo.lock
|
|
||||||
/.idea
|
/.idea
|
||||||
**/artifacts
|
**/artifacts
|
||||||
**/corpus
|
**/corpus
|
||||||
**/target
|
**/target
|
||||||
/fuzz/.gitignore
|
/fuzz/.gitignore
|
||||||
**/Cargo.lock
|
**/Cargo.lock
|
||||||
|
**/package-lock.json
|
||||||
|
**/node_modules
|
||||||
|
**/pkg
|
||||||
|
**/dist
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
workspace = { members = ['ffi'], exclude = ["dudect", "ct_cm4"] }
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "fips205"
|
name = "fips205"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
|
||||||
21
ffi/Cargo.toml
Normal file
21
ffi/Cargo.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "fips205-ffi"
|
||||||
|
version = "0.1.2"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
description = "C shared library exposing FIPS 205 (draft): Stateless Hash-Based Digital Signature Standard"
|
||||||
|
authors = ["Eric Schorn <eschorn@integritychain.com>"]
|
||||||
|
documentation = "https://docs.rs/fips205"
|
||||||
|
categories = ["cryptography", "no-std"]
|
||||||
|
repository = "https://github.com/integritychain/fips205"
|
||||||
|
keywords = ["FIPS", "FIPS205", "hash", "signature"]
|
||||||
|
rust-version = "1.70"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib", "cdylib"]
|
||||||
|
bench = false
|
||||||
|
name = "fips205"
|
||||||
|
|
||||||
|
[dependencies.fips205]
|
||||||
|
path = ".."
|
||||||
|
version = "0.1.2"
|
||||||
12
ffi/README.md
Normal file
12
ffi/README.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
FIPS 205 FFI
|
||||||
|
|
||||||
|
Thank you to Daniel Kahn Gillmor <dkg@fifthhorseman.net> for the FIPS 203 example.
|
||||||
|
|
||||||
|
Currently only implemented for `slh_dsa_sha2_128f` until A) more testing has been developed, B) better integration with build flow.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
$ cd ffi # here
|
||||||
|
$ cargo build
|
||||||
|
$ cd tests
|
||||||
|
$ make
|
||||||
|
~~~
|
||||||
50
ffi/fips205.h
Normal file
50
ffi/fips205.h
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef FIPS205_FIPS205_H
|
||||||
|
#define FIPS205_FIPS205_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint8_t slh_dsa_err;
|
||||||
|
|
||||||
|
const slh_dsa_err SLH_DSA_OK = 0;
|
||||||
|
const slh_dsa_err SLH_DSA_NULL_PTR_ERROR = 1;
|
||||||
|
const slh_dsa_err SLH_DSA_SERIALIZATION_ERROR = 2;
|
||||||
|
const slh_dsa_err SLH_DSA_DESERIALIZATION_ERROR = 3;
|
||||||
|
const slh_dsa_err SLH_DSA_KEYGEN_ERROR = 4;
|
||||||
|
const slh_dsa_err SLH_DSA_SIGN_ERROR = 5;
|
||||||
|
const slh_dsa_err SLH_DSA_VERIFY_ERROR = 6;
|
||||||
|
|
||||||
|
typedef struct slh_dsa_sha2_128f_public_key {
|
||||||
|
uint8_t data[32];
|
||||||
|
} slh_dsa_sha2_128f_public_key;
|
||||||
|
|
||||||
|
typedef struct slh_dsa_sha2_128f_private_key {
|
||||||
|
uint8_t data[64];
|
||||||
|
} slh_dsa_sha2_128f_private_key;
|
||||||
|
|
||||||
|
typedef struct slh_dsa_sha2_128f_signature {
|
||||||
|
uint8_t data[17088];
|
||||||
|
} slh_dsa_sha2_128f_signature;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
slh_dsa_err slh_dsa_sha2_128f_keygen(slh_dsa_sha2_128f_public_key *public_out,
|
||||||
|
slh_dsa_sha2_128f_private_key *private_out);
|
||||||
|
|
||||||
|
slh_dsa_err slh_dsa_sha2_128f_sign(const uint8_t *message_buf,
|
||||||
|
int message_length,
|
||||||
|
const slh_dsa_sha2_128f_private_key *private,
|
||||||
|
slh_dsa_sha2_128f_signature *signature_out);
|
||||||
|
|
||||||
|
slh_dsa_err slh_dsa_sha2_128f_verify(const uint8_t *message_buf,
|
||||||
|
int message_length,
|
||||||
|
const slh_dsa_sha2_128f_public_key *public,
|
||||||
|
const slh_dsa_sha2_128f_signature *signature_out);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
#endif //FIPS205_FIPS205_H
|
||||||
104
ffi/src/lib.rs
Normal file
104
ffi/src/lib.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use fips205;
|
||||||
|
use fips205::traits::{KeyGen, SerDes, Signer, Verifier};
|
||||||
|
|
||||||
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
|
pub const SLH_DSA_OK: u8 = 0;
|
||||||
|
pub const SLH_DSA_NULL_PTR_ERROR: u8 = 1;
|
||||||
|
pub const SLH_DSA_SERIALIZATION_ERROR: u8 = 2;
|
||||||
|
pub const SLH_DSA_DESERIALIZATION_ERROR: u8 = 3;
|
||||||
|
pub const SLH_DSA_KEYGEN_ERROR: u8 = 4;
|
||||||
|
pub const SLH_DSA_SIGN_ERROR: u8 = 5;
|
||||||
|
pub const SLH_DSA_VERIFY_ERROR: u8 = 6;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct slh_dsa_message {
|
||||||
|
data: [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// slh_dsa_sha2_128f
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct slh_dsa_sha2_128f_private_key {
|
||||||
|
data: [u8; fips205::slh_dsa_sha2_128f::SK_LEN],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct slh_dsa_sha2_128f_public_key {
|
||||||
|
data: [u8; fips205::slh_dsa_sha2_128f::PK_LEN],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct slh_dsa_sha2_128f_signature {
|
||||||
|
data: [u8; fips205::slh_dsa_sha2_128f::SIG_LEN],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn slh_dsa_sha2_128f_keygen(
|
||||||
|
public_out: Option<&mut slh_dsa_sha2_128f_public_key>,
|
||||||
|
private_out: Option<&mut slh_dsa_sha2_128f_private_key>,
|
||||||
|
) -> u8 {
|
||||||
|
//use fips205::traits::{KeyGen, SerDes};
|
||||||
|
|
||||||
|
let (Some(public_out), Some(private_out)) = (public_out, private_out) else {
|
||||||
|
return SLH_DSA_NULL_PTR_ERROR;
|
||||||
|
};
|
||||||
|
let Ok((pk, sk)) = fips205::slh_dsa_sha2_128f::KG::try_keygen_vt() else {
|
||||||
|
return SLH_DSA_KEYGEN_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
public_out.data = pk.into_bytes();
|
||||||
|
private_out.data = sk.into_bytes();
|
||||||
|
return SLH_DSA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn slh_dsa_sha2_128f_sign(
|
||||||
|
message_buf: *const u8,
|
||||||
|
message_len: c_int,
|
||||||
|
private_key: Option<&mut slh_dsa_sha2_128f_private_key>,
|
||||||
|
signature_out: Option<&mut slh_dsa_sha2_128f_signature>,
|
||||||
|
) -> u8 {
|
||||||
|
let (Some(private_key), Some(signature_out)) = (private_key, signature_out) else {
|
||||||
|
return SLH_DSA_NULL_PTR_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
if message_buf.is_null() {return SLH_DSA_NULL_PTR_ERROR};
|
||||||
|
|
||||||
|
let message = unsafe { std::slice::from_raw_parts(message_buf, message_len.try_into().unwrap()) };
|
||||||
|
|
||||||
|
let Ok(sk) = fips205::slh_dsa_sha2_128f::PrivateKey::try_from_bytes(&private_key.data) else {
|
||||||
|
return SLH_DSA_DESERIALIZATION_ERROR;
|
||||||
|
};
|
||||||
|
let Ok(sig) = sk.try_sign_ct(&message, true) else {
|
||||||
|
return SLH_DSA_SIGN_ERROR;
|
||||||
|
};
|
||||||
|
signature_out.data = sig;
|
||||||
|
return SLH_DSA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn slh_dsa_sha2_128f_verify(
|
||||||
|
message_buf: *const u8,
|
||||||
|
message_len: c_int,
|
||||||
|
public_key: Option<&mut slh_dsa_sha2_128f_public_key>,
|
||||||
|
signature: Option<&mut slh_dsa_sha2_128f_signature>,
|
||||||
|
) -> u8 {
|
||||||
|
let (Some(public_key), Some(signature)) = (public_key, signature) else {
|
||||||
|
return SLH_DSA_NULL_PTR_ERROR;
|
||||||
|
};
|
||||||
|
let message = unsafe { std::slice::from_raw_parts(message_buf, message_len.try_into().unwrap()) };
|
||||||
|
|
||||||
|
let Ok(sk) = fips205::slh_dsa_sha2_128f::PublicKey::try_from_bytes(&public_key.data) else {
|
||||||
|
return SLH_DSA_DESERIALIZATION_ERROR;
|
||||||
|
};
|
||||||
|
let res = sk.try_verify_vt(&message, &signature.data);
|
||||||
|
|
||||||
|
if res.is_ok() && res.unwrap() { SLH_DSA_OK } else { SLH_DSA_VERIFY_ERROR }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
19
ffi/tests/Makefile
Normal file
19
ffi/tests/Makefile
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
SO_LOCATION = ../../target/debug
|
||||||
|
FEATURES = slh_dsa_sha2_128f
|
||||||
|
FRAMES = public_key private_key signature sign verify keygen
|
||||||
|
|
||||||
|
BASELINES=$(foreach sz, $(FEATURES), baseline-$(sz))
|
||||||
|
CHECKS=$(foreach sz, $(FEATURES), runtest-$(sz))
|
||||||
|
|
||||||
|
check: $(CHECKS)
|
||||||
|
|
||||||
|
runtest-%: baseline-%
|
||||||
|
LD_LIBRARY_PATH=$(SO_LOCATION) ./$<
|
||||||
|
|
||||||
|
baseline-%: baseline.c ../fips205.h
|
||||||
|
$(CC) -o $@ -g -D SLHDSA=$* $(foreach v, $(FRAMES),-D SLHDSA_$(v)=$*_$(v)) -Werror -Wall -pedantic -L $(SO_LOCATION) $< -Wall -lfips205
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BASELINES)
|
||||||
|
|
||||||
|
.PHONY: clean check
|
||||||
42
ffi/tests/baseline.c
Normal file
42
ffi/tests/baseline.c
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../fips205.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, const char **argv) {
|
||||||
|
SLHDSA_public_key public;
|
||||||
|
SLHDSA_private_key private;
|
||||||
|
SLHDSA_signature sig;
|
||||||
|
uint8_t message[] = { 0x00, 0x11, 0x22 };
|
||||||
|
|
||||||
|
// Happy path
|
||||||
|
if (SLHDSA_keygen(&public, &private)) return 1;
|
||||||
|
if (SLHDSA_sign(message, sizeof message, &private, &sig)) return 1;
|
||||||
|
if (SLHDSA_verify(message, sizeof message, &public, &sig)) return 1;
|
||||||
|
|
||||||
|
// Verify should fail now
|
||||||
|
message[0] = 99;
|
||||||
|
if (SLHDSA_verify(message, sizeof message, &public, &sig) != SLH_DSA_VERIFY_ERROR) return 1;
|
||||||
|
|
||||||
|
// Null parameters
|
||||||
|
if (SLHDSA_keygen(&public, NULL) != SLH_DSA_NULL_PTR_ERROR) {
|
||||||
|
fprintf (stderr, "keygen should have failed with NULL private key\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (SLHDSA_keygen(NULL, &private) != SLH_DSA_NULL_PTR_ERROR) {
|
||||||
|
fprintf (stderr, "keygen should have failed with NULL public key\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SLHDSA_sign(NULL, sizeof message, &private, &sig) != SLH_DSA_NULL_PTR_ERROR) {
|
||||||
|
fprintf (stderr, "sign should have failed with NULL message\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (SLHDSA_sign(message, sizeof message, NULL, &sig) != SLH_DSA_NULL_PTR_ERROR) {
|
||||||
|
fprintf (stderr, "sign should have failed with NULL private key\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (SLHDSA_sign(message, sizeof message, &private, NULL) != SLH_DSA_NULL_PTR_ERROR) {
|
||||||
|
fprintf (stderr, "sign should have failed with NULL signature\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue