Requires Rust and Cargo to build; also requires OpenSSL v1.1.0 or higher.
Run `cargo build --release`, the binary will be built to `./target/release/chacha20`.
Run `cargo build --release`, the binary will be built to `./target/release/chacha20`.
### Testing
### Testing
@ -10,22 +10,37 @@ Run `cargo test && cargo build && ./test.sh debug` to test the program.
Alternatively, run `./test.sh` after building to test the release build's correctness.
Alternatively, run `./test.sh` after building to test the release build's correctness.
# Usage
# Usage
Copies stdin to stdout while encrypting or decrypting with the stream cipher.
Copies stdin to stdout while encrypting or decrypting with the stream cipher`chacha20_poly1305`.
## Modes
## Modes
* Encrypt - Encrypt stdin to stdout
* Encrypt - Encrypt stdin to stdout
* Decrypt - Decrypt stdin to stdout
* Decrypt - Decrypt stdin to stdout
* Keygen - Generate a random key and IV and print them to stdout
* Keygen - Generate a random key and IV and print them to stdout
To see a more detailed explenation run `chacha20` with no arguments.
To see a more detailed explenation run `chacha20 help`.
## Formats
The key and IV is expected/generated in base64 format.
The key and IV sizes respectively are 32 and 12 bytes.
The ciphertext input and output is raw binary data. You can encode this to text formats if you want with whatever tool you choose (Example with `base64` below.)
## Example
## Example
Encrypting and decrypting a string to binary with randomly generated keys
```shell
```shell
$ echo "Hello world!" | chacha20 e 2>keys.cck > output.cc20
$ echo "Hello world!" | chacha20 e 2>keys.cck > output.cc20
$ chacha20 d $(cat keys.cck) <output.cc20
$ chacha20 d $(cat keys.cck) <output.cc20
Hello world!
Hello world!
```
```
The same but with text instead of binary ciphertexts
Add `b-encrypt` mode to write the outputted bytes in base64 instead of raw bytes, and `b-decrypt` mode to read the inputted bytes in base64 instead of raw bytes
eprintln!("(Key size is {}, IV size is {})",cha::KEY_SIZE,cha::IV_SIZE);
eprintln!("(Key size is {}, IV size is {})",cha::KEY_SIZE,cha::IV_SIZE);
eprintln!("\nencrypt/decrypt:\n\tIf key and/or IV are not provided, they are generated randomly and printed to stderr in order on one line each");
eprintln!("(requires OpenSSL 1.1.0 or newer)");
eprintln!("\tIf the key and/or IV provided's size is lower than the cipher's key/IV size, the rest of the key/IV padded with 0s. If the size is higher, the extra bytes are ignored.");
eprintln!("\nencrypt/decrypt:\n\tIf a key and/or IV are not provided, they are generated randomly and printed to stderr in order on one line each.");
eprintln!("\nkeygen:\n\tThe key/iv is printed in the same way as auto-generated keys for the en/decryption modes, but to stdout instead of stderr");
eprintln!("\tIf the key and/or IV provided's size is lower than the cipher's key/IV size, the rest of the key/IV is padded with 0s. If the size is higher, the extra bytes are ignored.");
std::process::exit(1)
eprintln!("\nkeygen:\n\tThe key/iv is printed in the same way as auto-generated keys for the en/decryption modes, but to stdout instead of stderr.");
eprintln!("\nhelp:\n\tPrint this message to stderr then exit with code 0");
/// When writing, a temporary buffer stored in the structure is used. This buffer is **not** cleared after a write, for efficiency reasons. This may leave sensitive information in the buffer after the write operation.
/// The `flush()` implementation *does* clear this buffer.
//#[derive(Debug)]
//#[derive(Debug)]
pubstructSink<W>
pubstructSink<W>
{
{
@ -36,7 +40,7 @@ impl<W> Sink<W>
whereW: Write
whereW: Write
{
{
/// Create a new Chacha Sink stream wrapper
/// Create a new Chacha Sink stream wrapper
pubfnnew(stream: W,crypter: Crypter)-> Self
#[inline]fnnew(stream: W,crypter: Crypter)-> Self
{
{
Self{stream,crypter,buffer: SmallVec::new()}
Self{stream,crypter,buffer: SmallVec::new()}
}
}
@ -55,69 +59,72 @@ where W: Write
/// Consume into the inner stream
/// Consume into the inner stream
pubfninto_inner(self)-> W
#[inline]pubfninto_inner(self)-> W
{
{
self.stream
self.stream
}
}
/// Consume into the inner stream and crypter
/// Consume into the inner stream and crypter
pubfninto_parts(self)-> (W,Crypter)
#[inline]pubfninto_parts(self)-> (W,Crypter)
{
{
(self.stream,self.crypter)
(self.stream,self.crypter)
}
}
/// The crypter of this instance
/// The crypter of this instance
pubfncrypter(&self)-> &Crypter
#[inline]pubfncrypter(&self)-> &Crypter
{
{
&self.crypter
&self.crypter
}
}
/// The crypter of this instance
/// The crypter of this instance
pubfncrypter_mut(&mutself)-> &mutCrypter
#[inline]pubfncrypter_mut(&mutself)-> &mutCrypter
{
{
&mutself.crypter
&mutself.crypter
}
}
/// The inner stream
/// The inner stream
pubfninner(&self)-> &W
#[inline]pubfninner(&self)-> &W
{
{
&self.stream
&self.stream
}
}
/// The inner stream
/// The inner stream
pubfninner_mut(&mutself)-> &mutW
#[inline]pubfninner_mut(&mutself)-> &mutW
{
{
&mutself.stream
&mutself.stream
}
}
/// Perform the cipher transform on this input to the inner buffer, returning the number of bytes updated.