classicfm-discord-bot/node_modules/sodium/src/crypto_aead.cc
2024-05-09 14:45:10 -04:00

614 lines
20 KiB
C++
Executable file

/*
* Node Native Module for Lib Sodium
*
* @Author Pedro Paixao
* @email paixaop at gmail dot com
* @License MIT
*/
#include "node_sodium.h"
#include "crypto_aead.h"
/***
* Authenticated Encryption with Additional Data:
*
* Encrypts a message with a key and a nonce to keep it confidential Computes
* an authentication tag. This tag is used to make sure that the message, as
* well as optional, non-confidential (non-encrypted) data, haven't been
* tampered with.
*
* A typical use case for additional data is to store protocol-specific metadata
* about the message, such as its length and encoding.
*
* Supported Algorithms:
* * AES-GCM 256: API names use `aes256gcm`
* * ChaCha20-Poly1305: API names use `chacha20poly1305`
* * ChaCha20-Poly1305-IETF: API names use `chacha20poly1305-ietf`
*
* ### Modes
*
* #### Combined
* In combined mode, the authentication tag and the encrypted
* message are stored together. Functions return a buffer that includes the
* cipher text and authentication tag.
* Encrypt/Decrypt functions return a buffer with length equal to
* `message_length + crypto_aead_*_ABYTES` bytes.
*
* #### Detached
* In detached mode, the authentication tag and the encrypted
* message in different buffers. Detached function variants are named with the
* `_detached` sufix. Encrypt functions return:
*
* { cipherText: <buffer>, mac: <buffer> }
*
* ~ cipherText (Buffer): encrypted message
* ~ mac (Buffer): authentication tag (`crypto_aead_*_ABYTES` long)
*
* ### Constants
* Replace `ALGORITHM` with one of the supported algorithms (`aes256gcm`,
* `chacha20poly1305`, or `chacha20poly1305-ietf`)
*
* ~ crypto_aead_ALGORITHM_ABYTES: length of the authentication tag buffer
* ~ crypto_aead_ALGORITHM_KEYBYTES: length of secret key
* ~ crypto_aead_ALGORITHM_NPUBBYTES: lenght of public nonce
* ~ crypto_aead_ALGORITHM_NSECBYTES: length of secret nonce. Not used
*/
/**
* Crypto AEAD AES-GCM 256 API:
*
* The current implementation of this construction is hardware-accelerated and
* requires the Intel SSSE3 extensions, as well as the aesni and pclmul
* instructions.
*
* Intel Westmere processors (introduced in 2010) and newer meet the requirements.
*
* There are no plans to support non hardware-accelerated implementations of
* [AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode).
* If portability is a concern, use ChaCha20-Poly1305 instead.
*/
/**
* Precompute API:
*
* Speeding up the encryption/decryption process.
* The precompute API breaks down the encrypt/decrypt functions in two stages -
* "Before" and "After". The "before" stage is called once, everytime your
* application changes encryption keys. The "after" stage is called for every
* message you need to encrypt/decrypt.
* The functions `*_beforenm` implement the "before" stage, and the `*_afternm`
* the "after" stage. They offer the same functionality as their non-precompute
* counterparts but take a "state" object generated by the `*_beforenm` instead
* of an encryption key.
*
* **Sample**:
*
* var sodium = require('sodium').api;
*
* // Generate a random key
* var key = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(key);
*
* // Generate random nonce
* var nonce = Buffer.allocUnsafe(crypto_aead_aes256gcm_NPUBBYTES);
* sodium.randombytes_buf(nonce);
*
* // Precompute and generate the state
* var state = sodium.crypto_aead_aes256gcm_beforenm(key);
*
* var message = Buffer.from("this is a plain text message");
* var additionalData = Buffer.from("metadata");
*
* // Encrypt Data
* var cipherText = sodium.crypto_aead_aes256gcm_encrypt_afternm(
* message, additionalData, nonce, state);
*
* // Get the plain text, i.e., original message back
* var plainText = sodium.crypto_aead_aes256gcm_decrypt_afternm(
* cipherText, additionalData, nonce, state);
*/
/**
* crypto_aead_aes256gcm_is_available:
*
* Check hardware support for AES 256 GCM
*
* **Returns**:
*
* ~ true: if hardware supports AES 256 GCM
*
* **Sample**:
*
* if( sodium.crypto_aead_aes256gcm_is_available() ) {
* // You can use the crypto_aead_aes256gcm_*()
* }
* else {
* // Use crypto_aead_chacha20poly1305_*()
* }
*
*/
NAPI_METHOD(crypto_aead_aes256gcm_is_available) {
// Napi::Env env = info.Env();
Napi::Env env = info.Env();
if( crypto_aead_aes256gcm_is_available() == 1 ) {
return NAPI_TRUE;
}
return NAPI_FALSE;
}
/**
* crypto_aead_aes256gcm_beforenm:
* Precompute AES key expansion.
*
* Applications that encrypt several messages using the same key can gain a
* little speed by expanding the AES key only once, via the precalculation interface
* Initializes a context ctx by expanding the key k and always returns 0.
*
* var ctx = sodium.crypto_aead_aes256gcm_beforenm(key);
*
* ~ key (Buffer): AES 256 GCM Key buffer with crypto_aead_aes256gcm_KEYBYTES in length
*
* **Sample**:
*
* // Generate a random key
* var key = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(key);
* var state = sodium.crypto_aead_aes256gcm_beforenm(key);
*/
NAPI_METHOD(crypto_aead_aes256gcm_beforenm) {
// Napi::Env env = info.Env();
Napi::Env env = info.Env();
ARGS(1, "arguments key must be a buffer");
ARG_TO_UCHAR_BUFFER_LEN(key, crypto_aead_aes256gcm_KEYBYTES);
NEW_BUFFER_AND_PTR(ctxt, crypto_aead_aes256gcm_statebytes());
if (crypto_aead_aes256gcm_beforenm((crypto_aead_aes256gcm_state*)ctxt_ptr, key) == 0) {
return ctxt;
}
return NAPI_NULL;
}
/**
* crypto_aead_aes256gcm_encrypt_afternm:
* Encrypt data in Combined Mode
*
* var c = sodium.crypto_aead_aes256gcm_encrypt_afternm(
* message,
* additionalData,
* nonce,
* ctx);
*
* ~ message (Buffer): plain text buffer
* ~ additionalData (Buffer): non-confidential data to add to the cipher text. Can be `null`
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in length
* ~ ctx (Buffer): state computed by `crypto_aead_aes256gcm_beforenm()`
*
* **Returns**:
*
* ~ cipherText (Buffer): The encrypted message, as well as a tag authenticating
* both the confidential message `message` and non-confidential data `additionalData`
* ~ undefined: if `message` fails to encrypt
*
*/
NAPI_METHOD(crypto_aead_aes256gcm_encrypt_afternm) {
Napi::Env env = info.Env();
ARGS(4, "arguments message, additional data, nonce, and key must be buffers");
ARG_TO_UCHAR_BUFFER(m);
ARG_TO_UCHAR_BUFFER_OR_NULL(ad);
ARG_TO_UCHAR_BUFFER_LEN(npub, crypto_aead_aes256gcm_NPUBBYTES);
ARG_TO_UCHAR_BUFFER_LEN(ctx, crypto_aead_aes256gcm_statebytes());
NEW_BUFFER_AND_PTR(c, crypto_aead_aes256gcm_ABYTES + m_size);
sodium_memzero(c_ptr, crypto_aead_aes256gcm_ABYTES + m_size);
unsigned long long clen;
if( crypto_aead_aes256gcm_encrypt_afternm (c_ptr, &clen, m, m_size, ad, ad_size, NULL, npub, (crypto_aead_aes256gcm_state*)ctx) == 0 ) {
return c;
}
return NAPI_NULL;
}
/**
* crypto_aead_aes256gcm_decrypt_afternm:
* Decrypt data in Combined Mode
*
* var c = sodium.crypto_aead_aes256gcm_decrypt_afternm(
* cipherText,
* additionalData,
* nonce,
* ctx);
*
* ~ cipherText (Buffer): cipher text buffer, encrypted by crypto_aead_aes256gcm_encrypt_afternm()
* ~ additionalData (Buffer): non-confidential data to add to the cipher text. Can be `null`
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in length
* ~ ctx (Buffer): state computed by `crypto_aead_aes256gcm_beforenm()`
*
* **Returns**:
*
* ~ message (Buffer): plain text message
* ~ undefined: if `cipherText` is not valid
*
*/
NAPI_METHOD(crypto_aead_aes256gcm_decrypt_afternm) {
Napi::Env env = info.Env();
ARGS(4, "arguments chiper text, additional data, nonce, and key must be buffers");
ARG_TO_UCHAR_BUFFER(c);
if( c_size < crypto_aead_aes256gcm_ABYTES ) {
THROW_ERROR("argument cipher text must be at least crypto_aead_aes256gcm_ABYTES bytes long");
}
ARG_TO_UCHAR_BUFFER_OR_NULL(ad);
ARG_TO_UCHAR_BUFFER_LEN(npub, crypto_aead_aes256gcm_NPUBBYTES);
ARG_TO_UCHAR_BUFFER_LEN(ctx, crypto_aead_aes256gcm_statebytes());
NEW_BUFFER_AND_PTR(m, c_size - crypto_aead_aes256gcm_ABYTES);
unsigned long long mlen;
if( crypto_aead_aes256gcm_decrypt_afternm (m_ptr, &mlen, NULL, c, c_size, ad, ad_size, npub, (crypto_aead_aes256gcm_state*)ctx) == 0 ) {
return m;
}
return NAPI_NULL;
}
/**
* crypto_aead_aes256gcm_encrypt_detached_afternm:
* Encrypt data in Detached Mode
*
* var c = sodium.crypto_aead_aes256gcm_encrypt_detached_afternm(
* message,
* additionalData,
* nonce,
* ctx);
*
* ~ message (Buffer): plain text buffer
* ~ additionalData (Buffer): non-confidential data to add to the cipher text.
* Can be `null`
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in
* length
* ~ ctx (Buffer): state computed by `crypto_aead_aes256gcm_beforenm()`
*
* **Returns**:
*
* ~ object: `cipherText` buffer with ciphered text, and `mac` buffer with the
* authentication tag
*
* { cipherText: <buffer>, mac: <buffer> }
*
* ~ undefined: if `message` fails to encrypt
*
* **Sample**:
*
* var sodium = require('sodium').api;
*
* // Generate a random key
* var key = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(key);
*
* // Generate random nonce
* var nonce = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(nonce);
*
* // Precompute and generate the state
* var state = sodium.crypto_aead_aes256gcm_beforenm(key);
*
* var message = Buffer.from("this is a plain text message");
* var additionalData = Buffer.from("metadata");
*
* // Encrypt Data
* var c = sodium.crypto_aead_aes256gcm_encrypt_detached_afternm(
* message, additionalData, nonce, state);
*
* // Get the plain text, i.e., original message back
* var plainText = sodium.crypto_aead_aes256gcm_decrypt_detached_afternm(
* c.cipherText, c.mac, nonce, state);
*/
NAPI_METHOD(crypto_aead_aes256gcm_encrypt_detached_afternm) {
Napi::Env env = info.Env();
ARGS(4, "arguments message, additional data, nonce, and key must be buffers");
ARG_TO_UCHAR_BUFFER(m);
ARG_TO_UCHAR_BUFFER_OR_NULL(ad);
ARG_TO_UCHAR_BUFFER_LEN(npub, crypto_aead_aes256gcm_NPUBBYTES);
ARG_TO_UCHAR_BUFFER_LEN(ctx, crypto_aead_aes256gcm_statebytes());
NEW_BUFFER_AND_PTR(c, m_size);
NEW_BUFFER_AND_PTR(mac, crypto_aead_aes256gcm_ABYTES);
if( crypto_aead_aes256gcm_encrypt_detached_afternm(c_ptr, mac_ptr, NULL, m, m_size, ad, ad_size, NULL, npub, (crypto_aead_aes256gcm_state*)ctx) == 0 ) {
Napi::Object result = Napi::Object::New(env);
result.Set(Napi::String::New(env, "cipherText"), c);
result.Set(Napi::String::New(env, "mac"), mac);
return result;
}
return NAPI_NULL;
}
/**
* crypto_aead_aes256gcm_decrypt_detached_afternm:
* Encrypt data in Detached Mode
*
* var c = sodium.crypto_aead_aes256gcm_decrypt_detached_afternm(
* cipherText,
* mac,
* nonce,
* ctx);
*
* ~ cipherText (Buffer): cipher text buffer
* ~ mac (Buffer): authentication tag. Can be null
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in
* length
* ~ ctx (Buffer): state computed by `crypto_aead_aes256gcm_beforenm()`
*
* **Returns**:
*
* ~ message (Buffer): plain text message
* ~ undefined: if `message` fails to encrypt
*
* See: [crypto_aead_aes256gcm_encrypt_detached_afternm](#crypto_aead_aes256gcm_encrypt_detached_afternm)
*
*/
NAPI_METHOD(crypto_aead_aes256gcm_decrypt_detached_afternm) {
Napi::Env env = info.Env();
ARGS(4, "arguments cipher message, mac, additional data, nsec, nonce, and key must be buffers");
ARG_TO_UCHAR_BUFFER(c);
ARG_TO_UCHAR_BUFFER_LEN(mac, crypto_aead_aes256gcm_ABYTES);
ARG_TO_UCHAR_BUFFER_OR_NULL(ad);
ARG_TO_UCHAR_BUFFER_LEN(npub, crypto_aead_aes256gcm_NPUBBYTES);
ARG_TO_UCHAR_BUFFER_LEN(ctx, crypto_aead_aes256gcm_statebytes());
NEW_BUFFER_AND_PTR(m, c_size);
if( crypto_aead_aes256gcm_decrypt_detached_afternm(m_ptr, NULL, c, c_size, mac, ad, ad_size, npub, (crypto_aead_aes256gcm_state*)ctx) == 0 ) {
return m;
}
return NAPI_NULL;
}
/**
* crypto_aead_aes256gcm_encrypt:
* Encrypt Message in Combined Mode
*
* var c = sodium.crypto_aead_aes256gcm_encrypt(
* message,
* additionalData,
* nonce,
* key);
*
* ~ message (Buffer): plain text buffer
* ~ additionalData (Buffer): non-confidential data to add to the cipher text. Can be `null`
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in length
* ~ key (Buffer): secret key `sodium.crypto_aead_aes256gcm_KEYBYTES` in length
*
* **Returns**:
*
* ~ cipherText (Buffer): The encrypted message, as well as a tag authenticating
* both the confidential message `message` and non-confidential data `additionalData`
* ~ undefined: if `message` fails to encrypt
*
* **Sample**:
*
* var sodium = require('sodium').api;
*
* // Generate a random key
* var key = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(key);
*
* // Generate random nonce
* var nonce = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(nonce);
*
* var message = Buffer.from("this is a plain text message");
* var additionalData = Buffer.from("metadata");
*
* // Encrypt Data
* var cipherText = sodium.crypto_aead_aes256gcm_encrypt(
* message, additionalData, nonce, key);
*
* // Get the plain text, i.e., original message back
* var plainText = sodium.crypto_aead_aes256gcm_decrypt(
* cipherText, additionalData, nonce, key);
*/
/**
* crypto_aead_aes256gcm_decrypt:
* Encrypt Message in Combined Mode
*
* var m = sodium.crypto_aead_aes256gcm_decrypt(
* cipherText,
* additionalData,
* nonce,
* key);
*
* ~ cipherText (Buffer): encrypted buffer
* ~ additionalData (Buffer): non-confidential data to add to the cipher text. Can be `null`
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in length
* ~ key (Buffer): secret key `sodium.crypto_aead_aes256gcm_KEYBYTES` in length
*
* **Returns**:
*
* ~ plainText (Buffer): The decrypted plain text message
* ~ undefined: if `message` fails to encrypt
*
* **See**: [crypto_aead_aes256gcm_encrypt](#crypto_aead_aes256gcm_encrypt)
*/
CRYPTO_AEAD_DEF(aes256gcm)
/**
* crypto_aead_aes256gcm_encrypt_detached:
* Encrypt Message in Detached Mode
*
* var c = sodium.crypto_aead_aes256gcm_encrypt_detached(
* message,
* additionalData,
* nonce,
* key);
*
* ~ message (Buffer): plain text buffer
* ~ additionalData (Buffer): non-confidential data to add to the cipher text. Can be `null`
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in length
* ~ key (Buffer): secret key `sodium.crypto_aead_aes256gcm_KEYBYTES` in length
*
* **Returns**:
*
* ~ object: `cipherText` buffer with ciphered text, and `mac` buffer with the
* authentication tag
*
* { cipherText: <buffer>, mac: <buffer> }
*
* ~ undefined: if `message` fails to encrypt
*
* **Sample**:
*
* var sodium = require('sodium').api;
*
* // Generate a random key
* var key = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(key);
*
* // Generate random nonce
* var nonce = Buffer.allocUnsafe(crypto_aead_aes256gcm_KEYBYTES);
* sodium.randombytes_buf(nonce);
*
* var message = Buffer.from("this is a plain text message");
* var additionalData = Buffer.from("metadata");
*
* // Encrypt Data
* var c = sodium.crypto_aead_aes256gcm_encrypt_detached(
* message, additionalData, nonce, key);
*
* // Get the plain text, i.e., original message back
* var plainText = sodium.crypto_aead_aes256gcm_decrypt_detached(
* c.cipherText, c.mac, nonce, key);
*/
/**
* crypto_aead_aes256gcm_decrypt_detached:
* Encrypt Message in Detached Mode
*
* var m = sodium.crypto_aead_aes256gcm_decrypt(
* cipherText,
* mac,
* nonce,
* key);
*
* ~ cipherText (Buffer): encrypted buffer
* ~ mac (Buffer): authentication tag. Can be `null`
* ~ nonce (Buffer): a nonce with `sodium.crypto_aead_aes256gcm_NPUBBYTES` in length
* ~ key (Buffer): secret key `sodium.crypto_aead_aes256gcm_KEYBYTES` in length
*
* **Returns**:
*
* ~ plainText (Buffer): The decrypted plain text message
* ~ undefined: if `message` fails to encrypt
*
* **See**: [crypto_aead_aes256gcm_encrypt](#crypto_aead_aes256gcm_encrypt)
*/
CRYPTO_AEAD_DETACHED_DEF(aes256gcm)
/** Crypto AEAD ChaCha20-Poly1305 API: */
/**
* crypto_aead_chacha20poly1305_encrypt:
* Encrypt Message in Detached Mode using ChaCha20-Poly1305
*
* See [crypto_aead_aes256gcm_encrypt](#crypto_aead_aes256gcm_encrypt)
*/
/**
* crypto_aead_chacha20poly1305_decrypt:
* Dencrypt Message in Detached Mode using ChaCha20-Poly1305
*
* See [crypto_aead_aes256gcm_decrypt](#crypto_aead_aes256gcm_decrypt)
*/
CRYPTO_AEAD_DEF(chacha20poly1305)
/**
* crypto_aead_chacha20poly1305_encrypt_detached:
* Encrypt Message in Detached Mode using ChaCha20-Poly1305
*
* See [crypto_aead_aes256gcm_encrypt_detached](#crypto_aead_aes256gcm_encrypt_detached)
*/
/**
* crypto_aead_chacha20poly1305_decrypt_detached:
* Dencrypt Message in Detached Mode using ChaCha20-Poly1305
*
* See [crypto_aead_aes256gcm_decrypt_detached](#crypto_aead_aes256gcm_decrypt_detached)
*/
CRYPTO_AEAD_DETACHED_DEF(chacha20poly1305)
/** Crypto AEAD ChaCha20-Poly1305-IETF API: */
/**
* crypto_aead_chacha20poly1305_ietf_encrypt:
* Encrypt Message in Combined Mode using ChaCha20-Poly1305-IETF
*
* See [crypto_aead_aes256gcm_encrypt](#crypto_aead_aes256gcm_encrypt)
*/
/**
* crypto_aead_chacha20poly1305_ietf_decrypt:
* Dencrypt Message in Combined Mode using ChaCha20-Poly1305-IETF
*
* See [crypto_aead_aes256gcm_decrypt](#crypto_aead_aes256gcm_decrypt)
*/
CRYPTO_AEAD_DEF(chacha20poly1305_ietf)
/**
* crypto_aead_chacha20poly1305_ietf_encrypt_detached:
* Encrypt Message in Detached Mode using ChaCha20-Poly1305-IETF
*
* See [crypto_aead_aes256gcm_encrypt_detached](#crypto_aead_aes256gcm_encrypt_detached)
*/
/**
* crypto_aead_chacha20poly1305_decrypt_detached:
* Dencrypt Message in Detached Mode using ChaCha20-Poly1305-IETF
*
* See [crypto_aead_aes256gcm_decrypt_detached](#crypto_aead_aes256gcm_decrypt_detached)
*/
CRYPTO_AEAD_DETACHED_DEF(chacha20poly1305_ietf)
/**
* crypto_aead_chacha20poly1305_ietf_decrypt:
* Dencrypt Message in Combined Mode using ChaCha20-Poly1305-IETF
*
* See [crypto_aead_aes256gcm_decrypt](#crypto_aead_aes256gcm_decrypt)
*/
CRYPTO_AEAD_DEF(xchacha20poly1305_ietf)
/**
* crypto_aead_chacha20poly1305_decrypt_detached:
* Dencrypt Message in Detached Mode using ChaCha20-Poly1305-IETF
*
* See [crypto_aead_aes256gcm_decrypt_detached](#crypto_aead_aes256gcm_decrypt_detached)
*/
CRYPTO_AEAD_DETACHED_DEF(xchacha20poly1305_ietf)
/*
* Register function calls in node binding
*/
void register_crypto_aead(Napi::Env env, Napi::Object exports) {
EXPORT(crypto_aead_aes256gcm_is_available);
EXPORT(crypto_aead_aes256gcm_beforenm);
EXPORT(crypto_aead_aes256gcm_encrypt_afternm);
EXPORT(crypto_aead_aes256gcm_decrypt_afternm);
EXPORT(crypto_aead_aes256gcm_encrypt_detached_afternm);
EXPORT(crypto_aead_aes256gcm_decrypt_detached_afternm);
METHOD_AND_PROPS(aes256gcm);
METHOD_AND_PROPS(chacha20poly1305);
METHOD_AND_PROPS(chacha20poly1305_ietf);
METHOD_AND_PROPS(xchacha20poly1305_ietf);
}