From 55911a84becd308063babd0e3a789cf8fee6dd19 Mon Sep 17 00:00:00 2001 From: Christos Patsonakis Date: Wed, 7 Apr 2021 12:24:04 +0300 Subject: [PATCH] Doc updates --- README.md | 71 +++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 55bf353..f3b6119 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # js-mutual-auth-ecies -The Diffie-Hellman Integrated Encryption Scheme ([DHIES](http://web.cs.ucdavis.edu/~rogaway/papers/dhies.pdf)), or the Elliptic Curve Integrated Encryption Scheme ([ECIES](https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme)), as it is commonly referred to due to its most prominent instantiation based on elliptic curve-based groups, is a construction of a hybrid encryption scheme that has a wide array of attractive security properties. Examples include, semantic security against CCA and CCP enabled adversaries in the **standard model**. Moreover, ECIES provides several features that are important from a practical perspective, i.e., that are relevant to implementers/developers, such as efficiency, flexibility in terms of the employed cryptographic group, the symmetric encryption scheme, KMAC scheme and hash functions, as well as, an arbitrary message space. +The Diffie-Hellman Integrated Encryption Scheme ([DHIES](http://web.cs.ucdavis.edu/~rogaway/papers/dhies.pdf)), or the Elliptic Curve Integrated Encryption Scheme ([ECIES](https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme)), as it is commonly referred to due to its most prominent instantiation over elliptic curve-based groups, is a construction of a hybrid authenticated encryption scheme that has a wide array of attractive security properties. Examples include, semantic security against CCA and CCP enabled adversaries in the **standard model**. Moreover, ECIES has several features that are important from a practical perspective, i.e., that are relevant to implementers/developers, such as efficiency, flexibility in terms of the employed elliptic curve, the symmetric encryption and KMAC scheme, the hash function, as well as, an arbitrary message space. In this repository, we provide several different JavaScript implementations of ECIES. A subset of the implementations have **the added property that the message sender authenticates herself to the receiver (and only to the receiver). We stress that this is not the case in the standard ECIES scheme.** Hence, this repo was named `js-mutual-auth-ecies`. Although, in retrospect, we regretted the name choice as it is slightly misleading. # Disclaimer & Dependencies -The code of this repository was developed with the intent of being integrated with the [OpenDSU](https://github.com/PrivateSky/OpenDSU) codebase, as part of the [PharmaLedger H2020](https://pharmaledger.eu/) project's efforts. To ensure compatibility with the OpenDSU codebase, the implementations provided here depend on the `pskcrypto` module of OpenDSU which, for your convenience dear sir/madam/wherever-in-the-gender-spectrum-you-are, is provided here! We stress, however, that the involvement of the `pskcrypto` module relates **only** to key generation and converting keys to PEM format. Therefore, conceptually, one can easily strip `pskcrypto` entirely from the code base provided here with minimal effort. For a more elaborate description of the issues and our (unfortunate) experiences with JavaScript's `crypto` module, we refer the interested reader to the [NotesJSCrypto.md](NotesJSCrypto.md) file. +The code of this repository was developed with the intent of being integrated with the [OpenDSU](https://github.com/PrivateSky/OpenDSU) codebase, as part of the [PharmaLedger H2020](https://pharmaledger.eu/) project's efforts. To ensure compatibility with the OpenDSU codebase, the implementations provided here depend on the `pskcrypto` module of OpenDSU which, for your convenience dear sir/madam/wherever-in-the-gender-spectrum-you-are, is provided here! We stress, however, that the involvement of the `pskcrypto` module relates **only** to key generation and converting keys to PEM format. Therefore, conceptually, one can easily strip `pskcrypto` entirely from the code base provided here with minimal effort. Lastly, for a more elaborate description of the issues and our (unfortunate) experiences with JavaScript's `crypto` module, we refer the interested reader to the [NotesJSCrypto.md](NotesJSCrypto.md) file. # Overview -A subset of the implementations include the acronym *DOA* in their name, which stands for data origin authentication. Put simply, these implementations also authenticate the sender of the message to the receiver (and only to the receiver). In the following, we provide a succinct overview of the ECIES implementations that are provided in this repository, namely: +A subset of the implementations include the acronym *DOA* in their name, which stands for data origin authentication. Put simply, these implementations also authenticate the sender of the message to the receiver (and only to the receiver). In the following, we provide a succinct overview of the ECIES implementations that are provided in this repository: - [ECIES-DOA-DS](#ecies-doa-ds): This acronym stands for ECIES data origin authentication with digital signatures (DS), i.e., the sender authenticates herself **only** to the receiver by digitally signing the shared secret. - [ECIES-DOA-KMAC](#ecies-doa-kmac): This acronym stands for ECIES data origin authentication with keyed message authentication code. In this implementation, the sender uses her private key and the receivers public key to derive a shared ECDH secret. More details in the respective section. **(PENDING SECURITY VALIDATION, DO NOT USE RIGHT NOW)** @@ -24,20 +24,20 @@ As was previously noted, ECIES provides a wide range of flexibility in terms of 1. Key derivation function (KDF) 1. Hash function 1. Symmetric cipher -1. Keyed-hash message authentication code (KMAC) +1. Keyed message authentication code (KMAC) -We wish to preserve this property across all implementations provided here. To this end, we expose to developers an object that will allow them to configure the respective module according to their (use case) requirements. Moreover, this allows us to abstract the dependency on JavaScript's `crypto` module. Put simply, if you have another cryptographic library that you are more comfortable with, or even prefer using, with a little bit of coding, you will be able to use it. Lastly, we do not expect that all developers that will use the code provided here will have the ability to reason about the security of their choices. Hence, we developed a *default* `crypto` module (`crypto/` directory), which is shared across all implementations and was developed by having security as the first priority. The defaults for all the aforementioned abstract functions were chosen based on the seminal work that introduced [DHIES](http://web.cs.ucdavis.edu/~rogaway/papers/dhies.pdf), standards' specifications (ANSI X9.63, IEEE 1363a, ISO/IEC 18033-2 and SECG SEC1), as well as, the implementation guidelines of [Martinez et al.](https://www.tic.itefi.csic.es/CIBERDINE/Documetos/Cryptologia%20-%20Security%20and%20practical%20considerations%20when%20implementing%20ECIES%20-%20v1.0.pdf) +We wish to preserve ECIES's instantiation flexibility across all implementations provided here. To this end, we expose to developers an object that allows them to configure the respective module according to their (use case) requirements. Moreover, this allows us to abstract the dependency on JavaScript's `crypto` module. Put simply, if you have another cryptographic library that you are more comfortable with, or even prefer using, with a little bit of coding, you will be able to use it. Lastly, we do not expect that all developers that will use the code provided here will have the ability to reason about the security of their choices. Hence, we developed a *default* `crypto` module (`crypto/` directory), which is shared across all implementations and was developed by having security as the first priority. The defaults for all the aforementioned abstract functions were chosen based on the seminal work that introduced [DHIES](http://web.cs.ucdavis.edu/~rogaway/papers/dhies.pdf), standards' specifications (ANSI X9.63, IEEE 1363a, ISO/IEC 18033-2 and SECG SEC1), as well as, the implementation guidelines of [Martinez et al.](https://www.tic.itefi.csic.es/CIBERDINE/Documetos/Cryptologia%20-%20Security%20and%20practical%20considerations%20when%20implementing%20ECIES%20-%20v1.0.pdf) In the following, we document and briefly discuss the default instantiation options of the `crypto` module provided here: 1. Key agreement (KA): Elliptic Curve Diffie-Hellman Ephemeral (ECDHE). Although, we note that the implementation provided here allows for plain ECDH as well. 1. Key derivation function (KDF): KDF2 as defined in [ISO/IEC 18033-2](https://www.shoup.net/iso/std6.pdf). To provide for resilience against benign maleability, we refer the reader to the `common` module that illustrates how the input to this function should be computed, based on which we derive the symmetric encryption and KMAC keys. -1. Hash function: SHA-2-256, which is typically referred to as SHA256. However, we consider the latter naming misleading as it does not clearly convey the hash function family and, based on our real-world experience, causes confusion to some developers following the introduction of the Keccak hash function family (SHA-3), which also has a 256 bit instantiation. +1. Hash function: SHA-2-256, which is typically referred to as SHA256. However, we consider the latter naming convention misleading as it does not clearly convey the hash function family and, based on our real-world experience, causes confusion to some developers following the introduction of the Keccak hash function family (SHA-3), which also has a 256 bit instantiation. 1. Symmetric cipher: `AES-128-CBC`. -1. Keyed-hash message authentication code (KMAC): HMAC construction based on SHA-2-256 and a 128-bit key. +1. Keyed message authentication code (KMAC): HMAC construction based on SHA-2-256 and a 128-bit key. -An astute reader (or evidently anyone that reads this statement) may ponder as to why we did not employ a standard authenticated encryption scheme, such as `AES-128-GCM`. It is true that we could have employed, e.g., the `setAAD()` and `setAuthTag()` functions during encryption and decryption, respectively. From a conceptual point of view, we wanted to separate the process of symmetric encryption from that of MAC computation to provide for more flexibility. In addition, it is unclear how the aforementioned API computes the MAC. Are developers supposed to supply the KMAC key in the `setAAD()` function? The documentation does not elaborate on such important details. The only option would be to go through the code base of JavaScript's default `crypto` module, or even worse the underlying OpenSSL C-based library. We obviously did not and will not do that. Naturally, we acknowledge that our choice might incur a slight performance penalty, however, recall that security is our number one priority. +An astute reader (or evidently anyone that reads this statement) may ponder as to why we did not employ a standard authenticated encryption scheme, such as `AES-128-GCM`. It is true that we could have employed, e.g., the `setAAD()` and `setAuthTag()` functions during encryption and decryption, respectively. From a conceptual point of view, we wanted to separate the process of symmetric encryption from that of MAC computation to provide for more flexibility. In addition, it is unclear how the aforementioned API computes the MAC. Are developers supposed to supply the KMAC key in the `setAAD()` function? The documentation does not elaborate on such important details. The only option to infer such important information would be to go through the code base of JavaScript's default `crypto` module, or even worse the underlying OpenSSL C-based library. We obviously did not and will not do that. Naturally, we acknowledge that our choice might incur a slight performance penalty, however, recall that security is our number one priority. - That being said, it is important at this point to briefly discuss an important issue, i.e., the importance of **using different keys for encryption and KMAC computation**. We have witnessed several cases where implementations employ the same key for both of these processes. We stress, in short, that use of a single key `k` may allow an attacker to modify the ciphertext `ct` -mind you, without even having knowledge of the plaintext- to `ct'`, such that the KMAC will still be valid at the receiver's end. This does not apply to all symmetric cipher suites, however, it is considered best practice among the cryptographic community to use separate keys, or even more generally speaking, that implementers should not use a key (or key pair) for multiple purposes. +That being said, it is important at this point to briefly discuss an important issue, i.e., the importance of **using different keys for encryption and KMAC computation**. We have witnessed several cases where implementations employ the same key for both of these processes. We stress, in short, that use of a single key `k` may allow an attacker to modify the ciphertext `ct` -mind you, without even having knowledge of the plaintext- to `ct'`, such that the KMAC will still be valid at the receiver's end. This does not apply to all symmetric cipher suites, however, it is considered best practice among the cryptographic community to use separate keys, or even more generally speaking, that implementers should **not** use a key (or key pair) for multiple purposes. ## Configuration Options @@ -77,9 +77,6 @@ In the following, we elaborate on the concrete meaning of all these options. - #### **privateKeyPEM**: The signing private key in PEM format. - #### **buffer**: A buffer that contains the data to be signed. - #### **Returns**: The computed ECDSA digital signature. - -We note that digital signatures, by default, employ the SHA-2-256 hash function (refer to `crypto/config.js` for a complete list of cryptographic parameters) -

