diff --git a/TestScripts/tweetnacl.patch b/TestScripts/tweetnacl.patch
index 6f9e782f..0410e7cf 100644
--- a/TestScripts/tweetnacl.patch
+++ b/TestScripts/tweetnacl.patch
@@ -1,5 +1,5 @@
---- tweetnacl.c 2018-01-17 21:26:25.086390308 -0500
-+++ tweetnacl.cpp 2018-01-17 21:26:25.088390282 -0500
+--- tweetnacl.c 2018-01-18 12:36:44.497870997 -0500
++++ tweetnacl.cpp 2018-01-18 12:36:44.500871058 -0500
@@ -1,19 +1,33 @@
-#include "tweetnacl.h"
-#define FOR(i,n) for (i = 0;i < n;++i)
@@ -427,7 +427,7 @@
o[2*i]=t[i]&0xff;
o[2*i+1]=t[i]>>8;
}
-@@ -319,88 +340,88 @@
+@@ -319,88 +340,123 @@
static int neq25519(const gf a, const gf b)
{
@@ -523,6 +523,41 @@
}
- FOR(a,16) o[a]=c[a];
+ for(a=0; a<16; ++a) o[a]=c[a];
++}
++
++// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c
++static int has_small_order(const uint8_t s[32])
++{
++ CRYPTOPP_ALIGN_DATA(16)
++ const uint8_t blacklist[][32] = {
++ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++ { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++ { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 },
++ { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 },
++ { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++ { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++ { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++ { 0xcd, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 },
++ { 0x4c, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 },
++ { 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++ { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++ { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
++ };
++ CRYPTOPP_COMPILE_ASSERT(12 == COUNTOF(blacklist));
++
++ uint8_t c[12] = { 0 };
++ for (size_t j = 0; j < 32; j++) {
++ for (size_t i = 0; i < COUNTOF(blacklist); i++) {
++ c[i] |= s[j] ^ blacklist[i][j];
++ }
++ }
++
++ unsigned int k = 0;
++ for (size_t i = 0; i < COUNTOF(blacklist); i++) {
++ k |= (c[i] - 1);
++ }
++
++ return (int) ((k >> 8) & 1);
}
-int crypto_scalarmult(u8 *q,const u8 *n,const u8 *p)
@@ -543,7 +578,7 @@
b[i]=x[i];
d[i]=a[i]=c[i]=0;
}
-@@ -430,7 +451,7 @@
+@@ -430,7 +486,7 @@
sel25519(a,b,r);
sel25519(c,d,r);
}
@@ -552,7 +587,7 @@
x[i+16]=a[i];
x[i+32]=c[i];
x[i+48]=b[i];
-@@ -442,113 +463,115 @@
+@@ -442,113 +498,138 @@
return 0;
}
@@ -570,14 +605,23 @@
}
-int crypto_box_beforenm(u8 *k,const u8 *y,const u8 *x)
-+// S must not be all 0's
++// Avoid small order elements. Also see https://eprint.iacr.org/2017/806.pdf
++// and https://github.com/jedisct1/libsodium/commit/675149b9b8b66ff4.
+int crypto_box_beforenm(uint8_t *k,const uint8_t *y,const uint8_t *x)
++{
++ uint8_t s[32];
++ if(crypto_scalarmult(s,x,y) != 0) return -1;
++ if(has_small_order(s) != 0) return -1;
++ return crypto_core_hsalsa20(k,_0,s,sigma);
++}
++
++// Allow small order elements. Also see https://eprint.iacr.org/2017/806.pdf
++int crypto_box_beforenm_unchecked(uint8_t *k,const uint8_t *y,const uint8_t *x)
{
- u8 s[32];
- crypto_scalarmult(s,x,y);
+ uint8_t s[32];
+ if(crypto_scalarmult(s,x,y) != 0) return -1;
-+ if(verify_n(s,_0,32) != -1) return -1;
return crypto_core_hsalsa20(k,_0,s,sigma);
}
@@ -594,20 +638,28 @@
}
-int crypto_box(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *y,const u8 *x)
-+int crypto_box(uint8_t *c,const uint8_t *m,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x)
++int crypto_box(uint8_t *c, const uint8_t *m, uint64_t d, const uint8_t *n, const uint8_t *y, const uint8_t *x)
+ {
+- u8 k[32];
+- crypto_box_beforenm(k,y,x);
+- return crypto_box_afternm(c,m,d,n,k);
++ uint8_t k[32];
++ if (crypto_box_beforenm(k, y, x) != 0) return -1;
++ return crypto_box_afternm(c, m, d, n, k);
+ }
+
+-int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x)
++int crypto_box_unchecked(uint8_t *c, const uint8_t *m, uint64_t d, const uint8_t *n, const uint8_t *y, const uint8_t *x)
{
- u8 k[32];
- crypto_box_beforenm(k,y,x);
+ uint8_t k[32];
-+ if(crypto_box_beforenm(k,y,x) != 0) return -1;
- return crypto_box_afternm(c,m,d,n,k);
- }
-
--int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x)
++ crypto_box_beforenm_unchecked(k, y, x);
++ return crypto_box_afternm(c, m, d, n, k);
++}
++
+int crypto_box_open(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x)
- {
-- u8 k[32];
-- crypto_box_beforenm(k,y,x);
++{
+ uint8_t k[32];
+ if(crypto_box_beforenm(k,y,x) != 0) return -1;
return crypto_box_open_afternm(m,c,d,n,k);
@@ -643,6 +695,13 @@
- 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
- 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
- 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
++int crypto_box_open_unchecked(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x)
++{
++ uint8_t k[32];
++ crypto_box_beforenm_unchecked(k,y,x);
++ return crypto_box_open_afternm(m,c,d,n,k);
++}
++
+static uint64_t R(uint64_t x,int c) { return (x >> c) | (x << (64 - c)); }
+static uint64_t Ch(uint64_t x,uint64_t y,uint64_t z) { return (x & y) ^ (~x & z); }
+static uint64_t Maj(uint64_t x,uint64_t y,uint64_t z) { return (x & y) ^ (x & z) ^ (y & z); }
@@ -700,8 +759,9 @@
+ for(j=0; j<8; ++j) a[(j+1)%8] = b[j];
if (i%16 == 15)
- FOR(j,16)
-+ for(j=0; j<16; ++j)
- w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]);
+- w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]);
++ for(j=0; j<16; ++j)
++ w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]);
}
- FOR(i,8) { a[i] += z[i]; z[i] = a[i]; }
@@ -722,7 +782,7 @@
0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
-@@ -559,20 +582,20 @@
+@@ -559,20 +640,20 @@
0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
} ;
@@ -749,7 +809,7 @@
x[n] = 128;
n = 256-128*(n<112);
-@@ -580,12 +603,12 @@
+@@ -580,12 +661,12 @@
ts64(x+n-8,b<<3);
crypto_hashblocks(h,x,n);
@@ -764,7 +824,7 @@
{
gf a,b,c,d,t,e,f,g,h;
-@@ -610,14 +633,14 @@
+@@ -610,14 +691,14 @@
M(p[3], e, h);
}
@@ -782,7 +842,7 @@
{
gf tx, ty, zi;
inv25519(zi, p[2]);
-@@ -627,7 +650,7 @@
+@@ -627,7 +708,7 @@
r[31] ^= par25519(tx) << 7;
}
@@ -791,7 +851,7 @@
{
int i;
set25519(p[0],gf0);
-@@ -635,7 +658,7 @@
+@@ -635,7 +716,7 @@
set25519(p[2],gf1);
set25519(p[3],gf0);
for (i = 255;i >= 0;--i) {
@@ -800,7 +860,7 @@
cswap(p,q,b);
add(q,p);
add(p,p);
-@@ -643,7 +666,7 @@
+@@ -643,7 +724,7 @@
}
}
@@ -809,7 +869,7 @@
{
gf q[4];
set25519(q[0],X);
-@@ -653,9 +676,9 @@
+@@ -653,9 +734,9 @@
scalarmult(p,q,s);
}
@@ -821,7 +881,7 @@
gf p[4];
int i;
-@@ -668,50 +691,50 @@
+@@ -668,50 +749,50 @@
scalarbase(p,d);
pack(pk,p);
@@ -887,7 +947,7 @@
gf p[4];
crypto_hash(d, sk, 32);
-@@ -720,27 +743,27 @@
+@@ -720,27 +801,27 @@
d[31] |= 64;
*smlen = n+64;
@@ -922,7 +982,7 @@
{
gf t, chk, num, den, den2, den4, den6;
set25519(r[2],gf1);
-@@ -776,10 +799,10 @@
+@@ -776,10 +857,10 @@
return 0;
}
@@ -935,7 +995,7 @@
gf p[4],q[4];
*mlen = -1;
-@@ -787,8 +810,8 @@
+@@ -787,8 +868,8 @@
if (unpackneg(q,pk)) return -1;
@@ -946,7 +1006,7 @@
crypto_hash(h,m,n);
reduce(h);
scalarmult(p,q,h);
-@@ -799,11 +822,16 @@
+@@ -799,11 +880,17 @@
n -= 64;
if (crypto_verify_32(sm, t)) {
@@ -965,4 +1025,4 @@
+NAMESPACE_END // NaCl
+
+#endif // NO_OS_DEPENDENCE
-\ No newline at end of file
++
diff --git a/nacl.h b/nacl.h
index e967deb9..33da593d 100644
--- a/nacl.h
+++ b/nacl.h
@@ -20,23 +20,25 @@
/// NaCl typdef'd u64 as an unsigned long long, but Cygwin,
/// MinGW and MSYS are LP64 systems (not LLP64 systems). In
/// addition, Crypto++ was missing NaCl's signed 64-bit integer i64.
-/// \details Crypto++ rejects all 0-keys due to small points. The TweetNaCl
-/// library allowed them, so it may cause interop problems. Also see libsodium
-/// commit
-/// 675149b9b8b6, May the
-/// Fourth Be With You: A Microarchitectural Side Channel Attack on Several
-/// Real-World Applications of Curve25519 and RFC 7748, Elliptic Curves for
-/// Security, Section 6.
+/// \details Crypto++ rejects all-0's shared secrets due to small elements. The
+/// TweetNaCl library allowed them but the library predated the attack. If you wish
+/// to allow small elements then use the "unchecked" versions of crypto_box_unchecked,
+/// crypto_box_open_unchecked and crypto_box_beforenm_unchecked. Also see May the Fourth Be With You: A
+/// Microarchitectural Side Channel Attack on Several Real-World Applications of
+/// Curve25519, libsodium
+/// commit 675149b9b8b66ff4 and RFC
+/// 7748, Elliptic Curves for Security, Section 6.
/// \details TweetNaCl is well written but not well optimzed. It runs 2x to 4x
/// slower than optimized routines from libsodium. However, the library is still
-/// 2x to 4x faster than the algorithms NaCl was designed to replace.
-/// \details The Crypto++ wrapper for TweetNaCl requires OS features, and
-/// NO_OS_DEPENDENCE cannot be defined. The requirement is due to
-/// TweetNaCl's internal function randombytes. Crypto++ implemented
-/// randombytes using DefaultAutoSeededRNG, so OS integration
-/// must be enabled. You can use another generator like RDRAND to
-/// avoid the restriction.
+/// 2x to 4x faster than the algorithms NaCl was designed to replace.
+/// \details The Crypto++ wrapper for TweetNaCl requires OS features. That is,
+/// NO_OS_DEPENDENCE cannot be defined. It is due to TweetNaCl's
+/// internal function randombytes. Crypto++ used
+/// DefaultAutoSeededRNG within randombytes, so OS integration
+/// must be enabled. You can use another generator like RDRAND to
+/// avoid the restriction.
/// \sa TweetNaCl:
/// A crypto library in 100 tweets (20140917)
/// \since Crypto++ 6.0
@@ -211,6 +213,76 @@ int crypto_box_afternm(uint8_t *c,const uint8_t *m,uint64_t d,const uint8_t *n,c
/// \since Crypto++ 6.0
int crypto_box_open_afternm(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t *n,const uint8_t *k);
+/// \brief Encrypt and authenticate a message
+/// \param c output byte buffer
+/// \param m input byte buffer
+/// \param d size of the input byte buffer
+/// \param n nonce byte buffer
+/// \param y other's public key
+/// \param x private key
+/// \details crypto_box() uses crypto_box_curve25519xsalsa20poly1305.
+/// \details This version of crypto_box() does not check for small order elements. It is unsafe
+/// but it exists for backwards compatibility with downlevel clients. Without the compatibility
+/// interop with early versions of NaCl, libsodium and other libraries does not exist. The
+/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero
+/// and Zcash.
+/// \returns 0 on success, non-0 otherwise
+/// \warn This version of crypto_box() does not check for small order elements. It should not
+/// be used in new software.
+/// \sa NaCl crypto_box documentation,
+/// May the Fourth Be With You: A Microarchitectural
+/// Side Channel Attack on Several Real-World Applications of Curve25519,
+/// libsodium commit
+/// 675149b9b8b66ff4.
+/// \since Crypto++ 6.0
+int crypto_box_unchecked(uint8_t *c,const uint8_t *m,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x);
+
+/// \brief Verify and decrypt a message
+/// \param m output byte buffer
+/// \param c input byte buffer
+/// \param d size of the input byte buffer
+/// \param n nonce byte buffer
+/// \param y other's public key
+/// \param x private key
+/// \details crypto_box_open() uses crypto_box_curve25519xsalsa20poly1305.
+/// \details This version of crypto_box_open() does not check for small order elements. It is unsafe
+/// but it exists for backwards compatibility with downlevel clients. Without the compatibility
+/// interop with early versions of NaCl, libsodium and other libraries does not exist. The
+/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero
+/// and Zcash.
+/// \returns 0 on success, non-0 otherwise
+/// \warn This version of crypto_box_open() does not check for small order elements. It should not
+/// be used in new software.
+/// \sa NaCl crypto_box documentation,
+/// May the Fourth Be With You: A Microarchitectural
+/// Side Channel Attack on Several Real-World Applications of Curve25519,
+/// libsodium commit
+/// 675149b9b8b66ff4.
+/// \since Crypto++ 6.0
+int crypto_box_open_unchecked(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x);
+
+/// \brief Encrypt and authenticate a message
+/// \param k shared secret byte buffer
+/// \param y other's public key
+/// \param x private key
+/// \details crypto_box_beforenm() performs message-independent precomputation to derive the key.
+/// Once the key is derived multiple calls to crypto_box_afternm() can be made to process the message.
+/// \details This version of crypto_box_beforenm() does not check for small order elements. It is unsafe
+/// but it exists for backwards compatibility with downlevel clients. Without the compatibility
+/// interop with early versions of NaCl, libsodium and other libraries does not exist. The
+/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero
+/// and Zcash.
+/// \returns 0 on success, non-0 otherwise
+/// \warn This version of crypto_box_beforenm() does not check for small order elements. It should not
+/// be used in new software.
+/// \sa NaCl crypto_box documentation,
+/// May the Fourth Be With You: A Microarchitectural
+/// Side Channel Attack on Several Real-World Applications of Curve25519,
+/// libsodium commit
+/// 675149b9b8b66ff4.
+/// \since Crypto++ 6.0
+int crypto_box_beforenm_unchecked(uint8_t *k,const uint8_t *y,const uint8_t *x);
+
/// \brief TODO
int crypto_core_salsa20(uint8_t *out,const uint8_t *in,const uint8_t *k,const uint8_t *c);
diff --git a/tweetnacl.cpp b/tweetnacl.cpp
index f61bca00..afe7cd48 100644
--- a/tweetnacl.cpp
+++ b/tweetnacl.cpp
@@ -412,6 +412,41 @@ static void pow2523(gf o,const gf i)
for(a=0; a<16; ++a) o[a]=c[a];
}
+// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c
+static int has_small_order(const uint8_t s[32])
+{
+ CRYPTOPP_ALIGN_DATA(16)
+ const uint8_t blacklist[][32] = {
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 },
+ { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 },
+ { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
+ { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
+ { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
+ { 0xcd, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 },
+ { 0x4c, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 },
+ { 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+ };
+ CRYPTOPP_COMPILE_ASSERT(12 == COUNTOF(blacklist));
+
+ uint8_t c[12] = { 0 };
+ for (size_t j = 0; j < 32; j++) {
+ for (size_t i = 0; i < COUNTOF(blacklist); i++) {
+ c[i] |= s[j] ^ blacklist[i][j];
+ }
+ }
+
+ unsigned int k = 0;
+ for (size_t i = 0; i < COUNTOF(blacklist); i++) {
+ k |= (c[i] - 1);
+ }
+
+ return (int) ((k >> 8) & 1);
+}
+
int crypto_scalarmult(uint8_t *q,const uint8_t *n,const uint8_t *p)
{
uint8_t z[32];
@@ -474,12 +509,21 @@ int crypto_box_keypair(uint8_t *y,uint8_t *x)
return crypto_scalarmult_base(y,x);
}
-// S must not be all 0's
+// Avoid small order elements. Also see https://eprint.iacr.org/2017/806.pdf
+// and https://github.com/jedisct1/libsodium/commit/675149b9b8b66ff4.
int crypto_box_beforenm(uint8_t *k,const uint8_t *y,const uint8_t *x)
{
uint8_t s[32];
if(crypto_scalarmult(s,x,y) != 0) return -1;
- if(verify_n(s,_0,32) != -1) return -1;
+ if(has_small_order(s) != 0) return -1;
+ return crypto_core_hsalsa20(k,_0,s,sigma);
+}
+
+// Allow small order elements. Also see https://eprint.iacr.org/2017/806.pdf
+int crypto_box_beforenm_unchecked(uint8_t *k,const uint8_t *y,const uint8_t *x)
+{
+ uint8_t s[32];
+ if(crypto_scalarmult(s,x,y) != 0) return -1;
return crypto_core_hsalsa20(k,_0,s,sigma);
}
@@ -493,11 +537,18 @@ int crypto_box_open_afternm(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t
return crypto_secretbox_open(m,c,d,n,k);
}
-int crypto_box(uint8_t *c,const uint8_t *m,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x)
+int crypto_box(uint8_t *c, const uint8_t *m, uint64_t d, const uint8_t *n, const uint8_t *y, const uint8_t *x)
{
uint8_t k[32];
- if(crypto_box_beforenm(k,y,x) != 0) return -1;
- return crypto_box_afternm(c,m,d,n,k);
+ if (crypto_box_beforenm(k, y, x) != 0) return -1;
+ return crypto_box_afternm(c, m, d, n, k);
+}
+
+int crypto_box_unchecked(uint8_t *c, const uint8_t *m, uint64_t d, const uint8_t *n, const uint8_t *y, const uint8_t *x)
+{
+ uint8_t k[32];
+ crypto_box_beforenm_unchecked(k, y, x);
+ return crypto_box_afternm(c, m, d, n, k);
}
int crypto_box_open(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x)
@@ -507,6 +558,13 @@ int crypto_box_open(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t *n,cons
return crypto_box_open_afternm(m,c,d,n,k);
}
+int crypto_box_open_unchecked(uint8_t *m,const uint8_t *c,uint64_t d,const uint8_t *n,const uint8_t *y,const uint8_t *x)
+{
+ uint8_t k[32];
+ crypto_box_beforenm_unchecked(k,y,x);
+ return crypto_box_open_afternm(m,c,d,n,k);
+}
+
static uint64_t R(uint64_t x,int c) { return (x >> c) | (x << (64 - c)); }
static uint64_t Ch(uint64_t x,uint64_t y,uint64_t z) { return (x & y) ^ (~x & z); }
static uint64_t Maj(uint64_t x,uint64_t y,uint64_t z) { return (x & y) ^ (x & z) ^ (y & z); }
@@ -556,8 +614,8 @@ int crypto_hashblocks(uint8_t *x,const uint8_t *m,uint64_t n)
b[3] += t;
for(j=0; j<8; ++j) a[(j+1)%8] = b[j];
if (i%16 == 15)
- for(j=0; j<16; ++j)
- w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]);
+ for(j=0; j<16; ++j)
+ w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]);
}
for(i=0; i<8; ++i) { a[i] += z[i]; z[i] = a[i]; }
diff --git a/validat4.cpp b/validat4.cpp
index 53756cae..0cd434c7 100644
--- a/validat4.cpp
+++ b/validat4.cpp
@@ -117,6 +117,8 @@ bool TestCryptoBox()
bool pass = true; int rc;
+ // Reject small order elements
+
rc = crypto_box(c, m, 163, nonce, bobpk, alicesk);
pass = (rc == 0) && pass;
pass = (std::memcmp(c+16, exp1, 163-16) == 0) && pass;
@@ -133,6 +135,25 @@ bool TestCryptoBox()
rc = crypto_box_beforenm(k, small_order_p, alicesk);
pass = (rc != 0) && pass;
+
+ // Allow small order elements
+
+ rc = crypto_box_unchecked(c, m, 163, nonce, bobpk, alicesk);
+ pass = (rc == 0) && pass;
+ pass = (std::memcmp(c+16, exp1, 163-16) == 0) && pass;
+
+ rc = crypto_box_unchecked(c, m, 163, nonce, small_order_p, alicesk);
+ pass = (rc == 0) && pass;
+ std::memset(c, 0, sizeof(c));
+
+ rc = crypto_box_beforenm_unchecked(k, bobpk, alicesk);
+ pass = (rc == 0) && pass;
+ rc = crypto_box_afternm(c, m, 163, nonce, k);
+ pass = (rc == 0) && pass;
+ pass = (std::memcmp(c+16, exp2, 163-16) == 0) && pass;
+
+ rc = crypto_box_beforenm_unchecked(k, small_order_p, alicesk);
+ pass = (rc == 0) && pass;
return pass;
}
@@ -210,6 +231,8 @@ bool TestCryptoBoxOpen()
bool pass = true; int rc;
+ // Reject small order elements
+
rc = crypto_box_open(m, c, 163, nonce, alicepk, bobsk);
pass = (rc == 0) && pass;
pass = (std::memcmp(m+32, exp1, 163-32) == 0) && pass;
@@ -226,13 +249,28 @@ bool TestCryptoBoxOpen()
pass = (rc == 0) && pass;
pass = (std::memcmp(m+32, exp2, 163-32) == 0) && pass;
+ // Allow small order elements
+
+ rc = crypto_box_open_unchecked(m, c, 163, nonce, alicepk, bobsk);
+ pass = (rc == 0) && pass;
+ pass = (std::memcmp(m+32, exp1, 163-32) == 0) && pass;
+
+ rc = crypto_box_beforenm_unchecked(k, small_order_p, bobsk);
+ pass = (rc == 0) && pass;
+ rc = crypto_box_beforenm_unchecked(k, alicepk, bobsk);
+ pass = (rc == 0) && pass;
+
+ rc = crypto_box_open_afternm(m, c, 163, nonce, k);
+ pass = (rc == 0) && pass;
+ pass = (std::memcmp(m+32, exp2, 163-32) == 0) && pass;
+
return pass;
}
bool TestCryptoBoxKeys()
{
// https://github.com/jedisct1/libsodium/blob/master/test/default/box7.c
- const unsigned int MAX_TEST = 128;
+ const unsigned int MAX_TEST = 64;
const unsigned int MAX_MESSAGE = 4096;
uint8_t alicesk[crypto_box_SECRETKEYBYTES];
@@ -405,7 +443,7 @@ bool TestCryptoSign()
bool TestCryptoSignKeys()
{
// https://github.com/jedisct1/libsodium/blob/master/test/default/sign.c
- const unsigned int MAX_TEST = 128;
+ const unsigned int MAX_TEST = 64;
const unsigned int MAX_MESSAGE = 4096;
uint8_t pk[crypto_sign_PUBLICKEYBYTES];