diff --git a/src/main/java/com/pusher/client/crypto/nacl/AuthenticityException.java b/src/main/java/com/pusher/client/crypto/nacl/AuthenticityException.java new file mode 100644 index 00000000..18150119 --- /dev/null +++ b/src/main/java/com/pusher/client/crypto/nacl/AuthenticityException.java @@ -0,0 +1,27 @@ +/* +Copyright 2015 Eve Freeman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +*/ + +package com.pusher.client.crypto.nacl; + +public class AuthenticityException extends RuntimeException { +} diff --git a/src/main/java/com/pusher/client/crypto/nacl/Poly1305.java b/src/main/java/com/pusher/client/crypto/nacl/Poly1305.java new file mode 100644 index 00000000..307ebcf7 --- /dev/null +++ b/src/main/java/com/pusher/client/crypto/nacl/Poly1305.java @@ -0,0 +1,1559 @@ +/* +Copyright 2015 Eve Freeman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +*/ + +package com.pusher.client.crypto.nacl; + +public class Poly1305 { + public static int TAG_SIZE = 16; + + private static double alpham80 = 0.00000000558793544769287109375d; + private static double alpham48 = 24.0d; + private static double alpham16 = 103079215104.0d; + private static double alpha0 = 6755399441055744.0d; + private static double alpha18 = 1770887431076116955136.0d; + private static double alpha32 = 29014219670751100192948224.0d; + private static double alpha50 = 7605903601369376408980219232256.0d; + private static double alpha64 = 124615124604835863084731911901282304.0d; + private static double alpha82 = 32667107224410092492483962313449748299776.0d; + private static double alpha96 = 535217884764734955396857238543560676143529984.0d; + private static double alpha112 = 35076039295941670036888435985190792471742381031424.0d; + private static double alpha130 = 9194973245195333150150082162901855101712434733101613056.0d; + private static double scale = 0.0000000000000000000000000000000000000036734198463196484624023016788195177431833298649127735047148490821200539357960224151611328125d; + private static double offset0 = 6755408030990331.0d; + private static double offset1 = 29014256564239239022116864.0d; + private static double offset2 = 124615283061160854719918951570079744.0d; + private static double offset3 = 535219245894202480694386063513315216128475136.0d; + + private static long uint32(long x) { + return 0xFFFFFFFF & x; + } + + private static double longBitsToDouble(long bits) { + int s = ((bits >> 63) == 0) ? 1 : -1; + int e = (int) ((bits >> 52) & 0x7ffL); + long m = (e == 0) ? + (bits & 0xfffffffffffffL) << 1 : + (bits & 0xfffffffffffffL) | 0x10000000000000L; + return (double) s * (double) m * Math.pow(2, e - 1075); + } + + public static boolean verify(byte mac[], byte m[], byte key[]) { + byte tmp[] = sum(m, key); + //Util.printHex("tmp", tmp); + //Util.printHex("mac", mac); + return Subtle.constantTimeCompare(tmp, mac); + } + + // Sum generates an authenticator for m using a one-time key and puts the + // 16-byte result into out. Authenticating two different messages with the same + // key allows an attacker to forge messages at will. + public static byte[] sum(byte m[], byte key[]) { + byte r[] = key.clone(); + byte s[] = new byte[16]; + for (int i = 0; i < s.length; i++) { + s[i] = key[i + 16]; + } + + double y7; + double y6; + double y1; + double y0; + double y5; + double y4; + double x7; + double x6; + double x1; + double x0; + double y3; + double y2; + double x5; + double r3lowx0; + double x4; + double r0lowx6; + double x3; + double r3highx0; + double x2; + double r0highx6; + double r0lowx0; + double sr1lowx6; + double r0highx0; + double sr1highx6; + double sr3low; + double r1lowx0; + double sr2lowx6; + double r1highx0; + double sr2highx6; + double r2lowx0; + double sr3lowx6; + double r2highx0; + double sr3highx6; + double r1highx4; + double r1lowx4; + double r0highx4; + double r0lowx4; + double sr3highx4; + double sr3lowx4; + double sr2highx4; + double sr2lowx4; + double r0lowx2; + double r0highx2; + double r1lowx2; + double r1highx2; + double r2lowx2; + double r2highx2; + double sr3lowx2; + double sr3highx2; + double z0; + double z1; + double z2; + double z3; + long m0; + long m1; + long m2; + long m3; + long m00;//uint32 + long m01;//uint32 + long m02;//uint32 + long m03;//uint32 + long m10;//uint32 + long m11;//uint32 + long m12;//uint32 + long m13;//uint32 + long m20;//uint32 + long m21;//uint32 + long m22;//uint32 + long m23;//uint32 + long m30;//uint32 + long m31;//uint32 + long m32;//uint32 + long m33;//uint64 + long lbelow2;//int32 + long lbelow3;//int32 + long lbelow4;//int32 + long lbelow5;//int32 + long lbelow6;//int32 + long lbelow7;//int32 + long lbelow8;//int32 + long lbelow9;//int32 + long lbelow10;//int32 + long lbelow11;//int32 + long lbelow12;//int32 + long lbelow13;//int32 + long lbelow14;//int32 + long lbelow15;//int32 + long s00;//uint32 + long s01;//uint32 + long s02;//uint32 + long s03;//uint32 + long s10;//uint32 + long s11;//uint32 + long s12;//uint32 + long s13;//uint32 + long s20;//uint32 + long s21;//uint32 + long s22;//uint32 + long s23;//uint32 + long s30;//uint32 + long s31;//uint32 + long s32;//uint32 + long s33;//uint32 + long bits32;//uint64 + long f;//uint64 + long f0;//uint64 + long f1;//uint64 + long f2;//uint64 + long f3;//uint64 + long f4;//uint64 + long g;//uint64 + long g0;//uint64 + long g1;//uint64 + long g2;//uint64 + long g3;//uint64 + long g4;//uint64 + + long p = 0; + + int l = m.length; + + long r00 = 0xFF & r[0]; + long r01 = 0xFF & r[1]; + long r02 = 0xFF & r[2]; + long r0 = 2151; + + long r03 = 0xFF & r[3]; + r03 &= 15; + r0 <<= 51; + + long r10 = 0xFF & r[4]; + r10 &= 252; + r01 <<= 8; + r0 += r00; + + long r11 = 0xFF & r[5]; + r02 <<= 16; + r0 += r01; + + long r12 = 0xFF & r[6]; + r03 <<= 24; + r0 += r02; + + long r13 = 0xFF & r[7]; + r13 &= 15; + long r1 = 2215; + r0 += r03; + + long d0 = r0; + r1 <<= 51; + long r2 = 2279; + + long r20 = 0xFF & r[8]; + r20 &= 252; + r11 <<= 8; + r1 += r10; + + long r21 = 0xFF & r[9]; + r12 <<= 16; + r1 += r11; + + long r22 = 0xFF & r[10]; + r13 <<= 24; + r1 += r12; + + long r23 = 0xFF & r[11]; + r23 &= 15; + r2 <<= 51; + r1 += r13; + + long d1 = r1; + r21 <<= 8; + r2 += r20; + + long r30 = 0xFF & r[12]; + r30 &= 252; + r22 <<= 16; + r2 += r21; + + long r31 = 0xFF & r[13]; + r23 <<= 24; + r2 += r22; + + long r32 = 0xFF & r[14]; + r2 += r23; + long r3 = 2343; + + long d2 = r2; + r3 <<= 51; + + long r33 = 0xFF & r[15]; + r33 &= 15; + r31 <<= 8; + r3 += r30; + + r32 <<= 16; + r3 += r31; + + r33 <<= 24; + r3 += r32; + + r3 += r33; + double h0 = alpha32 - alpha32; + + long d3 = r3; + double h1 = alpha32 - alpha32; + + double h2 = alpha32 - alpha32; + + double h3 = alpha32 - alpha32; + + double h4 = alpha32 - alpha32; + + double r0low = Double.longBitsToDouble(d0); + double h5 = alpha32 - alpha32; + + double r1low = longBitsToDouble(d1); + double h6 = alpha32 - alpha32; + + double r2low = Double.longBitsToDouble(d2); + double h7 = alpha32 - alpha32; + + r0low -= alpha0; + + r1low -= alpha32; + + r2low -= alpha64; + + double r0high = r0low + alpha18; + + double r3low = Double.longBitsToDouble(d3); + + double r1high = r1low + alpha50; + double sr1low = scale * r1low; + + double r2high = r2low + alpha82; + double sr2low = scale * r2low; + + r0high -= alpha18; + double r0high_stack = r0high; + + r3low -= alpha96; + + r1high -= alpha50; + double r1high_stack = r1high; + + double sr1high = sr1low + alpham80; + + r0low -= r0high; + + r2high -= alpha82; + sr3low = scale * r3low; + + double sr2high = sr2low + alpham48; + + r1low -= r1high; + double r1low_stack = r1low; + + sr1high -= alpham80; + double sr1high_stack = sr1high; + + r2low -= r2high; + double r2low_stack = r2low; + + sr2high -= alpham48; + double sr2high_stack = sr2high; + + double r3high = r3low + alpha112; + double r0low_stack = r0low; + + sr1low -= sr1high; + double sr1low_stack = sr1low; + + double sr3high = sr3low + alpham16; + double r2high_stack = r2high; + + sr2low -= sr2high; + double sr2low_stack = sr2low; + + r3high -= alpha112; + double r3high_stack = r3high; + + sr3high -= alpham16; + double sr3high_stack = sr3high; + + r3low -= r3high; + double r3low_stack = r3low; + + sr3low -= sr3high; + double sr3low_stack = sr3low; + + + if (!(l < 16)) { + m00 = 0xFF & m[(int) p]; + m0 = 2151; + + m0 <<= 51; + m1 = 2215; + m01 = 0xFF & m[(int) p + 1]; + + m1 <<= 51; + m2 = 2279; + m02 = 0xFF & m[(int) p + 2]; + + m2 <<= 51; + m3 = 2343; + m03 = 0xFF & (m[(int) p + 3]); + + m10 = 0xFF & (m[(int) p + 4]); + m01 <<= 8; + m0 += m00; + + m11 = 0xFF & (m[(int) p + 5]); + m02 <<= 16; + m0 += m01; + + m12 = 0xFF & (m[(int) p + 6]); + m03 <<= 24; + m0 += m02; + + m13 = 0xFF & (m[(int) p + 7]); + m3 <<= 51; + m0 += m03; + + m20 = 0xFF & (m[(int) p + 8]); + m11 <<= 8; + m1 += m10; + + m21 = 0xFF & (m[(int) p + 9]); + m12 <<= 16; + m1 += m11; + + m22 = 0xFF & (m[(int) p + 10]); + m13 <<= 24; + m1 += m12; + + m23 = 0xFF & (m[(int) p + 11]); + m1 += m13; + + m30 = 0xFF & (m[(int) p + 12]); + m21 <<= 8; + m2 += m20; + + m31 = 0xFF & (m[(int) p + 13]); + m22 <<= 16; + m2 += m21; + + m32 = 0xFF & (m[(int) p + 14]); + m23 <<= 24; + m2 += m22; + + m33 = 0xFF & (m[(int) p + 15]); + m2 += m23; + + d0 = m0; + m31 <<= 8; + m3 += m30; + + d1 = m1; + m32 <<= 16; + m3 += m31; + + d2 = m2; + m33 += 256; + + m33 <<= 24; + m3 += m32; + + m3 += m33; + d3 = m3; + + p += 16; + l -= 16; + + z0 = Double.longBitsToDouble(d0); + + z1 = Double.longBitsToDouble(d1); + + z2 = Double.longBitsToDouble(d2); + + z3 = Double.longBitsToDouble(d3); + + z0 -= alpha0; + + z1 -= alpha32; + + z2 -= alpha64; + + z3 -= alpha96; + + h0 += z0; + + h1 += z1; + + h3 += z2; + + h5 += z3; + + while (l >= 16) { + //multiplyaddatleast16bytes: + + m2 = 2279; + m20 = 0xFF & (m[(int) p + 8]); + y7 = h7 + alpha130; + + m2 <<= 51; + m3 = 2343; + m21 = 0xFF & (m[(int) p + 9]); + y6 = h6 + alpha130; + + m3 <<= 51; + m0 = 2151; + m22 = 0xFF & (m[(int) p + 10]); + y1 = h1 + alpha32; + + m0 <<= 51; + m1 = 2215; + m23 = 0xFF & (m[(int) p + 11]); + y0 = h0 + alpha32; + + m1 <<= 51; + m30 = 0xFF & (m[(int) p + 12]); + y7 -= alpha130; + + m21 <<= 8; + m2 += m20; + m31 = 0xFF & (m[(int) p + 13]); + y6 -= alpha130; + + m22 <<= 16; + m2 += m21; + m32 = 0xFF & (m[(int) p + 14]); + y1 -= alpha32; + + m23 <<= 24; + m2 += m22; + m33 = 0xFF & (m[(int) p + 15]); + y0 -= alpha32; + + m2 += m23; + m00 = 0xFF & (m[(int) p + 0]); + y5 = h5 + alpha96; + + m31 <<= 8; + m3 += m30; + m01 = 0xFF & (m[(int) p + 1]); + y4 = h4 + alpha96; + + m32 <<= 16; + m02 = 0xFF & (m[(int) p + 2]); + x7 = h7 - y7; + y7 *= scale; + + m33 += 256; + m03 = 0xFF & (m[(int) p + 3]); + x6 = h6 - y6; + y6 *= scale; + + m33 <<= 24; + m3 += m31; + m10 = 0xFF & (m[(int) p + 4]); + x1 = h1 - y1; + + m01 <<= 8; + m3 += m32; + m11 = 0xFF & (m[(int) p + 5]); + x0 = h0 - y0; + + m3 += m33; + m0 += m00; + m12 = 0xFF & (m[(int) p + 6]); + y5 -= alpha96; + + m02 <<= 16; + m0 += m01; + m13 = 0xFF & (m[(int) p + 7]); + y4 -= alpha96; + + m03 <<= 24; + m0 += m02; + d2 = m2; + x1 += y7; + + m0 += m03; + d3 = m3; + x0 += y6; + + m11 <<= 8; + m1 += m10; + d0 = m0; + x7 += y5; + + m12 <<= 16; + m1 += m11; + x6 += y4; + + m13 <<= 24; + m1 += m12; + y3 = h3 + alpha64; + + m1 += m13; + d1 = m1; + y2 = h2 + alpha64; + + x0 += x1; + + x6 += x7; + + y3 -= alpha64; + r3low = r3low_stack; + + y2 -= alpha64; + r0low = r0low_stack; + + x5 = h5 - y5; + r3lowx0 = r3low * x0; + r3high = r3high_stack; + + x4 = h4 - y4; + r0lowx6 = r0low * x6; + r0high = r0high_stack; + + x3 = h3 - y3; + r3highx0 = r3high * x0; + sr1low = sr1low_stack; + + x2 = h2 - y2; + r0highx6 = r0high * x6; + sr1high = sr1high_stack; + + x5 += y3; + r0lowx0 = r0low * x0; + r1low = r1low_stack; + + h6 = r3lowx0 + r0lowx6; + sr1lowx6 = sr1low * x6; + r1high = r1high_stack; + + x4 += y2; + r0highx0 = r0high * x0; + sr2low = sr2low_stack; + + h7 = r3highx0 + r0highx6; + sr1highx6 = sr1high * x6; + sr2high = sr2high_stack; + + x3 += y1; + r1lowx0 = r1low * x0; + r2low = r2low_stack; + + h0 = r0lowx0 + sr1lowx6; + sr2lowx6 = sr2low * x6; + r2high = r2high_stack; + + x2 += y0; + r1highx0 = r1high * x0; + sr3low = sr3low_stack; + + h1 = r0highx0 + sr1highx6; + sr2highx6 = sr2high * x6; + sr3high = sr3high_stack; + + x4 += x5; + r2lowx0 = r2low * x0; + z2 = Double.longBitsToDouble(d2); + + h2 = r1lowx0 + sr2lowx6; + sr3lowx6 = sr3low * x6; + + x2 += x3; + r2highx0 = r2high * x0; + z3 = Double.longBitsToDouble(d3); + + h3 = r1highx0 + sr2highx6; + sr3highx6 = sr3high * x6; + + r1highx4 = r1high * x4; + z2 -= alpha64; + + h4 = r2lowx0 + sr3lowx6; + r1lowx4 = r1low * x4; + + r0highx4 = r0high * x4; + z3 -= alpha96; + + h5 = r2highx0 + sr3highx6; + r0lowx4 = r0low * x4; + + h7 += r1highx4; + sr3highx4 = sr3high * x4; + + h6 += r1lowx4; + sr3lowx4 = sr3low * x4; + + h5 += r0highx4; + sr2highx4 = sr2high * x4; + + h4 += r0lowx4; + sr2lowx4 = sr2low * x4; + + h3 += sr3highx4; + r0lowx2 = r0low * x2; + + h2 += sr3lowx4; + r0highx2 = r0high * x2; + + h1 += sr2highx4; + r1lowx2 = r1low * x2; + + h0 += sr2lowx4; + r1highx2 = r1high * x2; + + h2 += r0lowx2; + r2lowx2 = r2low * x2; + + h3 += r0highx2; + r2highx2 = r2high * x2; + + h4 += r1lowx2; + sr3lowx2 = sr3low * x2; + + h5 += r1highx2; + sr3highx2 = sr3high * x2; + + p += 16; + l -= 16; + h6 += r2lowx2; + + h7 += r2highx2; + + z1 = Double.longBitsToDouble(d1); + h0 += sr3lowx2; + + z0 = Double.longBitsToDouble(d0); + h1 += sr3highx2; + + z1 -= alpha32; + + z0 -= alpha0; + + h5 += z3; + + h3 += z2; + + h1 += z1; + + h0 += z0; + + } + + // multiplyaddatmost15bytes: + y7 = h7 + alpha130; + + y6 = h6 + alpha130; + + y1 = h1 + alpha32; + + y0 = h0 + alpha32; + + y7 -= alpha130; + + y6 -= alpha130; + + y1 -= alpha32; + + y0 -= alpha32; + + y5 = h5 + alpha96; + + y4 = h4 + alpha96; + + x7 = h7 - y7; + y7 *= scale; + + x6 = h6 - y6; + y6 *= scale; + + x1 = h1 - y1; + + x0 = h0 - y0; + + y5 -= alpha96; + + y4 -= alpha96; + + x1 += y7; + + x0 += y6; + + x7 += y5; + + x6 += y4; + + y3 = h3 + alpha64; + + y2 = h2 + alpha64; + + x0 += x1; + + x6 += x7; + + y3 -= alpha64; + r3low = r3low_stack; + + y2 -= alpha64; + r0low = r0low_stack; + + x5 = h5 - y5; + r3lowx0 = r3low * x0; + r3high = r3high_stack; + + x4 = h4 - y4; + r0lowx6 = r0low * x6; + r0high = r0high_stack; + + x3 = h3 - y3; + r3highx0 = r3high * x0; + sr1low = sr1low_stack; + + x2 = h2 - y2; + r0highx6 = r0high * x6; + sr1high = sr1high_stack; + + x5 += y3; + r0lowx0 = r0low * x0; + r1low = r1low_stack; + + h6 = r3lowx0 + r0lowx6; + sr1lowx6 = sr1low * x6; + r1high = r1high_stack; + + x4 += y2; + r0highx0 = r0high * x0; + sr2low = sr2low_stack; + + h7 = r3highx0 + r0highx6; + sr1highx6 = sr1high * x6; + sr2high = sr2high_stack; + + x3 += y1; + r1lowx0 = r1low * x0; + r2low = r2low_stack; + + h0 = r0lowx0 + sr1lowx6; + sr2lowx6 = sr2low * x6; + r2high = r2high_stack; + + x2 += y0; + r1highx0 = r1high * x0; + sr3low = sr3low_stack; + + h1 = r0highx0 + sr1highx6; + sr2highx6 = sr2high * x6; + sr3high = sr3high_stack; + + x4 += x5; + r2lowx0 = r2low * x0; + + h2 = r1lowx0 + sr2lowx6; + sr3lowx6 = sr3low * x6; + + x2 += x3; + r2highx0 = r2high * x0; + + h3 = r1highx0 + sr2highx6; + sr3highx6 = sr3high * x6; + + r1highx4 = r1high * x4; + + h4 = r2lowx0 + sr3lowx6; + r1lowx4 = r1low * x4; + + r0highx4 = r0high * x4; + + h5 = r2highx0 + sr3highx6; + r0lowx4 = r0low * x4; + + h7 += r1highx4; + sr3highx4 = sr3high * x4; + + h6 += r1lowx4; + sr3lowx4 = sr3low * x4; + + h5 += r0highx4; + sr2highx4 = sr2high * x4; + + h4 += r0lowx4; + sr2lowx4 = sr2low * x4; + + h3 += sr3highx4; + r0lowx2 = r0low * x2; + + h2 += sr3lowx4; + r0highx2 = r0high * x2; + + h1 += sr2highx4; + r1lowx2 = r1low * x2; + + h0 += sr2lowx4; + r1highx2 = r1high * x2; + + h2 += r0lowx2; + r2lowx2 = r2low * x2; + + h3 += r0highx2; + r2highx2 = r2high * x2; + + h4 += r1lowx2; + sr3lowx2 = sr3low * x2; + + h5 += r1highx2; + sr3highx2 = sr3high * x2; + + h6 += r2lowx2; + + h7 += r2highx2; + + h0 += sr3lowx2; + + h1 += sr3highx2; + } + + // addatmost15bytes: + + if (l > 0) { + lbelow2 = l - 2; + + lbelow3 = l - 3; + + lbelow2 >>= 31; + lbelow4 = l - 4; + + m00 = 0xFF & (m[(int) p + 0]); + lbelow3 >>= 31; + p += lbelow2; + + m01 = 0xFF & (m[(int) p + 1]); + lbelow4 >>= 31; + p += lbelow3; + + m02 = 0xFF & (m[(int) p + 2]); + p += lbelow4; + m0 = 2151; + + m03 = 0xFF & (m[(int) p + 3]); + m0 <<= 51; + m1 = 2215; + + m0 += m00; + m01 &= ~uint32(lbelow2); + + m02 &= ~uint32(lbelow3); + m01 -= uint32(lbelow2); + + m01 <<= 8; + m03 &= ~uint32(lbelow4); + + m0 += m01; + lbelow2 -= lbelow3; + + m02 += uint32(lbelow2); + lbelow3 -= lbelow4; + + m02 <<= 16; + m03 += uint32(lbelow3); + + m03 <<= 24; + m0 += m02; + + m0 += m03; + lbelow5 = l - 5; + + lbelow6 = l - 6; + lbelow7 = l - 7; + + lbelow5 >>= 31; + lbelow8 = l - 8; + + lbelow6 >>= 31; + p += lbelow5; + + m10 = 0xFF & (m[(int) p + 4]); + lbelow7 >>= 31; + p += lbelow6; + + m11 = 0xFF & (m[(int) p + 5]); + lbelow8 >>= 31; + p += lbelow7; + + m12 = 0xFF & (m[(int) p + 6]); + m1 <<= 51; + p += lbelow8; + + m13 = 0xFF & (m[(int) p + 7]); + m10 &= ~uint32(lbelow5); + lbelow4 -= lbelow5; + + m10 += uint32(lbelow4); + lbelow5 -= lbelow6; + + m11 &= ~uint32(lbelow6); + m11 += uint32(lbelow5); + + m11 <<= 8; + m1 += m10; + + m1 += m11; + m12 &= ~uint32(lbelow7); + + lbelow6 -= lbelow7; + m13 &= ~uint32(lbelow8); + + m12 += uint32(lbelow6); + lbelow7 -= lbelow8; + + m12 <<= 16; + m13 += uint32(lbelow7); + + m13 <<= 24; + m1 += m12; + + m1 += m13; + m2 = 2279; + + lbelow9 = l - 9; + m3 = 2343; + + lbelow10 = l - 10; + lbelow11 = l - 11; + + lbelow9 >>= 31; + lbelow12 = l - 12; + + lbelow10 >>= 31; + p += lbelow9; + + m20 = 0xFF & (m[(int) p + 8]); + lbelow11 >>= 31; + p += lbelow10; + + m21 = 0xFF & (m[(int) p + 9]); + lbelow12 >>= 31; + p += lbelow11; + + m22 = 0xFF & (m[(int) p + 10]); + m2 <<= 51; + p += lbelow12; + + m23 = 0xFF & (m[(int) p + 11]); + m20 &= ~uint32(lbelow9); + lbelow8 -= lbelow9; + + m20 += uint32(lbelow8); + lbelow9 -= lbelow10; + + m21 &= ~uint32(lbelow10); + m21 += uint32(lbelow9); + + m21 <<= 8; + m2 += m20; + + m2 += m21; + m22 &= ~uint32(lbelow11); + + lbelow10 -= lbelow11; + m23 &= ~uint32(lbelow12); + + m22 += uint32(lbelow10); + lbelow11 -= lbelow12; + + m22 <<= 16; + m23 += uint32(lbelow11); + + m23 <<= 24; + m2 += m22; + + m3 <<= 51; + lbelow13 = l - 13; + + lbelow13 >>= 31; + lbelow14 = l - 14; + + lbelow14 >>= 31; + p += lbelow13; + lbelow15 = l - 15; + + m30 = uint32(m[(int) p + 12]); + lbelow15 >>= 31; + p += lbelow14; + + m31 = 0xFF & (m[(int) p + 13]); + p += lbelow15; + m2 += m23; + + m32 = 0xFF & (m[(int) p + 14]); + m30 &= ~uint32(lbelow13); + lbelow12 -= lbelow13; + + m30 += uint32(lbelow12); + lbelow13 -= lbelow14; + + m3 += m30; + m31 &= ~uint32(lbelow14); + + m31 += uint32(lbelow13); + m32 &= ~uint32(lbelow15); + + m31 <<= 8; + lbelow14 -= lbelow15; + + m3 += m31; + m32 += uint32(lbelow14); + d0 = m0; + + m32 <<= 16; + m33 = lbelow15 + 1; + d1 = m1; + + m33 <<= 24; + m3 += m32; + d2 = m2; + + m3 += m33; + d3 = m3; + + z3 = Double.longBitsToDouble(d3); + ; + + z2 = Double.longBitsToDouble(d2); + + z1 = Double.longBitsToDouble(d1); + + z0 = Double.longBitsToDouble(d0); + + z3 -= alpha96; + + z2 -= alpha64; + + z1 -= alpha32; + + z0 -= alpha0; + + h5 += z3; + + h3 += z2; + + h1 += z1; + + h0 += z0; + + y7 = h7 + alpha130; + + y6 = h6 + alpha130; + + y1 = h1 + alpha32; + + y0 = h0 + alpha32; + + y7 -= alpha130; + + y6 -= alpha130; + + y1 -= alpha32; + + y0 -= alpha32; + + y5 = h5 + alpha96; + + y4 = h4 + alpha96; + + x7 = h7 - y7; + y7 *= scale; + + x6 = h6 - y6; + y6 *= scale; + + x1 = h1 - y1; + + x0 = h0 - y0; + + y5 -= alpha96; + + y4 -= alpha96; + + x1 += y7; + + x0 += y6; + + x7 += y5; + + x6 += y4; + + y3 = h3 + alpha64; + + y2 = h2 + alpha64; + + x0 += x1; + + x6 += x7; + + y3 -= alpha64; + r3low = r3low_stack; + + y2 -= alpha64; + r0low = r0low_stack; + + x5 = h5 - y5; + r3lowx0 = r3low * x0; + r3high = r3high_stack; + + x4 = h4 - y4; + r0lowx6 = r0low * x6; + r0high = r0high_stack; + + x3 = h3 - y3; + r3highx0 = r3high * x0; + sr1low = sr1low_stack; + + x2 = h2 - y2; + r0highx6 = r0high * x6; + sr1high = sr1high_stack; + + x5 += y3; + r0lowx0 = r0low * x0; + r1low = r1low_stack; + + h6 = r3lowx0 + r0lowx6; + sr1lowx6 = sr1low * x6; + r1high = r1high_stack; + + x4 += y2; + r0highx0 = r0high * x0; + sr2low = sr2low_stack; + + h7 = r3highx0 + r0highx6; + sr1highx6 = sr1high * x6; + sr2high = sr2high_stack; + + x3 += y1; + r1lowx0 = r1low * x0; + r2low = r2low_stack; + + h0 = r0lowx0 + sr1lowx6; + sr2lowx6 = sr2low * x6; + r2high = r2high_stack; + + x2 += y0; + r1highx0 = r1high * x0; + sr3low = sr3low_stack; + + h1 = r0highx0 + sr1highx6; + sr2highx6 = sr2high * x6; + sr3high = sr3high_stack; + + x4 += x5; + r2lowx0 = r2low * x0; + + h2 = r1lowx0 + sr2lowx6; + sr3lowx6 = sr3low * x6; + + x2 += x3; + r2highx0 = r2high * x0; + + h3 = r1highx0 + sr2highx6; + sr3highx6 = sr3high * x6; + + r1highx4 = r1high * x4; + + h4 = r2lowx0 + sr3lowx6; + r1lowx4 = r1low * x4; + + r0highx4 = r0high * x4; + + h5 = r2highx0 + sr3highx6; + r0lowx4 = r0low * x4; + + h7 += r1highx4; + sr3highx4 = sr3high * x4; + + h6 += r1lowx4; + sr3lowx4 = sr3low * x4; + + h5 += r0highx4; + sr2highx4 = sr2high * x4; + + h4 += r0lowx4; + sr2lowx4 = sr2low * x4; + + h3 += sr3highx4; + r0lowx2 = r0low * x2; + + h2 += sr3lowx4; + r0highx2 = r0high * x2; + + h1 += sr2highx4; + r1lowx2 = r1low * x2; + + h0 += sr2lowx4; + r1highx2 = r1high * x2; + + h2 += r0lowx2; + r2lowx2 = r2low * x2; + + h3 += r0highx2; + r2highx2 = r2high * x2; + + h4 += r1lowx2; + sr3lowx2 = sr3low * x2; + + h5 += r1highx2; + sr3highx2 = sr3high * x2; + + h6 += r2lowx2; + + h7 += r2highx2; + + h0 += sr3lowx2; + + h1 += sr3highx2; + } + + //nomorebytes: + + y7 = h7 + alpha130; + + y0 = h0 + alpha32; + + y1 = h1 + alpha32; + + y2 = h2 + alpha64; + + y7 -= alpha130; + + y3 = h3 + alpha64; + + y4 = h4 + alpha96; + + y5 = h5 + alpha96; + + x7 = h7 - y7; + y7 *= scale; + + y0 -= alpha32; + + y1 -= alpha32; + + y2 -= alpha64; + + h6 += x7; + + y3 -= alpha64; + + y4 -= alpha96; + + y5 -= alpha96; + + y6 = h6 + alpha130; + + x0 = h0 - y0; + + x1 = h1 - y1; + + x2 = h2 - y2; + + y6 -= alpha130; + + x0 += y7; + + x3 = h3 - y3; + + x4 = h4 - y4; + + x5 = h5 - y5; + + x6 = h6 - y6; + + y6 *= scale; + + x2 += y0; + + x3 += y1; + + x4 += y2; + + x0 += y6; + + x5 += y3; + + x6 += y4; + + x2 += x3; + + x0 += x1; + + x4 += x5; + + x6 += y5; + + x2 += offset1; + d1 = Double.doubleToLongBits(x2); + + x0 += offset0; + d0 = Double.doubleToLongBits(x0); + + x4 += offset2; + d2 = Double.doubleToLongBits(x4); + + x6 += offset3; + d3 = Double.doubleToLongBits(x6); + + f0 = d0; + + f1 = d1; + bits32 = 0xFFFFFFFFFFFFFFFFl; + + f2 = d2; + bits32 >>>= 32; + + f3 = d3; + f = f0 >> 32; + + f0 &= bits32; + f &= 255; + + f1 += f; + g0 = f0 + 5; + + g = g0 >> 32; + g0 &= bits32; + + f = f1 >> 32; + f1 &= bits32; + + f &= 255; + g1 = f1 + g; + + g = g1 >> 32; + f2 += f; + + f = f2 >> 32; + g1 &= bits32; + + f2 &= bits32; + f &= 255; + + f3 += f; + g2 = f2 + g; + + g = g2 >> 32; + g2 &= bits32; + + f4 = f3 >> 32; + f3 &= bits32; + + f4 &= 255; + g3 = f3 + g; + + g = g3 >> 32; + g3 &= bits32; + + g4 = f4 + g; + + g4 = g4 - 4; + s00 = 0xFF & (s[0]); + + f = g4 >> 63; + s01 = 0xFF & (s[1]); + + f0 &= f; + g0 &= ~f; + s02 = 0xFF & (s[2]); + + f1 &= f; + f0 |= g0; + s03 = 0xFF & (s[3]); + + g1 &= ~f; + f2 &= f; + s10 = 0xFF & (s[4]); + + f3 &= f; + g2 &= ~f; + s11 = 0xFF & (s[5]); + + g3 &= ~f; + f1 |= g1; + s12 = 0xFF & (s[6]); + + f2 |= g2; + f3 |= g3; + s13 = 0xFF & (s[7]); + + s01 <<= 8; + f0 += s00; + s20 = 0xFF & (s[8]); + + s02 <<= 16; + f0 += s01; + s21 = 0xFF & (s[9]); + + s03 <<= 24; + f0 += s02; + s22 = 0xFF & (s[10]); + + s11 <<= 8; + f1 += s10; + s23 = 0xFF & (s[11]); + + s12 <<= 16; + f1 += s11; + s30 = 0xFF & (s[12]); + + s13 <<= 24; + f1 += (s12); + s31 = 0xFF & s[13]; + + f0 += (s03); + f1 += (s13); + s32 = 0xFF & (s[14]); + + s21 <<= 8; + f2 += (s20); + s33 = 0xFF & (s[15]); + + s22 <<= 16; + f2 += (s21); + + s23 <<= 24; + f2 += (s22); + + s31 <<= 8; + f3 += (s30); + + s32 <<= 16; + f3 += (s31); + + s33 <<= 24; + f3 += (s32); + + f2 += (s23); + f3 += s33; + + byte out[] = new byte[16]; + out[0] = (byte) (f0); + f0 >>= 8; + out[1] = (byte) (f0); + f0 >>= 8; + out[2] = (byte) (f0); + f0 >>= 8; + out[3] = (byte) (f0); + f0 >>= 8; + f1 += f0; + + out[4] = (byte) (f1); + f1 >>= 8; + out[5] = (byte) (f1); + f1 >>= 8; + out[6] = (byte) (f1); + f1 >>= 8; + out[7] = (byte) (f1); + f1 >>= 8; + f2 += f1; + + out[8] = (byte) (f2); + f2 >>= 8; + out[9] = (byte) (f2); + f2 >>= 8; + out[10] = (byte) (f2); + f2 >>= 8; + out[11] = (byte) (f2); + f2 >>= 8; + f3 += f2; + + out[12] = (byte) f3; + f3 >>= 8; + out[13] = (byte) f3; + f3 >>= 8; + out[14] = (byte) f3; + f3 >>= 8; + out[15] = (byte) f3; + return out; + } +} diff --git a/src/main/java/com/pusher/client/crypto/nacl/Salsa.java b/src/main/java/com/pusher/client/crypto/nacl/Salsa.java new file mode 100644 index 00000000..a95e214c --- /dev/null +++ b/src/main/java/com/pusher/client/crypto/nacl/Salsa.java @@ -0,0 +1,433 @@ +/* +Copyright 2015 Eve Freeman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +*/ + +package com.pusher.client.crypto.nacl; + +public class Salsa { + public static byte[] SIGMA = {'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}; + + private static int rounds = 20; + + private static long mask(byte x) { + return 0xFFl & x; + } + + // core applies the Salsa20 core function to 16-byte input in, 32-byte key k, + // and 16-byte constant c, and puts the result into 64-byte array out. + public static byte[] core(byte in[], byte k[], byte c[]) { + byte out[] = new byte[64]; + long mask = 0xFFFFFFFFl; + + long j0 = mask & (mask(c[0]) | mask(c[1]) << 8 | mask(c[2]) << 16 | mask(c[3]) << 24); + long j1 = mask & (mask(k[0]) | mask(k[1]) << 8 | mask(k[2]) << 16 | mask(k[3]) << 24); + long j2 = mask & (mask(k[4]) | mask(k[5]) << 8 | mask(k[6]) << 16 | mask(k[7]) << 24); + long j3 = mask & (mask(k[8]) | mask(k[9]) << 8 | mask(k[10]) << 16 | mask(k[11]) << 24); + long j4 = mask & (mask(k[12]) | mask(k[13]) << 8 | mask(k[14]) << 16 | mask(k[15]) << 24); + long j5 = mask & (mask(c[4]) | mask(c[5]) << 8 | mask(c[6]) << 16 | mask(c[7]) << 24); + long j6 = mask & (mask(in[0]) | mask(in[1]) << 8 | mask(in[2]) << 16 | mask(in[3]) << 24); + long j7 = mask & (mask(in[4]) | mask(in[5]) << 8 | mask(in[6]) << 16 | mask(in[7]) << 24); + long j8 = mask & (mask(in[8]) | mask(in[9]) << 8 | mask(in[10]) << 16 | mask(in[11]) << 24); + long j9 = mask & (mask(in[12]) | mask(in[13]) << 8 | mask(in[14]) << 16 | mask(in[15]) << 24); + long j10 = mask & (mask(c[8]) | mask(c[9]) << 8 | mask(c[10]) << 16 | mask(c[11]) << 24); + long j11 = mask & (mask(k[16]) | mask(k[17]) << 8 | mask(k[18]) << 16 | mask(k[19]) << 24); + long j12 = mask & (mask(k[20]) | mask(k[21]) << 8 | mask(k[22]) << 16 | mask(k[23]) << 24); + long j13 = mask & (mask(k[24]) | mask(k[25]) << 8 | mask(k[26]) << 16 | mask(k[27]) << 24); + long j14 = mask & (mask(k[28]) | mask(k[29]) << 8 | mask(k[30]) << 16 | mask(k[31]) << 24); + long j15 = mask & (mask(c[12]) | mask(c[13]) << 8 | mask(c[14]) << 16 | mask(c[15]) << 24); + + long x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4; + long x5 = j5, x6 = j6, x7 = j7, x8 = j8; + long x9 = j9, x10 = j10, x11 = j11, x12 = j12; + long x13 = j13, x14 = j14, x15 = j15; + + for (int i = 0; i < rounds; i += 2) { + long u = mask & (x0 + x12); + x4 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x4 + x0); + x8 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x8 + x4); + x12 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x12 + x8); + x0 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x5 + x1); + x9 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x9 + x5); + x13 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x13 + x9); + x1 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x1 + x13); + x5 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x10 + x6); + x14 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x14 + x10); + x2 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x2 + x14); + x6 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x6 + x2); + x10 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x15 + x11); + x3 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x3 + x15); + x7 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x7 + x3); + x11 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x11 + x7); + x15 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x0 + x3); + x1 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x1 + x0); + x2 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x2 + x1); + x3 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x3 + x2); + x0 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x5 + x4); + x6 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x6 + x5); + x7 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x7 + x6); + x4 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x4 + x7); + x5 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x10 + x9); + x11 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x11 + x10); + x8 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x8 + x11); + x9 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x9 + x8); + x10 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x15 + x14); + x12 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x12 + x15); + x13 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x13 + x12); + x14 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x14 + x13); + x15 ^= mask & (u << 18 | u >>> (32 - 18)); + } + + x0 += j0; + x1 += j1; + x2 += j2; + x3 += j3; + x4 += j4; + x5 += j5; + x6 += j6; + x7 += j7; + x8 += j8; + x9 += j9; + x10 += j10; + x11 += j11; + x12 += j12; + x13 += j13; + x14 += j14; + x15 += j15; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + x5 &= mask; + x6 &= mask; + x7 &= mask; + x8 &= mask; + x9 &= mask; + x10 &= mask; + x11 &= mask; + x12 &= mask; + x13 &= mask; + x14 &= mask; + x15 &= mask; + + out[0] = (byte) (x0); + out[1] = (byte) (x0 >> 8); + out[2] = (byte) (x0 >> 16); + out[3] = (byte) (x0 >> 24); + + out[4] = (byte) (x1); + out[5] = (byte) (x1 >> 8); + out[6] = (byte) (x1 >> 16); + out[7] = (byte) (x1 >> 24); + + out[8] = (byte) (x2); + out[9] = (byte) (x2 >> 8); + out[10] = (byte) (x2 >> 16); + out[11] = (byte) (x2 >> 24); + + out[12] = (byte) (x3); + out[13] = (byte) (x3 >> 8); + out[14] = (byte) (x3 >> 16); + out[15] = (byte) (x3 >> 24); + + out[16] = (byte) (x4); + out[17] = (byte) (x4 >> 8); + out[18] = (byte) (x4 >> 16); + out[19] = (byte) (x4 >> 24); + + out[20] = (byte) (x5); + out[21] = (byte) (x5 >> 8); + out[22] = (byte) (x5 >> 16); + out[23] = (byte) (x5 >> 24); + + out[24] = (byte) (x6); + out[25] = (byte) (x6 >> 8); + out[26] = (byte) (x6 >> 16); + out[27] = (byte) (x6 >> 24); + + out[28] = (byte) (x7); + out[29] = (byte) (x7 >> 8); + out[30] = (byte) (x7 >> 16); + out[31] = (byte) (x7 >> 24); + + out[32] = (byte) (x8); + out[33] = (byte) (x8 >> 8); + out[34] = (byte) (x8 >> 16); + out[35] = (byte) (x8 >> 24); + + out[36] = (byte) (x9); + out[37] = (byte) (x9 >> 8); + out[38] = (byte) (x9 >> 16); + out[39] = (byte) (x9 >> 24); + + out[40] = (byte) (x10); + out[41] = (byte) (x10 >> 8); + out[42] = (byte) (x10 >> 16); + out[43] = (byte) (x10 >> 24); + + out[44] = (byte) (x11); + out[45] = (byte) (x11 >> 8); + out[46] = (byte) (x11 >> 16); + out[47] = (byte) (x11 >> 24); + + out[48] = (byte) (x12); + out[49] = (byte) (x12 >> 8); + out[50] = (byte) (x12 >> 16); + out[51] = (byte) (x12 >> 24); + + out[52] = (byte) (x13); + out[53] = (byte) (x13 >> 8); + out[54] = (byte) (x13 >> 16); + out[55] = (byte) (x13 >> 24); + + out[56] = (byte) (x14); + out[57] = (byte) (x14 >> 8); + out[58] = (byte) (x14 >> 16); + out[59] = (byte) (x14 >> 24); + + out[60] = (byte) (x15); + out[61] = (byte) (x15 >> 8); + out[62] = (byte) (x15 >> 16); + out[63] = (byte) (x15 >> 24); + return out; + } + + // XORKeyStream crypts bytes from in to out using the given key and counters. + // In and out may be the same slice but otherwise should not overlap. Counter + // contains the raw salsa20 counter bytes (both nonce and block counter). + public static byte[] XORKeyStream(byte in[], byte counter[], byte key[]) { + byte out[] = in.clone(); + byte block[]; + byte counterCopy[] = counter.clone(); + + int count = 0; + while (in.length >= 64) { + block = core(counterCopy, key, SIGMA); + + for (int i = 0; i < block.length; i++) { + byte x = block[i]; + out[i + 64 * count] = (byte) (in[i] ^ x); + } + long u = 1; + for (int i = 8; i < 16; i++) { + u += 0xFF & counterCopy[i]; + counterCopy[i] = (byte) (u); + u >>= 8; + } + byte temp[] = in.clone(); + in = new byte[in.length - 64]; + for (int i = 0; i < in.length; i++) { + in[i] = temp[i + 64]; + } + + count++; + } + + if (in.length > 0) { + block = core(counterCopy, key, SIGMA); + + for (int i = 0; i < in.length; i++) { + out[i + count * 64] = (byte) (in[i] ^ block[i]); + } + } + + return out; + } + + // HSalsa20 applies the HSalsa20 core function to a 16-byte input in, 32-byte + // key k, and 16-byte constant c, and returns the result as the 32-byte array + // out. + public static byte[] HSalsa20(byte[] in, byte[] k, byte[] c) { + long x0 = mask(c[0]) | mask(c[1]) << 8 | mask(c[2]) << 16 | mask(c[3]) << 24; + long x1 = mask(k[0]) | mask(k[1]) << 8 | mask(k[2]) << 16 | mask(k[3]) << 24; + long x2 = mask(k[4]) | mask(k[5]) << 8 | mask(k[6]) << 16 | mask(k[7]) << 24; + long x3 = mask(k[8]) | mask(k[9]) << 8 | mask(k[10]) << 16 | mask(k[11]) << 24; + long x4 = mask(k[12]) | mask(k[13]) << 8 | mask(k[14]) << 16 | mask(k[15]) << 24; + long x5 = mask(c[4]) | mask(c[5]) << 8 | mask(c[6]) << 16 | mask(c[7]) << 24; + long x6 = mask(in[0]) | mask(in[1]) << 8 | mask(in[2]) << 16 | mask(in[3]) << 24; + long x7 = mask(in[4]) | mask(in[5]) << 8 | mask(in[6]) << 16 | mask(in[7]) << 24; + long x8 = mask(in[8]) | mask(in[9]) << 8 | mask(in[10]) << 16 | mask(in[11]) << 24; + long x9 = mask(in[12]) | mask(in[13]) << 8 | mask(in[14]) << 16 | mask(in[15]) << 24; + long x10 = mask(c[8]) | mask(c[9]) << 8 | mask(c[10]) << 16 | mask(c[11]) << 24; + long x11 = mask(k[16]) | mask(k[17]) << 8 | mask(k[18]) << 16 | mask(k[19]) << 24; + long x12 = mask(k[20]) | mask(k[21]) << 8 | mask(k[22]) << 16 | mask(k[23]) << 24; + long x13 = mask(k[24]) | mask(k[25]) << 8 | mask(k[26]) << 16 | mask(k[27]) << 24; + long x14 = mask(k[28]) | mask(k[29]) << 8 | mask(k[30]) << 16 | mask(k[31]) << 24; + long x15 = mask(c[12]) | mask(c[13]) << 8 | mask(c[14]) << 16 | mask(c[15]) << 24; + + long mask = 0xFFFFFFFFl; + for (int i = 0; i < 20; i += 2) { + long u = mask & (x0 + x12); + x4 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x4 + x0); + x8 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x8 + x4); + x12 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x12 + x8); + x0 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x5 + x1); + x9 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x9 + x5); + x13 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x13 + x9); + x1 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x1 + x13); + x5 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x10 + x6); + x14 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x14 + x10); + x2 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x2 + x14); + x6 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x6 + x2); + x10 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x15 + x11); + x3 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x3 + x15); + x7 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x7 + x3); + x11 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x11 + x7); + x15 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x0 + x3); + x1 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x1 + x0); + x2 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x2 + x1); + x3 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x3 + x2); + x0 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x5 + x4); + x6 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x6 + x5); + x7 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x7 + x6); + x4 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x4 + x7); + x5 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x10 + x9); + x11 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x11 + x10); + x8 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x8 + x11); + x9 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x9 + x8); + x10 ^= mask & (u << 18 | u >>> (32 - 18)); + + u = mask & (x15 + x14); + x12 ^= mask & (u << 7 | u >>> (32 - 7)); + u = mask & (x12 + x15); + x13 ^= mask & (u << 9 | u >>> (32 - 9)); + u = mask & (x13 + x12); + x14 ^= mask & (u << 13 | u >>> (32 - 13)); + u = mask & (x14 + x13); + x15 ^= mask & (u << 18 | u >>> (32 - 18)); + } + + byte out[] = new byte[32]; + out[0] = (byte) x0; + out[1] = (byte) (x0 >> 8); + out[2] = (byte) (x0 >> 16); + out[3] = (byte) (x0 >> 24); + + out[4] = (byte) (x5); + out[5] = (byte) (x5 >> 8); + out[6] = (byte) (x5 >> 16); + out[7] = (byte) (x5 >> 24); + + out[8] = (byte) (x10); + out[9] = (byte) (x10 >> 8); + out[10] = (byte) (x10 >> 16); + out[11] = (byte) (x10 >> 24); + + out[12] = (byte) (x15); + out[13] = (byte) (x15 >> 8); + out[14] = (byte) (x15 >> 16); + out[15] = (byte) (x15 >> 24); + + out[16] = (byte) (x6); + out[17] = (byte) (x6 >> 8); + out[18] = (byte) (x6 >> 16); + out[19] = (byte) (x6 >> 24); + + out[20] = (byte) (x7); + out[21] = (byte) (x7 >> 8); + out[22] = (byte) (x7 >> 16); + out[23] = (byte) (x7 >> 24); + + out[24] = (byte) (x8); + out[25] = (byte) (x8 >> 8); + out[26] = (byte) (x8 >> 16); + out[27] = (byte) (x8 >> 24); + + out[28] = (byte) (x9); + out[29] = (byte) (x9 >> 8); + out[30] = (byte) (x9 >> 16); + out[31] = (byte) (x9 >> 24); + return out; + } +} diff --git a/src/main/java/com/pusher/client/crypto/nacl/SecretBoxOpener.java b/src/main/java/com/pusher/client/crypto/nacl/SecretBoxOpener.java new file mode 100644 index 00000000..fb2ecb04 --- /dev/null +++ b/src/main/java/com/pusher/client/crypto/nacl/SecretBoxOpener.java @@ -0,0 +1,138 @@ +/* +Copyright 2020 Pusher Ltd +Copyright 2015 Eve Freeman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +*/ + +package com.pusher.client.crypto.nacl; + +import java.util.Arrays; + +public class SecretBoxOpener { + + private static final int OVERHEAD = Poly1305.TAG_SIZE; + + private byte[] key; + + public SecretBoxOpener(byte[] key) { + // TODO: add a a little preconditions lib/class for that + if (key == null) throw new IllegalArgumentException("null key passed"); + if (key.length != 32) { + throw new IllegalArgumentException("key should be 32B, is: " + key.length + "B"); + } + + this.key = key; + } + + public byte[] open(byte box[], byte nonce[]) throws AuthenticityException { + if (key == null) { + throw new IllegalStateException("key has been cleared, create new instance"); + } + + byte subKey[] = new byte[32]; + byte counter[] = new byte[16]; + setup(subKey, counter, nonce, key); + + // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since + // Salsa20 works with 64-byte blocks, we also generate 32 bytes of + // keystream as a side effect. + byte firstBlock[] = new byte[64]; + for (int i = 0; i < firstBlock.length; i++) { + firstBlock[i] = 0; + } + firstBlock = Salsa.XORKeyStream(firstBlock, counter, subKey); + + byte poly1305Key[] = new byte[32]; + for (int i = 0; i < poly1305Key.length; i++) { + poly1305Key[i] = firstBlock[i]; + } + byte tag[] = new byte[Poly1305.TAG_SIZE]; + for (int i = 0; i < tag.length; i++) { + tag[i] = box[i]; + } + + byte cipher[] = new byte[box.length - Poly1305.TAG_SIZE]; + for (int i = 0; i < cipher.length; i++) { + cipher[i] = box[i + Poly1305.TAG_SIZE]; + } + if (!Poly1305.verify(tag, cipher, poly1305Key)) { + throw new AuthenticityException(); + } + + byte ret[] = new byte[box.length - OVERHEAD]; + for (int i = 0; i < ret.length; i++) { + ret[i] = box[i + OVERHEAD]; + } + // We XOR up to 32 bytes of box with the keystream generated from + // the first block. + byte firstMessageBlock[] = new byte[ret.length]; + if (ret.length > 32) { + firstMessageBlock = new byte[32]; + } + for (int i = 0; i < firstMessageBlock.length; i++) { + firstMessageBlock[i] = ret[i]; + } + for (int i = 0; i < firstMessageBlock.length; i++) { + ret[i] = (byte) (firstBlock[32 + i] ^ firstMessageBlock[i]); + } + + counter[8] = 1; + byte newbox[] = new byte[box.length - (firstMessageBlock.length + OVERHEAD)]; + for (int i = 0; i < newbox.length; i++) { + newbox[i] = box[i + firstMessageBlock.length + OVERHEAD]; + } + byte rest[] = Salsa.XORKeyStream(newbox, counter, subKey); + // Now decrypt the rest. + + for (int i = firstMessageBlock.length; i < ret.length; i++) { + ret[i] = rest[i - firstMessageBlock.length]; + } + return ret; + } + + public void clearKey() { + Arrays.fill(key, (byte) 0); + if (key[0] != 0) { + throw new SecurityException("key not cleared correctly"); + } + key = null; + // TODO: ensure implemented securely (so that the clearing code + // is not removed by compiler's optimisations) + } + + // subKey = byte[32], counter = byte[16], nonce = byte[24], key = byte[32] + private void setup(byte subKey[], byte counter[], byte nonce[], byte key[]) { + // We use XSalsa20 for encryption so first we need to generate a + // key and nonce with HSalsa20. + byte hNonce[] = new byte[16]; + for (int i = 0; i < hNonce.length; i++) { + hNonce[i] = nonce[i]; + } + byte newSubKey[] = Salsa.HSalsa20(hNonce, key, Salsa.SIGMA); + for (int i = 0; i < subKey.length; i++) { + subKey[i] = newSubKey[i]; + } + + for (int i = 0; i < nonce.length - 16; i++) { + counter[i] = nonce[i + 16]; + } + } +} diff --git a/src/main/java/com/pusher/client/crypto/nacl/Subtle.java b/src/main/java/com/pusher/client/crypto/nacl/Subtle.java new file mode 100644 index 00000000..ccfa3950 --- /dev/null +++ b/src/main/java/com/pusher/client/crypto/nacl/Subtle.java @@ -0,0 +1,45 @@ +/* +Copyright 2015 Eve Freeman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +*/ + +package com.pusher.client.crypto.nacl; + +public class Subtle { + public static boolean constantTimeCompare(byte x[], byte y[]) { + if (x.length != y.length) { + return false; + } + byte v = 0; + for (int i = 0; i < x.length; i++) { + v |= x[i] ^ y[i]; + } + return constantTimeByteEq(v, (byte) 0); + } + + public static boolean constantTimeByteEq(byte x, byte y) { + byte z = (byte) ~(x ^ y); + z &= (byte) (z >> 4); + z &= (byte) (z >> 2); + z &= (byte) (z >> 1); + return z == -1; + } +}