Skip to content

Commit

Permalink
Merge pull request #11 from thomastaylor312/feat/add_wasm_support
Browse files Browse the repository at this point in the history
feat(*): Adds support for wasm32 targets
  • Loading branch information
thomastaylor312 authored Dec 17, 2021
2 parents 173aee4 + 0b3d45a commit e2c121a
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 31 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/target
**/*.rs.bk
Cargo.lock
.idea
.idea
.vscode/
28 changes: 17 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
[package]
name = "nkeys"
version = "0.1.0"
authors = ["Kevin Hoffman <alothien@gmail.com>"]
edition = "2018"
version = "0.2.0"
authors = ["wasmCloud Team"]
edition = "2021"
description = "Rust implementation of the NATS nkeys library"
license = "Apache-2.0"
homepage = "https://github.com/encabulators/nkeys"
homepage = "https://github.com/wasmcloud/nkeys"
documentation = "https://docs.rs/nkeys"
repository = "https://github.com/encabulators/nkeys"
repository = "https://github.com/wasmcloud/nkeys"
readme = "README.md"
keywords = ["crypto", "nats", "ed25519", "cryptography"]
categories = ["cryptography", "authentication"]

[badges]
travis-ci = { repository = "encabulators/nkeys", branch = "master" }

[features]
cli = ["quicli", "structopt", "term-table", "exitfailure", "env_logger", "serde_json"]

Expand All @@ -23,9 +20,9 @@ name = "nk"
required-features = ["cli"]

[dependencies]
signatory = "0.21"
signatory = "0.23"
ed25519-dalek = { version = "1.0.1", default-features = false, features = ["u64_backend"] }
rand = "0.7.3"
rand = "0.8"
byteorder = "1.3.4"
data-encoding = "2.3.0"
log = "0.4.11"
Expand All @@ -35,5 +32,14 @@ quicli = { version = "0.4", optional = true }
structopt = { version = "0.3.17", optional = true }
term-table = { version = "1.3.0", optional = true }
exitfailure = { version = "0.5.1", optional =true }
env_logger = { version = "0.7.1", optional = true }
env_logger = { version = "0.9", optional = true }
serde_json = { version = "1.0", optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
# NOTE: We need this due to an underlying dependency being pulled in by
# `ed25519-dalek`. Even if we exclude `rand`, that crate pulls it in. `rand` pulls in the low level
# `getrandom` library, which explicitly doesn't support wasm32-unknown-unknown. This is a hack to
# get around that by enabling the `custom` feature of getrandom (even though we don't actually use
# the library). This makes `rand` compile in the dalek library even though we aren't actually using
# the `rand` part of it.
getrandom = { version = "0.2", default-features = false, features = ["custom"] }
7 changes: 3 additions & 4 deletions src/bin/nk/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ enum Command {
#[derive(StructOpt, Debug, Clone)]
enum Output {
Text,
JSON,
Json,
}

impl FromStr for Output {
type Err = OutputParseErr;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"json" => Ok(Output::JSON),
"json" => Ok(Output::Json),
"text" => Ok(Output::Text),
_ => Err(OutputParseErr),
}
Expand All @@ -63,7 +63,6 @@ impl fmt::Display for OutputParseErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
"error parsing output type, see help for the list of accepted outputs"
)
}
Expand Down Expand Up @@ -91,7 +90,7 @@ fn generate(kt: &KeyPairType, output_type: &Output) {
kp.seed().unwrap()
);
}
Output::JSON => {
Output::Json => {
let output = json!({
"public_key": kp.public_key(),
"seed": kp.seed().unwrap(),
Expand Down
70 changes: 55 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@
#![allow(dead_code)]

use std::fmt::{self, Debug};

use crc::{extract_crc, push_crc, valid_checksum};
use ed25519_dalek::{ExpandedSecretKey, PublicKey, SecretKey, Signature, Verifier};
use rand::prelude::*;
use std::fmt;
use std::fmt::Debug;

const ENCODED_SEED_LENGTH: usize = 58;

Expand Down Expand Up @@ -145,57 +145,95 @@ impl From<u8> for KeyPairType {
}

impl KeyPair {
/// Creates a new key pair of the given type
/// Creates a new key pair of the given type.
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new(kp_type: KeyPairType) -> KeyPair {
// If this unwrap fails, then the library is invalid, so the unwrap is OK here
let s = create_seed().unwrap();
KeyPair {
Self::new_from_raw(kp_type, generate_seed_rand()).unwrap()
}

/// Create a new keypair using a pre-existing set of random bytes.
///
/// Returns an error if there is an issue using the bytes to generate the key
/// NOTE: These bytes should be generated from a cryptographically secure random source.
pub fn new_from_raw(kp_type: KeyPairType, random_bytes: [u8; 32]) -> Result<KeyPair> {
let s = create_seed(random_bytes)?;
Ok(KeyPair {
kp_type,
pk: pk_from_seed(&s),
sk: Some(s),
}
})
}

/// Creates a new user key pair with a seed that has a **U** prefix
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new_user() -> KeyPair {
Self::new(KeyPairType::User)
}

/// Creates a new account key pair with a seed that has an **A** prefix
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new_account() -> KeyPair {
Self::new(KeyPairType::Account)
}

/// Creates a new operator key pair with a seed that has an **O** prefix
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new_operator() -> KeyPair {
Self::new(KeyPairType::Operator)
}

/// Creates a new cluster key pair with a seed that has the **C** prefix
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new_cluster() -> KeyPair {
Self::new(KeyPairType::Cluster)
}

/// Creates a new server key pair with a seed that has the **N** prefix
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new_server() -> KeyPair {
Self::new(KeyPairType::Server)
}

/// Creates a new module (e.g. WebAssembly) key pair with a seed that has the **M** prefix
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new_module() -> KeyPair {
Self::new(KeyPairType::Module)
}

/// Creates a new service / service provider key pair with a seed that has the **V** prefix
///
/// NOTE: This is not available if using on a wasm32-unknown-unknown target due to the lack of
/// rand support. Use [`new_from_raw`](KeyPair::new_from_raw) instead
#[cfg(not(target_arch = "wasm32"))]
pub fn new_service() -> KeyPair {
Self::new(KeyPairType::Service)
}

/// Returns the encoded, human-readable public key of this key pair
pub fn public_key(&self) -> String {
let mut raw = vec![];

raw.push(get_prefix_byte(&self.kp_type));
let mut raw = vec![get_prefix_byte(&self.kp_type)];

raw.extend(self.pk.as_bytes());

Expand All @@ -216,9 +254,9 @@ impl KeyPair {

/// Attempts to verify that the given signature is valid for the given input
pub fn verify(&self, input: &[u8], sig: &[u8]) -> Result<()> {
let mut fixedsig = [0; ed25519_dalek::ed25519::SIGNATURE_LENGTH];
let mut fixedsig = [0; ed25519_dalek::Signature::BYTE_SIZE];
fixedsig.copy_from_slice(sig);
let insig = ed25519_dalek::Signature::new(fixedsig);
let insig = ed25519_dalek::Signature::from_bytes(&fixedsig)?;

match self.pk.verify(input, &insig) {
Ok(()) => Ok(()),
Expand Down Expand Up @@ -288,7 +326,7 @@ impl KeyPair {
Err(err!(
InvalidPrefix,
"Incorrect byte prefix: {}",
source.chars().nth(0).unwrap()
source.chars().next().unwrap()
))
} else {
let b2 = (raw[0] & 7) << 5 | ((raw[1] & 248) >> 3);
Expand Down Expand Up @@ -323,11 +361,13 @@ fn decode_raw(raw: &[u8]) -> Result<Vec<u8>> {
}
}

fn create_seed() -> Result<SecretKey> {
fn generate_seed_rand() -> [u8; 32] {
let mut rng = rand::thread_rng();
let rnd_bytes = rng.gen::<[u8; 32]>();
rng.gen::<[u8; 32]>()
}

SecretKey::from_bytes(&rnd_bytes[..]).map_err(|e| e.into())
fn create_seed(rand_bytes: [u8; 32]) -> Result<SecretKey> {
SecretKey::from_bytes(&rand_bytes[..]).map_err(|e| e.into())
}

fn get_prefix_byte(kp_type: &KeyPairType) -> u8 {
Expand Down

0 comments on commit e2c121a

Please sign in to comment.