diff --git a/.gitignore b/.gitignore index e0281ae9..526277f9 100644 --- a/.gitignore +++ b/.gitignore @@ -134,6 +134,7 @@ test/default/secretbox7 test/default/secretbox8 test/default/secretbox_easy test/default/secretbox_easy2 +test/default/secretstream test/default/shorthash test/default/sign test/default/siphashx24 diff --git a/ChangeLog b/ChangeLog index ce502497..b3e331d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,8 @@ store keys to. - SSE2 implementations of `crypto_verify_*()` have been added. - Passwords can be hashed using a specific algorithm with the new `crypto_pwhash_str_alg()` function. + - Due to popular demand, base64 encoding (`sodium_bin2base64()`) and +decoding (`sodium_base642bin()`) have been implemented. * Version 1.0.13 - Javascript: the sumo builds now include all symbols. They were diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj b/builds/msvc/vs2010/libsodium/libsodium.vcxproj index 122b5330..e2a50bbe 100644 --- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj @@ -181,6 +181,7 @@ + diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters index 67cdb12b..366153e8 100644 --- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters @@ -336,6 +336,9 @@ randombytes\sysrandom + + sodium + sodium diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj b/builds/msvc/vs2012/libsodium/libsodium.vcxproj index 2430855f..d278f407 100644 --- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj @@ -181,6 +181,7 @@ + diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters index 67cdb12b..366153e8 100644 --- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters @@ -336,6 +336,9 @@ randombytes\sysrandom + + sodium + sodium diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj b/builds/msvc/vs2013/libsodium/libsodium.vcxproj index d4fa9fb2..5c4ba37d 100644 --- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj @@ -181,6 +181,7 @@ + diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters index 67cdb12b..366153e8 100644 --- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters @@ -336,6 +336,9 @@ randombytes\sysrandom + + sodium + sodium diff --git a/builds/msvc/vs2015/libsodium/libsodium.vcxproj b/builds/msvc/vs2015/libsodium/libsodium.vcxproj index 87379646..bb5a01f6 100644 --- a/builds/msvc/vs2015/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2015/libsodium/libsodium.vcxproj @@ -181,6 +181,7 @@ + diff --git a/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters index 67cdb12b..366153e8 100644 --- a/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters @@ -336,6 +336,9 @@ randombytes\sysrandom + + sodium + sodium diff --git a/builds/msvc/vs2017/libsodium/libsodium.vcxproj b/builds/msvc/vs2017/libsodium/libsodium.vcxproj index 8b59d53e..ff99c6fc 100644 --- a/builds/msvc/vs2017/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2017/libsodium/libsodium.vcxproj @@ -181,6 +181,7 @@ + diff --git a/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters index 67cdb12b..366153e8 100644 --- a/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters @@ -336,6 +336,9 @@ randombytes\sysrandom + + sodium + sodium diff --git a/configure.ac b/configure.ac index da6a261c..98df317b 100644 --- a/configure.ac +++ b/configure.ac @@ -280,16 +280,17 @@ AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wformat=2], [CWFLAGS="$CWFLAGS -Wformat=2"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wmissing-declarations], [CWFLAGS="$CWFLAGS -Wmissing-declarations"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wmissing-prototypes], [CWFLAGS="$CWFLAGS -Wmissing-prototypes"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wnested-externs], [CWFLAGS="$CWFLAGS -Wnested-externs"]) +AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wno-type-limits], [CWFLAGS="$CWFLAGS -Wno-type-limits"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wno-unknown-pragmas], [CWFLAGS="$CWFLAGS -Wno-unknown-pragmas"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wnormalized=id], [CWFLAGS="$CWFLAGS -Wnormalized=id"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wnull-dereference], [CWFLAGS="$CWFLAGS -Wnull-dereference"]) +AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wold-style-declaration], [CWFLAGS="$CWFLAGS -Wold-style-declaration"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wpointer-arith], [CWFLAGS="$CWFLAGS -Wpointer-arith"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wredundant-decls], [CWFLAGS="$CWFLAGS -Wredundant-decls"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wshorten-64-to-32], [CWFLAGS="$CWFLAGS -Wshorten-64-to-32"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wstrict-prototypes], [CWFLAGS="$CWFLAGS -Wstrict-prototypes"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wswitch-enum], [CWFLAGS="$CWFLAGS -Wswitch-enum"]) AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wvariable-decl], [CWFLAGS="$CWFLAGS -Wvariable-decl"]) -AX_CHECK_COMPILE_FLAG([$CWFLAGS -Wno-type-limits], [CWFLAGS="$CWFLAGS -Wno-type-limits"]) AX_CHECK_LINK_FLAG([-Wl,-z,relro], [LDFLAGS="$LDFLAGS -Wl,-z,relro"]) AX_CHECK_LINK_FLAG([-Wl,-z,now], [LDFLAGS="$LDFLAGS -Wl,-z,now"]) diff --git a/libsodium.vcxproj b/libsodium.vcxproj index cd0b7299..05448ee8 100644 --- a/libsodium.vcxproj +++ b/libsodium.vcxproj @@ -419,6 +419,7 @@ + diff --git a/libsodium.vcxproj.filters b/libsodium.vcxproj.filters index b0536551..c0bb58d8 100644 --- a/libsodium.vcxproj.filters +++ b/libsodium.vcxproj.filters @@ -327,6 +327,9 @@ Source Files + + Source Files + Source Files diff --git a/packaging/dotnet-core/desktop.targets b/packaging/dotnet-core/desktop.targets deleted file mode 100644 index b117c478..00000000 --- a/packaging/dotnet-core/desktop.targets +++ /dev/null @@ -1,16 +0,0 @@ - - - - x86\libsodium.dll - PreserveNewest - PreserveNewest - false - - - x64\libsodium.dll - PreserveNewest - PreserveNewest - false - - - \ No newline at end of file diff --git a/packaging/dotnet-core/libsodium.props b/packaging/dotnet-core/libsodium.props index 1986e39b..96f62f70 100644 --- a/packaging/dotnet-core/libsodium.props +++ b/packaging/dotnet-core/libsodium.props @@ -2,7 +2,7 @@ - netstandard1.1;net46 + netstandard1.1 true true false @@ -27,7 +27,6 @@ - diff --git a/packaging/dotnet-core/prepare.py b/packaging/dotnet-core/prepare.py index 44d2d8e4..610e4ebd 100755 --- a/packaging/dotnet-core/prepare.py +++ b/packaging/dotnet-core/prepare.py @@ -8,8 +8,8 @@ WINDOWS = [ # --------------------- ----------------- # # Runtime ID Platform # # --------------------- ----------------- # - ( 'win7-x64', 'x64' ), - ( 'win7-x86', 'Win32' ), + ( 'win-x64', 'x64' ), + ( 'win-x86', 'Win32' ), # --------------------- ----------------- # ] @@ -17,9 +17,7 @@ MACOS = [ # --------------------- ----------------- # # Runtime ID Codename # # --------------------- ----------------- # - ( 'osx.10.10-x64', 'yosemite' ), - ( 'osx.10.11-x64', 'el_capitan' ), - ( 'osx.10.12-x64', 'sierra' ), + ( 'osx-x64', 'sierra' ), # --------------------- ----------------- # ] @@ -27,22 +25,13 @@ LINUX = [ # --------------------- ----------------- # # Runtime ID Docker Image # # --------------------- ----------------- # - ( 'centos.7-x64', 'centos:7.1.1503' ), - ( 'debian.8-x64', 'debian:8.2' ), - ( 'fedora.24-x64', 'fedora:24' ), - ( 'fedora.25-x64', 'fedora:25' ), - ( 'fedora.26-x64', 'fedora:26' ), - ( 'opensuse.42.1-x64', 'opensuse:42.1' ), - ( 'ubuntu.14.04-x64', 'ubuntu:trusty' ), - ( 'ubuntu.16.04-x64', 'ubuntu:xenial' ), - ( 'ubuntu.16.10-x64', 'ubuntu:yakkety' ), + ( 'linux-x64', 'debian:stretch' ), # --------------------- ----------------- # ] EXTRAS = [ 'LICENSE', 'AUTHORS', 'ChangeLog' ] PROPSFILE = 'libsodium.props' -DESKTOPTARGETSFILE = 'desktop.targets' MAKEFILE = 'Makefile' BUILDDIR = 'build' CACHEDIR = 'cache' @@ -64,7 +53,6 @@ class Version: self.projfile = os.path.join(self.builddir, '{0}.{1}.pkgproj'.format(PACKAGE, package_version)) self.propsfile = os.path.join(self.builddir, '{0}.props'.format(PACKAGE)) self.pkgfile = os.path.join(BUILDDIR, '{0}.{1}.nupkg'.format(PACKAGE, package_version)) - self.desktoptargetsfile = os.path.join(self.builddir, 'build', 'net46', '{0}.targets'.format(PACKAGE)) class WindowsItem: @@ -212,11 +200,6 @@ def main(args): for item in items: item.make(f) - f.write('\n') - f.write('{0}: {1}\n'.format(version.desktoptargetsfile, DESKTOPTARGETSFILE)) - f.write('\t@mkdir -p $(dir $@)\n') - f.write('\tcp -f $< $@\n') - f.write('\n') f.write('{0}: {1}\n'.format(version.propsfile, PROPSFILE)) f.write('\t@mkdir -p $(dir $@)\n') @@ -237,7 +220,6 @@ def main(args): f.write('{0}:'.format(version.pkgfile)) f.write(' \\\n\t\t{0}'.format(version.projfile)) f.write(' \\\n\t\t{0}'.format(version.propsfile)) - f.write(' \\\n\t\t{0}'.format(version.desktoptargetsfile)) for item in items: f.write(' \\\n\t\t{0}'.format(item.packfile)) f.write('\n') @@ -246,14 +228,14 @@ def main(args): '-v $(abspath recipes):/io/recipes ' + '-v $(abspath $(dir $<)):/io/input ' + '-v $(abspath $(dir $@)):/io/output ' + - '{0} sh -x -e /io/recipes/{1} {2}\n'.format('microsoft/dotnet:1.1-sdk', 'pack', os.path.relpath(version.projfile, version.builddir))) + '{0} sh -x -e /io/recipes/{1} {2}\n'.format('microsoft/dotnet:2.0-sdk', 'pack', os.path.relpath(version.projfile, version.builddir))) f.write('\n') f.write('test: {0}\n'.format(version.pkgfile)) f.write('\t{0} run --rm '.format(DOCKER) + '-v $(abspath recipes):/io/recipes ' + '-v $(abspath $(dir $<)):/io/packages ' + - '{0} sh -x -e /io/recipes/{1} "{2}"\n'.format('microsoft/dotnet:1.1-sdk', 'test', version.package_version)) + '{0} sh -x -e /io/recipes/{1} "{2}"\n'.format('microsoft/dotnet:2.0-sdk', 'test', version.package_version)) print('prepared', MAKEFILE, 'to make', version.pkgfile, 'for libsodium', version.libsodium_version) return 0 diff --git a/packaging/dotnet-core/recipes/linux-x64 b/packaging/dotnet-core/recipes/linux-x64 new file mode 100644 index 00000000..e22c9efc --- /dev/null +++ b/packaging/dotnet-core/recipes/linux-x64 @@ -0,0 +1,4 @@ +apt-get update +apt-get install -y --no-install-recommends build-essential + +. $(dirname $0)/build diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index cf0cffb3..8186b806 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -62,6 +62,7 @@ libsodium_la_SOURCES = \ crypto_secretbox/crypto_secretbox.c \ crypto_secretbox/crypto_secretbox_easy.c \ crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c \ + crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c \ crypto_shorthash/crypto_shorthash.c \ crypto_shorthash/siphash24/shorthash_siphash24.c \ crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c \ @@ -87,6 +88,7 @@ libsodium_la_SOURCES = \ include/sodium/private/mutex.h \ include/sodium/private/sse2_64_32.h \ randombytes/randombytes.c \ + sodium/codecs.c \ sodium/core.c \ sodium/runtime.c \ sodium/utils.c \ diff --git a/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c b/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c index 51667d02..b5993367 100644 --- a/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c +++ b/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c @@ -1920,11 +1920,11 @@ ge_mul_l(ge_p3 *r, const ge_p3 *A) static const signed char aslide[253] = { 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - ge_cached Ai[8]; - ge_p1p1 t; - ge_p3 u; - ge_p3 A2; - int i; + ge_cached Ai[8]; + ge_p1p1 t; + ge_p3 u; + ge_p3 A2; + int i; ge_p3_to_cached(&Ai[0], A); ge_p3_dbl(&t, A); diff --git a/src/libsodium/crypto_pwhash/argon2/argon2-encoding.c b/src/libsodium/crypto_pwhash/argon2/argon2-encoding.c index 5224cb61..a08acdda 100644 --- a/src/libsodium/crypto_pwhash/argon2/argon2-encoding.c +++ b/src/libsodium/crypto_pwhash/argon2/argon2-encoding.c @@ -1,5 +1,6 @@ #include "argon2-encoding.h" #include "argon2-core.h" +#include "utils.h" #include #include #include @@ -9,19 +10,6 @@ * Example code for a decoder and encoder of "hash strings", with Argon2 * parameters. * - * This code comprises three sections: - * - * -- The first section contains generic Base64 encoding and decoding - * functions. It is conceptually applicable to any hash function - * implementation that uses Base64 to encode and decode parameters, - * salts and outputs. It could be made into a library, provided that - * the relevant functions are made public (non-static) and be given - * reasonable names to avoid collisions with other functions. - * - * -- The second section is specific to Argon2. It encodes and decodes - * the parameters, salts and outputs. It does not compute the hash - * itself. - * * The code was originally written by Thomas Pornin , * to whom comments and remarks may be sent. It is released under what * should amount to Public Domain or its closest equivalent; the @@ -39,156 +27,6 @@ */ /* ==================================================================== */ -/* - * Common code; could be shared between different hash functions. - * - * Note: the Base64 functions below assume that uppercase letters (resp. - * lowercase letters) have consecutive numerical codes, that fit on 8 - * bits. All modern systems use ASCII-compatible charsets, where these - * properties are true. If you are stuck with a dinosaur of a system - * that still defaults to EBCDIC then you already have much bigger - * interoperability issues to deal with. - */ - -/* - * Some macros for constant-time comparisons. These work over values in - * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". - */ -#define EQ(x, y) \ - ((((0U - ((unsigned) (x) ^ (unsigned) (y))) >> 8) & 0xFF) ^ 0xFF) -#define GT(x, y) ((((unsigned) (y) - (unsigned) (x)) >> 8) & 0xFF) -#define GE(x, y) (GT(y, x) ^ 0xFF) -#define LT(x, y) GT(y, x) -#define LE(x, y) GE(y, x) - -/* - * Convert value x (0..63) to corresponding Base64 character. - */ -static int -b64_byte_to_char(unsigned x) -{ - return (LT(x, 26) & (x + 'A')) | - (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | - (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') | - (EQ(x, 63) & '/'); -} - -/* - * Convert character c to the corresponding 6-bit value. If character c - * is not a Base64 character, then 0xFF (255) is returned. - */ -static unsigned -b64_char_to_byte(int c) -{ - unsigned x; - - x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | - (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | - (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | - (EQ(c, '/') & 63); - return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); -} - -/* - * Convert some bytes to Base64. 'dst_len' is the length (in characters) - * of the output buffer 'dst'; if that buffer is not large enough to - * receive the result (including the terminating 0), then (size_t)-1 - * is returned. Otherwise, the zero-terminated Base64 string is written - * in the buffer, and the output length (counted WITHOUT the terminating - * zero) is returned. - */ -static size_t -to_base64(char *dst, size_t dst_len, const void *src, size_t src_len) -{ - size_t olen; - const unsigned char *buf; - unsigned acc, acc_len; - - olen = (src_len / 3) << 2; - switch (src_len % 3) { - case 2: - olen++; - /* fall through */ - case 1: - olen += 2; - break; - } - if (dst_len <= olen) { - return (size_t) -1; - } - acc = 0; - acc_len = 0; - buf = (const unsigned char *) src; - while (src_len-- > 0) { - acc = (acc << 8) + (*buf++); - acc_len += 8; - while (acc_len >= 6) { - acc_len -= 6; - *dst++ = (char) b64_byte_to_char((acc >> acc_len) & 0x3F); - } - } - if (acc_len > 0) { - *dst++ = (char) b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); - } - *dst++ = 0; - return olen; -} - -/* - * Decode Base64 chars into bytes. The '*dst_len' value must initially - * contain the length of the output buffer '*dst'; when the decoding - * ends, the actual number of decoded bytes is written back in - * '*dst_len'. - * - * Decoding stops when a non-Base64 character is encountered, or when - * the output buffer capacity is exceeded. If an error occurred (output - * buffer is too small, invalid last characters leading to unprocessed - * buffered bits), then NULL is returned; otherwise, the returned value - * points to the first non-Base64 character in the source stream, which - * may be the terminating zero. - */ -static const char * -from_base64(void *dst, size_t *dst_len, const char *src) -{ - size_t len; - unsigned char *buf; - unsigned acc, acc_len; - - buf = (unsigned char *) dst; - len = 0; - acc = 0; - acc_len = 0; - for (;;) { - unsigned d; - - d = b64_char_to_byte(*src); - if (d == 0xFF) { - break; - } - src++; - acc = (acc << 6) + d; - acc_len += 6; - if (acc_len >= 8) { - acc_len -= 8; - if ((len++) >= *dst_len) { - return NULL; - } - *buf++ = (acc >> acc_len) & 0xFF; - } - } - - /* - * If the input length is equal to 1 modulo 4 (which is - * invalid), then there will remain 6 unprocessed bits; - * otherwise, only 0, 2 or 4 bits are buffered. The buffered - * bits must also all be zero. - */ - if (acc_len > 4 || (acc & ((1U << acc_len) - 1)) != 0) { - return NULL; - } - *dst_len = len; - return src; -} /* * Decode decimal integer from 'str'; the value is written in '*v'. @@ -300,14 +138,18 @@ decode_string(argon2_context *ctx, const char *str, argon2_type type) } while ((void)0, 0) /* Decoding base64 into a binary buffer */ -#define BIN(buf, max_len, len) \ - do { \ - size_t bin_len = (max_len); \ - str = from_base64(buf, &bin_len, str); \ - if (str == NULL || bin_len > UINT32_MAX) { \ - return ARGON2_DECODING_FAIL; \ - } \ - (len) = (uint32_t) bin_len; \ +#define BIN(buf, max_len, len) \ + do { \ + size_t bin_len = (max_len); \ + const char *str_end; \ + if (sodium_base642bin((buf), (max_len), str, strlen(str), NULL, \ + &bin_len, &str_end, \ + sodium_base64_VARIANT_ORIGINAL_NO_PADDING) != 0 || \ + bin_len > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (len) = (uint32_t) bin_len; \ + str = str_end; \ } while ((void) 0, 0) size_t maxsaltlen = ctx->saltlen; @@ -416,14 +258,16 @@ encode_string(char *dst, size_t dst_len, argon2_context *ctx, argon2_type type) SS(tmp); \ } while ((void) 0, 0) -#define SB(buf, len) \ - do { \ - size_t sb_len = to_base64(dst, dst_len, buf, len); \ - if (sb_len == (size_t) -1) { \ - return ARGON2_ENCODING_FAIL; \ - } \ - dst += sb_len; \ - dst_len -= sb_len; \ +#define SB(buf, len) \ + do { \ + size_t sb_len; \ + if (sodium_bin2base64(dst, dst_len, (buf), (len), \ + sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == NULL) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + sb_len = strlen(dst); \ + dst += sb_len; \ + dst_len -= sb_len; \ } while ((void) 0, 0) int validation_result; diff --git a/src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c b/src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c new file mode 100644 index 00000000..b2ed5141 --- /dev/null +++ b/src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c @@ -0,0 +1,237 @@ + +#include +#include +#include +#include + +#include "core.h" +#include "crypto_aead_chacha20poly1305.h" +#include "crypto_aead_xchacha20poly1305.h" +#include "crypto_core_hchacha20.h" +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_secretstream_xchacha20poly1305.h" +#include "randombytes.h" +#include "utils.h" + +#include "private/common.h" + +#define crypto_secretstream_xchacha20poly1305_COUNTERBYTES 4U +#define crypto_secretstream_xchacha20poly1305_INONCEBYTES 8U + +static const unsigned char _pad0[16] = { 0 }; + +void +crypto_secretstream_xchacha20poly1305_keygen + (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + randombytes_buf(k, crypto_secretstream_xchacha20poly1305_KEYBYTES); +} + +int +crypto_secretstream_xchacha20poly1305_init_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char out[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + COMPILER_ASSERT(crypto_secretstream_xchacha20poly1305_INITBYTES == + crypto_core_hchacha20_INPUTBYTES + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + + randombytes_buf(out, crypto_secretstream_xchacha20poly1305_INITBYTES); + crypto_core_hchacha20(state->k, out, k, NULL); + memcpy(state->nonce, out + crypto_core_hchacha20_INPUTBYTES, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->nonce + crypto_secretstream_xchacha20poly1305_INONCEBYTES, 0, + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + memset(state->_pad, 0, sizeof state->_pad); + + return 0; +} + +int +crypto_secretstream_xchacha20poly1305_init_pull + (crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char in[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + crypto_core_hchacha20(state->k, in, k, NULL); + memcpy(state->nonce, in + crypto_core_hchacha20_INPUTBYTES, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->nonce + crypto_secretstream_xchacha20poly1305_INONCEBYTES, 0, + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + memset(state->_pad, 0, sizeof state->_pad); + + return 0; +} + +void +crypto_secretstream_xchacha20poly1305_rekey + (crypto_secretstream_xchacha20poly1305_state *state) +{ + unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + + crypto_secretstream_xchacha20poly1305_INONCEBYTES]; + + crypto_stream_chacha20_ietf(new_key_and_inonce, sizeof new_key_and_inonce, + state->nonce, state->k); + memcpy(state->k, new_key_and_inonce, sizeof state->k); + memcpy(state->nonce, new_key_and_inonce + sizeof state->k, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->nonce + crypto_secretstream_xchacha20poly1305_INONCEBYTES, 0, + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); +} + +int +crypto_secretstream_xchacha20poly1305_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *out, unsigned long long *outlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, unsigned char tag) +{ + crypto_onetimeauth_poly1305_state poly1305_state; + unsigned char block[64U]; + unsigned char slen[8U]; + unsigned char *c; + unsigned char *mac; + unsigned int i; + + if (outlen_p != NULL) { + *outlen_p = 0U; + } + if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGESBYTES_MAX) { + sodium_misuse(); + } + crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + crypto_onetimeauth_poly1305_init(&poly1305_state, block); + sodium_memzero(block, sizeof block); + + crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + (0x10 - adlen) & 0xf); + memset(block, 0, sizeof block); + block[0] = tag; + + crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + state->nonce, 1U, state->k); + crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + out[0] = block[0]; + + c = out + (sizeof tag); + crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); + crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + crypto_onetimeauth_poly1305_update + (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + STORE64_LE(slen, (sizeof block) + mlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + + mac = c + mlen; + crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + sodium_memzero(&poly1305_state, sizeof poly1305_state); + + for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + state->nonce[i] ^= mac[i]; + } + sodium_increment(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + sodium_is_zero(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + crypto_secretstream_xchacha20poly1305_rekey(state); + } + if (outlen_p != NULL) { + *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; + } + return 0; +} + +int +crypto_secretstream_xchacha20poly1305_pull + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, + const unsigned char *in, unsigned long long inlen, + const unsigned char *ad, unsigned long long adlen) +{ + crypto_onetimeauth_poly1305_state poly1305_state; + unsigned char block[64U]; + unsigned char slen[8U]; + unsigned char mac[crypto_onetimeauth_poly1305_BYTES]; + const unsigned char *c; + const unsigned char *stored_mac; + unsigned long long mlen; + unsigned int i; + unsigned char tag; + + if (mlen_p != NULL) { + *mlen_p = 0U; + } + if (tag_p != NULL) { + *tag_p = 0xff; + } + if (inlen < crypto_secretstream_xchacha20poly1305_ABYTES) { + return -1; + } + mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; + if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGESBYTES_MAX) { + sodium_misuse(); + } + crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + crypto_onetimeauth_poly1305_init(&poly1305_state, block); + sodium_memzero(block, sizeof block); + + crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + (0x10 - adlen) & 0xf); + + memset(block, 0, sizeof block); + block[0] = in[0]; + crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + state->nonce, 1U, state->k); + tag = block[0]; + block[0] = in[0]; + crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + + c = in + (sizeof tag); + crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + crypto_onetimeauth_poly1305_update + (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + STORE64_LE(slen, (sizeof block) + mlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + sodium_memzero(&poly1305_state, sizeof poly1305_state); + + stored_mac = c + mlen; + if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { + sodium_memzero(mac, sizeof mac); + return -1; + } + + crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); + for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + state->nonce[i] ^= mac[i]; + } + sodium_increment(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + sodium_is_zero(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + crypto_secretstream_xchacha20poly1305_rekey(state); + } + if (mlen_p != NULL) { + *mlen_p = mlen; + } + if (tag_p != NULL) { + *tag_p = tag; + } + return 0; +} + +size_t +crypto_secretstream_xchacha20poly1305_statebytes(void) +{ + return sizeof(crypto_secretstream_xchacha20poly1305_state); +} diff --git a/src/libsodium/include/Makefile.am b/src/libsodium/include/Makefile.am index a63d127a..06f3f4a4 100644 --- a/src/libsodium/include/Makefile.am +++ b/src/libsodium/include/Makefile.am @@ -36,6 +36,7 @@ SODIUM_EXPORT = \ sodium/crypto_secretbox.h \ sodium/crypto_secretbox_xchacha20poly1305.h \ sodium/crypto_secretbox_xsalsa20poly1305.h \ + sodium/crypto_secretstream_xchacha20poly1305.h \ sodium/crypto_shorthash.h \ sodium/crypto_shorthash_siphash24.h \ sodium/crypto_sign.h \ diff --git a/src/libsodium/include/sodium.h b/src/libsodium/include/sodium.h index 1f79e87b..8c3e8bc7 100644 --- a/src/libsodium/include/sodium.h +++ b/src/libsodium/include/sodium.h @@ -35,6 +35,7 @@ #include "sodium/crypto_scalarmult_curve25519.h" #include "sodium/crypto_secretbox.h" #include "sodium/crypto_secretbox_xsalsa20poly1305.h" +#include "sodium/crypto_secretstream_xchacha20poly1305.h" #include "sodium/crypto_shorthash.h" #include "sodium/crypto_shorthash_siphash24.h" #include "sodium/crypto_sign.h" diff --git a/src/libsodium/include/sodium/crypto_pwhash.h b/src/libsodium/include/sodium/crypto_pwhash.h index da5f5461..d0b8bba7 100644 --- a/src/libsodium/include/sodium/crypto_pwhash.h +++ b/src/libsodium/include/sodium/crypto_pwhash.h @@ -94,6 +94,10 @@ size_t crypto_pwhash_opslimit_sensitive(void); SODIUM_EXPORT size_t crypto_pwhash_memlimit_sensitive(void); +/* + * With this function, do not forget to store all parameters, including the + * algorithm identifier in order to produce deterministic output. + */ SODIUM_EXPORT int crypto_pwhash(unsigned char * const out, unsigned long long outlen, const char * const passwd, unsigned long long passwdlen, @@ -101,6 +105,11 @@ int crypto_pwhash(unsigned char * const out, unsigned long long outlen, unsigned long long opslimit, size_t memlimit, int alg) __attribute__ ((warn_unused_result)); +/* + * The output string already includes all the required parameters, including + * the algorithm identifier. The string is all that has to be stored in + * order to verify a password. + */ SODIUM_EXPORT int crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], const char * const passwd, unsigned long long passwdlen, diff --git a/src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h b/src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h new file mode 100644 index 00000000..9b782d3c --- /dev/null +++ b/src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h @@ -0,0 +1,84 @@ +#ifndef crypto_secretstream_xchacha20poly1305_H +#define crypto_secretstream_xchacha20poly1305_H + +#include + +#include "crypto_aead_xchacha20poly1305.h" +#include "crypto_stream_chacha20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_secretstream_xchacha20poly1305_ABYTES \ + (1U + crypto_aead_xchacha20poly1305_ietf_ABYTES) + +#define crypto_secretstream_xchacha20poly1305_INITBYTES \ + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES + +#define crypto_secretstream_xchacha20poly1305_KEYBYTES \ + crypto_aead_xchacha20poly1305_ietf_KEYBYTES + +#define crypto_secretstream_xchacha20poly1305_MESSAGESBYTES_MAX \ + ((1ULL << 32) - 2ULL * 64ULL) + +#define crypto_secretstream_xchacha20poly1305_TAG_MESSAGE 0x00 +#define crypto_secretstream_xchacha20poly1305_TAG_PUSH 0x01 +#define crypto_secretstream_xchacha20poly1305_TAG_REKEY 0x02 + +#define crypto_secretstream_xchacha20poly1305_TAG_FINAL \ + (crypto_secretstream_xchacha20poly1305_TAG_PUSH | \ + crypto_secretstream_xchacha20poly1305_TAG_REKEY) + +typedef struct crypto_secretstream_xchacha20poly1305_state { + unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]; + unsigned char nonce[crypto_stream_chacha20_ietf_NONCEBYTES]; + unsigned char _pad[8]; +} crypto_secretstream_xchacha20poly1305_state; + +SODIUM_EXPORT +size_t crypto_secretstream_xchacha20poly1305_statebytes(void); + +SODIUM_EXPORT +void crypto_secretstream_xchacha20poly1305_keygen + (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_init_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char out[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_init_pull + (crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char in[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +void crypto_secretstream_xchacha20poly1305_rekey + (crypto_secretstream_xchacha20poly1305_state *state); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *out, unsigned long long *outlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, unsigned char tag); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_pull + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, + const unsigned char *in, unsigned long long inlen, + const unsigned char *ad, unsigned long long adlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libsodium/include/sodium/utils.h b/src/libsodium/include/sodium/utils.h index 0a7aadb4..ab00b0b1 100644 --- a/src/libsodium/include/sodium/utils.h +++ b/src/libsodium/include/sodium/utils.h @@ -61,6 +61,22 @@ int sodium_hex2bin(unsigned char * const bin, const size_t bin_maxlen, const char * const ignore, size_t * const bin_len, const char ** const hex_end); +#define sodium_base64_VARIANT_ORIGINAL 1 +#define sodium_base64_VARIANT_ORIGINAL_NO_PADDING 3 +#define sodium_base64_VARIANT_URLSAFE 5 +#define sodium_base64_VARIANT_URLSAFE_NO_PADDING 7 + +SODIUM_EXPORT +char *sodium_bin2base64(char * const b64, const size_t b64_maxlen, + const unsigned char * const bin, const size_t bin_len, + const int variant); + +SODIUM_EXPORT +int sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen, + const char * const b64, const size_t b64_len, + const char * const ignore, size_t * const bin_len, + const char ** const b64_end, const int variant); + SODIUM_EXPORT int sodium_mlock(void * const addr, const size_t len); diff --git a/src/libsodium/sodium/codecs.c b/src/libsodium/sodium/codecs.c new file mode 100644 index 00000000..7e203a5c --- /dev/null +++ b/src/libsodium/sodium/codecs.c @@ -0,0 +1,315 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "utils.h" + +/* Derived from original code by CodesInChaos */ +char * +sodium_bin2hex(char *const hex, const size_t hex_maxlen, + const unsigned char *const bin, const size_t bin_len) +{ + size_t i = (size_t) 0U; + unsigned int x; + int b; + int c; + + if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + while (i < bin_len) { + c = bin[i] & 0xf; + b = bin[i] >> 4; + x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | + (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); + hex[i * 2U] = (char) x; + x >>= 8; + hex[i * 2U + 1U] = (char) x; + i++; + } + hex[i * 2U] = 0U; + + return hex; +} + +int +sodium_hex2bin(unsigned char *const bin, const size_t bin_maxlen, + const char *const hex, const size_t hex_len, + const char *const ignore, size_t *const bin_len, + const char **const hex_end) +{ + size_t bin_pos = (size_t) 0U; + size_t hex_pos = (size_t) 0U; + int ret = 0; + unsigned char c; + unsigned char c_acc = 0U; + unsigned char c_alpha0, c_alpha; + unsigned char c_num0, c_num; + unsigned char c_val; + unsigned char state = 0U; + + while (hex_pos < hex_len) { + c = (unsigned char) hex[hex_pos]; + c_num = c ^ 48U; + c_num0 = (c_num - 10U) >> 8; + c_alpha = (c & ~32U) - 55U; + c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8; + if ((c_num0 | c_alpha0) == 0U) { + if (ignore != NULL && state == 0U && strchr(ignore, c) != NULL) { + hex_pos++; + continue; + } + break; + } + c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha); + if (bin_pos >= bin_maxlen) { + ret = -1; + errno = ERANGE; + break; + } + if (state == 0U) { + c_acc = c_val * 16U; + } else { + bin[bin_pos++] = c_acc | c_val; + } + state = ~state; + hex_pos++; + } + if (state != 0U) { + hex_pos--; + } + if (hex_end != NULL) { + *hex_end = &hex[hex_pos]; + } + if (ret != 0) { + bin_pos = (size_t) 0U; + } + if (bin_len != NULL) { + *bin_len = bin_pos; + } + return ret; +} + +/* + * Some macros for constant-time comparisons. These work over values in + * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". + * + * Original code by Thomas Pornin. + */ +#define EQ(x, y) \ + ((((0U - ((unsigned int) (x) ^ (unsigned int) (y))) >> 8) & 0xFF) ^ 0xFF) +#define GT(x, y) ((((unsigned int) (y) - (unsigned int) (x)) >> 8) & 0xFF) +#define GE(x, y) (GT(y, x) ^ 0xFF) +#define LT(x, y) GT(y, x) +#define LE(x, y) GE(y, x) + +static int +b64_byte_to_char(unsigned int x) +{ + return (LT(x, 26) & (x + 'A')) | + (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | + (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') | + (EQ(x, 63) & '/'); +} + +static unsigned int +b64_char_to_byte(int c) +{ + const unsigned int x = + (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | + (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | + (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | + (EQ(c, '/') & 63); + + return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); +} + +static int +b64_byte_to_urlsafe_char(unsigned int x) +{ + return (LT(x, 26) & (x + 'A')) | + (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | + (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '-') | + (EQ(x, 63) & '_'); +} + +static unsigned int +b64_urlsafe_char_to_byte(int c) +{ + const unsigned x = + (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | + (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | + (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '-') & 62) | + (EQ(c, '_') & 63); + + return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); +} + + +#define VARIANT_NO_PADDING_MASK 0x2U +#define VARIANT_URLSAFE_MASK 0x4U + +char * +sodium_bin2base64(char * const b64, const size_t b64_maxlen, + const unsigned char * const bin, const size_t bin_len, + const int variant) +{ + size_t acc_len = (size_t) 0; + size_t b64_len; + size_t b64_pos = (size_t) 0; + size_t bin_pos = (size_t) 0; + size_t nibbles; + size_t remainder; + unsigned int acc = 0U; + + if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) { + sodium_misuse(); + } + nibbles = bin_len / 3; + remainder = bin_len - 3 * nibbles; + b64_len = nibbles * 4; + if (remainder != 0) { + if ((((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) { + b64_len += 4; + } else { + b64_len += 2; + if (remainder == 2) { + b64_len++; + } + } + } + if (b64_maxlen <= b64_len) { + sodium_misuse(); + } + if ((((unsigned int) variant) & VARIANT_URLSAFE_MASK) != 0U) { + while (bin_pos < bin_len) { + acc = (acc << 8) + bin[bin_pos++]; + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc >> acc_len) & 0x3F); + } + } + if (acc_len > 0) { + b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc << (6 - acc_len)) & 0x3F); + } + } else { + while (bin_pos < bin_len) { + acc = (acc << 8) + bin[bin_pos++]; + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + b64[b64_pos++] = (char) b64_byte_to_char((acc >> acc_len) & 0x3F); + } + } + if (acc_len > 0) { + b64[b64_pos++] = (char) b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); + } + } + assert(b64_pos <= b64_len); + while (b64_pos < b64_len) { + b64[b64_pos++] = '='; + } + b64[b64_pos++] = 0; + + return b64; +} + +static int +_sodium_base642bin_skip_padding(const char * const b64, const size_t b64_len, + size_t * const b64_pos_p, + const char * const ignore, size_t padding_len) +{ + int c; + + while (padding_len > 0) { + if (*b64_pos_p >= b64_len) { + errno = ERANGE; + return -1; + } + c = b64[*b64_pos_p]; + if (c == '=') { + padding_len--; + } else if (ignore == NULL || strchr(ignore, c) == NULL) { + errno = EINVAL; + return -1; + } + (*b64_pos_p)++; + } + return 0; +} + +int +sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen, + const char * const b64, const size_t b64_len, + const char * const ignore, size_t * const bin_len, + const char ** const b64_end, const int variant) +{ + size_t acc_len = (size_t) 0; + size_t b64_pos = (size_t) 0; + size_t bin_pos = (size_t) 0; + int is_urlsafe; + int ret = 0; + unsigned int acc = 0U; + unsigned int d; + char c; + + if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) { + sodium_misuse(); + } + is_urlsafe = ((unsigned int) variant) & VARIANT_URLSAFE_MASK; + while (b64_pos < b64_len) { + c = b64[b64_pos]; + if (is_urlsafe) { + d = b64_urlsafe_char_to_byte(c); + } else { + d = b64_char_to_byte(c); + } + if (d == 0xFF) { + if (ignore != NULL && strchr(ignore, c) != NULL) { + if (b64_pos >= b64_len) { + errno = ERANGE; + ret = -1; + break; + } + b64_pos++; + continue; + } + break; + } + acc = (acc << 6) + d; + acc_len += 6; + if (acc_len >= 8) { + acc_len -= 8; + if (bin_pos >= bin_maxlen) { + errno = ERANGE; + ret = -1; + break; + } + bin[bin_pos++] = (acc >> acc_len) & 0xFF; + } + b64_pos++; + } + if (acc_len > 4U || (acc & ((1U << acc_len) - 1U)) != 0U) { + ret = -1; + } else if (ret == 0 && + (((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) { + ret = _sodium_base642bin_skip_padding(b64, b64_len, &b64_pos, ignore, + acc_len / 2); + } + if (ret != 0) { + bin_pos = (size_t) 0U; + } + if (bin_len != NULL) { + *bin_len = bin_pos; + } + if (b64_end != NULL) { + *b64_end = &b64[b64_pos]; + } + return ret; +} diff --git a/src/libsodium/sodium/utils.c b/src/libsodium/sodium/utils.c index bff6e359..e430cbb9 100644 --- a/src/libsodium/sodium/utils.c +++ b/src/libsodium/sodium/utils.c @@ -287,89 +287,6 @@ sodium_add(unsigned char *a, const unsigned char *b, const size_t len) } } -/* Derived from original code by CodesInChaos */ -char * -sodium_bin2hex(char *const hex, const size_t hex_maxlen, - const unsigned char *const bin, const size_t bin_len) -{ - size_t i = (size_t) 0U; - unsigned int x; - int b; - int c; - - if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) { - sodium_misuse(); /* LCOV_EXCL_LINE */ - } - while (i < bin_len) { - c = bin[i] & 0xf; - b = bin[i] >> 4; - x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | - (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); - hex[i * 2U] = (char) x; - x >>= 8; - hex[i * 2U + 1U] = (char) x; - i++; - } - hex[i * 2U] = 0U; - - return hex; -} - -int -sodium_hex2bin(unsigned char *const bin, const size_t bin_maxlen, - const char *const hex, const size_t hex_len, - const char *const ignore, size_t *const bin_len, - const char **const hex_end) -{ - size_t bin_pos = (size_t) 0U; - size_t hex_pos = (size_t) 0U; - int ret = 0; - unsigned char c; - unsigned char c_acc = 0U; - unsigned char c_alpha0, c_alpha; - unsigned char c_num0, c_num; - unsigned char c_val; - unsigned char state = 0U; - - while (hex_pos < hex_len) { - c = (unsigned char) hex[hex_pos]; - c_num = c ^ 48U; - c_num0 = (c_num - 10U) >> 8; - c_alpha = (c & ~32U) - 55U; - c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8; - if ((c_num0 | c_alpha0) == 0U) { - if (ignore != NULL && state == 0U && strchr(ignore, c) != NULL) { - hex_pos++; - continue; - } - break; - } - c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha); - if (bin_pos >= bin_maxlen) { - ret = -1; - errno = ERANGE; - break; - } - if (state == 0U) { - c_acc = c_val * 16U; - } else { - bin[bin_pos++] = c_acc | c_val; - } - state = ~state; - hex_pos++; - } - if (state != 0U) { - hex_pos--; - } - if (hex_end != NULL) { - *hex_end = &hex[hex_pos]; - } - if (bin_len != NULL) { - *bin_len = bin_pos; - } - return ret; -} - int _sodium_alloc_init(void) { diff --git a/test/default/Makefile.am b/test/default/Makefile.am index 2cda92e4..4e1d79d3 100644 --- a/test/default/Makefile.am +++ b/test/default/Makefile.am @@ -57,6 +57,7 @@ EXTRA_DIST = \ secretbox8.exp \ secretbox_easy.exp \ secretbox_easy2.exp \ + secretstream.exp \ shorthash.exp \ sign.exp \ siphashx24.exp \ @@ -127,6 +128,7 @@ DISTCLEANFILES = \ secretbox8.res \ secretbox_easy.res \ secretbox_easy2.res \ + secretstream.res \ shorthash.res \ sign.res \ siphashx24.res \ @@ -198,6 +200,7 @@ CLEANFILES = \ secretbox8.final \ secretbox_easy.final \ secretbox_easy2.final \ + secretstream.final \ shorthash.final \ sign.final \ siphashx24.final \ @@ -264,6 +267,7 @@ CLEANFILES = \ secretbox8.nexe \ secretbox_easy.nexe \ secretbox_easy2.nexe \ + secretstream.nexe \ shorthash.nexe \ sign.nexe \ siphashx24.nexe \ @@ -340,6 +344,7 @@ TESTS_TARGETS = \ secretbox8 \ secretbox_easy \ secretbox_easy2 \ + secretstream \ shorthash \ sign \ sodium_core \ @@ -525,6 +530,9 @@ secretbox_easy_LDADD = $(TESTS_LDADD) secretbox_easy2_SOURCE = cmptest.h secretbox_easy2.c secretbox_easy2_LDADD = $(TESTS_LDADD) +secretstream_SOURCE = cmptest.h secretstream.c +secretstream_LDADD = $(TESTS_LDADD) + shorthash_SOURCE = cmptest.h shorthash.c shorthash_LDADD = $(TESTS_LDADD) diff --git a/test/default/secretstream.c b/test/default/secretstream.c new file mode 100644 index 00000000..bd080667 --- /dev/null +++ b/test/default/secretstream.c @@ -0,0 +1,181 @@ + +#define TEST_NAME "secretstream" +#include "cmptest.h" + +int +main(void) +{ + crypto_secretstream_xchacha20poly1305_state *state; + unsigned char *header; + unsigned char *k; + unsigned char *c1, *c2, *c3; + unsigned char *m1, *m2, *m3; + unsigned char *m1_, *m2_, *m3_; + size_t m1_len, m2_len, m3_len; + int ret; + unsigned char tag; + + state = (crypto_secretstream_xchacha20poly1305_state *) + sodium_malloc(crypto_secretstream_xchacha20poly1305_statebytes()); + header = (unsigned char *) + sodium_malloc(crypto_secretstream_xchacha20poly1305_INITBYTES); + + m1_len = randombytes_uniform(1000); + m2_len = randombytes_uniform(1000); + m3_len = randombytes_uniform(1000); + + c1 = (unsigned char *) + sodium_malloc(m1_len + crypto_secretstream_xchacha20poly1305_ABYTES); + c2 = (unsigned char *) + sodium_malloc(m2_len + crypto_secretstream_xchacha20poly1305_ABYTES); + c3 = (unsigned char *) + sodium_malloc(m3_len + crypto_secretstream_xchacha20poly1305_ABYTES); + + m1 = (unsigned char *) sodium_malloc(m1_len); + m2 = (unsigned char *) sodium_malloc(m2_len); + m3 = (unsigned char *) sodium_malloc(m3_len); + m1_ = (unsigned char *) sodium_malloc(m1_len); + m2_ = (unsigned char *) sodium_malloc(m2_len); + m3_ = (unsigned char *) sodium_malloc(m3_len); + + randombytes_buf(m1, m1_len); + memcpy(m1_, m1, m1_len); + randombytes_buf(m2, m2_len); + memcpy(m2_, m2, m2_len); + randombytes_buf(m3, m3_len); + memcpy(m3_, m3, m3_len); + + k = (unsigned char *) + sodium_malloc(crypto_secretstream_xchacha20poly1305_KEYBYTES); + crypto_secretstream_xchacha20poly1305_keygen(k); + + /* push */ + + ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k); + assert(ret == 0); + + ret = crypto_secretstream_xchacha20poly1305_push + (state, c1, NULL, m1, m1_len, NULL, 0, 0); + assert(ret == 0); + + ret = crypto_secretstream_xchacha20poly1305_push + (state, c2, NULL, m2, m2_len, NULL, 0, 0); + assert(ret == 0); + + ret = crypto_secretstream_xchacha20poly1305_push + (state, c3, NULL, m3, m3_len, NULL, 0, + crypto_secretstream_xchacha20poly1305_TAG_FINAL); + assert(ret == 0); + + /* pull */ + + ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k); + assert(ret == 0); + + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m1, NULL, &tag, + c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == 0); + assert(tag == 0); + assert(memcmp(m1, m1_, m1_len) == 0); + + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m2, NULL, &tag, + c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == 0); + assert(tag == 0); + assert(memcmp(m2, m2_, m2_len) == 0); + + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m3, NULL, &tag, + c3, m3_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == 0); + assert(tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL); + assert(memcmp(m3, m3_, m3_len) == 0); + + /* previous with FINAL tag */ + + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m3, NULL, &tag, + c3, m3_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == -1); + + /* previous without a tag */ + + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m2, NULL, &tag, + c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == -1); + + /* without explicit rekeying */ + + ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k); + assert(ret == 0); + ret = crypto_secretstream_xchacha20poly1305_push + (state, c1, NULL, m1, m1_len, NULL, 0, 0); + assert(ret == 0); + ret = crypto_secretstream_xchacha20poly1305_push + (state, c2, NULL, m2, m2_len, NULL, 0, 0); + assert(ret == 0); + + ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k); + assert(ret == 0); + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m1, NULL, &tag, + c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == 0); + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m2, NULL, &tag, + c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == 0); + + /* with explicit rekeying */ + + ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k); + assert(ret == 0); + ret = crypto_secretstream_xchacha20poly1305_push + (state, c1, NULL, m1, m1_len, NULL, 0, 0); + assert(ret == 0); + + crypto_secretstream_xchacha20poly1305_rekey(state); + + ret = crypto_secretstream_xchacha20poly1305_push + (state, c2, NULL, m2, m2_len, NULL, 0, 0); + assert(ret == 0); + + ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k); + assert(ret == 0); + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m1, NULL, &tag, + c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == 0); + + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m2, NULL, &tag, + c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == -1); + + crypto_secretstream_xchacha20poly1305_rekey(state); + + ret = crypto_secretstream_xchacha20poly1305_pull + (state, m2, NULL, &tag, + c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0); + assert(ret == 0); + + sodium_free(m3_); + sodium_free(m2_); + sodium_free(m1_); + sodium_free(m3); + sodium_free(m2); + sodium_free(m1); + sodium_free(c3); + sodium_free(c2); + sodium_free(c1); + sodium_free(k); + sodium_free(header); + sodium_free(state); + + printf("OK\n"); + + return 0; +} diff --git a/test/default/secretstream.exp b/test/default/secretstream.exp new file mode 100644 index 00000000..d86bac9d --- /dev/null +++ b/test/default/secretstream.exp @@ -0,0 +1 @@ +OK diff --git a/test/default/sodium_utils.c b/test/default/sodium_utils.c index b9b93d53..09c22544 100644 --- a/test/default/sodium_utils.c +++ b/test/default/sodium_utils.c @@ -4,20 +4,26 @@ int main(void) { - unsigned char buf_add[1000]; - unsigned char buf1[1000]; - unsigned char buf2[1000]; - unsigned char buf1_rev[1000]; - unsigned char buf2_rev[1000]; - char buf3[33]; - unsigned char buf4[4]; - unsigned char nonce[24]; - char nonce_hex[49]; - const char * hex; - const char * hex_end; - size_t bin_len; - unsigned int i; - unsigned int j; + unsigned char buf_add[1000]; + unsigned char buf1[1000]; + unsigned char buf2[1000]; + unsigned char buf1_rev[1000]; + unsigned char buf2_rev[1000]; + char buf3[33]; + unsigned char buf4[4]; + unsigned char nonce[24]; + char nonce_hex[49]; + const char *b64; + char *b64_; + const char *b64_end; + unsigned char *bin; + const char *hex; + const char *hex_end; + size_t b64_len; + size_t bin_len; + size_t hex_len; + unsigned int i; + unsigned int j; randombytes_buf(buf1, sizeof buf1); memcpy(buf2, buf1, sizeof buf2); @@ -41,8 +47,8 @@ main(void) hex = "Cafe : 6942"; sodium_hex2bin(buf4, sizeof buf4, hex, strlen(hex), ": ", &bin_len, NULL); - printf("%lu:%02x%02x%02x%02x\n", (unsigned long) bin_len, buf4[2], buf4[3], - buf4[2], buf4[3]); + printf("%lu:%02x%02x%02x%02x\n", (unsigned long) bin_len, + buf4[2], buf4[3], buf4[2], buf4[3]); hex = "deadbeef"; if (sodium_hex2bin(buf1, 1U, hex, 8U, NULL, &bin_len, &hex_end) != -1) { @@ -72,6 +78,97 @@ main(void) } printf("dt5: %ld\n", (long) (hex_end - hex)); + printf("%s\n", + sodium_bin2base64(buf3, 31U, (const unsigned char *) "\xfb\xf0\xf1" "0123456789ABCDEFab", + 21U, sodium_base64_VARIANT_ORIGINAL)); + printf("%s\n", + sodium_bin2base64(buf3, 33U, (const unsigned char *) "\xfb\xf0\xf1" "0123456789ABCDEFabc", + 22U, sodium_base64_VARIANT_ORIGINAL_NO_PADDING)); + printf("%s\n", + sodium_bin2base64(buf3, 31U, (const unsigned char *) "\xfb\xf0\xf1" "0123456789ABCDEFab", + 21U, sodium_base64_VARIANT_URLSAFE)); + printf("%s\n", + sodium_bin2base64(buf3, 33U, (const unsigned char *) "\xfb\xf0\xf1" "0123456789ABCDEFabc", + 22U, sodium_base64_VARIANT_URLSAFE_NO_PADDING)); + printf("%s\n", + sodium_bin2base64(buf3, 1U, NULL, + 0U, sodium_base64_VARIANT_ORIGINAL)); + printf("%s\n", + sodium_bin2base64(buf3, 5U, (const unsigned char *) "a", + 1U, sodium_base64_VARIANT_ORIGINAL)); + printf("%s\n", + sodium_bin2base64(buf3, 5U, (const unsigned char *) "ab", + 2U, sodium_base64_VARIANT_ORIGINAL)); + printf("%s\n", + sodium_bin2base64(buf3, 5U, (const unsigned char *) "abc", + 3U, sodium_base64_VARIANT_ORIGINAL)); + printf("%s\n", + sodium_bin2base64(buf3, 1U, NULL, + 0U, sodium_base64_VARIANT_ORIGINAL_NO_PADDING)); + printf("%s\n", + sodium_bin2base64(buf3, 3U, (const unsigned char *) "a", + 1U, sodium_base64_VARIANT_ORIGINAL_NO_PADDING)); + printf("%s\n", + sodium_bin2base64(buf3, 4U, (const unsigned char *) "ab", + 2U, sodium_base64_VARIANT_ORIGINAL_NO_PADDING)); + printf("%s\n", + sodium_bin2base64(buf3, 5U, (const unsigned char *) "abc", + 3U, sodium_base64_VARIANT_ORIGINAL_NO_PADDING)); + + b64 = "VGhpcyBpcyBhIGpvdXJu" "\n" "ZXkgaW50by" " " "Bzb3VuZA=="; + memset(buf4, '*', sizeof buf4); + assert(sodium_base642bin(buf4, sizeof buf4, b64, strlen(b64), "\n\r ", &bin_len, + &b64_end, sodium_base64_VARIANT_ORIGINAL) == -1); + buf4[bin_len] = 0; + printf("[%s]\n", (const char *) buf4); + printf("[%s]\n", b64_end); + + memset(buf1, '*', sizeof buf1); + sodium_base642bin(buf1, sizeof buf1, b64, strlen(b64), "\n\r ", &bin_len, + &b64_end, sodium_base64_VARIANT_ORIGINAL); + buf1[bin_len] = 0; + printf("[%s]\n", (const char *) buf1); + assert(*b64_end == 0); + + memset(buf1, '*', sizeof buf1); + sodium_base642bin(buf1, sizeof buf1, b64, strlen(b64), NULL, &bin_len, + &b64_end, sodium_base64_VARIANT_ORIGINAL); + buf1[bin_len] = 0; + printf("[%s]\n", (const char *) buf1); + printf("[%s]\n", b64_end); + + assert(sodium_base642bin(buf1, sizeof buf1, b64, strlen(b64), NULL, NULL, + NULL, sodium_base64_VARIANT_ORIGINAL) == 0); + + assert(sodium_base642bin(buf1, sizeof buf1, b64, strlen(b64), NULL, NULL, + NULL, sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == 0); + assert(sodium_base642bin(buf1, sizeof buf1, b64, strlen(b64), " \r\n", NULL, + NULL, sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == 0); + assert(sodium_base642bin(buf1, sizeof buf1, b64, strlen(b64), NULL, NULL, + NULL, sodium_base64_VARIANT_URLSAFE_NO_PADDING) == 0); + assert(sodium_base642bin(buf1, sizeof buf1, b64, strlen(b64), " \r\n", NULL, + NULL, sodium_base64_VARIANT_URLSAFE_NO_PADDING) == 0); + + for (i = 0; i < 1000; i++) { + assert(sizeof buf1 >= 100); + bin_len = (size_t) randombytes_uniform(100); + bin = (unsigned char *) sodium_malloc(bin_len); + b64_len = 1 + (bin_len + 2) / 3 * 4; + b64_ = (char *) sodium_malloc(b64_len); + randombytes_buf(bin, bin_len); + memcpy(buf1, bin, bin_len); + b64 = sodium_bin2base64(b64_, b64_len + 10, bin, bin_len, + sodium_base64_VARIANT_URLSAFE); + assert(b64 != NULL); + assert(sodium_base642bin(bin, bin_len + 10, b64, b64_len, + NULL, NULL, &b64_end, + sodium_base64_VARIANT_URLSAFE) == 0); + assert(b64_end == &b64[b64_len - 1]); + assert(memcmp(bin, buf1, bin_len) == 0); + sodium_free(bin); + sodium_free(b64_); + } + memset(nonce, 0, sizeof nonce); sodium_increment(nonce, sizeof nonce); printf("%s\n", diff --git a/test/default/sodium_utils.exp b/test/default/sodium_utils.exp index 030a1cb3..233dc687 100644 --- a/test/default/sodium_utils.exp +++ b/test/default/sodium_utils.exp @@ -11,6 +11,25 @@ dt2: 2 dt3: 11 dt4: 11 dt5: 11 ++/DxMDEyMzQ1Njc4OUFCQ0RFRmFi ++/DxMDEyMzQ1Njc4OUFCQ0RFRmFiYw +-_DxMDEyMzQ1Njc4OUFCQ0RFRmFi +-_DxMDEyMzQ1Njc4OUFCQ0RFRmFiYw + +YQ== +YWI= +YWJj + +YQ +YWI +YWJj +[] +[BpcyBhIGpvdXJu +ZXkgaW50by Bzb3VuZA==] +[This is a journey into sound] +[This is a journ] +[ +ZXkgaW50by Bzb3VuZA==] 010000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000 010100000000000000000000000000000000000000000000