Skip to content

v1.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 22 Jul 12:20
· 2 commits to main since this release
Immutable release. Only release title and notes can be modified.
v1.0.0
a1c605e

dryoc v1.0.0

dryoc 1.0.0 hardens cryptographic boundary checks, replaces string-only errors with structured errors, and adds libsodium-compatible ChaCha20-Poly1305-IETF support. This is a backward-incompatible upgrade from v0.9.0: source APIs, accepted inputs, selected serde representations, and 32-bit/wasm secretstream framing changed.

Full Changelog: v0.9.0...v1.0.0

Breaking Changes

Errors and fallible APIs

  • Error::Message, Error::FromSlice, From<String>, and From<&str> were removed. Errors now use non-exhaustive, matchable variants such as AuthenticationFailed, InvalidLength, InvalidValue, InvalidKey, and Io; downstream matches must include a wildcard.
  • crypto_scalarmult, crypto_box_beforenm, crypto_box_detached, crypto_box_detached_afternm, crypto_secretbox_detached, KeyPair::precalculate, and PrecalcSecretKey::precalculate now return Result. Low-order X25519 public keys are rejected through scalarmult, box, key-exchange, and precalculation APIs.
  • Protected-memory traits, constructors, keypair generation, and protected precalculation now return dryoc::Error instead of std::io::Error.
  • Tag::from(u8) and PasswordHashAlgorithm::from(u32) were replaced by fallible TryFrom conversions.

API contracts

  • crypto_core_ed25519_is_valid_point_relaxed was removed; use the strict crypto_core_ed25519_is_valid_point. Signature verification and Ed25519-to-Curve25519 conversion now reject non-canonical, small-order, and mixed-order inputs.
  • crypto_box_seed_keypair, crypto_box_seed_keypair_inplace, and KeyPair::from_seed now require exactly CRYPTO_BOX_SEEDBYTES bytes.
  • Kdf::derive_subkey supports a const-generic output length, while derive_subkey_to_vec now requires an explicit length. Custom KDF main-key and KX session-key storage types must implement ZeroizeOnDrop.
  • Config::with_salt_length was removed; newly generated password hashes always use libsodium's 16-byte salt. Use Config::with_algorithm to select Argon2i or Argon2id.
  • PwHash::to_string() -> String was replaced by PwHash::to_encoded_string() -> Result<String, Error>.
  • Protected-memory .munlock() is available only for values in the Locked typestate.

Data, wire, and behavior compatibility

  • With serde, the Config/PwHash representation replaces salt_length with parallelism. StackByteArray<N> now rejects short or overlong sequences instead of padding or truncating them, and variable protected buffers no longer retain unused size-hint padding.
  • Secretstream now authenticates lengths as fixed-width little-endian u64 values. Streams produced by pre-1.0 builds on 32-bit or wasm targets are not wire-compatible and must be decrypted with the old version and re-encrypted with v1.0.0. The prior 64-bit little-endian encoding already used the same byte width.
  • Box, secretbox, AEAD, password-hash, KDF, and secretstream APIs enforce corrected size and encoding limits before allocation or output mutation. Code that depended on oversized buffers, malformed encodings, unknown stream-tag bits, or non-canonical keys/signatures will now receive an error.
  • Secret-bearing Debug output is redacted. Do not depend on previous debug strings or exact human-readable error text.

Migration Guide (v0.9.x -> v1.0.0)

1. Update and compile

Change the dependency requirement to dryoc = "1", then update and compile all targets and enabled features:

cargo update -p dryoc --precise 1.0.0
cargo check --all-targets

2. Handle new results and structured errors

Add ?, match, or an explicit expect at newly fallible calls:

let shared_key = crypto_box_beforenm(&public_key, &secret_key)?;
crypto_box_detached(&mut ciphertext, &mut mac, message, &nonce, &public_key, &secret_key)?;
let precalculated = keypair.precalculate(&third_party_public_key)?;

Replace string matching with structured matching and retain a wildcard because the enums are non-exhaustive:

match error {
    dryoc::Error::AuthenticationFailed => handle_authentication_failure(),
    dryoc::Error::InvalidLength { context, actual, constraint } => {
        handle_invalid_length(context, actual, constraint)
    }
    dryoc::Error::Io(source) => handle_io_error(source),
    other => handle_other_error(other),
}

If an API must still expose std::io::Error, explicitly handle dryoc::Error::Io(source) and define how non-I/O variants are translated.

3. Apply API replacements

  • Tag::from(byte) -> Tag::try_from(byte)?
  • PasswordHashAlgorithm::from(value) -> PasswordHashAlgorithm::try_from(value)?
  • pwhash.to_string() -> pwhash.to_encoded_string()?
  • kdf.derive_subkey_to_vec(id) -> kdf.derive_subkey_to_vec(id, length)
  • For fixed-size KDF output, let the destination type select the length: let subkey: StackByteArray<32> = kdf.derive_subkey(id)?;
  • Convert dynamic box seeds to an exact-size array and handle the slice-conversion error in the application before calling the seed APIs: let seed: &[u8; CRYPTO_BOX_SEEDBYTES] = seed_slice.try_into().expect("seed must be exactly 32 bytes");
  • Replace crypto_core_ed25519_is_valid_point_relaxed with crypto_core_ed25519_is_valid_point and handle values that no longer pass strict validation.

4. Migrate persisted data

Back up persisted serde-encoded Config/PwHash values before rewriting them. Replace the salt_length field with parallelism: 1; do not copy the old salt-length number into parallelism. Existing salt bytes remain part of PwHash, while newly generated salts are always 16 bytes. Valid libsodium-compatible encoded Argon2 strings do not need to be rehashed.

On 32-bit or wasm systems, decrypt any retained pre-1.0 secretstream ciphertext with v0.9.x and re-encrypt it with v1.0.0. Active stream state cannot be upgraded in place.

5. Validate application behavior

cargo test --all-targets
cargo clippy --all-targets -- -D warnings

If the application enables dryoc's nightly-only features, also run its feature combination with the nightly toolchain; for example, cargo +nightly test --all-targets --all-features.

Add negative tests for invalid lengths, low-order keys, non-canonical signatures, malformed password hashes, and unknown stream tags where the application previously assumed those inputs were accepted.

Highlights

  • Added Classic and Rustaceous ChaCha20-Poly1305-IETF APIs with RFC 8439 known-answer tests and libsodium interoperability coverage.
  • Added structured, dependency-free error types with contextual length and value constraints.
  • Hardened secret zeroization, protected-memory failure behavior, constant-time comparisons, output/state atomicity on authentication failure, and redaction of secret-bearing debug output.
  • Expanded MSRV, feature-matrix, wasm, Windows, fuzz, documentation, package, and publish validation; added an early SemVer compatibility check.
  • Documented WebAssembly support and the nightly feature requirements for the SIMD backend.

Pull Requests

Features

  • Structured error types (#141)
  • ChaCha20-Poly1305-IETF AEAD (#143)

Security and Correctness

  • Harden cryptographic safety invariants (#139)
  • Harden cryptographic APIs and release validation (#142)

Documentation

  • Overhaul public API documentation (#140)
  • Document WebAssembly support (#146)
  • Clarify SIMD build requirements (#148)

CI and Maintenance

  • Version and repository cleanup (#136, #138)
  • Authenticate cargo-binstall requests (#144)
  • Create draft GitHub releases (#145)
  • Check SemVer compatibility (#147)