diff --git a/.gitignore b/.gitignore
index 50d47f3d..9adea7ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,6 +72,7 @@ test/default/box7
test/default/box8
test/default/box_easy
test/default/box_easy2
+test/default/box_seal
test/default/box_seed
test/default/chacha20
test/default/core1
diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj b/builds/msvc/vs2010/libsodium/libsodium.vcxproj
index 04c8950e..42f8e490 100644
--- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj
@@ -163,6 +163,7 @@
+
diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters
index 438508a9..cd65154e 100644
--- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters
@@ -460,6 +460,9 @@
src\crypto_box
+
+ src\crypto_box
+
src\crypto_secretbox
diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj b/builds/msvc/vs2012/libsodium/libsodium.vcxproj
index d6edfc43..a7fb1b9a 100644
--- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj
@@ -163,6 +163,7 @@
+
diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters
index 438508a9..cd65154e 100644
--- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters
@@ -460,6 +460,9 @@
src\crypto_box
+
+ src\crypto_box
+
src\crypto_secretbox
diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj b/builds/msvc/vs2013/libsodium/libsodium.vcxproj
index bd30e82a..06cdd004 100644
--- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj
@@ -163,6 +163,7 @@
+
diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters
index 438508a9..cd65154e 100644
--- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters
@@ -460,6 +460,9 @@
src\crypto_box
+
+ src\crypto_box
+
src\crypto_secretbox
diff --git a/dist-build/emscripten.sh b/dist-build/emscripten.sh
index 29e120fe..728375c3 100755
--- a/dist-build/emscripten.sh
+++ b/dist-build/emscripten.sh
@@ -2,7 +2,7 @@
export MAKE_FLAGS='-j4'
export PREFIX="$(pwd)/libsodium-js"
-export EXPORTED_FUNCTIONS='["_crypto_aead_chacha20poly1305_abytes","_crypto_aead_chacha20poly1305_decrypt","_crypto_aead_chacha20poly1305_encrypt","_crypto_aead_chacha20poly1305_keybytes","_crypto_aead_chacha20poly1305_npubbytes","_crypto_aead_chacha20poly1305_nsecbytes","_crypto_auth","_crypto_auth_bytes","_crypto_auth_keybytes","_crypto_auth_verify","_crypto_box_beforenm","_crypto_box_beforenmbytes","_crypto_box_detached","_crypto_box_detached_afternm","_crypto_box_easy","_crypto_box_easy_afternm","_crypto_box_keypair","_crypto_box_macbytes","_crypto_box_noncebytes","_crypto_box_open_detached","_crypto_box_open_detached_afternm","_crypto_box_open_easy","_crypto_box_open_easy_afternm","_crypto_box_publickeybytes","_crypto_box_secretkeybytes","_crypto_box_seed_keypair","_crypto_box_seedbytes","_crypto_generichash","_crypto_generichash_bytes","_crypto_generichash_bytes_max","_crypto_generichash_bytes_min","_crypto_generichash_final","_crypto_generichash_init","_crypto_generichash_keybytes","_crypto_generichash_keybytes_max","_crypto_generichash_keybytes_min","_crypto_generichash_statebytes","_crypto_generichash_update","_crypto_hash","_crypto_hash_bytes","_crypto_pwhash_scryptsalsa208sha256","_crypto_pwhash_scryptsalsa208sha256_ll","_crypto_pwhash_scryptsalsa208sha256_memlimit_interactive","_crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive","_crypto_pwhash_scryptsalsa208sha256_opslimit_interactive","_crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive","_crypto_pwhash_scryptsalsa208sha256_saltbytes","_crypto_pwhash_scryptsalsa208sha256_str","_crypto_pwhash_scryptsalsa208sha256_str_verify","_crypto_pwhash_scryptsalsa208sha256_strbytes","_crypto_pwhash_scryptsalsa208sha256_strprefix","_crypto_scalarmult","_crypto_scalarmult_base","_crypto_scalarmult_bytes","_crypto_scalarmult_scalarbytes","_crypto_secretbox_detached","_crypto_secretbox_easy","_crypto_secretbox_keybytes","_crypto_secretbox_macbytes","_crypto_secretbox_noncebytes","_crypto_secretbox_open_detached","_crypto_secretbox_open_easy","_crypto_shorthash","_crypto_shorthash_bytes","_crypto_shorthash_keybytes","_crypto_sign","_crypto_sign_bytes","_crypto_sign_detached","_crypto_sign_ed25519_pk_to_curve25519","_crypto_sign_ed25519_sk_to_curve25519","_crypto_sign_keypair","_crypto_sign_open","_crypto_sign_publickeybytes","_crypto_sign_secretkeybytes","_crypto_sign_seed_keypair","_crypto_sign_seedbytes","_crypto_sign_verify_detached","_randombytes_buf","_randombytes_close","_randombytes_random","_randombytes_set_implementation","_randombytes_stir","_randombytes_uniform","_sodium_bin2hex","_sodium_hex2bin","_sodium_init","_sodium_library_version_major","_sodium_library_version_minor","_sodium_memcmp","_sodium_memzero","_sodium_version_string"]'
+export EXPORTED_FUNCTIONS='["_crypto_aead_chacha20poly1305_abytes","_crypto_aead_chacha20poly1305_decrypt","_crypto_aead_chacha20poly1305_encrypt","_crypto_aead_chacha20poly1305_keybytes","_crypto_aead_chacha20poly1305_npubbytes","_crypto_aead_chacha20poly1305_nsecbytes","_crypto_auth","_crypto_auth_bytes","_crypto_auth_keybytes","_crypto_auth_verify","_crypto_box_beforenm","_crypto_box_beforenmbytes","_crypto_box_detached","_crypto_box_detached_afternm","_crypto_box_easy","_crypto_box_easy_afternm","_crypto_box_keypair","_crypto_box_macbytes","_crypto_box_noncebytes","_crypto_box_open_detached","_crypto_box_open_detached_afternm","_crypto_box_open_easy","_crypto_box_open_easy_afternm","_crypto_box_publickeybytes","_crypto_box_seal","_crypto_box_seal_open","_crypto_box_sealbytes","_crypto_box_secretkeybytes","_crypto_box_seed_keypair","_crypto_box_seedbytes","_crypto_generichash","_crypto_generichash_bytes","_crypto_generichash_bytes_max","_crypto_generichash_bytes_min","_crypto_generichash_final","_crypto_generichash_init","_crypto_generichash_keybytes","_crypto_generichash_keybytes_max","_crypto_generichash_keybytes_min","_crypto_generichash_statebytes","_crypto_generichash_update","_crypto_hash","_crypto_hash_bytes","_crypto_pwhash_scryptsalsa208sha256","_crypto_pwhash_scryptsalsa208sha256_ll","_crypto_pwhash_scryptsalsa208sha256_memlimit_interactive","_crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive","_crypto_pwhash_scryptsalsa208sha256_opslimit_interactive","_crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive","_crypto_pwhash_scryptsalsa208sha256_saltbytes","_crypto_pwhash_scryptsalsa208sha256_str","_crypto_pwhash_scryptsalsa208sha256_str_verify","_crypto_pwhash_scryptsalsa208sha256_strbytes","_crypto_pwhash_scryptsalsa208sha256_strprefix","_crypto_scalarmult","_crypto_scalarmult_base","_crypto_scalarmult_bytes","_crypto_scalarmult_scalarbytes","_crypto_secretbox_detached","_crypto_secretbox_easy","_crypto_secretbox_keybytes","_crypto_secretbox_macbytes","_crypto_secretbox_noncebytes","_crypto_secretbox_open_detached","_crypto_secretbox_open_easy","_crypto_shorthash","_crypto_shorthash_bytes","_crypto_shorthash_keybytes","_crypto_sign","_crypto_sign_bytes","_crypto_sign_detached","_crypto_sign_ed25519_pk_to_curve25519","_crypto_sign_ed25519_sk_to_curve25519","_crypto_sign_keypair","_crypto_sign_open","_crypto_sign_publickeybytes","_crypto_sign_secretkeybytes","_crypto_sign_seed_keypair","_crypto_sign_seedbytes","_crypto_sign_verify_detached","_randombytes_buf","_randombytes_close","_randombytes_random","_randombytes_set_implementation","_randombytes_stir","_randombytes_uniform","_sodium_bin2hex","_sodium_hex2bin","_sodium_init","_sodium_library_version_major","_sodium_library_version_minor","_sodium_memcmp","_sodium_memzero","_sodium_version_string"]'
export TOTAL_MEMORY=33554432
export JS_EXPORTS_FLAGS="-s EXPORTED_FUNCTIONS=${EXPORTED_FUNCTIONS}"
export LDFLAGS="-s TOTAL_MEMORY=${TOTAL_MEMORY} -s RESERVED_FUNCTION_POINTERS=8 -s NO_BROWSER=1"
diff --git a/libsodium.vcxproj b/libsodium.vcxproj
index 4100a188..80714856 100644
--- a/libsodium.vcxproj
+++ b/libsodium.vcxproj
@@ -383,6 +383,7 @@
+
diff --git a/libsodium.vcxproj.filters b/libsodium.vcxproj.filters
index 18f0b461..4cee5b22 100644
--- a/libsodium.vcxproj.filters
+++ b/libsodium.vcxproj.filters
@@ -569,6 +569,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am
index c45119dc..d6813454 100644
--- a/src/libsodium/Makefile.am
+++ b/src/libsodium/Makefile.am
@@ -18,6 +18,7 @@ libsodium_la_SOURCES = \
crypto_auth/hmacsha512256/cp/verify_hmacsha512256.c \
crypto_box/crypto_box.c \
crypto_box/crypto_box_easy.c \
+ crypto_box/crypto_box_seal.c \
crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305_api.c \
crypto_box/curve25519xsalsa20poly1305/ref/api.h \
crypto_box/curve25519xsalsa20poly1305/ref/after_curve25519xsalsa20poly1305.c \
diff --git a/src/libsodium/crypto_box/crypto_box_seal.c b/src/libsodium/crypto_box/crypto_box_seal.c
new file mode 100644
index 00000000..0feab7ea
--- /dev/null
+++ b/src/libsodium/crypto_box/crypto_box_seal.c
@@ -0,0 +1,65 @@
+
+#include
+
+#include "crypto_box.h"
+#include "crypto_generichash.h"
+#include "utils.h"
+
+static int
+_crypto_box_seal_nonce(unsigned char *nonce,
+ const unsigned char *pk1, const unsigned char *pk2)
+{
+ crypto_generichash_state st;
+
+ crypto_generichash_init(&st, NULL, 0U, crypto_box_NONCEBYTES);
+ crypto_generichash_update(&st, pk1, crypto_box_PUBLICKEYBYTES);
+ crypto_generichash_update(&st, pk2, crypto_box_PUBLICKEYBYTES);
+ crypto_generichash_final(&st, nonce, crypto_box_NONCEBYTES);
+
+ return 0;
+}
+
+int
+crypto_box_seal(unsigned char *out, const unsigned char *in,
+ unsigned long long inlen, const unsigned char *pk)
+{
+ unsigned char nonce[crypto_box_NONCEBYTES];
+ unsigned char epk[crypto_box_PUBLICKEYBYTES];
+ unsigned char esk[crypto_box_SECRETKEYBYTES];
+ int ret;
+
+ if (crypto_box_keypair(epk, esk) != 0) {
+ return -1;
+ }
+ memcpy(out, epk, crypto_box_PUBLICKEYBYTES);
+ _crypto_box_seal_nonce(nonce, epk, pk);
+ ret = crypto_box_easy(out + crypto_box_PUBLICKEYBYTES, in, inlen,
+ nonce, pk, esk);
+ sodium_memzero(esk, sizeof esk);
+
+ return ret;
+}
+
+int
+crypto_box_seal_open(unsigned char *out, const unsigned char *in,
+ unsigned long long inlen,
+ const unsigned char *pk, const unsigned char *sk)
+{
+ unsigned char nonce[crypto_box_NONCEBYTES];
+
+ if (inlen < crypto_box_SEALBYTES) {
+ return -1;
+ }
+ _crypto_box_seal_nonce(nonce, in, pk);
+
+ (void) sizeof(int[crypto_box_PUBLICKEYBYTES < crypto_box_SEALBYTES ? 1 : -1]);
+ return crypto_box_open_easy(out, in + crypto_box_PUBLICKEYBYTES,
+ inlen - crypto_box_PUBLICKEYBYTES,
+ nonce, in, sk);
+}
+
+size_t
+crypto_box_sealbytes(void)
+{
+ return crypto_box_SEALBYTES;
+}
diff --git a/src/libsodium/include/sodium/crypto_box.h b/src/libsodium/include/sodium/crypto_box.h
index 8fff2d27..b780055a 100644
--- a/src/libsodium/include/sodium/crypto_box.h
+++ b/src/libsodium/include/sodium/crypto_box.h
@@ -106,6 +106,21 @@ int crypto_box_open_detached_afternm(unsigned char *m, const unsigned char *c,
unsigned long long clen, const unsigned char *n,
const unsigned char *k);
+/* -- Ephemeral SK interface -- */
+
+#define crypto_box_SEALBYTES (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
+SODIUM_EXPORT
+size_t crypto_box_sealbytes(void);
+
+SODIUM_EXPORT
+int crypto_box_seal(unsigned char *out, const unsigned char *in,
+ unsigned long long inlen, const unsigned char *pk);
+
+SODIUM_EXPORT
+int crypto_box_seal_open(unsigned char *out, const unsigned char *in,
+ unsigned long long inlen,
+ const unsigned char *pk, const unsigned char *sk);
+
/* -- NaCl compatibility interface ; Requires padding -- */
#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
diff --git a/test/default/Makefile.am b/test/default/Makefile.am
index d665ba02..a4bf6e7d 100644
--- a/test/default/Makefile.am
+++ b/test/default/Makefile.am
@@ -16,6 +16,7 @@ EXTRA_DIST = \
box8.exp \
box_easy.exp \
box_easy2.exp \
+ box_seal.exp \
box_seed.exp \
chacha20.exp \
core1.exp \
@@ -75,6 +76,7 @@ DISTCLEANFILES = \
box8.res \
box_easy.res \
box_easy2.res \
+ box_seal.res \
box_seed.res \
chacha20.res \
core1.res \
@@ -144,6 +146,7 @@ TESTS_TARGETS = \
box8 \
box_easy \
box_easy2 \
+ box_seal \
box_seed \
chacha20 \
core1 \
@@ -238,6 +241,9 @@ box_easy_LDADD = $(TESTS_LDADD)
box_easy2_SOURCE = cmptest.h box_easy2.c
box_easy2_LDADD = $(TESTS_LDADD)
+box_seal_SOURCE = cmptest.h box_seal.c
+box_seal_LDADD = $(TESTS_LDADD)
+
box_seed_SOURCE = cmptest.h box_seed.c
box_seed_LDADD = $(TESTS_LDADD)
diff --git a/test/default/box_seal.c b/test/default/box_seal.c
new file mode 100644
index 00000000..1d73e30c
--- /dev/null
+++ b/test/default/box_seal.c
@@ -0,0 +1,43 @@
+
+#define TEST_NAME "box_seal"
+#include "cmptest.h"
+
+int main(void)
+{
+ unsigned char pk[crypto_box_PUBLICKEYBYTES];
+ unsigned char sk[crypto_box_SECRETKEYBYTES];
+ unsigned char *c;
+ unsigned char *m;
+ unsigned char *m2;
+ size_t m_len;
+ size_t c_len;
+
+ crypto_box_keypair(pk, sk);
+ m_len = (size_t) randombytes_uniform(1000);
+ c_len = crypto_box_SEALBYTES + m_len;
+ m = (unsigned char *) sodium_malloc(m_len);
+ m2 = (unsigned char *) sodium_malloc(m_len);
+ c = (unsigned char *) sodium_malloc(c_len);
+ randombytes_buf(m, m_len);
+ if (crypto_box_seal(c, m, m_len, pk) != 0) {
+ printf("crypto_box_seal() failure\n");
+ return 1;
+ }
+ if (crypto_box_seal_open(m2, c, c_len, pk, sk) != 0) {
+ printf("crypto_box_seal_open() failure\n");
+ return 1;
+ }
+ printf("%d\n", memcmp(m, m2, m_len));
+
+ printf("%d\n", crypto_box_seal_open(m, c, 0U, pk, sk));
+ printf("%d\n", crypto_box_seal_open(m, c, c_len - 1U, pk, sk));
+ printf("%d\n", crypto_box_seal_open(m, c, c_len, sk, pk));
+
+ sodium_free(c);
+ sodium_free(m);
+ sodium_free(m2);
+
+ assert(crypto_box_sealbytes() == crypto_box_SEALBYTES);
+
+ return 0;
+}
diff --git a/test/default/box_seal.exp b/test/default/box_seal.exp
new file mode 100644
index 00000000..78ea705a
--- /dev/null
+++ b/test/default/box_seal.exp
@@ -0,0 +1,4 @@
+0
+-1
+-1
+-1