>### verifyDigitalSignature(publicKeyPEM, signature, buffer) @@ -90,6 +87,9 @@ We note that digital signatures, by default, employ the SHA-2-256 hash function - #### **Returns**: A boolean value indicating whether the input signature is valid (`true`) based on the remaining provided inputs, or not (`false`).
+We note that functions related to digital signatures, by default, employ the SHA-2-256 hash function (refer to `crypto/config.js` for a complete list of cryptographic parameters) +
+ >### symmetricEncrypt(key, plaintext, iv) - #### **Description:** Symmetric encryption algorithm. - #### **key**: The symmetric encryption key as a Buffer. @@ -100,52 +100,49 @@ We note that digital signatures, by default, employ the SHA-2-256 hash function >### symmetricDecrypt(key, ciphertext, iv) - #### **Description:** Symmetric decryption algorithm. -- #### **key**: The symmetric decryption key as a Buffer. It should be the same as the one that was used for encryption, although again this is handled internally by the ECIES implementations of `decrypt()` and, thus, is not visible to developers. +- #### **key**: The symmetric decryption key as a Buffer. It should be the same as the one that was used for encryption, although again this is handled internally by the ECIES implementations of `decrypt()` and, thus, is not "directly visible" to developers. - #### **ciphertext**: A Buffer that contains the ciphertext that will be used to produce the plaintext. -- #### **iv**: The cipher's initialization vector (IV), which is transmitted by the sender along with the ciphertext and the KMAC. +- #### **iv**: The cipher's initialization vector (IV), which is transmitted by the sender along with the ciphertext and the output of the KMAC function. - #### **Returns**: The plaintext as a Buffer. -The `KMAC` property is an object that provides two callable functions, which are as follows: +The `KMAC` property of the module's configuration is an object that provides two callable functions, which are defined as follows:
>### computeKMAC(key, data) - #### **Description:** Computes a message authentication code (MAC) based on the input key and the data for which we want to provide message integrity. -- #### **key**: The key, as a Buffer, that will be produced as input to the computation of the MAC. -- #### **data**: A Buffer that contains the data (ciphertext) that we want to provide integrity for. -- #### **iv**: The cipher's initialization vector (IV), a common parameter for the overwhelming majority of symmetric ciphers. Internally, the ECIES implementations of `encrypt()` generate cryptographically random and fresh IVs for each encrypted payload, so this is not "directly visible" to developers. +- #### **key**: The key, as a Buffer, that will be used as input to the computation of the MAC. +- #### **data**: A Buffer that contains the data that we want to provide integrity for. - #### **Returns**: The computed MAC as a Buffer, to which we interchangeably refer to as a `tag` as well.
>### verifyKMAC(tag, key, data) -- #### **Description:** Verification algorithm for message authentication codes, which allows us to infer if the data (ciphertext) were tampered with during transit. +- #### **Description:** Verification algorithm for message authentication codes, which allows us to infer if the data were tampered with during transit. - #### **tag**: The MAC, as a Buffer, as was computed and transmitted by the sender. -- #### **key**: The key, as a Buffer, that will be produced as input to the computation of the MAC. It has to be the same as the one that was used to compute the MAC. -- #### **data**: A Buffer that contains the data (ciphertext) against which we want to verify the input MAC. -- #### **Returns**: A boolean value indicating whether the input MAC (`tag`) is valid (`true`) based on the remaining provided inputs, or not (`false`). +- #### **key**: The key, as a Buffer, that will be used as input to the computation of the MAC. +- #### **data**: A Buffer that contains the data against which we want to verify the input MAC. +- #### **Returns**: A boolean value indicating whether the input MAC (`tag`) is valid (`true`) based on the input data, or not (`false`). -The `ECEphemeralKeyAgreement` property is essentially a class that provides an interface that can be used to perform both plain ECDH, as well as, ECDHE. Internally, the default implementation employs the `ECDH` functionalities of JavaScript's `crypto` module. The following callable functions are provided: +The `ECEphemeralKeyAgreement` property is essentially a class that provides an interface that can be used for ECDH and ECDHE. Internally, the default implementation employs the `ECDH` functionalities of JavaScript's `crypto` module. The following callable functions are provided:
>### generateEphemeralPublicKey() -- #### **Description:** An integral part of the encryption process of ECIES is the generation of an ephemeral asymmetric key pair, which is subsequently used to derive a shared secret (refer to the following function) based on the public key of the receiver. -- #### **Returns**: An ephemeral (freshly-generated) ECDH public key as a Buffer. - +- #### **Description:** An integral part of the encryption process of ECIES is the generation of an ephemeral asymmetric key pair, which is subsequently used to derive a shared secret (refer to the next function) based on the public key of the receiver. +- #### **Returns**: An ephemeral ECDH public key as a Buffer.
>### generateSharedSecretForPublicKey(theirECPublicKey) -- #### **Description:** This function should be called **exactly after** the `generateEphemeralPublicKey()` function (described above) to generate the shared secret that is, subsequently, used to derive the symmetric encryption key and the KMAC key. +- #### **Description:** This function should be called **exactly after** the `generateEphemeralPublicKey()` function (described above) to generate the shared secret that is, subsequently, used to derive the symmetric encryption and KMAC keys. - #### **theirECPublicKey**: The EC public key of the receiver as a Buffer. - #### **Returns**: The shared secret as a Buffer. -
>### computeSharedSecretFromKeyPair(myECPrivateKey, theirECPublicKey) -- #### **Description:** This function is, typically, invoked by the receiver to compute the shared secret, which will, subsequently, allow her to derive the symmetric encryption key and the MAC key. +- #### **Description:** This function is, typically, invoked by the receiver to compute the shared secret, which will, subsequently, allow her to derive the symmetric encryption and KMAC keys. - #### **myECPrivateKey**: The receiver's private key as a Buffer. - #### **theirECPublicKey**: The ephemeral public key as a Buffer. This is transmitted to the receiver in plaintext by the sender. - #### **Returns**: The shared secret as a Buffer. -Note that all the aforementioned functions will throw an `Error()` if, for instance, any of the input keys are invalid for the specific curve (by default, the `secp256k1` curve is employed). +Note that all the aforementioned functions will throw an `Error()` if, for instance, any of the input keys are invalid for the specific curve (by default, we employ the `secp256k1` curve). The `KDF` property of the default cryptographic configuration points to the implementation of the `KDF2` function (refer to `crypto/kdf.js` for implementation details). In the future, we may extend the set of KDF implementations. The signature of the function is as follows:
@@ -162,12 +159,14 @@ Lastly, the `params` property of the default cryptographic configuration contain - `symmetricCipherKeySize`: The byte size of the symmetric cipher's key. Since the default implementation employs `AES-128-CBC`, it's set to 16 bytes (128 bits). - `macKeySize`: The byte size of the key that will be input to the KMAC algorithms. Defaults to 16 bytes (128 bits). -- `ivSize`: The byte size of the symmetric cipher's IV which, for block ciphers, is equal to the size of the cipher's block, i.e., in 16 bytes (128 bits) for AES. +- `ivSize`: The byte size of the symmetric cipher's IV which, for block ciphers, is equal to the size of the cipher's block, i.e., 16 bytes (128 bits) for AES. -The `symmetricCipherKeySize` and `macKeySize` are required by the encryption and decryption algorithms of ECIES to compute the `outputByteSize` of the KDF. The `ivSize` is required by the encryption algorithm of ECIES to produce a sufficiently large and cryptographically random IV that will be used as input to the symmetric encryption algorithm. +The `symmetricCipherKeySize` and `macKeySize` are required by the encryption and decryption algorithms of ECIES implementations to compute the `outputByteSize` of the KDF. The `ivSize` is required by the encryption algorithm of ECIES to produce a sufficiently large and cryptographically random IV that will be used as input to the symmetric encryption algorithm. # ECIES-DOA-DS -In this version of the implementation, the main idea is that we use a digital signature to authenticate the sender of the message to the receiver. However, we really don't want a man-in-the-middle (MITM) to be able to infer the public key of the sender. Indeed, we only want the receiver of the message to be able to infer the public key of the sender. A high-level description of how we achieve this is as follows. The ECIES plaintext is comprised by three parts: 1) the sender's public key, 2) the actual message and, 3) a digital signature on the ECDHE secret. Since ECIES is based on ephemeral shared secrets, it (hopefully) is obvious that even if the same sender (public key) sends the same message to the same receiver, the resulting ciphertext will always have a different byte representation, or value (in the honest sender setting of course). Note also that ECDSA signatures are also randomized, which is another reason for which the resulting ciphertext will be different. In addition, since the ECDHE secret can only be computed by the receiver and is unique for each message, only the receiver can decrypt the ciphertext. Furthermore, since the sender's public key and signature is hidden inside the ECIES ciphertext, it is never exposed in transit. Hence, even if we assume a MITM that has a list of all the public keys in the world, the sender's identity is concealed. However, a malicious receiver `A` can reveal a message's origin to some other party `X` by taking advantage of the non-repudiation property of digital signatures. In order for `X` to be unequivocaly convinced, `A` is forced to reveal her private key to `X`. Lastly, we stress that a malicious receiver `A` cannot use an honest sender's `B` digital signature on some shared ephemeral secret `S` so that `A` can impersonate herself as `B` to some other receiver `C`, without breaking the discrete logarithm problem. +In this version of ECIES, the main idea is that we use a digital signature to authenticate the sender of the message to the receiver. However, we really don't want a man-in-the-middle (MITM) to be able to infer the public key of the sender. Indeed, we only want the receiver of the message to be able to infer the public key of the sender. A high-level description of how we achieve this is as follows. The ECIES plaintext is comprised by three parts: 1) the sender's public key, 2) the actual message and, 3) a digital signature on the ECDHE secret. Since ECIES is based on ephemeral shared secrets and since we use freshly-generated IVs for each transmitted message, it (hopefully) is obvious that even if the same sender (public key) sends the same message to the same receiver, the resulting ciphertext will always have a different byte representation (in the honest sender setting of course). Note also that ECDSA signatures are also randomized, which is another reason for which the resulting ciphertext will be different. In addition, since the ECDHE secret can only be computed by the receiver and is unique for each message, only the receiver can decrypt the ciphertext. Furthermore, since the sender's public key and signature is "hidden" inside the ECIES ciphertext, it is never exposed in transit. Hence, even if we assume a MITM that has a list of all the public keys in the world, the sender's identity is concealed. + +We stress that a malicious receiver `A` can reveal a message's origin to some other party `X` by taking advantage of the non-repudiation property of digital signatures. However, in order for `X` to be unequivocaly convinced, `A` is forced to reveal her private key to `X`. Lastly, we stress that a malicious receiver `A` cannot use an honest sender's `B` digital signature on some shared ephemeral secret `S` so that `A` can impersonate herself as `B` to some other receiver `C`, without breaking the discrete logarithm problem. ## Quick Start Guide If you are interested in just using this version of the implementation, without digging into the nitty gritty details, in the following, we provide a simple usage example, in which `Alice` wants to send a message to `Bob`: @@ -207,7 +206,7 @@ In this section, we document the main functions that are exposed by this module, >### encrypt(senderECKeyPairPEM, receiverECPublicKey, message) - #### **senderECKeyPairPEM**: An object with properties `publicKey` and `privateKey` that encompass the sender's EC key pair. Both keys should be in PEM format. -- #### **receiverECPublicKey**: The EC public key of the receiver as a Buffer. **Note** that this is not in a standardized format, i.e., DER or PEM. In short, this key should be in the same form as the ones returned by JavaScript's ECDH `crypto.generateKeys()` method, which, in short is a stripped version of DER encoding after removing the first 23 bytes. Refer to the [Notes on JavaScript's Crypto API](#notes-on-javascript\'s-crypto-api) section for more information. +- #### **receiverECPublicKey**: The EC public key of the receiver as a Buffer. **Note** that this is not in a standardized format, i.e., DER or PEM. In short, this key should be in the same form as the ones returned by JavaScript's `crypto.ecdh.generateKeys()` method. Refer to the [NotesJSCrypto.md](NotesJSCrypto.md) file for more information. - #### **message**: The message as a Buffer that we want to encrypt and send across the wire. - #### **Returns**: An encrypted envelope object (described below). @@ -234,7 +233,7 @@ The receiver of an encrypted envelope needs to infer which specific EC private k >### decrypt(receiverPrivateKey, encEnvelope) - #### **receiverPrivateKey**: The private key that corresponds to the one encoded in the `to` field of the input encrypted envelope. Regarding the format of this key, we refer the reader to our notes on the `receiverECPublicKey` of the `encrypt()` function. - #### **encEnvelope**: An encrypted envelope object as is output by the `encrypt()` function. -- #### **Returns**: An Object with two properties containing the sender's EC public key in PEM format and the transmitted message as a Buffer. +- #### **Returns**: An Object with two properties containing the sender's EC public key in PEM format and the message as a Buffer. The object that is output by the `decrypt()` function is as follows: ```json @@ -296,7 +295,7 @@ In this section, we document the main functions that are exposed by this module,
>### encrypt(receiverECPublicKey, message) -- #### **receiverECPublicKey**: The EC public key of the receiver as a Buffer. **Note** that this is not in a standardized format, i.e., DER or PEM. In short, this key should be in the same form as the ones returned by JavaScript's ECDH `crypto.generateKeys()` method, which, in short is a stripped version of DER encoding after removing the first 23 bytes. Refer to the [Notes on JavaScript's Crypto API](#notes-on-javascript\'s-crypto-api) section for more information. +- #### **receiverECPublicKey**: The EC public key of the receiver as a Buffer. **Note** that this is not in a standardized format, i.e., DER or PEM. In short, this key should be in the same form as the ones returned by JavaScript's `crypto.ecdh.generateKeys()` method. Refer to the [NotesJSCrypto.md](NotesJSCrypto.md) file for more information. - #### **message**: The message as a Buffer that we want to encrypt and send across the wire. - #### **Returns**: An encrypted envelope object (described below).