mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-03 19:53:49 +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
|
||||
/Cargo.lock
|
||||
**/target
|
||||
/.idea
|
||||
**/artifacts
|
||||
**/corpus
|
||||
**/target
|
||||
/fuzz/.gitignore
|
||||
**/Cargo.lock
|
||||
**/package-lock.json
|
||||
**/node_modules
|
||||
**/pkg
|
||||
**/dist
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
workspace = { members = ['ffi'], exclude = ["dudect", "ct_cm4"] }
|
||||
|
||||
[package]
|
||||
name = "fips205"
|
||||
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