cas-lib 0.2.85

A function wrapper layer for RustCrypto and Dalek-Cryptography. Intended to be used in FFI situations with a global heap deallactor at the top level project.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# Examples

This document provides runnable examples for each cryptographic module in `cas-lib`.
Most examples follow the same pattern described in
[issue #7](https://github.com/Cryptographic-API-Services/cas-lib/issues/7): read a file
from disk, get its bytes, and perform the cryptographic operation on them.

To try any of these:

```bash
cargo new cas-demo
cd cas-demo
cargo add cas-lib
# paste an example into src/main.rs, then:
cargo run
```

> **Note on "Digital Signature" and "ecdsa".** These two items appeared on the
> original checklist in issue #7 but the standalone Digital Signature
> implementation was removed from the library (it did little beyond what the
> hashers already provide), and a dedicated ECDSA module was never shipped.
> Use [Ed25519 signatures]#signatures-ed25519 or
> [RSA sign/verify]#asymmetric-rsa instead.

## Table of Contents

- [Password Hashers]#password-hashers
- [Symmetric]#symmetric
- [Hashers]#hashers
- [Asymmetric (RSA)]#asymmetric-rsa
- [Signatures (Ed25519)]#signatures-ed25519
- [Key Exchange (X25519)]#key-exchange-x25519
- [Message Authentication (HMAC)]#message-authentication-hmac
- [Hybrid (HPKE)]#hybrid-hpke
- [Sponges (ASCON-AEAD)]#sponges-ascon-aead
- [Compression (Zstandard)]#compression-zstandard

## Password Hashers
### Argon2
```rust
use cas_lib::password_hashers::{argon2::CASArgon, cas_password_hasher::CASPasswordHasher};

fn main() {
let password_to_hash = "HashThisBadPassword".to_string();
let hash = CASArgon::hash_password(password_to_hash);
println!("{}", hash)
}
```
### BCrypt
```rust
use cas_lib::password_hashers::{bcrypt::CASBCrypt, cas_password_hasher::CASPasswordHasher};

let password_to_hash = "HashThisBadPassword".to_string();
let hash = CASBCrypt::hash_password(password_to_hash);
println!("{}", hash);
```
### SCrypt
```rust
use cas_lib::password_hashers::{bcrypt::CASScrypt, cas_password_hasher::CASPasswordHasher};

let password_to_hash = "HashThisBadPassword".to_string();
let hash = CASScrypt::hash_password(password_to_hash);
println!("{}", hash);
```


## Symmetric

The symmetric module exposes AES-128-GCM, AES-256-GCM, and ChaCha20-Poly1305.
Nonces and keys are generated for you via `OsRng` — you never supply them
yourself. `encrypt_plaintext` returns the ciphertext with the authentication tag
appended; pass that same output back to `decrypt_ciphertext`. Each operation
returns a `Result`, so handle the error (here with `.unwrap()`).

### AES-256 GCM Mode
```rust
use std::{fs::File, io::Write, path::Path};

use cas_lib::symmetric::{aes::CASAES256, cas_symmetric_encryption::CASAES256Encryption};

fn main() {
    // Read the original file from disk.
    let path = Path::new("MikeMulchrone_Resume2024.docx");
    let file_bytes: Vec<u8> = std::fs::read(path).unwrap();

    // Generate a fresh key and nonce, then encrypt and write the ciphertext to disk.
    let aes_nonce = <CASAES256 as CASAES256Encryption>::generate_nonce();
    let aes_key = <CASAES256 as CASAES256Encryption>::generate_key();
    let encrypted_bytes = <CASAES256 as CASAES256Encryption>::encrypt_plaintext(
        aes_key.clone(),
        aes_nonce.clone(),
        file_bytes.clone(),
    )
    .unwrap();
    let mut file = File::create("encrypted.docx").unwrap();
    file.write_all(&encrypted_bytes).unwrap();

    // Decrypt with the same key and nonce; the result matches the original file.
    let decrypted_bytes =
        <CASAES256 as CASAES256Encryption>::decrypt_ciphertext(aes_key, aes_nonce, encrypted_bytes)
            .unwrap();
    let mut file = File::create("decrypted.docx").unwrap();
    file.write_all(&decrypted_bytes).unwrap();

    assert_eq!(file_bytes, decrypted_bytes);
}
```

### AES-128 GCM Mode
```rust
use std::{fs::File, io::Write, path::Path};

use cas_lib::symmetric::{aes::CASAES128, cas_symmetric_encryption::CASAES128Encryption};

fn main() {
    let path = Path::new("MikeMulchrone_Resume2024.docx");
    let file_bytes: Vec<u8> = std::fs::read(path).unwrap();

    let aes_nonce = <CASAES128 as CASAES128Encryption>::generate_nonce();
    let aes_key = <CASAES128 as CASAES128Encryption>::generate_key();
    let encrypted_bytes = <CASAES128 as CASAES128Encryption>::encrypt_plaintext(
        aes_key.clone(),
        aes_nonce.clone(),
        file_bytes.clone(),
    )
    .unwrap();
    let mut file = File::create("encrypted.docx").unwrap();
    file.write_all(&encrypted_bytes).unwrap();

    let decrypted_bytes =
        <CASAES128 as CASAES128Encryption>::decrypt_ciphertext(aes_key, aes_nonce, encrypted_bytes)
            .unwrap();
    let mut file = File::create("decrypted.docx").unwrap();
    file.write_all(&decrypted_bytes).unwrap();

    assert_eq!(file_bytes, decrypted_bytes);
}
```

### ChaCha20-Poly1305
```rust
use std::{fs::File, io::Write, path::Path};

use cas_lib::symmetric::{
    cas_symmetric_encryption::Chacha20Poly1305Encryption, chacha20poly1305::CASChacha20Poly1305,
};

fn main() {
    let path = Path::new("MikeMulchrone_Resume2024.docx");
    let file_bytes: Vec<u8> = std::fs::read(path).unwrap();

    let nonce = <CASChacha20Poly1305 as Chacha20Poly1305Encryption>::generate_nonce();
    let key = <CASChacha20Poly1305 as Chacha20Poly1305Encryption>::generate_key();
    let encrypted_bytes = <CASChacha20Poly1305 as Chacha20Poly1305Encryption>::encrypt_plaintext(
        key.clone(),
        nonce.clone(),
        file_bytes.clone(),
    )
    .unwrap();
    let mut file = File::create("encrypted.docx").unwrap();
    file.write_all(&encrypted_bytes).unwrap();

    let decrypted_bytes =
        <CASChacha20Poly1305 as Chacha20Poly1305Encryption>::decrypt_ciphertext(
            key,
            nonce,
            encrypted_bytes,
        )
        .unwrap();
    let mut file = File::create("decrypted.docx").unwrap();
    file.write_all(&decrypted_bytes).unwrap();

    assert_eq!(file_bytes, decrypted_bytes);
}
```


## Hashers

The hashers module provides SHA-2 / SHA-3 style digests (256- and 512-bit) via
the `CASHasher` trait. A digest is deterministic, so hashing the same file twice
produces equal output, while two different files produce different output. The
example below reads two files from disk and demonstrates both the `true`
(identical content) and `false` (different content) comparison cases described in
issue #7. `verify_256` / `verify_512` re-hash the data and compare it against a
previously produced digest.

```rust
use std::path::Path;

use cas_lib::hashers::{cas_hasher::CASHasher, sha::CASSHA};

fn main() {
    // Hash the first file.
    let path = Path::new("file_a.docx");
    let file_a: Vec<u8> = std::fs::read(path).unwrap();
    let hash_a = <CASSHA as CASHasher>::hash_256(file_a.clone());

    // Hashing the SAME file again yields the SAME digest -> true.
    let hash_a_again = <CASSHA as CASHasher>::hash_256(file_a.clone());
    println!("same file matches: {}", hash_a == hash_a_again); // true

    // Hashing a DIFFERENT file yields a DIFFERENT digest -> false.
    let path_b = Path::new("file_b.docx");
    let file_b: Vec<u8> = std::fs::read(path_b).unwrap();
    let hash_b = <CASSHA as CASHasher>::hash_256(file_b);
    println!("different file matches: {}", hash_a == hash_b); // false

    // verify_256 re-hashes the data and checks it against an existing digest.
    let verified = <CASSHA as CASHasher>::verify_256(hash_a, file_a);
    println!("verify_256: {}", verified); // true

    // 512-bit variants are also available:
    //   <CASSHA as CASHasher>::hash_512(data);
    //   <CASSHA as CASHasher>::verify_512(digest, data);
}
```


## Asymmetric (RSA)

The asymmetric module wraps RSA. Keys are PEM-encoded strings. Key sizes below
2048 bits are rejected. RSA here is used for signing and verifying a document's
bytes; every operation returns a `Result`.

```rust
use cas_lib::asymmetric::{
    cas_rsa::CASRSA,
    types::{CASRSAEncryption, RSAKeyPairResult},
};

fn main() {
    // Generate a 2048-bit RSA key pair (PEM-encoded strings).
    let key_pair: RSAKeyPairResult = CASRSA::generate_rsa_keys(2048).unwrap();

    // Read the document to sign.
    let document: Vec<u8> = std::fs::read("contract.pdf").unwrap();

    // Sign with the private key.
    let signature = CASRSA::sign(key_pair.private_key, document.clone()).unwrap();

    // Verify with the public key -> true when the document is unmodified.
    let is_valid = CASRSA::verify(key_pair.public_key, document, signature).unwrap();
    println!("signature valid: {}", is_valid); // true
}
```


## Signatures (Ed25519)

The signatures module provides Ed25519. `get_ed25519_key_pair` returns a key
pair; signing produces a 64-byte signature plus the 32-byte verification
(public) key. You can verify either with the full key pair or with just the
public key — the latter is what a remote verifier would typically hold.

```rust
use cas_lib::signatures::ed25519::{
    ed25519_sign_with_key_pair, ed25519_verify_with_public_key, get_ed25519_key_pair,
};

fn main() {
    // Generate a key pair.
    let key_pair = get_ed25519_key_pair();

    // Read the message/document to sign from disk.
    let message: Vec<u8> = std::fs::read("message.txt").unwrap();

    // Sign with the key pair.
    let signature = ed25519_sign_with_key_pair(key_pair.key_pair, message.clone()).unwrap();

    // A verifier holding only the public key can confirm the signature -> true.
    let is_valid =
        ed25519_verify_with_public_key(signature.public_key, signature.signature, message).unwrap();
    println!("signature valid: {}", is_valid); // true
}
```


## Key Exchange (X25519)

The key_exchange module implements X25519 Diffie-Hellman. Each party generates a
secret/public key pair; combining your secret key with the other party's public
key yields a shared secret that is identical on both sides. That shared secret
can then be turned into a symmetric key (see
[`key_from_x25519_shared_secret`](#symmetric) on the AES types).

```rust
use cas_lib::key_exchange::{
    cas_key_exchange::CASKeyExchange,
    x25519::{X25519, X25519SecretPublicKeyResult},
};

fn main() {
    // Each party generates a secret + public key pair.
    let alice: X25519SecretPublicKeyResult = X25519::generate_secret_and_public_key();
    let bob: X25519SecretPublicKeyResult = X25519::generate_secret_and_public_key();

    // Each side combines their own secret with the other's public key.
    let alice_shared = X25519::diffie_hellman(alice.secret_key, bob.public_key).unwrap();
    let bob_shared = X25519::diffie_hellman(bob.secret_key, alice.public_key).unwrap();

    // Both sides derive the SAME shared secret -> true.
    println!("shared secrets match: {}", alice_shared == bob_shared); // true
}
```


## Message Authentication (HMAC)

The message module provides HMAC. `sign` produces a tag over a message using a
shared key; `verify` recomputes the tag and confirms it matches. A correct
key + message + signature triple verifies as `true`.

```rust
use cas_lib::message::{cas_hmac::CASHMAC, hmac::HMAC};

fn main() {
    // Shared secret key and the message bytes (read a file here in practice).
    let key: Vec<u8> = vec![1, 2, 3, 4, 5];
    let message: Vec<u8> = std::fs::read("message.txt").unwrap();

    // Produce an authentication tag.
    let signature = HMAC::sign(key.clone(), message.clone()).unwrap();

    // Verify the tag with the same key and message -> true.
    let is_valid = HMAC::verify(key, message, signature).unwrap();
    println!("hmac valid: {}", is_valid); // true
}
```


## Hybrid (HPKE)

The hybrid module implements HPKE (Hybrid Public Key Encryption). The recipient
generates a key pair and an `info` string. A sender encrypts to the recipient's
public key, producing an encapsulated key, the ciphertext, and an authentication
tag. The recipient decrypts using their private key plus those three values.

```rust
use std::path::Path;

use cas_lib::hybrid::{cas_hybrid::CASHybrid, hpke::CASHPKE};

fn main() {
    // Read the file to encrypt.
    let file_bytes: Vec<u8> = std::fs::read(Path::new("secret.docx")).unwrap();

    // Recipient generates a key pair and info string.
    let (private_key, public_key, info_str) = CASHPKE::generate_key_pair();

    // Sender encrypts to the recipient's public key.
    let (encapped_key, ciphertext, tag) =
        CASHPKE::encrypt(file_bytes.clone(), public_key, info_str.clone()).unwrap();

    // Recipient decrypts with their private key + the encapsulated key + tag.
    let decrypted_bytes =
        CASHPKE::decrypt(ciphertext, private_key, encapped_key, tag, info_str).unwrap();

    assert_eq!(file_bytes, decrypted_bytes);
    println!("hpke round-trip succeeded");
}
```


## Sponges (ASCON-AEAD)

The sponges module provides ASCON-AEAD, a lightweight authenticated cipher. As
with the symmetric module, the key and nonce are generated for you, and
`encrypt` / `decrypt` round-trip the file bytes.

```rust
use std::{fs::File, io::Write, path::Path};

use cas_lib::sponges::{ascon_aead::AsconAead, cas_ascon_aead::CASAsconAead};

fn main() {
    let path = Path::new("secret.docx");
    let file_bytes: Vec<u8> = std::fs::read(path).unwrap();

    let nonce = <AsconAead as CASAsconAead>::generate_nonce();
    let key = <AsconAead as CASAsconAead>::generate_key();

    let encrypted_bytes =
        <AsconAead as CASAsconAead>::encrypt(key.clone(), nonce.clone(), file_bytes.clone())
            .unwrap();
    let mut file = File::create("encrypted.docx").unwrap();
    file.write_all(&encrypted_bytes).unwrap();

    let decrypted_bytes =
        <AsconAead as CASAsconAead>::decrypt(key, nonce, encrypted_bytes).unwrap();
    let mut file = File::create("decrypted.docx").unwrap();
    file.write_all(&decrypted_bytes).unwrap();

    assert_eq!(file_bytes, decrypted_bytes);
}
```


## Compression (Zstandard)

The compression module wraps Zstandard. `compress` takes the data and a
compression level (0-22; higher means smaller but slower); `decompress` restores
the original bytes exactly.

```rust
use cas_lib::compression::zstd::{compress, decompress};

fn main() {
    // Read a file from disk.
    let original: Vec<u8> = std::fs::read("large_log.txt").unwrap();

    // Compress at level 9.
    let compressed: Vec<u8> = compress(original.clone(), 9).unwrap();
    println!(
        "compressed {} bytes down to {} bytes",
        original.len(),
        compressed.len()
    );

    // Decompress back to the original bytes.
    let decompressed: Vec<u8> = decompress(compressed).unwrap();
    assert_eq!(original, decompressed);
}
```