m511chacha20 0.0.3
m511chacha20: ^0.0.3 copied to clipboard
End-to-End-encryption Suite with curve M-511 for ECDH and ChaCha20 for files, strings and maps.
This package provides curve M-511 for ECDH and ChaCha20 for symmetric encryption. Together, they provide the building blocks for end-to-end encryption.
Introduction #
Elliptic Curve Diffie-Hellman (ECDH) allows two parties to establish a shared secret over an insecure channel, even in the presence of an eavesdropper. This package implements ECDH based on the elliptic curve M-511, as specified in Bernstein et al. (2013) https://eprint.iacr.org/2013/647.pdf and considered safe according to https://safecurves.cr.yp.to. It provides 256-bit security, matching the 256-bit key size used by ChaCha20.
ChaCha20 is a widely used, fast, and secure symmetric encryption algorithm, implemented according to RFC 7539 (https://datatracker.ietf.org/doc/html/rfc7539). ChaCha20 uses a secret key and a nonce to generate a pseudorandom keystream. Encryption is performed by XORing this keystream with the plaintext. Therefore, it acts like a key expansion mechanism that expands a secret key and nonce into a pseudorandom keystream that can be used like an infinite One-Time Pad.
Features #
- ECDH with curve M-511
- Chacha20 encryption
Getting started #
Add the package by writing
flutter pub add m511chacha20
Full E2EE rundown #
First, Alice and Bob each create a Keypair.
KeyPair alice = KeyPair.fresh();
KeyPair bob = KeyPair.fresh();
Each KeyPair has a public key hex that is safe to be published.
alice.publicKeyHex
bob.publicKeyHex
Alice and Bob each compute the same shared key. This key can be used to derive a shared key.
BigInt aliceSharedSecret = KeyPair.computeSharedSecret(alice.privateKeyHex, bob.publicKeyHex);
BigInt bobSharedSecret = KeyPair.computeSharedSecret(bob.privateKeyHex, alice.publicKeyHex);
expect(aliceSharedSecret, bobSharedSecret);
You can then use this key, to create a ChaCha20 encrypter:
ChaCha20 chaCha20 = ChaCha20(ChaCha20Key.fromBigInt(commonSecret));
To encrypt or decrypt a message, you must provide a nonce; You can imagine a nonce as an "extra piece of randomness". While for a key it is important to be entirely secret, for a nonce it is important to be entirely random.
Nonce.fromUUID(...) or
Nonce.fromString(..)
will hash the string using sha256 and take the 12 leading bytes (96 bits) to create a nonce from a string. Once you have a nonce, you can finally encrypt and decrypt using chacha20 like
chaCha20.encrypt(plainText, nonce)
chaCha20.decrypt(cipherText, nonce)
File encryption #
If you want to encrypt or decrypt Files, you can use
await computeFileListEncryptionPromise(
FileListEncryptionPromise(
filePromises: [
FileEncryptionPromise(
inputFile: "test/test_files/plaintext_example.txt",
nonce: nonce,
key: key,
outputFile: "test/test_files/encrypted_example.txt"
)
]
),
onCipherFinished: (CipherResult cipherResult) {
finishCalled = true;
}
)
Full example #
KeyPair alice = KeyPair.fresh();
KeyPair bob = KeyPair.fresh();
BigInt aliceSharedSecret = KeyPair.computeSharedSecret(
alice.privateKeyHex,
bob.publicKeyHex
);
BigInt bobSharedSecret = KeyPair.computeSharedSecret(
bob.privateKeyHex,
alice.publicKeyHex
);
BigInt commonSecret = KeyPair.computeSharedSecret(bob.privateKeyHex,alice.publicKeyHex);
Nonce nonce = Nonce.fromUUID(Uuid().v1());
ChaCha20 chacha20 = ChaCha20(ChaCha20Key.fromBigInt(commonSecret));
String cipherText = chacha20.encrypt(plainText, nonce);
String plainText = chacha20.decrypt(cipherText,nonce);
File Encryption
bool wasSuccess = await computeFileListEncryptionPromise(
FileListEncryptionPromise(
filePromises: [
FileEncryptionPromise(
inputFile: "test/test_files/plaintext_example.txt",
nonce: nonce,
key: key,
outputFile: "test/test_files/encrypted_example.txt"
)
]
),
onCipherFinished: (CipherResult cipherResult) {
// ADD YOUR LOGIC HERE
}
)
Additional information #
You can contribute on github https://codeberg.org/LocalityMedia/m511chacha20