Public-key authenticated encryption
Example combined mode
const string MESSAGE = "hello bob";
var alice = PublicKeyBox.GenerateKeyPair();
var bob = PublicKeyBox.GenerateKeyPair();
var nonce = PublicKeyBox.GenerateNonce();
//alice encrypts a message for bob
var encrypted = PublicKeyBox.Create(MESSAGE, nonce, alice.PrivateKey, bob.PublicKey);
//bob decrypt the message
var decrypted = PublicKeyBox.Open(encrypted, nonce, bob.PrivateKey, alice.PublicKey);
Purpose
Using public-key authenticated encryption, Bob can encrypt a confidential message specifically for Alice, using Alice's public key.
Using Bob's public key, Alice can verify that the encrypted message was actually created by Bob and was not tampered with, before eventually decrypting it.
Alice only needs Bob's public key, the nonce and the ciphertext. Bob should never ever share his secret key, even with Alice.
And in order to send messages to Alice, Bob only needs Alice's public key. Alice should never ever share her secret key either, even with Bob.
Alice can reply to Bob using the same system, without having to generate a distinct key pair.
The nonce doesn't have to be confidential, but it should be used with just one invokation of Open()
for a particular pair of public and secret keys.
One easy way to generate a nonce is to use PublicKeyBox.GenerateNonce()
, considering the size of nonces the risk of any random collisions is negligible. For some applications, if you wish to use nonces to detect missing messages or to ignore replayed messages, it is also ok to use a simple incrementing counter as a nonce.
When doing so you must ensure that the same value can never be re-used (for example you may have multiple threads or even hosts generating messages using the same key pairs).
This system provides mutual authentication. However, a typical use case is to secure communications between a server, whose public key is known in advance, and clients connecting anonymously.
Random Helpers
public static KeyPair GenerateKeyPair()
Namespace: Sodium.PublicKeyBox
Uses Sodium.SodiumCore.GetRandomBytes()
to generate a key pair based on a random seed.
public static KeyPair GenerateKeyPair(byte[] privateKey)
Namespace: Sodium.PublicKeyBox
Uses Sodium.SodiumCore.GetRandomBytes()
to generate a key pair based on the provided private key.
The privateKey
seed must be 32
bytes, otherwise the function throws a SeedOutOfRangeException
.
libsodium-net
KeyPair
public static byte[] GenerateNonce()
Namespace: Sodium.PublicKeyBox
Uses Sodium.SodiumCore.GetRandomBytes()
to generate a 24 byte nonce.
Combined mode
In combined mode, the authentication tag and the encrypted message are stored together. This is usually what you want, as
Encrypt
public static byte[] Create(byte[] message, byte[] nonce, byte[] secretKey, byte[] publicKey)
//there exists an overloaded version:
public static byte[] Create(string message, byte[] nonce, byte[] secretKey, byte[] publicKey)
This is the .NET equivalent of crypto_box_easy
.
Namespace: Sodium.PublicKeyBox
The Create()
function encrypts a message
, with a recipient's publicKey
, a sender's secretKey
and a nonce
.
The secretKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The publicKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The nonce
must be 24
bytes, otherwise the function throws a NonceOutOfRangeException
.
The function returns a byte array (encrypted message) on success, or throws an CryptographicException()
on failure.
Decrypt
public static byte[] Open(byte[] cipherText, byte[] nonce, byte[] secretKey, byte[] publicKey)
This is the .NET equivalent of crypto_box_open_easy
.
Namespace: Sodium.PublicKeyBox
The Open()
function decrypts a message cipherText
, with a recipient's secretKey
, a sender's publicKey
and a nonce
.
The secretKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The publicKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The nonce
must be 24
bytes, otherwise the function throws a NonceOutOfRangeException
.
The function returns a byte array (unencrypted message) on success, or throws an CryptographicException()
on failure.
Detached mode
Some applications may need to store the authentication tag and the encrypted message at different locations.
For this specific use case, "detached" variants of the functions above are available.
Note: Because libsodium-net
do not work with pointers like libsodium
we make use of a DetachedBox
object instead:
/// <param name="cipherText">The cipher.</param>
/// <param name="mac">The 16 byte mac.</param>
public DetachedBox(byte[] cipherText, byte[] mac)
{
CipherText = cipherText;
Mac = mac;
}
Encrypt
public static DetachedBox CreateDetached(byte[] message, byte[] nonce, byte[] secretKey, byte[] publicKey)
//there exists an overloaded version:
public static DetachedBox CreateDetached(string message, byte[] nonce, byte[] secretKey, byte[] publicKey)
This is the .NET equivalent of crypto_box_detached
.
Namespace: Sodium.PublicKeyBox
The CreateDetached()
function encrypts a message
, with a recipient's publicKey
, a sender's secretKey
and a nonce
.
The secretKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The publicKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The nonce
must be 24
bytes, otherwise the function throws a NonceOutOfRangeException
.
The function returns a DetachedBox
on success, or throws an CryptographicException()
on failure.
Decrypt
public static byte[] OpenDetached(byte[] cipherText, byte[] mac, byte[] nonce, byte[] secretKey, byte[] publicKey)
//there exists some overloaded versions:
public static byte[] OpenDetached(string cipherText, byte[] mac, byte[] nonce, byte[] secretKey, byte[] publicKey)
public static byte[] OpenDetached(DetachedBox detached, byte[] nonce, byte[] secretKey, byte[] publicKey)
This is the .NET equivalent of crypto_box_open_detached
.
Namespace: Sodium.PublicKeyBox
The OpenDetached()
function decrypts a message cipherText
, with a recipient's secretKey
, a sender's publicKey
, amac
and a nonce
.
The secretKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The publicKey
must be 32
bytes, otherwise the function throws a KeyOutOfRangeException
.
The nonce
must be 24
bytes, otherwise the function throws a NonceOutOfRangeException
.
The mac
must be 16
bytes, otherwise the method throws a MacOutOfRangeException
.
The same exceptions will be thrown on the overloaded version which used the detached
object.
The function returns a byte array (unencrypted message) on success, or throws an CryptographicException()
on failure.
Algorithm details
- Key exchange: Curve25519
- Encryption: XSalsa20 stream cipher
- Authentication: Poly1305 MAC