mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-11-01 07:51:15 +00:00
Merge f2dc1388ca190f855d72e1c9b76c155fb5268977 into c8f45408b1984753a4df7f05aff03ceaa17bbba6
This commit is contained in:
commit
fa62e63c35
@ -1,9 +1,8 @@
|
||||
package com.bitchat.android.noise
|
||||
|
||||
import android.util.Log
|
||||
import com.bitchat.android.noise.southernstorm.protocol.*
|
||||
import com.bitchat.android.util.toHexString
|
||||
import java.security.SecureRandom
|
||||
import com.bitchat.android.noise.southernstorm.protocol.CipherState
|
||||
import com.bitchat.android.noise.southernstorm.protocol.HandshakeState
|
||||
|
||||
|
||||
/**
|
||||
@ -263,7 +262,7 @@ class NoiseSession(
|
||||
if (handshakeState?.needsLocalKeyPair() == true) {
|
||||
Log.d(TAG, "Local static key pair is required for XX pattern")
|
||||
|
||||
val localKeyPair = handshakeState?.getLocalKeyPair()
|
||||
val localKeyPair = handshakeState?.localKeyPair
|
||||
if (localKeyPair != null) {
|
||||
// FIXED: Use the provided persistent identity keys with our local fork
|
||||
// Our local fork properly supports setting pre-existing keys
|
||||
@ -393,7 +392,7 @@ class NoiseSession(
|
||||
Log.d(TAG, "Read handshake message, payload length: $payloadLength prefix=$readPrefix currentPattern: $currentPattern")
|
||||
|
||||
// Check what action the handshake state wants us to take next
|
||||
val action = handshakeStateLocal.getAction()
|
||||
val action = handshakeStateLocal.action
|
||||
Log.d(TAG, "Handshake action after processing message: $action")
|
||||
|
||||
return when (action) {
|
||||
@ -404,7 +403,7 @@ class NoiseSession(
|
||||
currentPattern++
|
||||
val response = responseBuffer.copyOf(responseLength)
|
||||
|
||||
Log.d(TAG, "Generated handshake response: ${response.size} bytes, action still: ${handshakeStateLocal.getAction()} currentPattern: $currentPattern")
|
||||
Log.d(TAG, "Generated handshake response: ${response.size} bytes, action still: ${handshakeStateLocal.action} currentPattern: $currentPattern")
|
||||
completeHandshake()
|
||||
response
|
||||
}
|
||||
@ -454,12 +453,12 @@ class NoiseSession(
|
||||
// Split handshake state into transport ciphers
|
||||
val cipherPair = handshakeState?.split()
|
||||
|
||||
sendCipher = cipherPair?.getSender()
|
||||
receiveCipher = cipherPair?.getReceiver()
|
||||
sendCipher = cipherPair?.sender
|
||||
receiveCipher = cipherPair?.receiver
|
||||
|
||||
// Extract remote static key if available
|
||||
if (handshakeState?.hasRemotePublicKey() == true) {
|
||||
val remoteDH = handshakeState?.getRemotePublicKey()
|
||||
val remoteDH = handshakeState?.remotePublicKey
|
||||
if (remoteDH != null) {
|
||||
remoteStaticPublicKey = ByteArray(32)
|
||||
remoteDH.getPublicKey(remoteStaticPublicKey!!, 0)
|
||||
@ -468,7 +467,7 @@ class NoiseSession(
|
||||
}
|
||||
|
||||
// Extract handshake hash for channel binding
|
||||
handshakeHash = handshakeState?.getHandshakeHash()
|
||||
handshakeHash = handshakeState?.handshakeHash
|
||||
|
||||
// Clean up handshake state
|
||||
handshakeState?.destroy()
|
||||
|
||||
@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable;
|
||||
|
||||
/**
|
||||
* Fallback implementation of BLAKE2b for the Noise library.
|
||||
*
|
||||
* This implementation only supports message digesting with an output
|
||||
* length of 64 bytes and a limit of 2^64 - 1 bytes of input.
|
||||
* Keyed hashing and variable-length digests are not supported.
|
||||
*/
|
||||
public class Blake2bMessageDigest extends MessageDigest implements Destroyable {
|
||||
|
||||
private long[] h;
|
||||
private byte[] block;
|
||||
private long[] m;
|
||||
private long[] v;
|
||||
private long length;
|
||||
private int posn;
|
||||
|
||||
/**
|
||||
* Constructs a new BLAKE2b message digest object.
|
||||
*/
|
||||
public Blake2bMessageDigest() {
|
||||
super("BLAKE2B-512");
|
||||
h = new long [8];
|
||||
block = new byte [128];
|
||||
m = new long [16];
|
||||
v = new long [16];
|
||||
engineReset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineDigest() {
|
||||
byte[] digest = new byte [64];
|
||||
try {
|
||||
engineDigest(digest, 0, 64);
|
||||
} catch (DigestException e) {
|
||||
// Shouldn't happen, but just in case.
|
||||
Arrays.fill(digest, (byte)0);
|
||||
}
|
||||
return digest;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineDigest(byte[] buf, int offset, int len) throws DigestException
|
||||
{
|
||||
if (len < 64)
|
||||
throw new DigestException("Invalid digest length for BLAKE2b");
|
||||
Arrays.fill(block, posn, 128, (byte)0);
|
||||
transform(-1);
|
||||
for (int index = 0; index < 8; ++index) {
|
||||
long value = h[index];
|
||||
buf[offset++] = (byte)value;
|
||||
buf[offset++] = (byte)(value >> 8);
|
||||
buf[offset++] = (byte)(value >> 16);
|
||||
buf[offset++] = (byte)(value >> 24);
|
||||
buf[offset++] = (byte)(value >> 32);
|
||||
buf[offset++] = (byte)(value >> 40);
|
||||
buf[offset++] = (byte)(value >> 48);
|
||||
buf[offset++] = (byte)(value >> 56);
|
||||
}
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineGetDigestLength() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineReset() {
|
||||
h[0] = 0x6a09e667f3bcc908L ^ 0x01010040;
|
||||
h[1] = 0xbb67ae8584caa73bL;
|
||||
h[2] = 0x3c6ef372fe94f82bL;
|
||||
h[3] = 0xa54ff53a5f1d36f1L;
|
||||
h[4] = 0x510e527fade682d1L;
|
||||
h[5] = 0x9b05688c2b3e6c1fL;
|
||||
h[6] = 0x1f83d9abfb41bd6bL;
|
||||
h[7] = 0x5be0cd19137e2179L;
|
||||
length = 0;
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte input) {
|
||||
if (posn >= 128) {
|
||||
transform(0);
|
||||
posn = 0;
|
||||
}
|
||||
block[posn++] = input;
|
||||
++length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte[] input, int offset, int len) {
|
||||
while (len > 0) {
|
||||
if (posn >= 128) {
|
||||
transform(0);
|
||||
posn = 0;
|
||||
}
|
||||
int temp = (128 - posn);
|
||||
if (temp > len)
|
||||
temp = len;
|
||||
System.arraycopy(input, offset, block, posn, temp);
|
||||
posn += temp;
|
||||
length += temp;
|
||||
offset += temp;
|
||||
len -= temp;
|
||||
}
|
||||
}
|
||||
|
||||
// Permutation on the message input state for BLAKE2b.
|
||||
static final byte[][] sigma = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
||||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
||||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
||||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0},
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
};
|
||||
|
||||
private void transform(long f0)
|
||||
{
|
||||
int index;
|
||||
int offset;
|
||||
|
||||
// Unpack the input block from little-endian into host-endian.
|
||||
for (index = 0, offset = 0; index < 16; ++index, offset += 8) {
|
||||
m[index] = (block[offset] & 0xFFL) |
|
||||
((block[offset + 1] & 0xFFL) << 8) |
|
||||
((block[offset + 2] & 0xFFL) << 16) |
|
||||
((block[offset + 3] & 0xFFL) << 24) |
|
||||
((block[offset + 4] & 0xFFL) << 32) |
|
||||
((block[offset + 5] & 0xFFL) << 40) |
|
||||
((block[offset + 6] & 0xFFL) << 48) |
|
||||
((block[offset + 7] & 0xFFL) << 56);
|
||||
}
|
||||
|
||||
// Format the block to be hashed.
|
||||
for (index = 0; index < 8; ++index)
|
||||
v[index] = h[index];
|
||||
v[8] = 0x6a09e667f3bcc908L;
|
||||
v[9] = 0xbb67ae8584caa73bL;
|
||||
v[10] = 0x3c6ef372fe94f82bL;
|
||||
v[11] = 0xa54ff53a5f1d36f1L;
|
||||
v[12] = 0x510e527fade682d1L ^ length;
|
||||
v[13] = 0x9b05688c2b3e6c1fL;
|
||||
v[14] = 0x1f83d9abfb41bd6bL ^ f0;
|
||||
v[15] = 0x5be0cd19137e2179L;
|
||||
|
||||
// Perform the 12 BLAKE2b rounds.
|
||||
for (index = 0; index < 12; ++index) {
|
||||
// Column round.
|
||||
quarterRound(0, 4, 8, 12, 0, index);
|
||||
quarterRound(1, 5, 9, 13, 1, index);
|
||||
quarterRound(2, 6, 10, 14, 2, index);
|
||||
quarterRound(3, 7, 11, 15, 3, index);
|
||||
|
||||
// Diagonal round.
|
||||
quarterRound(0, 5, 10, 15, 4, index);
|
||||
quarterRound(1, 6, 11, 12, 5, index);
|
||||
quarterRound(2, 7, 8, 13, 6, index);
|
||||
quarterRound(3, 4, 9, 14, 7, index);
|
||||
}
|
||||
|
||||
// Combine the new and old hash values.
|
||||
for (index = 0; index < 8; ++index)
|
||||
h[index] ^= (v[index] ^ v[index + 8]);
|
||||
}
|
||||
|
||||
private static long rightRotate32(long v)
|
||||
{
|
||||
return v << 32 | (v >>> 32);
|
||||
}
|
||||
|
||||
private static long rightRotate24(long v)
|
||||
{
|
||||
return v << 40 | (v >>> 24);
|
||||
}
|
||||
|
||||
private static long rightRotate16(long v)
|
||||
{
|
||||
return v << 48 | (v >>> 16);
|
||||
}
|
||||
|
||||
private static long rightRotate63(long v)
|
||||
{
|
||||
return v << 1 | (v >>> 63);
|
||||
}
|
||||
|
||||
private void quarterRound(int a, int b, int c, int d, int i, int row)
|
||||
{
|
||||
v[a] += v[b] + m[sigma[row][2 * i]];
|
||||
v[d] = rightRotate32(v[d] ^ v[a]);
|
||||
v[c] += v[d];
|
||||
v[b] = rightRotate24(v[b] ^ v[c]);
|
||||
v[a] += v[b] + m[sigma[row][2 * i + 1]];
|
||||
v[d] = rightRotate16(v[d] ^ v[a]);
|
||||
v[c] += v[d];
|
||||
v[b] = rightRotate63(v[b] ^ v[c]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Arrays.fill(h, (long)0);
|
||||
Arrays.fill(block, (byte)0);
|
||||
Arrays.fill(m, (long)0);
|
||||
Arrays.fill(v, (long)0);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable
|
||||
import java.security.DigestException
|
||||
import java.security.MessageDigest
|
||||
|
||||
|
||||
/**
|
||||
* Fallback implementation of BLAKE2b for the Noise library.
|
||||
*
|
||||
* This implementation only supports message digesting with an output
|
||||
* length of 64 bytes and a limit of 2^64 - 1 bytes of input.
|
||||
* Keyed hashing and variable-length digests are not supported.
|
||||
*/
|
||||
class Blake2bMessageDigest : MessageDigest("BLAKE2B-512"), Destroyable {
|
||||
private val h = LongArray(8)
|
||||
private val block = ByteArray(128)
|
||||
private val m = LongArray(16)
|
||||
private val v = LongArray(16)
|
||||
private var length: Long = 0
|
||||
private var posn = 0
|
||||
|
||||
init {
|
||||
engineReset()
|
||||
}
|
||||
|
||||
override fun engineDigest(): ByteArray {
|
||||
val digest = ByteArray(64)
|
||||
try {
|
||||
engineDigest(digest, 0, 64)
|
||||
} catch (e: DigestException) {
|
||||
// Shouldn't happen, but just in case.
|
||||
digest.fill(0)
|
||||
}
|
||||
return digest
|
||||
}
|
||||
|
||||
@Throws(DigestException::class)
|
||||
override fun engineDigest(buf: ByteArray, offset: Int, len: Int): Int {
|
||||
var offset = offset
|
||||
if (len < 64) throw DigestException("Invalid digest length for BLAKE2b")
|
||||
block.fill(0, posn, 128)
|
||||
transform(-1)
|
||||
for (index in 0..7) {
|
||||
val value = h[index]
|
||||
buf[offset++] = value.toByte()
|
||||
buf[offset++] = (value shr 8).toByte()
|
||||
buf[offset++] = (value shr 16).toByte()
|
||||
buf[offset++] = (value shr 24).toByte()
|
||||
buf[offset++] = (value shr 32).toByte()
|
||||
buf[offset++] = (value shr 40).toByte()
|
||||
buf[offset++] = (value shr 48).toByte()
|
||||
buf[offset++] = (value shr 56).toByte()
|
||||
}
|
||||
return 32
|
||||
}
|
||||
|
||||
override fun engineGetDigestLength(): Int = 64
|
||||
|
||||
override fun engineReset() {
|
||||
h[0] = 0x6a09e667f3bcc908L xor 0x01010040L
|
||||
h[1] = -0x4498517a7b3558c5L
|
||||
h[2] = 0x3c6ef372fe94f82bL
|
||||
h[3] = -0x5ab00ac5a0e2c90fL
|
||||
h[4] = 0x510e527fade682d1L
|
||||
h[5] = -0x64fa9773d4c193e1L
|
||||
h[6] = 0x1f83d9abfb41bd6bL
|
||||
h[7] = 0x5be0cd19137e2179L
|
||||
length = 0
|
||||
posn = 0
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: Byte) {
|
||||
if (posn >= 128) {
|
||||
transform(0)
|
||||
posn = 0
|
||||
}
|
||||
block[posn++] = input
|
||||
++length
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: ByteArray, offset: Int, len: Int) {
|
||||
var currentOffset = offset
|
||||
var remainingLen = len
|
||||
while (remainingLen > 0) {
|
||||
if (posn >= 128) {
|
||||
transform(0)
|
||||
posn = 0
|
||||
}
|
||||
var temp = 128 - posn
|
||||
if (temp > remainingLen) temp = remainingLen
|
||||
|
||||
input.copyInto(block, posn, currentOffset, currentOffset + temp)
|
||||
posn += temp
|
||||
length += temp.toLong()
|
||||
currentOffset += temp
|
||||
remainingLen -= temp
|
||||
}
|
||||
}
|
||||
|
||||
private fun transform(f0: Long) {
|
||||
var currentOffset = 0
|
||||
|
||||
// Unpack the input block from little-endian into host-endian.
|
||||
for (index in 0 until 16) {
|
||||
m[index] = (block[currentOffset].toLong() and 0xFFL) or
|
||||
((block[currentOffset + 1].toLong() and 0xFFL) shl 8) or
|
||||
((block[currentOffset + 2].toLong() and 0xFFL) shl 16) or
|
||||
((block[currentOffset + 3].toLong() and 0xFFL) shl 24) or
|
||||
((block[currentOffset + 4].toLong() and 0xFFL) shl 32) or
|
||||
((block[currentOffset + 5].toLong() and 0xFFL) shl 40) or
|
||||
((block[currentOffset + 6].toLong() and 0xFFL) shl 48) or
|
||||
((block[currentOffset + 7].toLong() and 0xFFL) shl 56)
|
||||
currentOffset += 8
|
||||
}
|
||||
|
||||
|
||||
// Format the block to be hashed.
|
||||
for (index in 0 until 8) {
|
||||
v[index] = h[index]
|
||||
}
|
||||
|
||||
v[8] = 0x6a09e667f3bcc908L
|
||||
v[9] = -0x4498517a7b3558c5L
|
||||
v[10] = 0x3c6ef372fe94f82bL
|
||||
v[11] = -0x5ab00ac5a0e2c90fL
|
||||
v[12] = 0x510e527fade682d1L xor length
|
||||
v[13] = -0x64fa9773d4c193e1L
|
||||
v[14] = 0x1f83d9abfb41bd6bL xor f0
|
||||
v[15] = 0x5be0cd19137e2179L
|
||||
|
||||
|
||||
// Perform the 12 BLAKE2b rounds.
|
||||
for (index in 0 until 12) {
|
||||
// Column round.
|
||||
quarterRound(0, 4, 8, 12, 0, index)
|
||||
quarterRound(1, 5, 9, 13, 1, index)
|
||||
quarterRound(2, 6, 10, 14, 2, index)
|
||||
quarterRound(3, 7, 11, 15, 3, index)
|
||||
|
||||
// Diagonal round.
|
||||
quarterRound(0, 5, 10, 15, 4, index)
|
||||
quarterRound(1, 6, 11, 12, 5, index)
|
||||
quarterRound(2, 7, 8, 13, 6, index)
|
||||
quarterRound(3, 4, 9, 14, 7, index)
|
||||
}
|
||||
|
||||
|
||||
// Combine the new and old hash values.
|
||||
for (index in 0 until 8) {
|
||||
h[index] = h[index] xor (v[index] xor v[index + 8])
|
||||
}
|
||||
}
|
||||
|
||||
private fun quarterRound(a: Int, b: Int, c: Int, d: Int, i: Int, row: Int) {
|
||||
v[a] += v[b] + m[sigma[row][2 * i].toInt()]
|
||||
v[d] = rightRotate32(v[d] xor v[a])
|
||||
v[c] += v[d]
|
||||
v[b] = rightRotate24(v[b] xor v[c])
|
||||
v[a] += v[b] + m[sigma[row][2 * i + 1].toInt()]
|
||||
v[d] = rightRotate16(v[d] xor v[a])
|
||||
v[c] += v[d]
|
||||
v[b] = rightRotate63(v[b] xor v[c])
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
h.fill(0L)
|
||||
block.fill(0)
|
||||
m.fill(0L)
|
||||
v.fill(0L)
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Permutation on the message input state for BLAKE2b.
|
||||
val sigma: Array<ByteArray> = arrayOf(
|
||||
byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
byteArrayOf(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3),
|
||||
byteArrayOf(11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4),
|
||||
byteArrayOf(7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8),
|
||||
byteArrayOf(9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13),
|
||||
byteArrayOf(2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9),
|
||||
byteArrayOf(12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11),
|
||||
byteArrayOf(13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10),
|
||||
byteArrayOf(6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5),
|
||||
byteArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0),
|
||||
byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
byteArrayOf(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3),
|
||||
)
|
||||
|
||||
private fun rightRotate32(v: Long): Long = (v shl 32) or (v ushr 32)
|
||||
private fun rightRotate24(v: Long): Long = (v shl 40) or (v ushr 24)
|
||||
private fun rightRotate16(v: Long): Long = (v shl 48) or (v ushr 16)
|
||||
private fun rightRotate63(v: Long): Long = (v shl 1) or (v ushr 63)
|
||||
}
|
||||
}
|
||||
@ -1,233 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable;
|
||||
|
||||
/**
|
||||
* Fallback implementation of BLAKE2s for the Noise library.
|
||||
*
|
||||
* This implementation only supports message digesting with an output
|
||||
* length of 32 bytes. Keyed hashing and variable-length digests are
|
||||
* not supported.
|
||||
*/
|
||||
public class Blake2sMessageDigest extends MessageDigest implements Destroyable {
|
||||
|
||||
private int[] h;
|
||||
private byte[] block;
|
||||
private int[] m;
|
||||
private int[] v;
|
||||
private long length;
|
||||
private int posn;
|
||||
|
||||
/**
|
||||
* Constructs a new BLAKE2s message digest object.
|
||||
*/
|
||||
public Blake2sMessageDigest() {
|
||||
super("BLAKE2S-256");
|
||||
h = new int [8];
|
||||
block = new byte [64];
|
||||
m = new int [16];
|
||||
v = new int [16];
|
||||
engineReset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineDigest() {
|
||||
byte[] digest = new byte [32];
|
||||
try {
|
||||
engineDigest(digest, 0, 32);
|
||||
} catch (DigestException e) {
|
||||
// Shouldn't happen, but just in case.
|
||||
Arrays.fill(digest, (byte)0);
|
||||
}
|
||||
return digest;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineDigest(byte[] buf, int offset, int len) throws DigestException
|
||||
{
|
||||
if (len < 32)
|
||||
throw new DigestException("Invalid digest length for BLAKE2s");
|
||||
Arrays.fill(block, posn, 64, (byte)0);
|
||||
transform(-1);
|
||||
for (int index = 0; index < 8; ++index) {
|
||||
int value = h[index];
|
||||
buf[offset++] = (byte)value;
|
||||
buf[offset++] = (byte)(value >> 8);
|
||||
buf[offset++] = (byte)(value >> 16);
|
||||
buf[offset++] = (byte)(value >> 24);
|
||||
}
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineGetDigestLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineReset() {
|
||||
h[0] = 0x6A09E667 ^ 0x01010020;
|
||||
h[1] = 0xBB67AE85;
|
||||
h[2] = 0x3C6EF372;
|
||||
h[3] = 0xA54FF53A;
|
||||
h[4] = 0x510E527F;
|
||||
h[5] = 0x9B05688C;
|
||||
h[6] = 0x1F83D9AB;
|
||||
h[7] = 0x5BE0CD19;
|
||||
length = 0;
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte input) {
|
||||
if (posn >= 64) {
|
||||
transform(0);
|
||||
posn = 0;
|
||||
}
|
||||
block[posn++] = input;
|
||||
++length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte[] input, int offset, int len) {
|
||||
while (len > 0) {
|
||||
if (posn >= 64) {
|
||||
transform(0);
|
||||
posn = 0;
|
||||
}
|
||||
int temp = (64 - posn);
|
||||
if (temp > len)
|
||||
temp = len;
|
||||
System.arraycopy(input, offset, block, posn, temp);
|
||||
posn += temp;
|
||||
length += temp;
|
||||
offset += temp;
|
||||
len -= temp;
|
||||
}
|
||||
}
|
||||
|
||||
// Permutation on the message input state for BLAKE2s.
|
||||
static final byte[][] sigma = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
||||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
||||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
||||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0}
|
||||
};
|
||||
|
||||
private void transform(int f0)
|
||||
{
|
||||
int index;
|
||||
int offset;
|
||||
|
||||
// Unpack the input block from little-endian into host-endian.
|
||||
for (index = 0, offset = 0; index < 16; ++index, offset += 4) {
|
||||
m[index] = (block[offset] & 0xFF) |
|
||||
((block[offset + 1] & 0xFF) << 8) |
|
||||
((block[offset + 2] & 0xFF) << 16) |
|
||||
((block[offset + 3] & 0xFF) << 24);
|
||||
}
|
||||
|
||||
// Format the block to be hashed.
|
||||
for (index = 0; index < 8; ++index)
|
||||
v[index] = h[index];
|
||||
v[8] = 0x6A09E667;
|
||||
v[9] = 0xBB67AE85;
|
||||
v[10] = 0x3C6EF372;
|
||||
v[11] = 0xA54FF53A;
|
||||
v[12] = 0x510E527F ^ (int)length;
|
||||
v[13] = 0x9B05688C ^ (int)(length >> 32);
|
||||
v[14] = 0x1F83D9AB ^ f0;
|
||||
v[15] = 0x5BE0CD19;
|
||||
|
||||
// Perform the 10 BLAKE2s rounds.
|
||||
for (index = 0; index < 10; ++index) {
|
||||
// Column round.
|
||||
quarterRound(0, 4, 8, 12, 0, index);
|
||||
quarterRound(1, 5, 9, 13, 1, index);
|
||||
quarterRound(2, 6, 10, 14, 2, index);
|
||||
quarterRound(3, 7, 11, 15, 3, index);
|
||||
|
||||
// Diagonal round.
|
||||
quarterRound(0, 5, 10, 15, 4, index);
|
||||
quarterRound(1, 6, 11, 12, 5, index);
|
||||
quarterRound(2, 7, 8, 13, 6, index);
|
||||
quarterRound(3, 4, 9, 14, 7, index);
|
||||
}
|
||||
|
||||
// Combine the new and old hash values.
|
||||
for (index = 0; index < 8; ++index)
|
||||
h[index] ^= (v[index] ^ v[index + 8]);
|
||||
}
|
||||
|
||||
private static int rightRotate16(int v)
|
||||
{
|
||||
return v << 16 | (v >>> 16);
|
||||
}
|
||||
|
||||
private static int rightRotate12(int v)
|
||||
{
|
||||
return v << 20 | (v >>> 12);
|
||||
}
|
||||
|
||||
private static int rightRotate8(int v)
|
||||
{
|
||||
return v << 24 | (v >>> 8);
|
||||
}
|
||||
|
||||
private static int rightRotate7(int v)
|
||||
{
|
||||
return v << 25 | (v >>> 7);
|
||||
}
|
||||
|
||||
private void quarterRound(int a, int b, int c, int d, int i, int row)
|
||||
{
|
||||
v[a] += v[b] + m[sigma[row][2 * i]];
|
||||
v[d] = rightRotate16(v[d] ^ v[a]);
|
||||
v[c] += v[d];
|
||||
v[b] = rightRotate12(v[b] ^ v[c]);
|
||||
v[a] += v[b] + m[sigma[row][2 * i + 1]];
|
||||
v[d] = rightRotate8(v[d] ^ v[a]);
|
||||
v[c] += v[d];
|
||||
v[b] = rightRotate7(v[b] ^ v[c]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Arrays.fill(h, (int)0);
|
||||
Arrays.fill(block, (byte)0);
|
||||
Arrays.fill(m, (int)0);
|
||||
Arrays.fill(v, (int)0);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable
|
||||
import java.security.DigestException
|
||||
import java.security.MessageDigest
|
||||
|
||||
/**
|
||||
* Fallback implementation of BLAKE2s for the Noise library.
|
||||
*
|
||||
* This implementation only supports message digesting with an output
|
||||
* length of 32 bytes. Keyed hashing and variable-length digests are
|
||||
* not supported.
|
||||
*/
|
||||
class Blake2sMessageDigest : MessageDigest("BLAKE2S-256"), Destroyable {
|
||||
private val h = IntArray(8)
|
||||
private val block = ByteArray(64)
|
||||
private val m = IntArray(16)
|
||||
private val v = IntArray(16)
|
||||
private var length: Long = 0
|
||||
private var posn = 0
|
||||
|
||||
init {
|
||||
engineReset()
|
||||
}
|
||||
|
||||
|
||||
override fun engineDigest(): ByteArray {
|
||||
val digest = ByteArray(32)
|
||||
try {
|
||||
engineDigest(digest, 0, 32)
|
||||
} catch (e: DigestException) {
|
||||
// Shouldn't happen, but just in case.
|
||||
digest.fill(0)
|
||||
}
|
||||
return digest
|
||||
}
|
||||
|
||||
@Throws(DigestException::class)
|
||||
override fun engineDigest(buf: ByteArray, offset: Int, len: Int): Int {
|
||||
var offset = offset
|
||||
if (len < 32) throw DigestException("Invalid digest length for BLAKE2s")
|
||||
block.fill(0, posn, 64)
|
||||
transform(-1)
|
||||
for (index in 0..7) {
|
||||
val value = h[index]
|
||||
buf[offset++] = value.toByte()
|
||||
buf[offset++] = (value shr 8).toByte()
|
||||
buf[offset++] = (value shr 16).toByte()
|
||||
buf[offset++] = (value shr 24).toByte()
|
||||
}
|
||||
return 32
|
||||
}
|
||||
|
||||
override fun engineGetDigestLength(): Int = 32
|
||||
|
||||
|
||||
override fun engineReset() {
|
||||
h[0] = 0x6A09E667 xor 0x01010020
|
||||
h[1] = -0x4498517b
|
||||
h[2] = 0x3C6EF372
|
||||
h[3] = -0x5ab00ac6
|
||||
h[4] = 0x510E527F
|
||||
h[5] = -0x64fa9774
|
||||
h[6] = 0x1F83D9AB
|
||||
h[7] = 0x5BE0CD19
|
||||
length = 0
|
||||
posn = 0
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: Byte) {
|
||||
if (posn >= 64) {
|
||||
transform(0)
|
||||
posn = 0
|
||||
}
|
||||
block[posn++] = input
|
||||
++length
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: ByteArray, offset: Int, len: Int) {
|
||||
var currentOffset = offset
|
||||
var remainingLen = len
|
||||
while (remainingLen > 0) {
|
||||
if (posn >= 64) {
|
||||
transform(0)
|
||||
posn = 0
|
||||
}
|
||||
var temp = 64 - posn
|
||||
if (temp > remainingLen) temp = remainingLen
|
||||
|
||||
input.copyInto(block, posn, currentOffset, currentOffset + temp)
|
||||
posn += temp
|
||||
length += temp.toLong()
|
||||
currentOffset += temp
|
||||
remainingLen -= temp
|
||||
}
|
||||
}
|
||||
|
||||
private fun transform(f0: Int) {
|
||||
var currentOffset = 0
|
||||
|
||||
|
||||
// Unpack the input block from little-endian into host-endian.
|
||||
for (index in 0 until 16) {
|
||||
m[index] = (block[currentOffset].toInt() and 0xFF) or
|
||||
((block[currentOffset + 1].toInt() and 0xFF) shl 8) or
|
||||
((block[currentOffset + 2].toInt() and 0xFF) shl 16) or
|
||||
((block[currentOffset + 3].toInt() and 0xFF) shl 24)
|
||||
currentOffset += 4
|
||||
}
|
||||
|
||||
// Format the block to be hashed.
|
||||
for (index in 0 until 8) {
|
||||
v[index] = h[index]
|
||||
}
|
||||
v[8] = 0x6A09E667
|
||||
v[9] = -0x4498517b
|
||||
v[10] = 0x3C6EF372
|
||||
v[11] = -0x5ab00ac6
|
||||
v[12] = 0x510E527F xor length.toInt()
|
||||
v[13] = -0x64fa9774 xor (length shr 32).toInt()
|
||||
v[14] = 0x1F83D9AB xor f0
|
||||
v[15] = 0x5BE0CD19
|
||||
|
||||
|
||||
// Perform the 10 BLAKE2s rounds.
|
||||
for (index in 0 until 10) {
|
||||
// Column round.
|
||||
quarterRound(0, 4, 8, 12, 0, index)
|
||||
quarterRound(1, 5, 9, 13, 1, index)
|
||||
quarterRound(2, 6, 10, 14, 2, index)
|
||||
quarterRound(3, 7, 11, 15, 3, index)
|
||||
|
||||
// Diagonal round.
|
||||
quarterRound(0, 5, 10, 15, 4, index)
|
||||
quarterRound(1, 6, 11, 12, 5, index)
|
||||
quarterRound(2, 7, 8, 13, 6, index)
|
||||
quarterRound(3, 4, 9, 14, 7, index)
|
||||
}
|
||||
|
||||
|
||||
// Combine the new and old hash values.
|
||||
for (index in 0 until 8) {
|
||||
h[index] = h[index] xor (v[index] xor v[index + 8])
|
||||
}
|
||||
}
|
||||
|
||||
private fun quarterRound(a: Int, b: Int, c: Int, d: Int, i: Int, row: Int) {
|
||||
v[a] += v[b] + m[sigma[row][2 * i].toInt()]
|
||||
v[d] = rightRotate16(v[d] xor v[a])
|
||||
v[c] += v[d]
|
||||
v[b] = rightRotate12(v[b] xor v[c])
|
||||
v[a] += v[b] + m[sigma[row][2 * i + 1].toInt()]
|
||||
v[d] = rightRotate8(v[d] xor v[a])
|
||||
v[c] += v[d]
|
||||
v[b] = rightRotate7(v[b] xor v[c])
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
h.fill(0)
|
||||
block.fill(0)
|
||||
m.fill(0)
|
||||
v.fill(0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Permutation on the message input state for BLAKE2s.
|
||||
val sigma: Array<ByteArray> = arrayOf(
|
||||
byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
byteArrayOf(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3),
|
||||
byteArrayOf(11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4),
|
||||
byteArrayOf(7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8),
|
||||
byteArrayOf(9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13),
|
||||
byteArrayOf(2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9),
|
||||
byteArrayOf(12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11),
|
||||
byteArrayOf(13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10),
|
||||
byteArrayOf(6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5),
|
||||
byteArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0)
|
||||
)
|
||||
|
||||
private fun rightRotate16(v: Int): Int = (v shl 16) or (v ushr 16)
|
||||
private fun rightRotate12(v: Int): Int = (v shl 20) or (v ushr 12)
|
||||
private fun rightRotate8(v: Int): Int = (v shl 24) or (v ushr 8)
|
||||
private fun rightRotate7(v: Int): Int = (v shl 25) or (v ushr 7)
|
||||
}
|
||||
}
|
||||
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
/**
|
||||
* Implementation of the ChaCha20 core hash transformation.
|
||||
*/
|
||||
public final class ChaChaCore {
|
||||
|
||||
private ChaChaCore() {}
|
||||
|
||||
/**
|
||||
* Hashes an input block with ChaCha20.
|
||||
*
|
||||
* @param output The output block, which must contain at least 16
|
||||
* elements and must not overlap with the input.
|
||||
* @param input The input block, which must contain at least 16
|
||||
* elements.
|
||||
*/
|
||||
public static void hash(int[] output, int[] input)
|
||||
{
|
||||
int index;
|
||||
|
||||
// Copy the input to the output to start with.
|
||||
for (index = 0; index < 16; ++index)
|
||||
output[index] = input[index];
|
||||
|
||||
// Perform the 20 ChaCha rounds in groups of two.
|
||||
for (index = 0; index < 20; index += 2) {
|
||||
// Column round.
|
||||
quarterRound(output, 0, 4, 8, 12);
|
||||
quarterRound(output, 1, 5, 9, 13);
|
||||
quarterRound(output, 2, 6, 10, 14);
|
||||
quarterRound(output, 3, 7, 11, 15);
|
||||
|
||||
// Diagonal round.
|
||||
quarterRound(output, 0, 5, 10, 15);
|
||||
quarterRound(output, 1, 6, 11, 12);
|
||||
quarterRound(output, 2, 7, 8, 13);
|
||||
quarterRound(output, 3, 4, 9, 14);
|
||||
}
|
||||
|
||||
// Add the input block to the output.
|
||||
for (index = 0; index < 16; ++index)
|
||||
output[index] += input[index];
|
||||
}
|
||||
|
||||
private static int char4(char c1, char c2, char c3, char c4)
|
||||
{
|
||||
return (((int)c1) & 0xFF) | ((((int)c2) & 0xFF) << 8) | ((((int)c3) & 0xFF) << 16) | ((((int)c4) & 0xFF) << 24);
|
||||
}
|
||||
|
||||
private static int fromLittleEndian(byte[] key, int offset)
|
||||
{
|
||||
return (key[offset] & 0xFF) | ((key[offset + 1] & 0xFF) << 8) | ((key[offset + 2] & 0xFF) << 16) | ((key[offset + 3] & 0xFF) << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a ChaCha20 block with a 128-bit key.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words.
|
||||
* @param key The buffer containing the key.
|
||||
* @param offset Offset of the key in the buffer.
|
||||
*/
|
||||
public static void initKey128(int[] output, byte[] key, int offset)
|
||||
{
|
||||
output[0] = char4('e', 'x', 'p', 'a');
|
||||
output[1] = char4('n', 'd', ' ', '1');
|
||||
output[2] = char4('6', '-', 'b', 'y');
|
||||
output[3] = char4('t', 'e', ' ', 'k');
|
||||
output[4] = fromLittleEndian(key, offset);
|
||||
output[5] = fromLittleEndian(key, offset + 4);
|
||||
output[6] = fromLittleEndian(key, offset + 8);
|
||||
output[7] = fromLittleEndian(key, offset + 12);
|
||||
output[8] = output[4];
|
||||
output[9] = output[5];
|
||||
output[10] = output[6];
|
||||
output[11] = output[7];
|
||||
output[12] = 0;
|
||||
output[13] = 0;
|
||||
output[14] = 0;
|
||||
output[15] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a ChaCha20 block with a 256-bit key.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words.
|
||||
* @param key The buffer containing the key.
|
||||
* @param offset Offset of the key in the buffer.
|
||||
*/
|
||||
public static void initKey256(int[] output, byte[] key, int offset)
|
||||
{
|
||||
output[0] = char4('e', 'x', 'p', 'a');
|
||||
output[1] = char4('n', 'd', ' ', '3');
|
||||
output[2] = char4('2', '-', 'b', 'y');
|
||||
output[3] = char4('t', 'e', ' ', 'k');
|
||||
output[4] = fromLittleEndian(key, offset);
|
||||
output[5] = fromLittleEndian(key, offset + 4);
|
||||
output[6] = fromLittleEndian(key, offset + 8);
|
||||
output[7] = fromLittleEndian(key, offset + 12);
|
||||
output[8] = fromLittleEndian(key, offset + 16);
|
||||
output[9] = fromLittleEndian(key, offset + 20);
|
||||
output[10] = fromLittleEndian(key, offset + 24);
|
||||
output[11] = fromLittleEndian(key, offset + 28);
|
||||
output[12] = 0;
|
||||
output[13] = 0;
|
||||
output[14] = 0;
|
||||
output[15] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the 64-bit initialization vector in a ChaCha20 block.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words and must have been initialized by initKey256()
|
||||
* or initKey128().
|
||||
* @param iv The 64-bit initialization vector value.
|
||||
*
|
||||
* The counter portion of the output block is set to zero.
|
||||
*/
|
||||
public static void initIV(int[] output, long iv)
|
||||
{
|
||||
output[12] = 0;
|
||||
output[13] = 0;
|
||||
output[14] = (int)iv;
|
||||
output[15] = (int)(iv >> 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the 64-bit initialization vector and counter in a ChaCha20 block.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words and must have been initialized by initKey256()
|
||||
* or initKey128().
|
||||
* @param iv The 64-bit initialization vector value.
|
||||
* @param counter The 64-bit counter value.
|
||||
*/
|
||||
public static void initIV(int[] output, long iv, long counter)
|
||||
{
|
||||
output[12] = (int)counter;
|
||||
output[13] = (int)(counter >> 32);
|
||||
output[14] = (int)iv;
|
||||
output[15] = (int)(iv >> 32);
|
||||
}
|
||||
|
||||
private static int leftRotate16(int v)
|
||||
{
|
||||
return v << 16 | (v >>> 16);
|
||||
}
|
||||
|
||||
private static int leftRotate12(int v)
|
||||
{
|
||||
return v << 12 | (v >>> 20);
|
||||
}
|
||||
|
||||
private static int leftRotate8(int v)
|
||||
{
|
||||
return v << 8 | (v >>> 24);
|
||||
}
|
||||
|
||||
private static int leftRotate7(int v)
|
||||
{
|
||||
return v << 7 | (v >>> 25);
|
||||
}
|
||||
|
||||
private static void quarterRound(int[] v, int a, int b, int c, int d)
|
||||
{
|
||||
v[a] += v[b];
|
||||
v[d] = leftRotate16(v[d] ^ v[a]);
|
||||
v[c] += v[d];
|
||||
v[b] = leftRotate12(v[b] ^ v[c]);
|
||||
v[a] += v[b];
|
||||
v[d] = leftRotate8(v[d] ^ v[a]);
|
||||
v[c] += v[d];
|
||||
v[b] = leftRotate7(v[b] ^ v[c]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
/**
|
||||
* Implementation of the ChaCha20 core hash transformation.
|
||||
*/
|
||||
object ChaChaCore {
|
||||
/**
|
||||
* Hashes an input block with ChaCha20.
|
||||
*
|
||||
* @param output The output block, which must contain at least 16
|
||||
* elements and must not overlap with the input.
|
||||
* @param input The input block, which must contain at least 16
|
||||
* elements.
|
||||
*/
|
||||
fun hash(output: IntArray, input: IntArray) {
|
||||
// Copy the input to the output to start with.
|
||||
input.copyInto(output, 0, 0, 16)
|
||||
|
||||
// Perform the 20 ChaCha rounds in groups of two.
|
||||
for (index in 0 until 20 step 2) {
|
||||
// Column round.
|
||||
quarterRound(output, 0, 4, 8, 12)
|
||||
quarterRound(output, 1, 5, 9, 13)
|
||||
quarterRound(output, 2, 6, 10, 14)
|
||||
quarterRound(output, 3, 7, 11, 15)
|
||||
|
||||
// Diagonal round.
|
||||
quarterRound(output, 0, 5, 10, 15)
|
||||
quarterRound(output, 1, 6, 11, 12)
|
||||
quarterRound(output, 2, 7, 8, 13)
|
||||
quarterRound(output, 3, 4, 9, 14)
|
||||
}
|
||||
|
||||
// Add the input block to the output.
|
||||
for (index in 0 until 16) {
|
||||
output[index] += input[index]
|
||||
}
|
||||
}
|
||||
|
||||
private fun char4(c1: Char, c2: Char, c3: Char, c4: Char): Int =
|
||||
(c1.code and 0xFF) or
|
||||
((c2.code and 0xFF) shl 8) or
|
||||
((c3.code and 0xFF) shl 16) or
|
||||
((c4.code and 0xFF) shl 24)
|
||||
|
||||
private fun fromLittleEndian(key: ByteArray, offset: Int): Int =
|
||||
(key[offset].toInt() and 0xFF) or
|
||||
((key[offset + 1].toInt() and 0xFF) shl 8) or
|
||||
((key[offset + 2].toInt() and 0xFF) shl 16) or
|
||||
((key[offset + 3].toInt() and 0xFF) shl 24)
|
||||
|
||||
|
||||
/**
|
||||
* Initializes a ChaCha20 block with a 128-bit key.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words.
|
||||
* @param key The buffer containing the key.
|
||||
* @param offset Offset of the key in the buffer.
|
||||
*/
|
||||
fun initKey128(output: IntArray, key: ByteArray, offset: Int) {
|
||||
output[0] = char4('e', 'x', 'p', 'a')
|
||||
output[1] = char4('n', 'd', ' ', '1')
|
||||
output[2] = char4('6', '-', 'b', 'y')
|
||||
output[3] = char4('t', 'e', ' ', 'k')
|
||||
output[4] = fromLittleEndian(key, offset)
|
||||
output[5] = fromLittleEndian(key, offset + 4)
|
||||
output[6] = fromLittleEndian(key, offset + 8)
|
||||
output[7] = fromLittleEndian(key, offset + 12)
|
||||
output[8] = output[4]
|
||||
output[9] = output[5]
|
||||
output[10] = output[6]
|
||||
output[11] = output[7]
|
||||
output[12] = 0
|
||||
output[13] = 0
|
||||
output[14] = 0
|
||||
output[15] = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a ChaCha20 block with a 256-bit key.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words.
|
||||
* @param key The buffer containing the key.
|
||||
* @param offset Offset of the key in the buffer.
|
||||
*/
|
||||
fun initKey256(output: IntArray, key: ByteArray, offset: Int) {
|
||||
output[0] = char4('e', 'x', 'p', 'a')
|
||||
output[1] = char4('n', 'd', ' ', '3')
|
||||
output[2] = char4('2', '-', 'b', 'y')
|
||||
output[3] = char4('t', 'e', ' ', 'k')
|
||||
output[4] = fromLittleEndian(key, offset)
|
||||
output[5] = fromLittleEndian(key, offset + 4)
|
||||
output[6] = fromLittleEndian(key, offset + 8)
|
||||
output[7] = fromLittleEndian(key, offset + 12)
|
||||
output[8] = fromLittleEndian(key, offset + 16)
|
||||
output[9] = fromLittleEndian(key, offset + 20)
|
||||
output[10] = fromLittleEndian(key, offset + 24)
|
||||
output[11] = fromLittleEndian(key, offset + 28)
|
||||
output[12] = 0
|
||||
output[13] = 0
|
||||
output[14] = 0
|
||||
output[15] = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the 64-bit initialization vector in a ChaCha20 block.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words and must have been initialized by initKey256()
|
||||
* or initKey128().
|
||||
* @param iv The 64-bit initialization vector value.
|
||||
*
|
||||
* The counter portion of the output block is set to zero.
|
||||
*/
|
||||
fun initIV(output: IntArray, iv: Long) {
|
||||
output[12] = 0
|
||||
output[13] = 0
|
||||
output[14] = iv.toInt()
|
||||
output[15] = (iv shr 32).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the 64-bit initialization vector and counter in a ChaCha20 block.
|
||||
*
|
||||
* @param output The output block, which must consist of at
|
||||
* least 16 words and must have been initialized by initKey256()
|
||||
* or initKey128().
|
||||
* @param iv The 64-bit initialization vector value.
|
||||
* @param counter The 64-bit counter value.
|
||||
*/
|
||||
fun initIV(output: IntArray, iv: Long, counter: Long) {
|
||||
output[12] = counter.toInt()
|
||||
output[13] = (counter shr 32).toInt()
|
||||
output[14] = iv.toInt()
|
||||
output[15] = (iv shr 32).toInt()
|
||||
}
|
||||
|
||||
private fun leftRotate16(v: Int): Int = (v shl 16) or (v ushr 16)
|
||||
|
||||
private fun leftRotate12(v: Int): Int = (v shl 12) or (v ushr 20)
|
||||
|
||||
|
||||
private fun leftRotate8(v: Int): Int = (v shl 8) or (v ushr 24)
|
||||
|
||||
|
||||
private fun leftRotate7(v: Int): Int = (v shl 7) or (v ushr 25)
|
||||
|
||||
|
||||
private fun quarterRound(v: IntArray, a: Int, b: Int, c: Int, d: Int) {
|
||||
v[a] += v[b]
|
||||
v[d] = leftRotate16(v[d] xor v[a])
|
||||
v[c] += v[d]
|
||||
v[b] = leftRotate12(v[b] xor v[c])
|
||||
v[a] += v[b]
|
||||
v[d] = leftRotate8(v[d] xor v[a])
|
||||
v[c] += v[d]
|
||||
v[b] = leftRotate7(v[b] xor v[c])
|
||||
}
|
||||
}
|
||||
@ -1,531 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Implementation of the Curve25519 elliptic curve algorithm.
|
||||
*
|
||||
* This implementation is based on that from arduinolibs:
|
||||
* https://github.com/rweather/arduinolibs
|
||||
*
|
||||
* Differences in this version are due to using 26-bit limbs for the
|
||||
* representation instead of the 8/16/32-bit limbs in the original.
|
||||
*
|
||||
* References: http://cr.yp.to/ecdh.html, RFC 7748
|
||||
*/
|
||||
public final class Curve25519 {
|
||||
|
||||
// Numbers modulo 2^255 - 19 are broken up into ten 26-bit words.
|
||||
private static final int NUM_LIMBS_255BIT = 10;
|
||||
private static final int NUM_LIMBS_510BIT = 20;
|
||||
private int[] x_1;
|
||||
private int[] x_2;
|
||||
private int[] x_3;
|
||||
private int[] z_2;
|
||||
private int[] z_3;
|
||||
private int[] A;
|
||||
private int[] B;
|
||||
private int[] C;
|
||||
private int[] D;
|
||||
private int[] E;
|
||||
private int[] AA;
|
||||
private int[] BB;
|
||||
private int[] DA;
|
||||
private int[] CB;
|
||||
private long[] t1;
|
||||
private int[] t2;
|
||||
|
||||
/**
|
||||
* Constructs the temporary state holder for Curve25519 evaluation.
|
||||
*/
|
||||
private Curve25519()
|
||||
{
|
||||
// Allocate memory for all of the temporary variables we will need.
|
||||
x_1 = new int [NUM_LIMBS_255BIT];
|
||||
x_2 = new int [NUM_LIMBS_255BIT];
|
||||
x_3 = new int [NUM_LIMBS_255BIT];
|
||||
z_2 = new int [NUM_LIMBS_255BIT];
|
||||
z_3 = new int [NUM_LIMBS_255BIT];
|
||||
A = new int [NUM_LIMBS_255BIT];
|
||||
B = new int [NUM_LIMBS_255BIT];
|
||||
C = new int [NUM_LIMBS_255BIT];
|
||||
D = new int [NUM_LIMBS_255BIT];
|
||||
E = new int [NUM_LIMBS_255BIT];
|
||||
AA = new int [NUM_LIMBS_255BIT];
|
||||
BB = new int [NUM_LIMBS_255BIT];
|
||||
DA = new int [NUM_LIMBS_255BIT];
|
||||
CB = new int [NUM_LIMBS_255BIT];
|
||||
t1 = new long [NUM_LIMBS_510BIT];
|
||||
t2 = new int [NUM_LIMBS_510BIT];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy all sensitive data in this object.
|
||||
*/
|
||||
private void destroy() {
|
||||
// Destroy all temporary variables.
|
||||
Arrays.fill(x_1, 0);
|
||||
Arrays.fill(x_2, 0);
|
||||
Arrays.fill(x_3, 0);
|
||||
Arrays.fill(z_2, 0);
|
||||
Arrays.fill(z_3, 0);
|
||||
Arrays.fill(A, 0);
|
||||
Arrays.fill(B, 0);
|
||||
Arrays.fill(C, 0);
|
||||
Arrays.fill(D, 0);
|
||||
Arrays.fill(E, 0);
|
||||
Arrays.fill(AA, 0);
|
||||
Arrays.fill(BB, 0);
|
||||
Arrays.fill(DA, 0);
|
||||
Arrays.fill(CB, 0);
|
||||
Arrays.fill(t1, 0L);
|
||||
Arrays.fill(t2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a number modulo 2^255 - 19 where it is known that the
|
||||
* number can be reduced with only 1 trial subtraction.
|
||||
*
|
||||
* @param x The number to reduce, and the result.
|
||||
*/
|
||||
private void reduceQuick(int[] x)
|
||||
{
|
||||
int index, carry;
|
||||
|
||||
// Perform a trial subtraction of (2^255 - 19) from "x" which is
|
||||
// equivalent to adding 19 and subtracting 2^255. We add 19 here;
|
||||
// the subtraction of 2^255 occurs in the next step.
|
||||
carry = 19;
|
||||
for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
|
||||
carry += x[index];
|
||||
t2[index] = carry & 0x03FFFFFF;
|
||||
carry >>= 26;
|
||||
}
|
||||
|
||||
// If there was a borrow, then the original "x" is the correct answer.
|
||||
// If there was no borrow, then "t2" is the correct answer. Select the
|
||||
// correct answer but do it in a way that instruction timing will not
|
||||
// reveal which value was selected. Borrow will occur if bit 21 of
|
||||
// "t2" is zero. Turn the bit into a selection mask.
|
||||
int mask = -((t2[NUM_LIMBS_255BIT - 1] >> 21) & 0x01);
|
||||
int nmask = ~mask;
|
||||
t2[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
|
||||
for (index = 0; index < NUM_LIMBS_255BIT; ++index)
|
||||
x[index] = (x[index] & nmask) | (t2[index] & mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The value to be reduced. This array will be
|
||||
* modified during the reduction.
|
||||
* @param size The number of limbs in the high order half of x.
|
||||
*/
|
||||
private void reduce(int[] result, int[] x, int size)
|
||||
{
|
||||
int index, limb, carry;
|
||||
|
||||
// Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
|
||||
// either produce the answer we want or it will produce a
|
||||
// value of the form "answer + j * (2^255 - 19)". There are
|
||||
// 5 left-over bits in the top-most limb of the bottom half.
|
||||
carry = 0;
|
||||
limb = x[NUM_LIMBS_255BIT - 1] >> 21;
|
||||
x[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
|
||||
for (index = 0; index < size; ++index) {
|
||||
limb += x[NUM_LIMBS_255BIT + index] << 5;
|
||||
carry += (limb & 0x03FFFFFF) * 19 + x[index];
|
||||
x[index] = carry & 0x03FFFFFF;
|
||||
limb >>= 26;
|
||||
carry >>= 26;
|
||||
}
|
||||
if (size < NUM_LIMBS_255BIT) {
|
||||
// The high order half of the number is short; e.g. for mulA24().
|
||||
// Propagate the carry through the rest of the low order part.
|
||||
for (index = size; index < NUM_LIMBS_255BIT; ++index) {
|
||||
carry += x[index];
|
||||
x[index] = carry & 0x03FFFFFF;
|
||||
carry >>= 26;
|
||||
}
|
||||
}
|
||||
|
||||
// The "j" value may still be too large due to the final carry-out.
|
||||
// We must repeat the reduction. If we already have the answer,
|
||||
// then this won't do any harm but we must still do the calculation
|
||||
// to preserve the overall timing. The "j" value will be between
|
||||
// 0 and 19, which means that the carry we care about is in the
|
||||
// top 5 bits of the highest limb of the bottom half.
|
||||
carry = (x[NUM_LIMBS_255BIT - 1] >> 21) * 19;
|
||||
x[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
|
||||
for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
|
||||
carry += x[index];
|
||||
result[index] = carry & 0x03FFFFFF;
|
||||
carry >>= 26;
|
||||
}
|
||||
|
||||
// At this point "x" will either be the answer or it will be the
|
||||
// answer plus (2^255 - 19). Perform a trial subtraction to
|
||||
// complete the reduction process.
|
||||
reduceQuick(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to multiply.
|
||||
* @param y The second number to multiply.
|
||||
*/
|
||||
private void mul(int[] result, int[] x, int[] y)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
// Multiply the two numbers to create the intermediate result.
|
||||
long v = x[0];
|
||||
for (i = 0; i < NUM_LIMBS_255BIT; ++i) {
|
||||
t1[i] = v * y[i];
|
||||
}
|
||||
for (i = 1; i < NUM_LIMBS_255BIT; ++i) {
|
||||
v = x[i];
|
||||
for (j = 0; j < (NUM_LIMBS_255BIT - 1); ++j) {
|
||||
t1[i + j] += v * y[j];
|
||||
}
|
||||
t1[i + NUM_LIMBS_255BIT - 1] = v * y[NUM_LIMBS_255BIT - 1];
|
||||
}
|
||||
|
||||
// Propagate carries and convert back into 26-bit words.
|
||||
v = t1[0];
|
||||
t2[0] = ((int)v) & 0x03FFFFFF;
|
||||
for (i = 1; i < NUM_LIMBS_510BIT; ++i) {
|
||||
v = (v >> 26) + t1[i];
|
||||
t2[i] = ((int)v) & 0x03FFFFFF;
|
||||
}
|
||||
|
||||
// Reduce the result modulo 2^255 - 19.
|
||||
reduce(result, t2, NUM_LIMBS_255BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Squares a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to square.
|
||||
*/
|
||||
private void square(int[] result, int[] x)
|
||||
{
|
||||
mul(result, x, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a number by the a24 constant, modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to multiply by a24.
|
||||
*/
|
||||
private void mulA24(int[] result, int[] x)
|
||||
{
|
||||
long a24 = 121665;
|
||||
long carry = 0;
|
||||
int index;
|
||||
for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
|
||||
carry += a24 * x[index];
|
||||
t2[index] = ((int)carry) & 0x03FFFFFF;
|
||||
carry >>= 26;
|
||||
}
|
||||
t2[NUM_LIMBS_255BIT] = ((int)carry) & 0x03FFFFFF;
|
||||
reduce(result, t2, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to add.
|
||||
* @param y The second number to add.
|
||||
*/
|
||||
private void add(int[] result, int[] x, int[] y)
|
||||
{
|
||||
int index, carry;
|
||||
carry = x[0] + y[0];
|
||||
result[0] = carry & 0x03FFFFFF;
|
||||
for (index = 1; index < NUM_LIMBS_255BIT; ++index) {
|
||||
carry = (carry >> 26) + x[index] + y[index];
|
||||
result[index] = carry & 0x03FFFFFF;
|
||||
}
|
||||
reduceQuick(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to subtract.
|
||||
* @param y The second number to subtract.
|
||||
*/
|
||||
private void sub(int[] result, int[] x, int[] y)
|
||||
{
|
||||
int index, borrow;
|
||||
|
||||
// Subtract y from x to generate the intermediate result.
|
||||
borrow = 0;
|
||||
for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
|
||||
borrow = x[index] - y[index] - ((borrow >> 26) & 0x01);
|
||||
result[index] = borrow & 0x03FFFFFF;
|
||||
}
|
||||
|
||||
// If we had a borrow, then the result has gone negative and we
|
||||
// have to add 2^255 - 19 to the result to make it positive again.
|
||||
// The top bits of "borrow" will be all 1's if there is a borrow
|
||||
// or it will be all 0's if there was no borrow. Easiest is to
|
||||
// conditionally subtract 19 and then mask off the high bits.
|
||||
borrow = result[0] - ((-((borrow >> 26) & 0x01)) & 19);
|
||||
result[0] = borrow & 0x03FFFFFF;
|
||||
for (index = 1; index < NUM_LIMBS_255BIT; ++index) {
|
||||
borrow = result[index] - ((borrow >> 26) & 0x01);
|
||||
result[index] = borrow & 0x03FFFFFF;
|
||||
}
|
||||
result[NUM_LIMBS_255BIT - 1] &= 0x001FFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditional swap of two values.
|
||||
*
|
||||
* @param select Set to 1 to swap, 0 to leave as-is.
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
*/
|
||||
private static void cswap(int select, int[] x, int[] y)
|
||||
{
|
||||
int dummy;
|
||||
select = -select;
|
||||
for (int index = 0; index < NUM_LIMBS_255BIT; ++index) {
|
||||
dummy = select & (x[index] ^ y[index]);
|
||||
x[index] ^= dummy;
|
||||
y[index] ^= dummy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise x to the power of (2^250 - 1).
|
||||
*
|
||||
* @param result The result. Must not overlap with x.
|
||||
* @param x The argument.
|
||||
*/
|
||||
private void pow250(int[] result, int[] x)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
// The big-endian hexadecimal expansion of (2^250 - 1) is:
|
||||
// 03FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
|
||||
//
|
||||
// The naive implementation needs to do 2 multiplications per 1 bit and
|
||||
// 1 multiplication per 0 bit. We can improve upon this by creating a
|
||||
// pattern 0000000001 ... 0000000001. If we square and multiply the
|
||||
// pattern by itself we can turn the pattern into the partial results
|
||||
// 0000000011 ... 0000000011, 0000000111 ... 0000000111, etc.
|
||||
// This averages out to about 1.1 multiplications per 1 bit instead of 2.
|
||||
|
||||
// Build a pattern of 250 bits in length of repeated copies of 0000000001.
|
||||
square(A, x);
|
||||
for (j = 0; j < 9; ++j)
|
||||
square(A, A);
|
||||
mul(result, A, x);
|
||||
for (i = 0; i < 23; ++i) {
|
||||
for (j = 0; j < 10; ++j)
|
||||
square(A, A);
|
||||
mul(result, result, A);
|
||||
}
|
||||
|
||||
// Multiply bit-shifted versions of the 0000000001 pattern into
|
||||
// the result to "fill in" the gaps in the pattern.
|
||||
square(A, result);
|
||||
mul(result, result, A);
|
||||
for (j = 0; j < 8; ++j) {
|
||||
square(A, A);
|
||||
mul(result, result, A);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the reciprocal of a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result. Must not overlap with x.
|
||||
* @param x The argument.
|
||||
*/
|
||||
private void recip(int[] result, int[] x)
|
||||
{
|
||||
// The reciprocal is the same as x ^ (p - 2) where p = 2^255 - 19.
|
||||
// The big-endian hexadecimal expansion of (p - 2) is:
|
||||
// 7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFEB
|
||||
// Start with the 250 upper bits of the expansion of (p - 2).
|
||||
pow250(result, x);
|
||||
|
||||
// Deal with the 5 lowest bits of (p - 2), 01011, from highest to lowest.
|
||||
square(result, result);
|
||||
square(result, result);
|
||||
mul(result, result, x);
|
||||
square(result, result);
|
||||
square(result, result);
|
||||
mul(result, result, x);
|
||||
square(result, result);
|
||||
mul(result, result, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the curve for every bit in a secret key.
|
||||
*
|
||||
* @param s The 32-byte secret key.
|
||||
*/
|
||||
private void evalCurve(byte[] s)
|
||||
{
|
||||
int sposn = 31;
|
||||
int sbit = 6;
|
||||
int svalue = s[sposn] | 0x40;
|
||||
int swap = 0;
|
||||
int select;
|
||||
|
||||
// Iterate over all 255 bits of "s" from the highest to the lowest.
|
||||
// We ignore the high bit of the 256-bit representation of "s".
|
||||
for (;;) {
|
||||
// Conditional swaps on entry to this bit but only if we
|
||||
// didn't swap on the previous bit.
|
||||
select = (svalue >> sbit) & 0x01;
|
||||
swap ^= select;
|
||||
cswap(swap, x_2, x_3);
|
||||
cswap(swap, z_2, z_3);
|
||||
swap = select;
|
||||
|
||||
// Evaluate the curve.
|
||||
add(A, x_2, z_2); // A = x_2 + z_2
|
||||
square(AA, A); // AA = A^2
|
||||
sub(B, x_2, z_2); // B = x_2 - z_2
|
||||
square(BB, B); // BB = B^2
|
||||
sub(E, AA, BB); // E = AA - BB
|
||||
add(C, x_3, z_3); // C = x_3 + z_3
|
||||
sub(D, x_3, z_3); // D = x_3 - z_3
|
||||
mul(DA, D, A); // DA = D * A
|
||||
mul(CB, C, B); // CB = C * B
|
||||
add(x_3, DA, CB); // x_3 = (DA + CB)^2
|
||||
square(x_3, x_3);
|
||||
sub(z_3, DA, CB); // z_3 = x_1 * (DA - CB)^2
|
||||
square(z_3, z_3);
|
||||
mul(z_3, z_3, x_1);
|
||||
mul(x_2, AA, BB); // x_2 = AA * BB
|
||||
mulA24(z_2, E); // z_2 = E * (AA + a24 * E)
|
||||
add(z_2, z_2, AA);
|
||||
mul(z_2, z_2, E);
|
||||
|
||||
// Move onto the next lower bit of "s".
|
||||
if (sbit > 0) {
|
||||
--sbit;
|
||||
} else if (sposn == 0) {
|
||||
break;
|
||||
} else if (sposn == 1) {
|
||||
--sposn;
|
||||
svalue = s[sposn] & 0xF8;
|
||||
sbit = 7;
|
||||
} else {
|
||||
--sposn;
|
||||
svalue = s[sposn];
|
||||
sbit = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// Final conditional swaps.
|
||||
cswap(swap, x_2, x_3);
|
||||
cswap(swap, z_2, z_3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the Curve25519 curve.
|
||||
*
|
||||
* @param result Buffer to place the result of the evaluation into.
|
||||
* @param offset Offset into the result buffer.
|
||||
* @param privateKey The private key to use in the evaluation.
|
||||
* @param publicKey The public key to use in the evaluation, or null
|
||||
* if the base point of the curve should be used.
|
||||
*/
|
||||
public static void eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey)
|
||||
{
|
||||
Curve25519 state = new Curve25519();
|
||||
try {
|
||||
// Unpack the public key value. If null, use 9 as the base point.
|
||||
Arrays.fill(state.x_1, 0);
|
||||
if (publicKey != null) {
|
||||
// Convert the input value from little-endian into 26-bit limbs.
|
||||
for (int index = 0; index < 32; ++index) {
|
||||
int bit = (index * 8) % 26;
|
||||
int word = (index * 8) / 26;
|
||||
int value = publicKey[index] & 0xFF;
|
||||
if (bit <= (26 - 8)) {
|
||||
state.x_1[word] |= value << bit;
|
||||
} else {
|
||||
state.x_1[word] |= value << bit;
|
||||
state.x_1[word] &= 0x03FFFFFF;
|
||||
state.x_1[word + 1] |= value >> (26 - bit);
|
||||
}
|
||||
}
|
||||
|
||||
// Just in case, we reduce the number modulo 2^255 - 19 to
|
||||
// make sure that it is in range of the field before we start.
|
||||
// This eliminates values between 2^255 - 19 and 2^256 - 1.
|
||||
state.reduceQuick(state.x_1);
|
||||
state.reduceQuick(state.x_1);
|
||||
} else {
|
||||
state.x_1[0] = 9;
|
||||
}
|
||||
|
||||
// Initialize the other temporary variables.
|
||||
Arrays.fill(state.x_2, 0); // x_2 = 1
|
||||
state.x_2[0] = 1;
|
||||
Arrays.fill(state.z_2, 0); // z_2 = 0
|
||||
System.arraycopy(state.x_1, 0, state.x_3, 0, state.x_1.length); // x_3 = x_1
|
||||
Arrays.fill(state.z_3, 0); // z_3 = 1
|
||||
state.z_3[0] = 1;
|
||||
|
||||
// Evaluate the curve for every bit of the private key.
|
||||
state.evalCurve(privateKey);
|
||||
|
||||
// Compute x_2 * (z_2 ^ (p - 2)) where p = 2^255 - 19.
|
||||
state.recip(state.z_3, state.z_2);
|
||||
state.mul(state.x_2, state.x_2, state.z_3);
|
||||
|
||||
// Convert x_2 into little-endian in the result buffer.
|
||||
for (int index = 0; index < 32; ++index) {
|
||||
int bit = (index * 8) % 26;
|
||||
int word = (index * 8) / 26;
|
||||
if (bit <= (26 - 8))
|
||||
result[offset + index] = (byte)(state.x_2[word] >> bit);
|
||||
else
|
||||
result[offset + index] = (byte)((state.x_2[word] >> bit) | (state.x_2[word + 1] << (26 - bit)));
|
||||
}
|
||||
} finally {
|
||||
// Clean up all temporary state before we exit.
|
||||
state.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
/**
|
||||
* Implementation of the Curve25519 elliptic curve algorithm.
|
||||
*
|
||||
* This implementation is based on that from arduinolibs:
|
||||
* https://github.com/rweather/arduinolibs
|
||||
*
|
||||
* Differences in this version are due to using 26-bit limbs for the
|
||||
* representation instead of the 8/16/32-bit limbs in the original.
|
||||
*
|
||||
* References: http://cr.yp.to/ecdh.html, RFC 7748
|
||||
*/
|
||||
class Curve25519 {
|
||||
private val x_1 = IntArray(NUM_LIMBS_255BIT)
|
||||
private val x_2 = IntArray(NUM_LIMBS_255BIT)
|
||||
private val x_3 = IntArray(NUM_LIMBS_255BIT)
|
||||
private val z_2 = IntArray(NUM_LIMBS_255BIT)
|
||||
private val z_3 = IntArray(NUM_LIMBS_255BIT)
|
||||
private val A = IntArray(NUM_LIMBS_255BIT)
|
||||
private val B = IntArray(NUM_LIMBS_255BIT)
|
||||
private val C = IntArray(NUM_LIMBS_255BIT)
|
||||
private val D = IntArray(NUM_LIMBS_255BIT)
|
||||
private val E = IntArray(NUM_LIMBS_255BIT)
|
||||
private val AA = IntArray(NUM_LIMBS_255BIT)
|
||||
private val BB = IntArray(NUM_LIMBS_255BIT)
|
||||
private val DA = IntArray(NUM_LIMBS_255BIT)
|
||||
private val CB = IntArray(NUM_LIMBS_255BIT)
|
||||
private val t1 = LongArray(NUM_LIMBS_510BIT)
|
||||
private val t2 = IntArray(NUM_LIMBS_510BIT)
|
||||
|
||||
/**
|
||||
* Destroy all sensitive data in this object.
|
||||
*/
|
||||
private fun destroy() {
|
||||
// Destroy all temporary variables.
|
||||
x_1.fill(0)
|
||||
x_2.fill(0)
|
||||
x_3.fill(0)
|
||||
z_2.fill(0)
|
||||
z_3.fill(0)
|
||||
A.fill(0)
|
||||
B.fill(0)
|
||||
C.fill(0)
|
||||
D.fill(0)
|
||||
E.fill(0)
|
||||
AA.fill(0)
|
||||
BB.fill(0)
|
||||
DA.fill(0)
|
||||
CB.fill(0)
|
||||
t1.fill(0L)
|
||||
t2.fill(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a number modulo 2^255 - 19 where it is known that the
|
||||
* number can be reduced with only 1 trial subtraction.
|
||||
*
|
||||
* @param x The number to reduce, and the result.
|
||||
*/
|
||||
private fun reduceQuick(x: IntArray) {
|
||||
// Perform a trial subtraction of (2^255 - 19) from "x" which is
|
||||
// equivalent to adding 19 and subtracting 2^255. We add 19 here;
|
||||
// the subtraction of 2^255 occurs in the next step.
|
||||
var carry = 19
|
||||
for (index in 0 until NUM_LIMBS_255BIT) {
|
||||
carry += x[index]
|
||||
t2[index] = carry and 0x03FFFFFF
|
||||
carry = carry shr 26
|
||||
}
|
||||
|
||||
// If there was a borrow, then the original "x" is the correct answer.
|
||||
// If there was no borrow, then "t2" is the correct answer. Select the
|
||||
// correct answer but do it in a way that instruction timing will not
|
||||
// reveal which value was selected. Borrow will occur if bit 21 of
|
||||
// "t2" is zero. Turn the bit into a selection mask.
|
||||
val mask = -((t2[NUM_LIMBS_255BIT - 1] shr 21) and 0x01)
|
||||
val nmask = mask.inv()
|
||||
t2[NUM_LIMBS_255BIT - 1] = t2[NUM_LIMBS_255BIT - 1] and 0x001FFFFF
|
||||
for (index in 0 until NUM_LIMBS_255BIT) {
|
||||
x[index] = (x[index] and nmask) or (t2[index] and mask)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The value to be reduced. This array will be
|
||||
* modified during the reduction.
|
||||
* @param size The number of limbs in the high order half of x.
|
||||
*/
|
||||
private fun reduce(result: IntArray, x: IntArray, size: Int) {
|
||||
// Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
|
||||
// either produce the answer we want or it will produce a
|
||||
// value of the form "answer + j * (2^255 - 19)". There are
|
||||
// 5 left-over bits in the top-most limb of the bottom half.
|
||||
var carry = 0
|
||||
var limb = x[NUM_LIMBS_255BIT - 1] shr 21
|
||||
x[NUM_LIMBS_255BIT - 1] = x[NUM_LIMBS_255BIT - 1] and 0x001FFFFF
|
||||
for (index in 0 until size) {
|
||||
limb += x[NUM_LIMBS_255BIT + index] shl 5
|
||||
carry += (limb and 0x03FFFFFF) * 19 + x[index]
|
||||
x[index] = carry and 0x03FFFFFF
|
||||
limb = limb shr 26
|
||||
carry = carry shr 26
|
||||
}
|
||||
if (size < NUM_LIMBS_255BIT) {
|
||||
// The high order half of the number is short; e.g. for mulA24().
|
||||
// Propagate the carry through the rest of the low order part.
|
||||
for (index in size until NUM_LIMBS_255BIT) {
|
||||
carry += x[index]
|
||||
x[index] = carry and 0x03FFFFFF
|
||||
carry = carry shr 26
|
||||
}
|
||||
}
|
||||
|
||||
// The "j" value may still be too large due to the final carry-out.
|
||||
// We must repeat the reduction. If we already have the answer,
|
||||
// then this won't do any harm but we must still do the calculation
|
||||
// to preserve the overall timing. The "j" value will be between
|
||||
// 0 and 19, which means that the carry we care about is in the
|
||||
// top 5 bits of the highest limb of the bottom half.
|
||||
carry = (x[NUM_LIMBS_255BIT - 1] shr 21) * 19
|
||||
x[NUM_LIMBS_255BIT - 1] = x[NUM_LIMBS_255BIT - 1] and 0x001FFFFF
|
||||
for (index in 0 until NUM_LIMBS_255BIT) {
|
||||
carry += x[index]
|
||||
result[index] = carry and 0x03FFFFFF
|
||||
carry = carry shr 26
|
||||
}
|
||||
|
||||
// At this point "x" will either be the answer or it will be the
|
||||
// answer plus (2^255 - 19). Perform a trial subtraction to
|
||||
// complete the reduction process.
|
||||
reduceQuick(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to multiply.
|
||||
* @param y The second number to multiply.
|
||||
*/
|
||||
private fun mul(result: IntArray, x: IntArray, y: IntArray) {
|
||||
// Multiply the two numbers to create the intermediate result.
|
||||
var v = x[0].toLong()
|
||||
for (i in 0 until NUM_LIMBS_255BIT) {
|
||||
t1[i] = v * y[i]
|
||||
}
|
||||
for (i in 1 until NUM_LIMBS_255BIT) {
|
||||
v = x[i].toLong()
|
||||
for (j in 0 until (NUM_LIMBS_255BIT - 1)) {
|
||||
t1[i + j] += v * y[j]
|
||||
}
|
||||
t1[i + NUM_LIMBS_255BIT - 1] = v * y[NUM_LIMBS_255BIT - 1]
|
||||
}
|
||||
|
||||
// Propagate carries and convert back into 26-bit words.
|
||||
v = t1[0]
|
||||
t2[0] = v.toInt() and 0x03FFFFFF
|
||||
for (i in 1 until NUM_LIMBS_510BIT) {
|
||||
v = (v shr 26) + t1[i]
|
||||
t2[i] = v.toInt() and 0x03FFFFFF
|
||||
}
|
||||
|
||||
// Reduce the result modulo 2^255 - 19.
|
||||
reduce(result, t2, NUM_LIMBS_255BIT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Squares a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to square.
|
||||
*/
|
||||
private fun square(result: IntArray, x: IntArray) {
|
||||
mul(result, x, x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a number by the a24 constant, modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to multiply by a24.
|
||||
*/
|
||||
private fun mulA24(result: IntArray, x: IntArray) {
|
||||
val a24: Long = 121665
|
||||
var carry: Long = 0
|
||||
for (index in 0 until NUM_LIMBS_255BIT) {
|
||||
carry += a24 * x[index]
|
||||
t2[index] = carry.toInt() and 0x03FFFFFF
|
||||
carry = carry shr 26
|
||||
}
|
||||
t2[NUM_LIMBS_255BIT] = carry.toInt() and 0x03FFFFFF
|
||||
reduce(result, t2, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to add.
|
||||
* @param y The second number to add.
|
||||
*/
|
||||
private fun add(result: IntArray, x: IntArray, y: IntArray) {
|
||||
var carry = x[0] + y[0]
|
||||
result[0] = carry and 0x03FFFFFF
|
||||
for (index in 1 until NUM_LIMBS_255BIT) {
|
||||
carry = (carry shr 26) + x[index] + y[index]
|
||||
result[index] = carry and 0x03FFFFFF
|
||||
}
|
||||
reduceQuick(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to subtract.
|
||||
* @param y The second number to subtract.
|
||||
*/
|
||||
private fun sub(result: IntArray, x: IntArray, y: IntArray) {
|
||||
// Subtract y from x to generate the intermediate result.
|
||||
var borrow = 0
|
||||
for (index in 0 until NUM_LIMBS_255BIT) {
|
||||
borrow = x[index] - y[index] - ((borrow shr 26) and 0x01)
|
||||
result[index] = borrow and 0x03FFFFFF
|
||||
}
|
||||
|
||||
// If we had a borrow, then the result has gone negative and we
|
||||
// have to add 2^255 - 19 to the result to make it positive again.
|
||||
// The top bits of "borrow" will be all 1's if there is a borrow
|
||||
// or it will be all 0's if there was no borrow. Easiest is to
|
||||
// conditionally subtract 19 and then mask off the high bits.
|
||||
borrow = result[0] - ((-((borrow shr 26) and 0x01)) and 19)
|
||||
result[0] = borrow and 0x03FFFFFF
|
||||
for (index in 1 until NUM_LIMBS_255BIT) {
|
||||
borrow = result[index] - ((borrow shr 26) and 0x01)
|
||||
result[index] = borrow and 0x03FFFFFF
|
||||
}
|
||||
result[NUM_LIMBS_255BIT - 1] = result[NUM_LIMBS_255BIT - 1] and 0x001FFFFF
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise x to the power of (2^250 - 1).
|
||||
*
|
||||
* @param result The result. Must not overlap with x.
|
||||
* @param x The argument.
|
||||
*/
|
||||
private fun pow250(result: IntArray, x: IntArray) {
|
||||
// The big-endian hexadecimal expansion of (2^250 - 1) is:
|
||||
// 03FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
|
||||
//
|
||||
// The naive implementation needs to do 2 multiplications per 1 bit and
|
||||
// 1 multiplication per 0 bit. We can improve upon this by creating a
|
||||
// pattern 0000000001 ... 0000000001. If we square and multiply the
|
||||
// pattern by itself we can turn the pattern into the partial results
|
||||
// 0000000011 ... 0000000011, 0000000111 ... 0000000111, etc.
|
||||
// This averages out to about 1.1 multiplications per 1 bit instead of 2.
|
||||
|
||||
// Build a pattern of 250 bits in length of repeated copies of 0000000001.
|
||||
square(A, x)
|
||||
repeat(9) {
|
||||
square(A, A)
|
||||
}
|
||||
mul(result, A, x)
|
||||
repeat(23) {
|
||||
repeat(10) {
|
||||
square(A, A)
|
||||
}
|
||||
mul(result, result, A)
|
||||
}
|
||||
|
||||
// Multiply bit-shifted versions of the 0000000001 pattern into
|
||||
// the result to "fill in" the gaps in the pattern.
|
||||
square(A, result)
|
||||
mul(result, result, A)
|
||||
repeat(8) {
|
||||
square(A, A)
|
||||
mul(result, result, A)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the reciprocal of a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result. Must not overlap with x.
|
||||
* @param x The argument.
|
||||
*/
|
||||
private fun recip(result: IntArray, x: IntArray) {
|
||||
// The reciprocal is the same as x ^ (p - 2) where p = 2^255 - 19.
|
||||
// Start with the 250 upper bits of the expansion of (p - 2).
|
||||
pow250(result, x)
|
||||
|
||||
// Deal with the 5 lowest bits of (p - 2), 01011, from highest to lowest.
|
||||
repeat(2) { square(result, result) }
|
||||
mul(result, result, x)
|
||||
repeat(2) { square(result, result) }
|
||||
mul(result, result, x)
|
||||
square(result, result)
|
||||
mul(result, result, x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the curve for every bit in a secret key.
|
||||
*
|
||||
* @param s The 32-byte secret key.
|
||||
*/
|
||||
private fun evalCurve(s: ByteArray) {
|
||||
var sposn = 31
|
||||
var sbit = 6
|
||||
var svalue = s[sposn].toInt() or 0x40
|
||||
var swap = 0
|
||||
|
||||
// Iterate over all 255 bits of "s" from the highest to the lowest.
|
||||
// We ignore the high bit of the 256-bit representation of "s".
|
||||
while (true) {
|
||||
// Conditional swaps on entry to this bit but only if we
|
||||
// didn't swap on the previous bit.
|
||||
val select = (svalue shr sbit) and 0x01
|
||||
swap = swap xor select
|
||||
cswap(swap, x_2, x_3)
|
||||
cswap(swap, z_2, z_3)
|
||||
swap = select
|
||||
|
||||
// Evaluate the curve.
|
||||
add(A, x_2, z_2) // A = x_2 + z_2
|
||||
square(AA, A) // AA = A^2
|
||||
sub(B, x_2, z_2) // B = x_2 - z_2
|
||||
square(BB, B) // BB = B^2
|
||||
sub(E, AA, BB) // E = AA - BB
|
||||
add(C, x_3, z_3) // C = x_3 + z_3
|
||||
sub(D, x_3, z_3) // D = x_3 - z_3
|
||||
mul(DA, D, A) // DA = D * A
|
||||
mul(CB, C, B) // CB = C * B
|
||||
add(x_3, DA, CB) // x_3 = (DA + CB)^2
|
||||
square(x_3, x_3)
|
||||
sub(z_3, DA, CB) // z_3 = x_1 * (DA - CB)^2
|
||||
square(z_3, z_3)
|
||||
mul(z_3, z_3, x_1)
|
||||
mul(x_2, AA, BB) // x_2 = AA * BB
|
||||
mulA24(z_2, E) // z_2 = E * (AA + a24 * E)
|
||||
add(z_2, z_2, AA)
|
||||
mul(z_2, z_2, E)
|
||||
|
||||
// Move onto the next lower bit of "s".
|
||||
if (sbit > 0) {
|
||||
--sbit
|
||||
} else if (sposn == 0) {
|
||||
break
|
||||
} else if (sposn == 1) {
|
||||
--sposn
|
||||
svalue = s[sposn].toInt() and 0xF8
|
||||
sbit = 7
|
||||
} else {
|
||||
--sposn
|
||||
svalue = s[sposn].toInt()
|
||||
sbit = 7
|
||||
}
|
||||
}
|
||||
|
||||
// Final conditional swaps.
|
||||
cswap(swap, x_2, x_3)
|
||||
cswap(swap, z_2, z_3)
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Numbers modulo 2^255 - 19 are broken up into ten 26-bit words.
|
||||
private const val NUM_LIMBS_255BIT = 10
|
||||
private const val NUM_LIMBS_510BIT = 20
|
||||
|
||||
/**
|
||||
* Conditional swap of two values.
|
||||
*
|
||||
* @param select Set to 1 to swap, 0 to leave as-is.
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
*/
|
||||
private fun cswap(select: Int, x: IntArray, y: IntArray) {
|
||||
val s = -select
|
||||
for (index in 0 until NUM_LIMBS_255BIT) {
|
||||
val dummy = s and (x[index] xor y[index])
|
||||
x[index] = x[index] xor dummy
|
||||
y[index] = y[index] xor dummy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the Curve25519 curve.
|
||||
*
|
||||
* @param result Buffer to place the result of the evaluation into.
|
||||
* @param offset Offset into the result buffer.
|
||||
* @param privateKey The private key to use in the evaluation.
|
||||
* @param publicKey The public key to use in the evaluation, or null
|
||||
* if the base point of the curve should be used.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun eval(result: ByteArray, offset: Int, privateKey: ByteArray, publicKey: ByteArray?) {
|
||||
val state = Curve25519()
|
||||
try {
|
||||
// Unpack the public key value. If null, use 9 as the base point.
|
||||
state.x_1.fill(0)
|
||||
if (publicKey != null) {
|
||||
// Convert the input value from little-endian into 26-bit limbs.
|
||||
for (index in 0 until 32) {
|
||||
val bit = (index * 8) % 26
|
||||
val word = (index * 8) / 26
|
||||
val value = publicKey[index].toInt() and 0xFF
|
||||
if (bit <= (26 - 8)) {
|
||||
state.x_1[word] = state.x_1[word] or (value shl bit)
|
||||
} else {
|
||||
state.x_1[word] = state.x_1[word] or (value shl bit)
|
||||
state.x_1[word] = state.x_1[word] and 0x03FFFFFF
|
||||
state.x_1[word + 1] = state.x_1[word + 1] or (value shr (26 - bit))
|
||||
}
|
||||
}
|
||||
|
||||
// Just in case, we reduce the number modulo 2^255 - 19 to
|
||||
// make sure that it is in range of the field before we start.
|
||||
// This eliminates values between 2^255 - 19 and 2^256 - 1.
|
||||
state.reduceQuick(state.x_1)
|
||||
state.reduceQuick(state.x_1)
|
||||
} else {
|
||||
state.x_1[0] = 9
|
||||
}
|
||||
|
||||
// Initialize the other temporary variables.
|
||||
state.x_2.fill(0) // x_2 = 1
|
||||
state.x_2[0] = 1
|
||||
state.z_2.fill(0) // z_2 = 0
|
||||
state.x_1.copyInto(state.x_3) // x_3 = x_1
|
||||
state.z_3.fill(0) // z_3 = 1
|
||||
state.z_3[0] = 1
|
||||
|
||||
|
||||
// Evaluate the curve for every bit of the private key.
|
||||
state.evalCurve(privateKey)
|
||||
|
||||
// Compute x_2 * (z_2 ^ (p - 2)) where p = 2^255 - 19.
|
||||
state.recip(state.z_3, state.z_2)
|
||||
state.mul(state.x_2, state.x_2, state.z_3)
|
||||
|
||||
// Convert x_2 into little-endian in the result buffer.
|
||||
for (index in 0 until 32) {
|
||||
val bit = (index * 8) % 26
|
||||
val word = (index * 8) / 26
|
||||
if (bit <= (26 - 8)) {
|
||||
result[offset + index] = (state.x_2[word] shr bit).toByte()
|
||||
} else {
|
||||
result[offset + index] =
|
||||
((state.x_2[word] shr bit) or (state.x_2[word + 1] shl (26 - bit))).toByte()
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Clean up all temporary state before we exit.
|
||||
state.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,622 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Portions of this code were extracted from the p448/arch_32 field
|
||||
arithmetic implementation in Ed448-Goldilocks and converted from
|
||||
C into Java. The LICENSE.txt file for the imported code follows:
|
||||
|
||||
----
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011 Stanford University.
|
||||
Copyright (c) 2014 Cryptography Research, Inc.
|
||||
|
||||
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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Implementation of the Curve448 elliptic curve algorithm.
|
||||
*
|
||||
* Reference: RFC 7748
|
||||
*/
|
||||
public final class Curve448 {
|
||||
|
||||
// Numbers modulo 2^448 - 2^224 - 1 are broken up into sixteen 28-bit words.
|
||||
private int[] x_1;
|
||||
private int[] x_2;
|
||||
private int[] x_3;
|
||||
private int[] z_2;
|
||||
private int[] z_3;
|
||||
private int[] A;
|
||||
private int[] B;
|
||||
private int[] C;
|
||||
private int[] D;
|
||||
private int[] E;
|
||||
private int[] AA;
|
||||
private int[] BB;
|
||||
private int[] DA;
|
||||
private int[] CB;
|
||||
private int[] aa;
|
||||
private int[] bb;
|
||||
|
||||
/**
|
||||
* Constructs the temporary state holder for Curve448 evaluation.
|
||||
*/
|
||||
private Curve448()
|
||||
{
|
||||
// Allocate memory for all of the temporary variables we will need.
|
||||
x_1 = new int [16];
|
||||
x_2 = new int [16];
|
||||
x_3 = new int [16];
|
||||
z_2 = new int [16];
|
||||
z_3 = new int [16];
|
||||
A = new int [16];
|
||||
B = new int [16];
|
||||
C = new int [16];
|
||||
D = new int [16];
|
||||
E = new int [16];
|
||||
AA = new int [16];
|
||||
BB = new int [16];
|
||||
DA = new int [16];
|
||||
CB = new int [16];
|
||||
aa = new int [8];
|
||||
bb = new int [8];
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy all sensitive data in this object.
|
||||
*/
|
||||
private void destroy() {
|
||||
// Destroy all temporary variables.
|
||||
Arrays.fill(x_1, 0);
|
||||
Arrays.fill(x_2, 0);
|
||||
Arrays.fill(x_3, 0);
|
||||
Arrays.fill(z_2, 0);
|
||||
Arrays.fill(z_3, 0);
|
||||
Arrays.fill(A, 0);
|
||||
Arrays.fill(B, 0);
|
||||
Arrays.fill(C, 0);
|
||||
Arrays.fill(D, 0);
|
||||
Arrays.fill(E, 0);
|
||||
Arrays.fill(AA, 0);
|
||||
Arrays.fill(BB, 0);
|
||||
Arrays.fill(DA, 0);
|
||||
Arrays.fill(CB, 0);
|
||||
Arrays.fill(aa, 0);
|
||||
Arrays.fill(bb, 0);
|
||||
}
|
||||
|
||||
/* Beginning of code imported from Ed448-Goldilocks */
|
||||
|
||||
private static long widemul_32(int a, int b)
|
||||
{
|
||||
return ((long)a) * b;
|
||||
}
|
||||
|
||||
// p448_mul()
|
||||
private void mul(int[] c, int[] a, int[] b)
|
||||
{
|
||||
long accum0 = 0, accum1 = 0, accum2 = 0;
|
||||
int mask = (1<<28) - 1;
|
||||
|
||||
int i,j;
|
||||
for (i=0; i<8; i++) {
|
||||
aa[i] = a[i] + a[i+8];
|
||||
bb[i] = b[i] + b[i+8];
|
||||
}
|
||||
|
||||
for (j=0; j<8; j++) {
|
||||
accum2 = 0;
|
||||
|
||||
for (i=0; i<=j; i++) {
|
||||
accum2 += widemul_32(a[j-i],b[i]);
|
||||
accum1 += widemul_32(aa[j-i],bb[i]);
|
||||
accum0 += widemul_32(a[8+j-i], b[8+i]);
|
||||
}
|
||||
|
||||
accum1 -= accum2;
|
||||
accum0 += accum2;
|
||||
accum2 = 0;
|
||||
|
||||
for (; i<8; i++) {
|
||||
accum0 -= widemul_32(a[8+j-i], b[i]);
|
||||
accum2 += widemul_32(aa[8+j-i], bb[i]);
|
||||
accum1 += widemul_32(a[16+j-i], b[8+i]);
|
||||
}
|
||||
|
||||
accum1 += accum2;
|
||||
accum0 += accum2;
|
||||
|
||||
c[j] = ((int)(accum0)) & mask;
|
||||
c[j+8] = ((int)(accum1)) & mask;
|
||||
|
||||
accum0 >>>= 28;
|
||||
accum1 >>>= 28;
|
||||
}
|
||||
|
||||
accum0 += accum1;
|
||||
accum0 += c[8];
|
||||
accum1 += c[0];
|
||||
c[8] = ((int)(accum0)) & mask;
|
||||
c[0] = ((int)(accum1)) & mask;
|
||||
|
||||
accum0 >>>= 28;
|
||||
accum1 >>>= 28;
|
||||
c[9] += ((int)(accum0));
|
||||
c[1] += ((int)(accum1));
|
||||
}
|
||||
|
||||
// p448_mulw()
|
||||
private static void mulw(int[] c, int[] a, long b)
|
||||
{
|
||||
int bhi = (int)(b>>28), blo = ((int)b) & ((1<<28)-1);
|
||||
|
||||
long accum0, accum8;
|
||||
int mask = (1<<28) - 1;
|
||||
|
||||
int i;
|
||||
|
||||
accum0 = widemul_32(blo, a[0]);
|
||||
accum8 = widemul_32(blo, a[8]);
|
||||
accum0 += widemul_32(bhi, a[15]);
|
||||
accum8 += widemul_32(bhi, a[15] + a[7]);
|
||||
|
||||
c[0] = ((int)accum0) & mask; accum0 >>>= 28;
|
||||
c[8] = ((int)accum8) & mask; accum8 >>>= 28;
|
||||
|
||||
for (i=1; i<8; i++) {
|
||||
accum0 += widemul_32(blo, a[i]);
|
||||
accum8 += widemul_32(blo, a[i+8]);
|
||||
|
||||
accum0 += widemul_32(bhi, a[i-1]);
|
||||
accum8 += widemul_32(bhi, a[i+7]);
|
||||
|
||||
c[i] = ((int)accum0) & mask; accum0 >>>= 28;
|
||||
c[i+8] = ((int)accum8) & mask; accum8 >>>= 28;
|
||||
}
|
||||
|
||||
accum0 += accum8 + c[8];
|
||||
c[8] = ((int)accum0) & mask;
|
||||
c[9] += accum0 >>> 28;
|
||||
|
||||
accum8 += c[0];
|
||||
c[0] = ((int)accum8) & mask;
|
||||
c[1] += accum8 >>> 28;
|
||||
}
|
||||
|
||||
// p448_weak_reduce
|
||||
private static void weak_reduce(int[] a)
|
||||
{
|
||||
int mask = (1<<28) - 1;
|
||||
int tmp = a[15] >>> 28;
|
||||
int i;
|
||||
a[8] += tmp;
|
||||
for (i=15; i>0; i--) {
|
||||
a[i] = (a[i] & mask) + (a[i-1]>>>28);
|
||||
}
|
||||
a[0] = (a[0] & mask) + tmp;
|
||||
}
|
||||
|
||||
// p448_strong_reduce
|
||||
private static void strong_reduce(int[] a)
|
||||
{
|
||||
int mask = (1<<28) - 1;
|
||||
|
||||
/* first, clear high */
|
||||
a[8] += a[15]>>>28;
|
||||
a[0] += a[15]>>>28;
|
||||
a[15] &= mask;
|
||||
|
||||
/* now the total is less than 2^448 - 2^(448-56) + 2^(448-56+8) < 2p */
|
||||
|
||||
/* compute total_value - p. No need to reduce mod p. */
|
||||
|
||||
long scarry = 0;
|
||||
int i;
|
||||
for (i=0; i<16; i++) {
|
||||
scarry = scarry + (a[i] & 0xFFFFFFFFL) - ((i==8)?mask-1:mask);
|
||||
a[i] = (int)(scarry & mask);
|
||||
scarry >>= 28;
|
||||
}
|
||||
|
||||
/* uncommon case: it was >= p, so now scarry = 0 and this = x
|
||||
* common case: it was < p, so now scarry = -1 and this = x - p + 2^448
|
||||
* so let's add back in p. will carry back off the top for 2^448.
|
||||
*/
|
||||
|
||||
int scarry_mask = (int)(scarry & mask);
|
||||
long carry = 0;
|
||||
|
||||
/* add it back */
|
||||
for (i=0; i<16; i++) {
|
||||
carry = carry + (a[i] & 0xFFFFFFFFL) + ((i==8)?(scarry_mask&~1):scarry_mask);
|
||||
a[i] = (int)(carry & mask);
|
||||
carry >>>= 28;
|
||||
}
|
||||
}
|
||||
|
||||
// field_add()
|
||||
private static void add(int[] out, int[] a, int[] b)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
out[i] = a[i] + b[i];
|
||||
weak_reduce(out);
|
||||
}
|
||||
|
||||
// field_sub()
|
||||
private static void sub(int[] out, int[] a, int[] b)
|
||||
{
|
||||
int i;
|
||||
|
||||
// p448_sub_RAW(out, a, b)
|
||||
for (i = 0; i < 16; ++i)
|
||||
out[i] = a[i] - b[i];
|
||||
|
||||
// p448_bias(out, 2)
|
||||
int co1 = ((1 << 28) - 1) * 2;
|
||||
int co2 = co1 - 2;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
if (i != 8)
|
||||
out[i] += co1;
|
||||
else
|
||||
out[i] += co2;
|
||||
}
|
||||
|
||||
weak_reduce(out);
|
||||
}
|
||||
|
||||
// p448_serialize()
|
||||
private static void serialize(byte[] serial, int offset, int[] x)
|
||||
{
|
||||
int i,j;
|
||||
for (i=0; i<8; i++) {
|
||||
long limb = x[2*i] + (((long)x[2*i+1])<<28);
|
||||
for (j=0; j<7; j++) {
|
||||
serial[offset+7*i+j] = (byte)limb;
|
||||
limb >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int is_zero(int x)
|
||||
{
|
||||
long xx = x & 0xFFFFFFFFL;
|
||||
xx--;
|
||||
return (int)(xx >> 32);
|
||||
}
|
||||
|
||||
// p448_deserialize()
|
||||
private static int deserialize(int[] x, byte[] serial, int offset)
|
||||
{
|
||||
int i,j;
|
||||
for (i=0; i<8; i++) {
|
||||
long out = 0;
|
||||
for (j=0; j<7; j++) {
|
||||
out |= (serial[offset+7*i+j] & 0xFFL)<<(8*j);
|
||||
}
|
||||
x[2*i] = ((int)out) & ((1<<28)-1);
|
||||
x[2*i+1] = (int)(out >>> 28);
|
||||
}
|
||||
|
||||
/* Check for reduction.
|
||||
*
|
||||
* The idea is to create a variable ge which is all ones (rather, 56 ones)
|
||||
* if and only if the low $i$ words of $x$ are >= those of p.
|
||||
*
|
||||
* Remember p = little_endian(1111,1111,1111,1111,1110,1111,1111,1111)
|
||||
*/
|
||||
int ge = -1, mask = (1<<28)-1;
|
||||
for (i=0; i<8; i++) {
|
||||
ge &= x[i];
|
||||
}
|
||||
|
||||
/* At this point, ge = 1111 iff bottom are all 1111. Now propagate if 1110, or set if 1111 */
|
||||
ge = (ge & (x[8] + 1)) | is_zero(x[8] ^ mask);
|
||||
|
||||
/* Propagate the rest */
|
||||
for (i=9; i<16; i++) {
|
||||
ge &= x[i];
|
||||
}
|
||||
|
||||
return ~is_zero(ge ^ mask);
|
||||
}
|
||||
|
||||
/* End of code imported from Ed448-Goldilocks */
|
||||
|
||||
/**
|
||||
* Squares a number modulo 2^448 - 2^224 - 1.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to square.
|
||||
*/
|
||||
private void square(int[] result, int[] x)
|
||||
{
|
||||
mul(result, x, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditional swap of two values.
|
||||
*
|
||||
* @param select Set to 1 to swap, 0 to leave as-is.
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
*/
|
||||
private static void cswap(int select, int[] x, int[] y)
|
||||
{
|
||||
int dummy;
|
||||
select = -select;
|
||||
for (int index = 0; index < 16; ++index) {
|
||||
dummy = select & (x[index] ^ y[index]);
|
||||
x[index] ^= dummy;
|
||||
y[index] ^= dummy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the reciprocal of a number modulo 2^448 - 2^224 - 1.
|
||||
*
|
||||
* @param result The result. Must not overlap with z_2.
|
||||
* @param z_2 The argument.
|
||||
*/
|
||||
private void recip(int[] result, int[] z_2)
|
||||
{
|
||||
int posn;
|
||||
|
||||
/* Compute z_2 ^ (p - 2)
|
||||
|
||||
The value p - 2 is: FF...FEFF...FD, which from highest to lowest is
|
||||
223 one bits, followed by a zero bit, followed by 222 one bits,
|
||||
followed by another zero bit, and a final one bit.
|
||||
|
||||
The naive implementation that squares for every bit and multiplies
|
||||
for every 1 bit requires 893 multiplications. The following can
|
||||
do the same operation in 483 multiplications. The basic idea is to
|
||||
create bit patterns and then "shift" them into position. We start
|
||||
with a 4 bit pattern 1111, which we can square 4 times to get
|
||||
11110000 and then multiply by the 1111 pattern to get 11111111.
|
||||
We then repeat that to turn 11111111 into 1111111111111111, etc.
|
||||
*/
|
||||
square(B, z_2); /* Set A to a 4 bit pattern */
|
||||
mul(A, B, z_2);
|
||||
square(B, A);
|
||||
mul(A, B, z_2);
|
||||
square(B, A);
|
||||
mul(A, B, z_2);
|
||||
square(B, A); /* Set C to a 6 bit pattern */
|
||||
mul(C, B, z_2);
|
||||
square(B, C);
|
||||
mul(C, B, z_2);
|
||||
square(B, C); /* Set A to a 8 bit pattern */
|
||||
mul(A, B, z_2);
|
||||
square(B, A);
|
||||
mul(A, B, z_2);
|
||||
square(E, A); /* Set E to a 16 bit pattern */
|
||||
square(B, E);
|
||||
for (posn = 1; posn < 4; ++posn) {
|
||||
square(E, B);
|
||||
square(B, E);
|
||||
}
|
||||
mul(E, B, A);
|
||||
square(AA, E); /* Set AA to a 32 bit pattern */
|
||||
square(B, AA);
|
||||
for (posn = 1; posn < 8; ++posn) {
|
||||
square(AA, B);
|
||||
square(B, AA);
|
||||
}
|
||||
mul(AA, B, E);
|
||||
square(BB, AA); /* Set BB to a 64 bit pattern */
|
||||
square(B, BB);
|
||||
for (posn = 1; posn < 16; ++posn) {
|
||||
square(BB, B);
|
||||
square(B, BB);
|
||||
}
|
||||
mul(BB, B, AA);
|
||||
square(DA, BB); /* Set DA to a 128 bit pattern */
|
||||
square(B, DA);
|
||||
for (posn = 1; posn < 32; ++posn) {
|
||||
square(DA, B);
|
||||
square(B, DA);
|
||||
}
|
||||
mul(DA, B, BB);
|
||||
square(CB, DA); /* Set CB to a 192 bit pattern */
|
||||
square(B, CB); /* 192 = 128 + 64 */
|
||||
for (posn = 1; posn < 32; ++posn) {
|
||||
square(CB, B);
|
||||
square(B, CB);
|
||||
}
|
||||
mul(CB, B, BB);
|
||||
square(DA, CB); /* Set DA to a 208 bit pattern */
|
||||
square(B, DA); /* 208 = 128 + 64 + 16 */
|
||||
for (posn = 1; posn < 8; ++posn) {
|
||||
square(DA, B);
|
||||
square(B, DA);
|
||||
}
|
||||
mul(DA, B, E);
|
||||
square(CB, DA); /* Set CB to a 216 bit pattern */
|
||||
square(B, CB); /* 216 = 128 + 64 + 16 + 8 */
|
||||
for (posn = 1; posn < 4; ++posn) {
|
||||
square(CB, B);
|
||||
square(B, CB);
|
||||
}
|
||||
mul(CB, B, A);
|
||||
square(DA, CB); /* Set DA to a 222 bit pattern */
|
||||
square(B, DA); /* 222 = 128 + 64 + 16 + 8 + 6 */
|
||||
for (posn = 1; posn < 3; ++posn) {
|
||||
square(DA, B);
|
||||
square(B, DA);
|
||||
}
|
||||
mul(DA, B, C);
|
||||
square(CB, DA); /* Set CB to a 224 bit pattern */
|
||||
mul(B, CB, z_2); /* CB = DA|1|0 */
|
||||
square(CB, B);
|
||||
square(BB, CB); /* Set BB to a 446 bit pattern */
|
||||
square(B, BB); /* BB = DA|1|0|DA */
|
||||
for (posn = 1; posn < 111; ++posn) {
|
||||
square(BB, B);
|
||||
square(B, BB);
|
||||
}
|
||||
mul(BB, B, DA);
|
||||
square(B, BB); /* Set result to a 448 bit pattern */
|
||||
square(BB, B); /* result = DA|1|0|DA|01 */
|
||||
mul(result, BB, z_2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the curve for every bit in a secret key.
|
||||
*
|
||||
* @param s The 56-byte secret key.
|
||||
*/
|
||||
private void evalCurve(byte[] s)
|
||||
{
|
||||
int sposn = 55;
|
||||
int sbit = 7;
|
||||
int svalue = s[sposn] | 0x80;
|
||||
int swap = 0;
|
||||
int select;
|
||||
|
||||
// Iterate over all 448 bits of "s" from the highest to the lowest.
|
||||
for (;;) {
|
||||
// Conditional swaps on entry to this bit but only if we
|
||||
// didn't swap on the previous bit.
|
||||
select = (svalue >> sbit) & 0x01;
|
||||
swap ^= select;
|
||||
cswap(swap, x_2, x_3);
|
||||
cswap(swap, z_2, z_3);
|
||||
swap = select;
|
||||
|
||||
// Evaluate the curve.
|
||||
add(A, x_2, z_2); // A = x_2 + z_2
|
||||
square(AA, A); // AA = A^2
|
||||
sub(B, x_2, z_2); // B = x_2 - z_2
|
||||
square(BB, B); // BB = B^2
|
||||
sub(E, AA, BB); // E = AA - BB
|
||||
add(C, x_3, z_3); // C = x_3 + z_3
|
||||
sub(D, x_3, z_3); // D = x_3 - z_3
|
||||
mul(DA, D, A); // DA = D * A
|
||||
mul(CB, C, B); // CB = C * B
|
||||
add(z_2, DA, CB); // x_3 = (DA + CB)^2
|
||||
square(x_3, z_2);
|
||||
sub(z_2, DA, CB); // z_3 = x_1 * (DA - CB)^2
|
||||
square(x_2, z_2);
|
||||
mul(z_3, x_1, x_2);
|
||||
mul(x_2, AA, BB); // x_2 = AA * BB
|
||||
mulw(z_2, E, 39081); // z_2 = E * (AA + a24 * E)
|
||||
add(A, AA, z_2);
|
||||
mul(z_2, E, A);
|
||||
|
||||
// Move onto the next lower bit of "s".
|
||||
if (sbit > 0) {
|
||||
--sbit;
|
||||
} else if (sposn == 0) {
|
||||
break;
|
||||
} else if (sposn == 1) {
|
||||
--sposn;
|
||||
svalue = s[sposn] & 0xFC;
|
||||
sbit = 7;
|
||||
} else {
|
||||
--sposn;
|
||||
svalue = s[sposn];
|
||||
sbit = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// Final conditional swaps.
|
||||
cswap(swap, x_2, x_3);
|
||||
cswap(swap, z_2, z_3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the Curve448 curve.
|
||||
*
|
||||
* @param result Buffer to place the result of the evaluation into.
|
||||
* @param offset Offset into the result buffer.
|
||||
* @param privateKey The private key to use in the evaluation.
|
||||
* @param publicKey The public key to use in the evaluation, or null
|
||||
* if the base point of the curve should be used.
|
||||
* @return Returns true if the curve evaluation was successful,
|
||||
* false if the publicKey value is out of range.
|
||||
*/
|
||||
public static boolean eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey)
|
||||
{
|
||||
Curve448 state = new Curve448();
|
||||
int success = -1;
|
||||
try {
|
||||
// Unpack the public key value. If null, use 5 as the base point.
|
||||
Arrays.fill(state.x_1, 0);
|
||||
if (publicKey != null) {
|
||||
// Convert the input value from little-endian into 28-bit limbs.
|
||||
// It is possible that the public key is out of range. If so,
|
||||
// delay reporting that state until the function completes.
|
||||
success = deserialize(state.x_1, publicKey, 0);
|
||||
} else {
|
||||
state.x_1[0] = 5;
|
||||
}
|
||||
|
||||
// Initialize the other temporary variables.
|
||||
Arrays.fill(state.x_2, 0); // x_2 = 1
|
||||
state.x_2[0] = 1;
|
||||
Arrays.fill(state.z_2, 0); // z_2 = 0
|
||||
System.arraycopy(state.x_1, 0, state.x_3, 0, state.x_1.length); // x_3 = x_1
|
||||
Arrays.fill(state.z_3, 0); // z_3 = 1
|
||||
state.z_3[0] = 1;
|
||||
|
||||
// Evaluate the curve for every bit of the private key.
|
||||
state.evalCurve(privateKey);
|
||||
|
||||
// Compute x_2 * (z_2 ^ (p - 2)) where p = 2^448 - 2^224 - 1.
|
||||
state.recip(state.z_3, state.z_2);
|
||||
state.mul(state.x_1, state.x_2, state.z_3);
|
||||
|
||||
// Convert x_2 into little-endian in the result buffer.
|
||||
strong_reduce(state.x_1);
|
||||
serialize(result, offset, state.x_1);
|
||||
} finally {
|
||||
// Clean up all temporary state before we exit.
|
||||
state.destroy();
|
||||
}
|
||||
return (success & 0x01) != 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,567 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
|
||||
Portions of this code were extracted from the p448/arch_32 field
|
||||
arithmetic implementation in Ed448-Goldilocks and converted from
|
||||
C into Java. The LICENSE.txt file for the imported code follows:
|
||||
|
||||
----
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011 Stanford University.
|
||||
Copyright (c) 2014 Cryptography Research, Inc.
|
||||
|
||||
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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the Curve448 elliptic curve algorithm.
|
||||
*
|
||||
* Reference: RFC 7748
|
||||
*/
|
||||
class Curve448 private constructor() {
|
||||
// Numbers modulo 2^448 - 2^224 - 1 are broken up into sixteen 28-bit words.
|
||||
private val x_1 = IntArray(16)
|
||||
private val x_2 = IntArray(16)
|
||||
private val x_3 = IntArray(16)
|
||||
private val z_2 = IntArray(16)
|
||||
private val z_3 = IntArray(16)
|
||||
private val A = IntArray(16)
|
||||
private val B = IntArray(16)
|
||||
private val C = IntArray(16)
|
||||
private val D = IntArray(16)
|
||||
private val E = IntArray(16)
|
||||
private val AA = IntArray(16)
|
||||
private val BB = IntArray(16)
|
||||
private val DA = IntArray(16)
|
||||
private val CB = IntArray(16)
|
||||
private val aa = IntArray(8)
|
||||
private val bb = IntArray(8)
|
||||
|
||||
|
||||
/**
|
||||
* Destroy all sensitive data in this object.
|
||||
*/
|
||||
private fun destroy() {
|
||||
// Destroy all temporary variables.
|
||||
x_1.fill(0)
|
||||
x_2.fill(0)
|
||||
x_3.fill(0)
|
||||
z_2.fill(0)
|
||||
z_3.fill(0)
|
||||
A.fill(0)
|
||||
B.fill(0)
|
||||
C.fill(0)
|
||||
D.fill(0)
|
||||
E.fill(0)
|
||||
AA.fill(0)
|
||||
BB.fill(0)
|
||||
DA.fill(0)
|
||||
CB.fill(0)
|
||||
aa.fill(0)
|
||||
bb.fill(0)
|
||||
}
|
||||
|
||||
// p448_mul()
|
||||
private fun mul(c: IntArray, a: IntArray, b: IntArray) {
|
||||
var accum0 = 0L
|
||||
var accum1 = 0L
|
||||
val mask = (1 shl 28) - 1
|
||||
|
||||
for (i in 0 until 8) {
|
||||
aa[i] = a[i] + a[i + 8]
|
||||
bb[i] = b[i] + b[i + 8]
|
||||
}
|
||||
|
||||
for (j in 0 until 8) {
|
||||
var accum2 = 0L
|
||||
|
||||
for (i in 0..j) {
|
||||
accum2 += widemul_32(a[j - i], b[i])
|
||||
accum1 += widemul_32(aa[j - i], bb[i])
|
||||
accum0 += widemul_32(a[8 + j - i], b[8 + i])
|
||||
}
|
||||
|
||||
accum1 -= accum2
|
||||
accum0 += accum2
|
||||
accum2 = 0
|
||||
|
||||
for (i in (j + 1) until 8) {
|
||||
accum0 -= widemul_32(a[8 + j - i], b[i])
|
||||
accum2 += widemul_32(aa[8 + j - i], bb[i])
|
||||
accum1 += widemul_32(a[16 + j - i], b[8 + i])
|
||||
}
|
||||
|
||||
accum1 += accum2
|
||||
accum0 += accum2
|
||||
|
||||
c[j] = accum0.toInt() and mask
|
||||
c[j + 8] = accum1.toInt() and mask
|
||||
|
||||
accum0 = accum0 ushr 28
|
||||
accum1 = accum1 ushr 28
|
||||
}
|
||||
|
||||
accum0 += accum1
|
||||
accum0 += c[8].toLong()
|
||||
accum1 += c[0].toLong()
|
||||
c[8] = accum0.toInt() and mask
|
||||
c[0] = accum1.toInt() and mask
|
||||
|
||||
accum0 = accum0 ushr 28
|
||||
accum1 = accum1 ushr 28
|
||||
c[9] += accum0.toInt()
|
||||
c[1] += accum1.toInt()
|
||||
}
|
||||
|
||||
/* End of code imported from Ed448-Goldilocks */
|
||||
/**
|
||||
* Squares a number modulo 2^448 - 2^224 - 1.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to square.
|
||||
*/
|
||||
private fun square(result: IntArray, x: IntArray) {
|
||||
mul(result, x, x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the reciprocal of a number modulo 2^448 - 2^224 - 1.
|
||||
*
|
||||
* @param result The result. Must not overlap with z_2.
|
||||
* @param z_2 The argument.
|
||||
*/
|
||||
private fun recip(result: IntArray, z_2: IntArray) {
|
||||
/* Compute z_2 ^ (p - 2)
|
||||
|
||||
The value p - 2 is: FF...FEFF...FD, which from highest to lowest is
|
||||
223 one bits, followed by a zero bit, followed by 222 one bits,
|
||||
followed by another zero bit, and a final one bit.
|
||||
|
||||
The naive implementation that squares for every bit and multiplies
|
||||
for every 1 bit requires 893 multiplications. The following can
|
||||
do the same operation in 483 multiplications. The basic idea is to
|
||||
create bit patterns and then "shift" them into position. We start
|
||||
with a 4 bit pattern 1111, which we can square 4 times to get
|
||||
11110000 and then multiply by the 1111 pattern to get 11111111.
|
||||
We then repeat that to turn 11111111 into 1111111111111111, etc.
|
||||
*/
|
||||
square(B, z_2) /* Set A to a 4 bit pattern */
|
||||
mul(A, B, z_2)
|
||||
square(B, A)
|
||||
mul(A, B, z_2)
|
||||
square(B, A)
|
||||
mul(A, B, z_2)
|
||||
square(B, A) /* Set C to a 6 bit pattern */
|
||||
mul(C, B, z_2)
|
||||
square(B, C)
|
||||
mul(C, B, z_2)
|
||||
square(B, C) /* Set A to a 8 bit pattern */
|
||||
mul(A, B, z_2)
|
||||
square(B, A)
|
||||
mul(A, B, z_2)
|
||||
square(E, A) /* Set E to a 16 bit pattern */
|
||||
square(B, E)
|
||||
repeat(3) {
|
||||
square(E, B)
|
||||
square(B, E)
|
||||
}
|
||||
mul(E, B, A)
|
||||
square(AA, E) /* Set AA to a 32 bit pattern */
|
||||
square(B, AA)
|
||||
repeat(7) {
|
||||
square(AA, B)
|
||||
square(B, AA)
|
||||
}
|
||||
mul(AA, B, E)
|
||||
square(BB, AA) /* Set BB to a 64 bit pattern */
|
||||
square(B, BB)
|
||||
repeat(15) {
|
||||
square(BB, B)
|
||||
square(B, BB)
|
||||
}
|
||||
mul(BB, B, AA)
|
||||
square(DA, BB) /* Set DA to a 128 bit pattern */
|
||||
square(B, DA)
|
||||
repeat(31) {
|
||||
square(DA, B)
|
||||
square(B, DA)
|
||||
}
|
||||
mul(DA, B, BB)
|
||||
square(CB, DA) /* Set CB to a 192 bit pattern */
|
||||
square(B, CB) /* 192 = 128 + 64 */
|
||||
repeat(31) {
|
||||
square(CB, B)
|
||||
square(B, CB)
|
||||
}
|
||||
mul(CB, B, BB)
|
||||
square(DA, CB) /* Set DA to a 208 bit pattern */
|
||||
square(B, DA) /* 208 = 128 + 64 + 16 */
|
||||
repeat(7) {
|
||||
square(DA, B)
|
||||
square(B, DA)
|
||||
}
|
||||
mul(DA, B, E)
|
||||
square(CB, DA) /* Set CB to a 216 bit pattern */
|
||||
square(B, CB) /* 216 = 128 + 64 + 16 + 8 */
|
||||
repeat(3) {
|
||||
square(CB, B)
|
||||
square(B, CB)
|
||||
}
|
||||
mul(CB, B, A)
|
||||
square(DA, CB) /* Set DA to a 222 bit pattern */
|
||||
square(B, DA) /* 222 = 128 + 64 + 16 + 8 + 6 */
|
||||
repeat(2) {
|
||||
square(DA, B)
|
||||
square(B, DA)
|
||||
}
|
||||
mul(DA, B, C)
|
||||
square(CB, DA) /* Set CB to a 224 bit pattern */
|
||||
mul(B, CB, z_2) /* CB = DA|1|0 */
|
||||
square(CB, B)
|
||||
square(BB, CB) /* Set BB to a 446 bit pattern */
|
||||
square(B, BB) /* BB = DA|1|0|DA */
|
||||
repeat(110) {
|
||||
square(BB, B)
|
||||
square(B, BB)
|
||||
}
|
||||
mul(BB, B, DA)
|
||||
square(B, BB) /* Set result to a 448 bit pattern */
|
||||
square(BB, B) /* result = DA|1|0|DA|01 */
|
||||
mul(result, BB, z_2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the curve for every bit in a secret key.
|
||||
*
|
||||
* @param s The 56-byte secret key.
|
||||
*/
|
||||
private fun evalCurve(s: ByteArray) {
|
||||
var sposn = 55
|
||||
var sbit = 7
|
||||
var svalue = s[sposn].toInt() or 0x80
|
||||
var swap = 0
|
||||
|
||||
// Iterate over all 448 bits of "s" from the highest to the lowest.
|
||||
while (true) {
|
||||
// Conditional swaps on entry to this bit but only if we
|
||||
// didn't swap on the previous bit.
|
||||
val select = (svalue shr sbit) and 0x01
|
||||
swap = swap xor select
|
||||
cswap(swap, x_2, x_3)
|
||||
cswap(swap, z_2, z_3)
|
||||
swap = select
|
||||
|
||||
// Evaluate the curve.
|
||||
add(A, x_2, z_2) // A = x_2 + z_2
|
||||
square(AA, A) // AA = A^2
|
||||
sub(B, x_2, z_2) // B = x_2 - z_2
|
||||
square(BB, B) // BB = B^2
|
||||
sub(E, AA, BB) // E = AA - BB
|
||||
add(C, x_3, z_3) // C = x_3 + z_3
|
||||
sub(D, x_3, z_3) // D = x_3 - z_3
|
||||
mul(DA, D, A) // DA = D * A
|
||||
mul(CB, C, B) // CB = C * B
|
||||
add(z_2, DA, CB) // x_3 = (DA + CB)^2
|
||||
square(x_3, z_2)
|
||||
sub(z_2, DA, CB) // z_3 = x_1 * (DA - CB)^2
|
||||
square(x_2, z_2)
|
||||
mul(z_3, x_1, x_2)
|
||||
mul(x_2, AA, BB) // x_2 = AA * BB
|
||||
mulw(z_2, E, 39081) // z_2 = E * (AA + a24 * E)
|
||||
add(A, AA, z_2)
|
||||
mul(z_2, E, A)
|
||||
|
||||
// Move onto the next lower bit of "s".
|
||||
if (sbit > 0) {
|
||||
--sbit
|
||||
} else if (sposn == 0) {
|
||||
break
|
||||
} else if (sposn == 1) {
|
||||
--sposn
|
||||
svalue = s[sposn].toInt() and 0xFC
|
||||
sbit = 7
|
||||
} else {
|
||||
--sposn
|
||||
svalue = s[sposn].toInt()
|
||||
sbit = 7
|
||||
}
|
||||
}
|
||||
|
||||
// Final conditional swaps.
|
||||
cswap(swap, x_2, x_3)
|
||||
cswap(swap, z_2, z_3)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/* Beginning of code imported from Ed448-Goldilocks */
|
||||
private fun widemul_32(a: Int, b: Int): Long = (a.toLong()) * b
|
||||
|
||||
// p448_mulw()
|
||||
private fun mulw(c: IntArray, a: IntArray, b: Long) {
|
||||
val bhi = (b shr 28).toInt()
|
||||
val blo = b.toInt() and ((1 shl 28) - 1)
|
||||
|
||||
var accum0 = widemul_32(blo, a[0])
|
||||
var accum8 = widemul_32(blo, a[8])
|
||||
accum0 += widemul_32(bhi, a[15])
|
||||
accum8 += widemul_32(bhi, a[15] + a[7])
|
||||
|
||||
val mask = (1 shl 28) - 1
|
||||
|
||||
c[0] = accum0.toInt() and mask
|
||||
accum0 = accum0 ushr 28
|
||||
c[8] = accum8.toInt() and mask
|
||||
accum8 = accum8 ushr 28
|
||||
|
||||
for (i in 1 until 8) {
|
||||
accum0 += widemul_32(blo, a[i])
|
||||
accum8 += widemul_32(blo, a[i + 8])
|
||||
|
||||
accum0 += widemul_32(bhi, a[i - 1])
|
||||
accum8 += widemul_32(bhi, a[i + 7])
|
||||
|
||||
c[i] = accum0.toInt() and mask
|
||||
accum0 = accum0 ushr 28
|
||||
c[i + 8] = accum8.toInt() and mask
|
||||
accum8 = accum8 ushr 28
|
||||
}
|
||||
|
||||
accum0 += accum8 + c[8]
|
||||
c[8] = accum0.toInt() and mask
|
||||
c[9] += (accum0 ushr 28).toInt()
|
||||
|
||||
accum8 += c[0].toLong()
|
||||
c[0] = accum8.toInt() and mask
|
||||
c[1] += (accum8 ushr 28).toInt()
|
||||
}
|
||||
|
||||
|
||||
// p448_weak_reduce
|
||||
private fun weak_reduce(a: IntArray) {
|
||||
val mask = (1 shl 28) - 1
|
||||
val tmp = a[15] ushr 28
|
||||
a[8] += tmp
|
||||
for (i in 15 downTo 1) {
|
||||
a[i] = (a[i] and mask) + (a[i - 1] ushr 28)
|
||||
}
|
||||
a[0] = (a[0] and mask) + tmp
|
||||
}
|
||||
|
||||
// p448_strong_reduce
|
||||
private fun strong_reduce(a: IntArray) {
|
||||
val mask = (1 shl 28) - 1
|
||||
|
||||
/* first, clear high */
|
||||
a[8] += a[15] ushr 28
|
||||
a[0] += a[15] ushr 28
|
||||
a[15] = a[15] and mask
|
||||
|
||||
var scarry = 0L
|
||||
for (i in 0 until 16) {
|
||||
scarry = scarry + (a[i].toLong() and 0xFFFFFFFFL) - (if (i == 8) mask - 1 else mask)
|
||||
a[i] = (scarry and mask.toLong()).toInt()
|
||||
scarry = scarry shr 28
|
||||
}
|
||||
|
||||
val scarryMask = (scarry and mask.toLong()).toInt()
|
||||
var carry = 0L
|
||||
|
||||
for (i in 0 until 16) {
|
||||
carry += (a[i].toLong() and 0xFFFFFFFFL) + (if (i == 8) scarryMask and 1.inv() else scarryMask)
|
||||
a[i] = (carry and mask.toLong()).toInt()
|
||||
carry = carry ushr 28
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// field_add()
|
||||
private fun add(out: IntArray, a: IntArray, b: IntArray) {
|
||||
for (i in 0..15) out[i] = a[i] + b[i]
|
||||
weak_reduce(out)
|
||||
}
|
||||
|
||||
// field_sub()
|
||||
private fun sub(out: IntArray, a: IntArray, b: IntArray) {
|
||||
for (i in 0 until 16) {
|
||||
out[i] = a[i] - b[i]
|
||||
}
|
||||
|
||||
val co1 = ((1 shl 28) - 1) * 2
|
||||
val co2 = co1 - 2
|
||||
for (i in 0 until 16) {
|
||||
if (i != 8) out[i] += co1 else out[i] += co2
|
||||
}
|
||||
|
||||
weak_reduce(out)
|
||||
}
|
||||
|
||||
// p448_serialize()
|
||||
private fun serialize(serial: ByteArray, offset: Int, x: IntArray) {
|
||||
for (i in 0 until 8) {
|
||||
var limb = x[2 * i].toLong() + (x[2 * i + 1].toLong() shl 28)
|
||||
for (j in 0 until 7) {
|
||||
serial[offset + 7 * i + j] = limb.toByte()
|
||||
limb = limb shr 8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun is_zero(x: Int): Int {
|
||||
var xx = x.toLong() and 0xFFFFFFFFL
|
||||
xx--
|
||||
return (xx shr 32).toInt()
|
||||
}
|
||||
|
||||
// p448_deserialize()
|
||||
private fun deserialize(x: IntArray, serial: ByteArray, offset: Int): Int {
|
||||
for (i in 0 until 8) {
|
||||
var out = 0L
|
||||
for (j in 0 until 7) {
|
||||
out = out or ((serial[offset + 7 * i + j].toLong() and 0xFFL) shl (8 * j))
|
||||
}
|
||||
x[2 * i] = out.toInt() and ((1 shl 28) - 1)
|
||||
x[2 * i + 1] = (out ushr 28).toInt()
|
||||
}
|
||||
|
||||
/* Check for reduction.
|
||||
*
|
||||
* The idea is to create a variable ge which is all ones (rather, 56 ones)
|
||||
* if and only if the low $i$ words of $x$ are >= those of p.
|
||||
*
|
||||
* Remember p = little_endian(1111,1111,1111,1111,1110,1111,1111,1111)
|
||||
*/
|
||||
var ge = -1
|
||||
val mask = (1 shl 28) - 1
|
||||
for (i in 0 until 8) {
|
||||
ge = ge and x[i]
|
||||
}
|
||||
|
||||
/* At this point, ge = 1111 iff bottom are all 1111. Now propagate if 1110, or set if 1111 */
|
||||
ge = (ge and (x[8] + 1)) or is_zero(x[8] xor mask)
|
||||
|
||||
/* Propagate the rest */
|
||||
for (i in 9 until 16) {
|
||||
ge = ge and x[i]
|
||||
}
|
||||
|
||||
|
||||
return is_zero(ge xor mask).inv()
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditional swap of two values.
|
||||
*
|
||||
* @param select Set to 1 to swap, 0 to leave as-is.
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
*/
|
||||
private fun cswap(select: Int, x: IntArray, y: IntArray) {
|
||||
val s = -select
|
||||
for (index in 0..15) {
|
||||
val dummy = s and (x[index] xor y[index])
|
||||
x[index] = x[index] xor dummy
|
||||
y[index] = y[index] xor dummy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the Curve448 curve.
|
||||
*
|
||||
* @param result Buffer to place the result of the evaluation into.
|
||||
* @param offset Offset into the result buffer.
|
||||
* @param privateKey The private key to use in the evaluation.
|
||||
* @param publicKey The public key to use in the evaluation, or null
|
||||
* if the base point of the curve should be used.
|
||||
* @return Returns true if the curve evaluation was successful,
|
||||
* false if the publicKey value is out of range.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun eval(
|
||||
result: ByteArray,
|
||||
offset: Int,
|
||||
privateKey: ByteArray,
|
||||
publicKey: ByteArray?
|
||||
): Boolean {
|
||||
val state = Curve448()
|
||||
var success = -1
|
||||
try {
|
||||
// Unpack the public key value. If null, use 5 as the base point.
|
||||
state.x_1.fill(0)
|
||||
if (publicKey != null) {
|
||||
// Convert the input value from little-endian into 28-bit limbs.
|
||||
// It is possible that the public key is out of range. If so,
|
||||
// delay reporting that state until the function completes.
|
||||
success = deserialize(state.x_1, publicKey, 0)
|
||||
} else {
|
||||
state.x_1[0] = 5
|
||||
}
|
||||
|
||||
// Initialize the other temporary variables.
|
||||
state.x_2.fill(0)
|
||||
state.x_2[0] = 1
|
||||
state.z_2.fill(0)
|
||||
state.x_1.copyInto(state.x_3)
|
||||
state.z_3.fill(0)
|
||||
state.z_3[0] = 1
|
||||
|
||||
|
||||
// Evaluate the curve for every bit of the private key.
|
||||
state.evalCurve(privateKey)
|
||||
|
||||
// Compute x_2 * (z_2 ^ (p - 2)) where p = 2^448 - 2^224 - 1.
|
||||
state.recip(state.z_3, state.z_2)
|
||||
state.mul(state.x_1, state.x_2, state.z_3)
|
||||
|
||||
// Convert x_2 into little-endian in the result buffer.
|
||||
strong_reduce(state.x_1)
|
||||
serialize(result, offset, state.x_1)
|
||||
} finally {
|
||||
// Clean up all temporary state before we exit.
|
||||
state.destroy()
|
||||
}
|
||||
return (success and 0x01) != 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,204 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable;
|
||||
|
||||
/**
|
||||
* Implementation of the GHASH primitive for GCM.
|
||||
*/
|
||||
public final class GHASH implements Destroyable {
|
||||
|
||||
private long[] H;
|
||||
private byte[] Y;
|
||||
int posn;
|
||||
|
||||
/**
|
||||
* Constructs a new GHASH object.
|
||||
*/
|
||||
public GHASH()
|
||||
{
|
||||
H = new long [2];
|
||||
Y = new byte [16];
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this GHASH object with a new key.
|
||||
*
|
||||
* @param key The key, which must contain at least 16 bytes.
|
||||
* @param offset The offset of the first key byte.
|
||||
*/
|
||||
public void reset(byte[] key, int offset)
|
||||
{
|
||||
H[0] = readBigEndian(key, offset);
|
||||
H[1] = readBigEndian(key, offset + 8);
|
||||
Arrays.fill(Y, (byte)0);
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the GHASH object but retains the previous key.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
Arrays.fill(Y, (byte)0);
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this GHASH object with more data.
|
||||
*
|
||||
* @param data Buffer containing the data.
|
||||
* @param offset Offset of the first data byte in the buffer.
|
||||
* @param length The number of bytes from the buffer to hash.
|
||||
*/
|
||||
public void update(byte[] data, int offset, int length)
|
||||
{
|
||||
while (length > 0) {
|
||||
int size = 16 - posn;
|
||||
if (size > length)
|
||||
size = length;
|
||||
for (int index = 0; index < size; ++index)
|
||||
Y[posn + index] ^= data[offset + index];
|
||||
posn += size;
|
||||
length -= size;
|
||||
offset += size;
|
||||
if (posn == 16) {
|
||||
GF128_mul(Y, H);
|
||||
posn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the GHASH process and returns the tag.
|
||||
*
|
||||
* @param tag Buffer to receive the tag.
|
||||
* @param offset Offset of the first byte of the tag.
|
||||
* @param length The length of the tag, which must be less
|
||||
* than or equal to 16.
|
||||
*/
|
||||
public void finish(byte[] tag, int offset, int length)
|
||||
{
|
||||
pad();
|
||||
System.arraycopy(Y, 0, tag, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the input to a 16-byte boundary.
|
||||
*/
|
||||
public void pad()
|
||||
{
|
||||
if (posn != 0) {
|
||||
// Padding involves XOR'ing the rest of state->Y with zeroes,
|
||||
// which does nothing. Immediately process the next chunk.
|
||||
GF128_mul(Y, H);
|
||||
posn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the input to a 16-byte boundary and then adds a block
|
||||
* containing the AD and data lengths.
|
||||
*
|
||||
* @param adLen Length of the associated data in bytes.
|
||||
* @param dataLen Length of the data in bytes.
|
||||
*/
|
||||
public void pad(long adLen, long dataLen)
|
||||
{
|
||||
byte[] temp = new byte [16];
|
||||
try {
|
||||
pad();
|
||||
writeBigEndian(temp, 0, adLen * 8);
|
||||
writeBigEndian(temp, 8, dataLen * 8);
|
||||
update(temp, 0, 16);
|
||||
} finally {
|
||||
Arrays.fill(temp, (byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Arrays.fill(H, 0L);
|
||||
Arrays.fill(Y, (byte)0);
|
||||
}
|
||||
|
||||
private static long readBigEndian(byte[] buf, int offset)
|
||||
{
|
||||
return ((buf[offset] & 0xFFL) << 56) |
|
||||
((buf[offset + 1] & 0xFFL) << 48) |
|
||||
((buf[offset + 2] & 0xFFL) << 40) |
|
||||
((buf[offset + 3] & 0xFFL) << 32) |
|
||||
((buf[offset + 4] & 0xFFL) << 24) |
|
||||
((buf[offset + 5] & 0xFFL) << 16) |
|
||||
((buf[offset + 6] & 0xFFL) << 8) |
|
||||
(buf[offset + 7] & 0xFFL);
|
||||
}
|
||||
|
||||
private static void writeBigEndian(byte[] buf, int offset, long value)
|
||||
{
|
||||
buf[offset] = (byte)(value >> 56);
|
||||
buf[offset + 1] = (byte)(value >> 48);
|
||||
buf[offset + 2] = (byte)(value >> 40);
|
||||
buf[offset + 3] = (byte)(value >> 32);
|
||||
buf[offset + 4] = (byte)(value >> 24);
|
||||
buf[offset + 5] = (byte)(value >> 16);
|
||||
buf[offset + 6] = (byte)(value >> 8);
|
||||
buf[offset + 7] = (byte)value;
|
||||
}
|
||||
|
||||
private static void GF128_mul(byte[] Y, long[] H)
|
||||
{
|
||||
long Z0 = 0; // Z = 0
|
||||
long Z1 = 0;
|
||||
long V0 = H[0]; // V = H
|
||||
long V1 = H[1];
|
||||
|
||||
// Multiply Z by V for the set bits in Y, starting at the top.
|
||||
// This is a very simple bit by bit version that may not be very
|
||||
// fast but it should be resistant to cache timing attacks.
|
||||
for (int posn = 0; posn < 16; ++posn) {
|
||||
int value = Y[posn] & 0xFF;
|
||||
for (int bit = 7; bit >= 0; --bit) {
|
||||
// Extract the high bit of "value" and turn it into a mask.
|
||||
long mask = -((long)((value >> bit) & 0x01));
|
||||
|
||||
// XOR V with Z if the bit is 1.
|
||||
Z0 ^= (V0 & mask);
|
||||
Z1 ^= (V1 & mask);
|
||||
|
||||
// Rotate V right by 1 bit.
|
||||
mask = ((~(V1 & 0x01)) + 1) & 0xE100000000000000L;
|
||||
V1 = (V1 >>> 1) | (V0 << 63);
|
||||
V0 = (V0 >>> 1) ^ mask;
|
||||
}
|
||||
}
|
||||
|
||||
// We have finished the block so copy Z into Y and byte-swap.
|
||||
writeBigEndian(Y, 0, Z0);
|
||||
writeBigEndian(Y, 8, Z1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable
|
||||
|
||||
/**
|
||||
* Implementation of the GHASH primitive for GCM.
|
||||
*/
|
||||
class GHASH : Destroyable {
|
||||
private val h = LongArray(2)
|
||||
private val y = ByteArray(16)
|
||||
private var posn: Int = 0
|
||||
|
||||
/**
|
||||
* Resets this GHASH object with a new key.
|
||||
*
|
||||
* @param key The key, which must contain at least 16 bytes.
|
||||
* @param offset The offset of the first key byte.
|
||||
*/
|
||||
fun reset(key: ByteArray, offset: Int) {
|
||||
h[0] = readBigEndian(key, offset)
|
||||
h[1] = readBigEndian(key, offset + 8)
|
||||
y.fill(0)
|
||||
posn = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the GHASH object but retains the previous key.
|
||||
*/
|
||||
fun reset() {
|
||||
y.fill(0)
|
||||
posn = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this GHASH object with more data.
|
||||
*
|
||||
* @param data Buffer containing the data.
|
||||
* @param offset Offset of the first data byte in the buffer.
|
||||
* @param length The number of bytes from the buffer to hash.
|
||||
*/
|
||||
fun update(data: ByteArray, offset: Int, length: Int) {
|
||||
var currentOffset = offset
|
||||
var remainingLength = length
|
||||
while (remainingLength > 0) {
|
||||
var size = 16 - posn
|
||||
if (size > remainingLength) size = remainingLength
|
||||
for (index in 0 until size) {
|
||||
y[posn + index] = (y[posn + index].toInt() xor data[currentOffset + index].toInt()).toByte()
|
||||
}
|
||||
posn += size
|
||||
remainingLength -= size
|
||||
currentOffset += size
|
||||
if (posn == 16) {
|
||||
gf128Mul(y, h)
|
||||
posn = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the GHASH process and returns the tag.
|
||||
*
|
||||
* @param tag Buffer to receive the tag.
|
||||
* @param offset Offset of the first byte of the tag.
|
||||
* @param length The length of the tag, which must be less
|
||||
* than or equal to 16.
|
||||
*/
|
||||
fun finish(tag: ByteArray, offset: Int, length: Int) {
|
||||
pad()
|
||||
y.copyInto(tag, destinationOffset = offset, startIndex = 0, endIndex = length)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the input to a 16-byte boundary.
|
||||
*/
|
||||
fun pad() {
|
||||
if (posn != 0) {
|
||||
// Padding involves XOR'ing the rest of state->Y with zeroes,
|
||||
// which does nothing. Immediately process the next chunk.
|
||||
gf128Mul(y, h)
|
||||
posn = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the input to a 16-byte boundary and then adds a block
|
||||
* containing the AD and data lengths.
|
||||
*
|
||||
* @param adLen Length of the associated data in bytes.
|
||||
* @param dataLen Length of the data in bytes.
|
||||
*/
|
||||
fun pad(adLen: Long, dataLen: Long) {
|
||||
val temp = ByteArray(16)
|
||||
try {
|
||||
pad()
|
||||
writeBigEndian(temp, 0, adLen * 8)
|
||||
writeBigEndian(temp, 8, dataLen * 8)
|
||||
update(temp, 0, 16)
|
||||
} finally {
|
||||
temp.fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
h.fill(0L)
|
||||
y.fill(0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun readBigEndian(buf: ByteArray, offset: Int): Long {
|
||||
return ((buf[offset].toLong() and 0xFFL) shl 56) or
|
||||
((buf[offset + 1].toLong() and 0xFFL) shl 48) or
|
||||
((buf[offset + 2].toLong() and 0xFFL) shl 40) or
|
||||
((buf[offset + 3].toLong() and 0xFFL) shl 32) or
|
||||
((buf[offset + 4].toLong() and 0xFFL) shl 24) or
|
||||
((buf[offset + 5].toLong() and 0xFFL) shl 16) or
|
||||
((buf[offset + 6].toLong() and 0xFFL) shl 8) or
|
||||
(buf[offset + 7].toLong() and 0xFFL)
|
||||
}
|
||||
|
||||
private fun writeBigEndian(buf: ByteArray, offset: Int, value: Long) {
|
||||
buf[offset] = (value shr 56).toByte()
|
||||
buf[offset + 1] = (value shr 48).toByte()
|
||||
buf[offset + 2] = (value shr 40).toByte()
|
||||
buf[offset + 3] = (value shr 32).toByte()
|
||||
buf[offset + 4] = (value shr 24).toByte()
|
||||
buf[offset + 5] = (value shr 16).toByte()
|
||||
buf[offset + 6] = (value shr 8).toByte()
|
||||
buf[offset + 7] = value.toByte()
|
||||
}
|
||||
|
||||
private fun gf128Mul(y: ByteArray, h: LongArray) {
|
||||
var z0: Long = 0 // Z = 0
|
||||
var z1: Long = 0
|
||||
var v0 = h[0] // V = H
|
||||
var v1 = h[1]
|
||||
|
||||
// Multiply Z by V for the set bits in Y, starting at the top.
|
||||
// This is a very simple bit by bit version that may not be very
|
||||
// fast but it should be resistant to cache timing attacks.
|
||||
for (pos in 0..15) {
|
||||
val value = y[pos].toInt() and 0xFF
|
||||
for (bit in 7 downTo 0) {
|
||||
// Extract the high bit of "value" and turn it into a mask.
|
||||
var mask = -(((value shr bit) and 0x01).toLong())
|
||||
|
||||
// XOR V with Z if the bit is 1.
|
||||
z0 = z0 xor (v0 and mask)
|
||||
z1 = z1 xor (v1 and mask)
|
||||
|
||||
// Rotate V right by 1 bit.
|
||||
mask = (((v1 and 0x01L).inv()) + 1) and -0x1f00000000000000L
|
||||
v1 = (v1 ushr 1) or (v0 shl 63)
|
||||
v0 = (v0 ushr 1) xor mask
|
||||
}
|
||||
}
|
||||
|
||||
// We have finished the block so copy Z into Y and byte-swap.
|
||||
writeBigEndian(y, 0, z0)
|
||||
writeBigEndian(y, 8, z1)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,831 @@
|
||||
/*
|
||||
* Based on the public domain C reference code for New Hope.
|
||||
* This Java version is also placed into the public domain.
|
||||
*
|
||||
* Original authors: Erdem Alkim, Léo Ducas, Thomas Pöppelmann, Peter Schwabe
|
||||
* Java port: Rhys Weatherley
|
||||
*/
|
||||
package com.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
import java.security.SecureRandom
|
||||
|
||||
|
||||
/**
|
||||
* NewHope key exchange algorithm.
|
||||
*
|
||||
* This class implements the standard "ref" version of the New Hope
|
||||
* algorithm.
|
||||
*
|
||||
* @see NewHopeTor
|
||||
*/
|
||||
open class NewHope {
|
||||
// -------------- newhope.c --------------
|
||||
private var sk: Poly? = null
|
||||
|
||||
/**
|
||||
* Destroys sensitive material in this object.
|
||||
*/
|
||||
fun destroy() {
|
||||
sk?.destroy()
|
||||
sk = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the keypair for Alice.
|
||||
*/
|
||||
fun keygen(send: ByteArray, sendOffset: Int) {
|
||||
val a = Poly()
|
||||
val e = Poly()
|
||||
val r = Poly()
|
||||
val pk = Poly()
|
||||
val seed = ByteArray(SEEDBYTES + 32)
|
||||
val noiseseed = ByteArray(32)
|
||||
|
||||
try {
|
||||
randombytes(seed)
|
||||
sha3256(seed, 0, seed, 0, SEEDBYTES) /* Don't send output of system RNG */
|
||||
seed.copyInto(noiseseed, 0, SEEDBYTES, SEEDBYTES + 32)
|
||||
|
||||
uniform(a.coeffs, seed)
|
||||
|
||||
val currentSk = sk ?: Poly().also { sk = it }
|
||||
currentSk.getnoise(noiseseed, 0.toByte())
|
||||
currentSk.ntt()
|
||||
|
||||
e.getnoise(noiseseed, 1.toByte())
|
||||
e.ntt()
|
||||
|
||||
r.pointwise(currentSk, a)
|
||||
pk.add(e, r)
|
||||
|
||||
encode_a(send, sendOffset, pk, seed)
|
||||
} finally {
|
||||
a.destroy()
|
||||
e.destroy()
|
||||
r.destroy()
|
||||
pk.destroy()
|
||||
seed.fill(0)
|
||||
noiseseed.fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the public key and shared secret for Bob.
|
||||
*
|
||||
* @param sharedkey Buffer to place the shared secret for Bob in.
|
||||
* @param sharedkeyOffset Offset of the first byte in the sharedkey buffer to populate.
|
||||
* @param send Buffer to place the public key for Bob in to be sent to Alice.
|
||||
* @param sendOffset Offset of the first byte in the send buffer to populate.
|
||||
* @param received Buffer containing the public key value received from Alice.
|
||||
* @param receivedOffset Offset of the first byte of the value received from Alice.
|
||||
*/
|
||||
fun sharedb(
|
||||
sharedkey: ByteArray, sharedkeyOffset: Int,
|
||||
send: ByteArray, sendOffset: Int,
|
||||
received: ByteArray, receivedOffset: Int
|
||||
) {
|
||||
val sp = Poly()
|
||||
val ep = Poly()
|
||||
val v = Poly()
|
||||
val a = Poly()
|
||||
val pka = Poly()
|
||||
val c = Poly()
|
||||
val epp = Poly()
|
||||
val bp = Poly()
|
||||
val seed = ByteArray(SEEDBYTES)
|
||||
val noiseseed = ByteArray(32)
|
||||
val skey = ByteArray(32)
|
||||
|
||||
try {
|
||||
randombytes(noiseseed)
|
||||
|
||||
decode_a(pka, seed, received, receivedOffset)
|
||||
uniform(a.coeffs, seed)
|
||||
|
||||
sp.getnoise(noiseseed, 0.toByte())
|
||||
sp.ntt()
|
||||
ep.getnoise(noiseseed, 1.toByte())
|
||||
ep.ntt()
|
||||
|
||||
bp.pointwise(a, sp)
|
||||
bp.add(bp, ep)
|
||||
|
||||
v.pointwise(pka, sp)
|
||||
v.invntt()
|
||||
|
||||
epp.getnoise(noiseseed, 2.toByte())
|
||||
v.add(v, epp)
|
||||
|
||||
helprec(c, v, noiseseed, 3.toByte())
|
||||
|
||||
encode_b(send, sendOffset, bp, c)
|
||||
|
||||
rec(skey, v, c)
|
||||
|
||||
sha3256(sharedkey, sharedkeyOffset, skey, 0, 32)
|
||||
} finally {
|
||||
sp.destroy()
|
||||
ep.destroy()
|
||||
v.destroy()
|
||||
a.destroy()
|
||||
pka.destroy()
|
||||
c.destroy()
|
||||
epp.destroy()
|
||||
bp.destroy()
|
||||
seed.fill(0)
|
||||
noiseseed.fill(0)
|
||||
skey.fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the shared secret for Alice.
|
||||
*/
|
||||
fun shareda(
|
||||
sharedkey: ByteArray, sharedkeyOffset: Int,
|
||||
received: ByteArray, receivedOffset: Int
|
||||
) {
|
||||
val v = Poly()
|
||||
val bp = Poly()
|
||||
val c = Poly()
|
||||
val skey = ByteArray(32)
|
||||
|
||||
try {
|
||||
decode_b(bp, c, received, receivedOffset)
|
||||
|
||||
val currentSk = sk ?: throw IllegalStateException("Private key not initialized")
|
||||
v.pointwise(currentSk, bp)
|
||||
v.invntt()
|
||||
|
||||
rec(skey, v, c)
|
||||
|
||||
sha3256(sharedkey, sharedkeyOffset, skey, 0, 32)
|
||||
} finally {
|
||||
v.destroy()
|
||||
bp.destroy()
|
||||
c.destroy()
|
||||
skey.fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun randombytes(buffer: ByteArray) {
|
||||
SecureRandom().nextBytes(buffer)
|
||||
}
|
||||
|
||||
// -------------- poly.c --------------
|
||||
inner class Poly {
|
||||
val coeffs = CharArray(PARAM_N)
|
||||
|
||||
fun destroy() {
|
||||
coeffs.fill(0.toChar())
|
||||
}
|
||||
|
||||
fun frombytes(a: ByteArray, offset: Int) {
|
||||
for (i in 0 until PARAM_N / 4) {
|
||||
coeffs[4 * i + 0] = ((a[offset + 7 * i + 0].toInt() and 0xff) or ((a[offset + 7 * i + 1].toInt() and 0x3f) shl 8)).toChar()
|
||||
coeffs[4 * i + 1] = (((a[offset + 7 * i + 1].toInt() and 0xc0) shr 6) or ((a[offset + 7 * i + 2].toInt() and 0xff) shl 2) or ((a[offset + 7 * i + 3].toInt() and 0x0f) shl 10)).toChar()
|
||||
coeffs[4 * i + 2] = (((a[offset + 7 * i + 3].toInt() and 0xf0) shr 4) or ((a[offset + 7 * i + 4].toInt() and 0xff) shl 4) or ((a[offset + 7 * i + 5].toInt() and 0x03) shl 12)).toChar()
|
||||
coeffs[4 * i + 3] = (((a[offset + 7 * i + 5].toInt() and 0xfc) shr 2) or ((a[offset + 7 * i + 6].toInt() and 0xff) shl 6)).toChar()
|
||||
}
|
||||
}
|
||||
|
||||
fun tobytes(r: ByteArray, offset: Int) {
|
||||
for (i in 0 until PARAM_N / 4) {
|
||||
var t0 = barrett_reduce(coeffs[4 * i + 0].code)
|
||||
var t1 = barrett_reduce(coeffs[4 * i + 1].code)
|
||||
var t2 = barrett_reduce(coeffs[4 * i + 2].code)
|
||||
var t3 = barrett_reduce(coeffs[4 * i + 3].code)
|
||||
|
||||
var m = t0 - PARAM_Q
|
||||
var mask = m shr 15
|
||||
t0 = m xor ((t0 xor m) and mask)
|
||||
|
||||
m = t1 - PARAM_Q
|
||||
mask = m shr 15
|
||||
t1 = m xor ((t1 xor m) and mask)
|
||||
|
||||
m = t2 - PARAM_Q
|
||||
mask = m shr 15
|
||||
t2 = m xor ((t2 xor m) and mask)
|
||||
|
||||
m = t3 - PARAM_Q
|
||||
mask = m shr 15
|
||||
t3 = m xor ((t3 xor m) and mask)
|
||||
|
||||
r[offset + 7 * i + 0] = (t0 and 0xff).toByte()
|
||||
r[offset + 7 * i + 1] = ((t0 shr 8) or (t1 shl 6)).toByte()
|
||||
r[offset + 7 * i + 2] = (t1 shr 2).toByte()
|
||||
r[offset + 7 * i + 3] = ((t1 shr 10) or (t2 shl 4)).toByte()
|
||||
r[offset + 7 * i + 4] = (t2 shr 4).toByte()
|
||||
r[offset + 7 * i + 5] = ((t2 shr 12) or (t3 shl 2)).toByte()
|
||||
r[offset + 7 * i + 6] = (t3 shr 6).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
fun getnoise(seed: ByteArray, nonce: Byte) {
|
||||
val buf = ByteArray(4 * PARAM_N)
|
||||
try {
|
||||
crypto_stream_chacha20(buf, 0, 4 * PARAM_N, nonce.toLong(), seed)
|
||||
for (i in 0 until PARAM_N) {
|
||||
var a = (buf[4 * i].toInt() and 0xff) or ((buf[4 * i + 1].toInt() and 0xff) shl 8)
|
||||
a = a - ((a shr 1) and 0x5555)
|
||||
a = (a and 0x3333) + ((a shr 2) and 0x3333)
|
||||
a = ((a shr 4) + a) and 0x0F0F
|
||||
a = ((a shr 8) + a) and 0x00FF
|
||||
|
||||
var b = (buf[4 * i + 2].toInt() and 0xff) or ((buf[4 * i + 3].toInt() and 0xff) shl 8)
|
||||
b = b - ((b shr 1) and 0x5555)
|
||||
b = (b and 0x3333) + ((b shr 2) and 0x3333)
|
||||
b = ((b shr 4) + b) and 0x0F0F
|
||||
b = ((b shr 8) + b) and 0x00FF
|
||||
|
||||
coeffs[i] = (a + PARAM_Q - b).toChar()
|
||||
}
|
||||
} finally {
|
||||
buf.fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
fun pointwise(a: Poly, b: Poly) {
|
||||
for (i in 0 until PARAM_N) {
|
||||
val t = montgomery_reduce(3186 * b.coeffs[i].code)
|
||||
coeffs[i] = montgomery_reduce(a.coeffs[i].code * t).toChar()
|
||||
}
|
||||
}
|
||||
|
||||
fun add(a: Poly, b: Poly) {
|
||||
for (i in 0 until PARAM_N) {
|
||||
coeffs[i] = barrett_reduce(a.coeffs[i].code + b.coeffs[i].code).toChar()
|
||||
}
|
||||
}
|
||||
|
||||
fun ntt() {
|
||||
mul_coefficients(coeffs, psis_bitrev_montgomery)
|
||||
ntt_global(coeffs, omegas_montgomery)
|
||||
}
|
||||
|
||||
fun invntt() {
|
||||
bitrev_vector(coeffs)
|
||||
ntt_global(coeffs, omegas_inv_montgomery)
|
||||
mul_coefficients(coeffs, psis_inv_montgomery)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives the public "a" value from a 32-byte seed.
|
||||
*/
|
||||
protected open fun uniform(coeffs: CharArray, seed: ByteArray) {
|
||||
var pos = 0
|
||||
var ctr = 0
|
||||
val state = LongArray(25)
|
||||
var nblocks = 14
|
||||
val buf = ByteArray(SHAKE128_RATE * nblocks)
|
||||
|
||||
try {
|
||||
shake128_absorb(state, seed, 0, SEEDBYTES)
|
||||
shake128_squeezeblocks(buf, 0, nblocks, state)
|
||||
|
||||
while (ctr < PARAM_N) {
|
||||
val value = (buf[pos].toInt() and 0xff) or ((buf[pos + 1].toInt() and 0xff) shl 8)
|
||||
if (value < 5 * PARAM_Q) coeffs[ctr++] = value.toChar()
|
||||
pos += 2
|
||||
if (pos > SHAKE128_RATE * nblocks - 2) {
|
||||
nblocks = 1
|
||||
shake128_squeezeblocks(buf, 0, nblocks, state)
|
||||
pos = 0
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
state.fill(0)
|
||||
buf.fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// -------------- params.h --------------
|
||||
const val PARAM_N = 1024
|
||||
const val PARAM_Q = 12289
|
||||
const val POLY_BYTES = 1792
|
||||
const val SEEDBYTES = 32
|
||||
const val RECBYTES = 256
|
||||
const val SHAKE128_RATE = 168
|
||||
const val SHAREDBYTES = 32
|
||||
const val SENDABYTES = POLY_BYTES + SEEDBYTES
|
||||
const val SENDBBYTES = POLY_BYTES + RECBYTES
|
||||
|
||||
private fun encode_a(r: ByteArray, roffset: Int, pk: Poly, seed: ByteArray) {
|
||||
pk.tobytes(r, roffset)
|
||||
seed.copyInto(r, POLY_BYTES + roffset, 0, SEEDBYTES)
|
||||
}
|
||||
|
||||
private fun decode_a(pk: Poly, seed: ByteArray, r: ByteArray, roffset: Int) {
|
||||
pk.frombytes(r, roffset)
|
||||
r.copyInto(seed, 0, POLY_BYTES + roffset, POLY_BYTES + roffset + SEEDBYTES)
|
||||
}
|
||||
|
||||
private fun encode_b(r: ByteArray, roffset: Int, b: Poly, c: Poly) {
|
||||
b.tobytes(r, roffset)
|
||||
for (i in 0 until PARAM_N / 4) {
|
||||
r[POLY_BYTES + roffset + i] = (c.coeffs[4 * i].code or (c.coeffs[4 * i + 1].code shl 2) or (c.coeffs[4 * i + 2].code shl 4) or (c.coeffs[4 * i + 3].code shl 6)).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
private fun decode_b(b: Poly, c: Poly, r: ByteArray, roffset: Int) {
|
||||
b.frombytes(r, roffset)
|
||||
for (i in 0 until PARAM_N / 4) {
|
||||
val v = r[POLY_BYTES + roffset + i].toInt()
|
||||
c.coeffs[4 * i + 0] = (v and 0x03).toChar()
|
||||
c.coeffs[4 * i + 1] = ((v shr 2) and 0x03).toChar()
|
||||
c.coeffs[4 * i + 2] = ((v shr 4) and 0x03).toChar()
|
||||
c.coeffs[4 * i + 3] = ((v shr 6) and 0x03).toChar()
|
||||
}
|
||||
}
|
||||
|
||||
private fun montgomery_reduce(a: Int): Int {
|
||||
val u = (a * 12287) and ((1 shl 18) - 1)
|
||||
return (a + u * PARAM_Q) ushr 18
|
||||
}
|
||||
|
||||
private fun barrett_reduce(a: Int): Int {
|
||||
val a16 = a and 0xffff
|
||||
val u = (a16 * 5) shr 16
|
||||
return (a16 - u * PARAM_Q) and 0xffff
|
||||
}
|
||||
|
||||
// -------------- error_correction.c --------------
|
||||
private fun abs(v: Int): Int {
|
||||
val mask = v shr 31
|
||||
return (v xor mask) - mask
|
||||
}
|
||||
|
||||
private fun f(v0: IntArray, v0offset: Int, v1: IntArray, v1offset: Int, x: Int): Int {
|
||||
var b = x * 2730
|
||||
var t = b shr 25
|
||||
b = x - t * 12289
|
||||
b = 12288 - b
|
||||
t -= (b shr 31)
|
||||
v0[v0offset] = (t shr 1) + (t and 1)
|
||||
t -= 1
|
||||
v1[v1offset] = (t shr 1) + (t and 1)
|
||||
return abs(x - (v0[v0offset] * 2 * PARAM_Q))
|
||||
}
|
||||
|
||||
private fun g(x: Int): Int {
|
||||
var b = x * 2730
|
||||
var t = b shr 27
|
||||
b = x - t * 49156
|
||||
b = 49155 - b
|
||||
t -= (b shr 31)
|
||||
t = (t shr 1) + (t and 1)
|
||||
return abs(t * 8 * PARAM_Q - x)
|
||||
}
|
||||
|
||||
private fun helprec(c: Poly, v: Poly, seed: ByteArray, nonce: Byte) {
|
||||
val v0 = IntArray(8)
|
||||
val rand = ByteArray(32)
|
||||
try {
|
||||
crypto_stream_chacha20(rand, 0, 32, nonce.toLong() shl 56, seed)
|
||||
for (i in 0 until 256) {
|
||||
val rbit = (rand[i shr 3].toInt() shr (i and 7)) and 1
|
||||
var k = f(v0, 0, v0, 4, 8 * v.coeffs[i].code + 4 * rbit)
|
||||
k += f(v0, 1, v0, 5, 8 * v.coeffs[256 + i].code + 4 * rbit)
|
||||
k += f(v0, 2, v0, 6, 8 * v.coeffs[512 + i].code + 4 * rbit)
|
||||
k += f(v0, 3, v0, 7, 8 * v.coeffs[768 + i].code + 4 * rbit)
|
||||
k = (2 * PARAM_Q - 1 - k) shr 31
|
||||
val vt0 = (k.inv() and v0[0]) xor (k and v0[4])
|
||||
val vt1 = (k.inv() and v0[1]) xor (k and v0[5])
|
||||
val vt2 = (k.inv() and v0[2]) xor (k and v0[6])
|
||||
val vt3 = (k.inv() and v0[3]) xor (k and v0[7])
|
||||
c.coeffs[i] = ((vt0 - vt3) and 3).toChar()
|
||||
c.coeffs[256 + i] = ((vt1 - vt3) and 3).toChar()
|
||||
c.coeffs[512 + i] = ((vt2 - vt3) and 3).toChar()
|
||||
c.coeffs[768 + i] = ((-k + 2 * vt3) and 3).toChar()
|
||||
}
|
||||
} finally {
|
||||
v0.fill(0); rand.fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun rec(key: ByteArray, v: Poly, c: Poly) {
|
||||
key.fill(0)
|
||||
for (i in 0 until 256) {
|
||||
val c768 = c.coeffs[768 + i].code
|
||||
val t0 = 16 * PARAM_Q + 8 * v.coeffs[i].code - PARAM_Q * (2 * c.coeffs[i].code + c768)
|
||||
val t1 = 16 * PARAM_Q + 8 * v.coeffs[256 + i].code - PARAM_Q * (2 * c.coeffs[256 + i].code + c768)
|
||||
val t2 = 16 * PARAM_Q + 8 * v.coeffs[512 + i].code - PARAM_Q * (2 * c.coeffs[512 + i].code + c768)
|
||||
val t3 = 16 * PARAM_Q + 8 * v.coeffs[768 + i].code - PARAM_Q * c768
|
||||
key[i shr 3] = (key[i shr 3].toInt() or (LDDecode(t0, t1, t2, t3) shl (i and 7))).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
private fun LDDecode(xi0: Int, xi1: Int, xi2: Int, xi3: Int): Int {
|
||||
var t = g(xi0) + g(xi1) + g(xi2) + g(xi3)
|
||||
return ((t - 8 * PARAM_Q) shr 31) and 1
|
||||
}
|
||||
|
||||
private fun bitrev_vector(poly: CharArray) {
|
||||
for (p in 0 until 496) {
|
||||
val indices = bitrev_table_combined[p]
|
||||
val i = indices and 0x03FF
|
||||
val r = indices shr 10
|
||||
val tmp = poly[i]
|
||||
poly[i] = poly[r]
|
||||
poly[r] = tmp
|
||||
}
|
||||
}
|
||||
|
||||
private fun mul_coefficients(poly: CharArray, factors: CharArray) {
|
||||
for (i in 0 until PARAM_N) {
|
||||
poly[i] = montgomery_reduce(poly[i].code * factors[i].code).toChar()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ntt_global(a: CharArray, omega: CharArray) {
|
||||
for (i in 0 until 10 step 2) {
|
||||
var dist = 1 shl i
|
||||
repeat(dist) { start ->
|
||||
var tw = 0
|
||||
var j = start
|
||||
while (j < PARAM_N - 1) {
|
||||
val w = omega[tw++]; val tmp = a[j]
|
||||
a[j] = (tmp.code + a[j + dist].code).toChar()
|
||||
a[j + dist] = montgomery_reduce(w.code * (tmp.code + 3 * PARAM_Q - a[dist + j].code)).toChar()
|
||||
j += 2 * dist
|
||||
}
|
||||
}
|
||||
dist = dist shl 1
|
||||
repeat(dist) { start ->
|
||||
var tw = 0
|
||||
var j = start
|
||||
while (j < PARAM_N - 1) {
|
||||
val w = omega[tw++]; val tmp = a[j]
|
||||
a[j] = barrett_reduce(tmp.code + a[j + dist].code).toChar()
|
||||
a[j + dist] = montgomery_reduce(w.code * (tmp.code + 3 * PARAM_Q - a[dist + j].code)).toChar()
|
||||
j += 2 * dist
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun crypto_stream_chacha20(c: ByteArray, coffset: Int, clen: Int, n: Long, k: ByteArray) {
|
||||
if (clen <= 0) return
|
||||
var off = coffset; var len = clen; var blk = 0
|
||||
while (len >= 64) {
|
||||
crypto_core_chacha20(c, off, n, blk++, k)
|
||||
len -= 64; off += 64
|
||||
}
|
||||
if (len > 0) {
|
||||
val block = ByteArray(64)
|
||||
try {
|
||||
crypto_core_chacha20(block, 0, n, blk, k)
|
||||
block.copyInto(c, off, 0, len)
|
||||
} finally { block.fill(0) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun crypto_core_chacha20(out: ByteArray, outOffset: Int, nonce: Long, blknum: Int, k: ByteArray) {
|
||||
val state = IntArray(16)
|
||||
state[0] = 0x61707865; state[1] = 0x3320646e; state[2] = 0x79622d32; state[3] = 0x6b206574
|
||||
for (i in 0 until 8) state[4 + i] = (k[4 * i].toInt() and 0xff) or ((k[4 * i + 1].toInt() and 0xff) shl 8) or ((k[4 * i + 2].toInt() and 0xff) shl 16) or ((k[4 * i + 3].toInt() and 0xff) shl 24)
|
||||
state[12] = blknum; state[13] = 0; state[14] = nonce.toInt(); state[15] = (nonce ushr 32).toInt()
|
||||
val working = state.copyOf()
|
||||
for (i in 0 until 20 step 2) {
|
||||
qr(working, 0, 4, 8, 12); qr(working, 1, 5, 9, 13); qr(working, 2, 6, 10, 14); qr(working, 3, 7, 11, 15)
|
||||
qr(working, 0, 5, 10, 15); qr(working, 1, 6, 11, 12); qr(working, 2, 7, 8, 13); qr(working, 3, 4, 9, 14)
|
||||
}
|
||||
for (i in 0 until 16) {
|
||||
val v = working[i] + state[i]
|
||||
out[outOffset + 4 * i] = v.toByte()
|
||||
out[outOffset + 4 * i + 1] = (v shr 8).toByte()
|
||||
out[outOffset + 4 * i + 2] = (v shr 16).toByte()
|
||||
out[outOffset + 4 * i + 3] = (v shr 24).toByte()
|
||||
}
|
||||
}
|
||||
private fun qr(v: IntArray, a: Int, b: Int, c: Int, d: Int) {
|
||||
v[a] += v[b]; v[d] = rotl(v[d] xor v[a], 16)
|
||||
v[c] += v[d]; v[b] = rotl(v[b] xor v[c], 12)
|
||||
v[a] += v[b]; v[d] = rotl(v[d] xor v[a], 8)
|
||||
v[c] += v[d]; v[b] = rotl(v[b] xor v[c], 7)
|
||||
}
|
||||
private fun rotl(v: Int, n: Int) = (v shl n) or (v ushr (32 - n))
|
||||
|
||||
fun shake128_absorb(s: LongArray, input: ByteArray, offset: Int, len: Int) {
|
||||
keccak_absorb(s, SHAKE128_RATE, input, offset, len, 0x1F.toByte())
|
||||
}
|
||||
|
||||
fun shake128_squeezeblocks(output: ByteArray, offset: Int, nblocks: Int, s: LongArray) {
|
||||
keccak_squeezeblocks(output, offset, nblocks, s, SHAKE128_RATE)
|
||||
}
|
||||
|
||||
private fun keccak_absorb(s: LongArray, r: Int, m: ByteArray, offset: Int, mlen: Int, p: Byte) {
|
||||
var off = offset; var len = mlen
|
||||
s.fill(0L)
|
||||
while (len >= r) {
|
||||
for (i in 0 until r / 8) s[i] = s[i] xor load64(m, off + 8 * i)
|
||||
KeccakF1600_StatePermute(s)
|
||||
len -= r; off += r
|
||||
}
|
||||
val t = ByteArray(200)
|
||||
try {
|
||||
for (i in 0 until len) t[i] = m[off + i]
|
||||
t[len] = p; t[r - 1] = (t[r - 1].toInt() or 128).toByte()
|
||||
for (i in 0 until r / 8) s[i] = s[i] xor load64(t, 8 * i)
|
||||
} finally { t.fill(0) }
|
||||
}
|
||||
|
||||
private fun keccak_squeezeblocks(h: ByteArray, offset: Int, nblocks: Int, s: LongArray, r: Int) {
|
||||
var off = offset
|
||||
repeat(nblocks) {
|
||||
KeccakF1600_StatePermute(s)
|
||||
for (i in 0 until (r shr 3)) store64(h, off + 8 * i, s[i])
|
||||
off += r
|
||||
}
|
||||
}
|
||||
|
||||
private fun load64(x: ByteArray, off: Int): Long {
|
||||
var r = 0L
|
||||
for (i in 0..7) r = r or ((x[off + i].toLong() and 0xffL) shl (8 * i))
|
||||
return r
|
||||
}
|
||||
|
||||
private fun store64(x: ByteArray, off: Int, u: Long) {
|
||||
var v = u
|
||||
for (i in 0..7) { x[off + i] = v.toByte(); v = v shr 8 }
|
||||
}
|
||||
|
||||
private fun KeccakF1600_StatePermute(s: LongArray) {
|
||||
// Minimal Keccak-f[1600] implementation
|
||||
repeat(24) { r ->
|
||||
val bc = LongArray(5)
|
||||
for (i in 0..4) bc[i] = s[i] xor s[i + 5] xor s[i + 10] xor s[i + 15] xor s[i + 20]
|
||||
for (i in 0..4) {
|
||||
val t = bc[(i + 4) % 5] xor rol64(bc[(i + 1) % 5], 1)
|
||||
for (j in 0..20 step 5) s[i + j] = s[i + j] xor t
|
||||
}
|
||||
var cur = s[1]; var last = 0L
|
||||
for (i in 0..23) {
|
||||
val next = s[keccak_pi[i]]; s[keccak_pi[i]] = rol64(cur, keccak_rho[i])
|
||||
cur = next
|
||||
}
|
||||
for (j in 0..20 step 5) {
|
||||
for (i in 0..4) bc[i] = s[i + j]
|
||||
for (i in 0..4) s[i + j] = bc[i] xor (bc[(i + 1) % 5].inv() and bc[(i + 2) % 5])
|
||||
}
|
||||
s[0] = s[0] xor KeccakF_RoundConstants[r]
|
||||
}
|
||||
}
|
||||
private fun rol64(a: Long, n: Int) = if (n == 0) a else (a shl n) or (a ushr (64 - n))
|
||||
private val keccak_rho = intArrayOf(1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14)
|
||||
private val keccak_pi = intArrayOf(10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1)
|
||||
private val KeccakF_RoundConstants = longArrayOf(
|
||||
0x0000000000000001L, 0x0000000000008082L, -0x7FFFFFFFFFFF7F76L, -0x7FFFFFFF7FFF8000L,
|
||||
0x000000000000808BL, 0x0000000080000001L, -0x7FFFFFFF7FFF7F7FL, -0x7FFFFFFFFFFF7FF7L,
|
||||
0x000000000000008AL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL,
|
||||
0x000000008000808BL, -0x7FFFFFFFFFFFFF75L, -0x7FFFFFFFFFFF7F77L, -0x7FFFFFFFFFFF7FFDL,
|
||||
-0x7FFFFFFFFFFF7FFEL, -0x7FFFFFFFFFFFFF80L, 0x000000000000800AL, -0x7FFFFFFF7FFFFFF6L,
|
||||
-0x7FFFFFFF7FFF7F7FL, -0x7FFFFFFFFFFF7F80L, 0x0000000080000001L, -0x7FFFFFFF7FFF7FF8L
|
||||
)
|
||||
|
||||
private fun sha3256(output: ByteArray, outOffset: Int, input: ByteArray, inOffset: Int, len: Int) {
|
||||
val s = LongArray(25)
|
||||
keccak_absorb(s, 136, input, inOffset, len, 0x06.toByte())
|
||||
val t = ByteArray(136)
|
||||
keccak_squeezeblocks(t, 0, 1, s, 136)
|
||||
t.copyInto(output, outOffset, 0, 32)
|
||||
}
|
||||
|
||||
private val omegas_montgomery = charArrayOf(
|
||||
4075.toChar(), 6974.toChar(), 7373.toChar(), 7965.toChar(), 3262.toChar(), 5079.toChar(), 522.toChar(), 2169.toChar(), 6364.toChar(), 1018.toChar(), 1041.toChar(), 8775.toChar(), 2344.toChar(), 11011.toChar(), 5574.toChar(), 1973.toChar(),
|
||||
4536.toChar(), 1050.toChar(), 6844.toChar(), 3860.toChar(), 3818.toChar(), 6118.toChar(), 2683.toChar(), 1190.toChar(), 4789.toChar(), 7822.toChar(), 7540.toChar(), 6752.toChar(), 5456.toChar(), 4449.toChar(), 3789.toChar(), 12142.toChar(),
|
||||
11973.toChar(), 382.toChar(), 3988.toChar(), 468.toChar(), 6843.toChar(), 5339.toChar(), 6196.toChar(), 3710.toChar(), 11316.toChar(), 1254.toChar(), 5435.toChar(), 10930.toChar(), 3998.toChar(), 10256.toChar(), 10367.toChar(), 3879.toChar(),
|
||||
11889.toChar(), 1728.toChar(), 6137.toChar(), 4948.toChar(), 5862.toChar(), 6136.toChar(), 3643.toChar(), 6874.toChar(), 8724.toChar(), 654.toChar(), 10302.toChar(), 1702.toChar(), 7083.toChar(), 6760.toChar(), 56.toChar(), 3199.toChar(),
|
||||
9987.toChar(), 605.toChar(), 11785.toChar(), 8076.toChar(), 5594.toChar(), 9260.toChar(), 6403.toChar(), 4782.toChar(), 6212.toChar(), 4624.toChar(), 9026.toChar(), 8689.toChar(), 4080.toChar(), 11868.toChar(), 6221.toChar(), 3602.toChar(),
|
||||
975.toChar(), 8077.toChar(), 8851.toChar(), 9445.toChar(), 5681.toChar(), 3477.toChar(), 1105.toChar(), 142.toChar(), 241.toChar(), 12231.toChar(), 1003.toChar(), 3532.toChar(), 5009.toChar(), 1956.toChar(), 6008.toChar(), 11404.toChar(),
|
||||
7377.toChar(), 2049.toChar(), 10968.toChar(), 12097.toChar(), 7591.toChar(), 5057.toChar(), 3445.toChar(), 4780.toChar(), 2920.toChar(), 7048.toChar(), 3127.toChar(), 8120.toChar(), 11279.toChar(), 6821.toChar(), 11502.toChar(), 8807.toChar(),
|
||||
12138.toChar(), 2127.toChar(), 2839.toChar(), 3957.toChar(), 431.toChar(), 1579.toChar(), 6383.toChar(), 9784.toChar(), 5874.toChar(), 677.toChar(), 3336.toChar(), 6234.toChar(), 2766.toChar(), 1323.toChar(), 9115.toChar(), 12237.toChar(),
|
||||
2031.toChar(), 6956.toChar(), 6413.toChar(), 2281.toChar(), 3969.toChar(), 3991.toChar(), 12133.toChar(), 9522.toChar(), 4737.toChar(), 10996.toChar(), 4774.toChar(), 5429.toChar(), 11871.toChar(), 3772.toChar(), 453.toChar(), 5908.toChar(),
|
||||
2882.toChar(), 1805.toChar(), 2051.toChar(), 1954.toChar(), 11713.toChar(), 3963.toChar(), 2447.toChar(), 6142.toChar(), 8174.toChar(), 3030.toChar(), 1843.toChar(), 2361.toChar(), 12071.toChar(), 2908.toChar(), 3529.toChar(), 3434.toChar(),
|
||||
3202.toChar(), 7796.toChar(), 2057.toChar(), 5369.toChar(), 11939.toChar(), 1512.toChar(), 6906.toChar(), 10474.toChar(), 11026.toChar(), 49.toChar(), 10806.toChar(), 5915.toChar(), 1489.toChar(), 9789.toChar(), 5942.toChar(), 10706.toChar(),
|
||||
10431.toChar(), 7535.toChar(), 426.toChar(), 8974.toChar(), 3757.toChar(), 10314.toChar(), 9364.toChar(), 347.toChar(), 5868.toChar(), 9551.toChar(), 9634.toChar(), 6554.toChar(), 10596.toChar(), 9280.toChar(), 11566.toChar(), 174.toChar(),
|
||||
2948.toChar(), 2503.toChar(), 6507.toChar(), 10723.toChar(), 11606.toChar(), 2459.toChar(), 64.toChar(), 3656.toChar(), 8455.toChar(), 5257.toChar(), 5919.toChar(), 7856.toChar(), 1747.toChar(), 9166.toChar(), 5486.toChar(), 9235.toChar(),
|
||||
6065.toChar(), 835.toChar(), 3570.toChar(), 4240.toChar(), 11580.toChar(), 4046.toChar(), 10970.toChar(), 9139.toChar(), 1058.toChar(), 8210.toChar(), 11848.toChar(), 922.toChar(), 7967.toChar(), 1958.toChar(), 10211.toChar(), 1112.toChar(),
|
||||
3728.toChar(), 4049.toChar(), 11130.toChar(), 5990.toChar(), 1404.toChar(), 325.toChar(), 948.toChar(), 11143.toChar(), 6190.toChar(), 295.toChar(), 11637.toChar(), 5766.toChar(), 8212.toChar(), 8273.toChar(), 2919.toChar(), 8527.toChar(),
|
||||
6119.toChar(), 6992.toChar(), 8333.toChar(), 1360.toChar(), 2555.toChar(), 6167.toChar(), 1200.toChar(), 7105.toChar(), 7991.toChar(), 3329.toChar(), 9597.toChar(), 12121.toChar(), 5106.toChar(), 5961.toChar(), 10695.toChar(), 10327.toChar(),
|
||||
3051.toChar(), 9923.toChar(), 4896.toChar(), 9326.toChar(), 81.toChar(), 3091.toChar(), 1000.toChar(), 7969.toChar(), 4611.toChar(), 726.toChar(), 1853.toChar(), 12149.toChar(), 4255.toChar(), 11112.toChar(), 2768.toChar(), 10654.toChar(),
|
||||
1062.toChar(), 2294.toChar(), 3553.toChar(), 4805.toChar(), 2747.toChar(), 4846.toChar(), 8577.toChar(), 9154.toChar(), 1170.toChar(), 2319.toChar(), 790.toChar(), 11334.toChar(), 9275.toChar(), 9088.toChar(), 1326.toChar(), 5086.toChar(),
|
||||
9094.toChar(), 6429.toChar(), 11077.toChar(), 10643.toChar(), 3504.toChar(), 3542.toChar(), 8668.toChar(), 9744.toChar(), 1479.toChar(), 1.toChar(), 8246.toChar(), 7143.toChar(), 11567.toChar(), 10984.toChar(), 4134.toChar(), 5736.toChar(),
|
||||
4978.toChar(), 10938.toChar(), 5777.toChar(), 8961.toChar(), 4591.toChar(), 5728.toChar(), 6461.toChar(), 5023.toChar(), 9650.toChar(), 7468.toChar(), 949.toChar(), 9664.toChar(), 2975.toChar(), 11726.toChar(), 2744.toChar(), 9283.toChar(),
|
||||
10092.toChar(), 5067.toChar(), 12171.toChar(), 2476.toChar(), 3748.toChar(), 11336.toChar(), 6522.toChar(), 827.toChar(), 9452.toChar(), 5374.toChar(), 12159.toChar(), 7935.toChar(), 3296.toChar(), 3949.toChar(), 9893.toChar(), 4452.toChar(),
|
||||
10908.toChar(), 2525.toChar(), 3584.toChar(), 8112.toChar(), 8011.toChar(), 10616.toChar(), 4989.toChar(), 6958.toChar(), 11809.toChar(), 9447.toChar(), 12280.toChar(), 1022.toChar(), 11950.toChar(), 9821.toChar(), 11745.toChar(), 5791.toChar(),
|
||||
5092.toChar(), 2089.toChar(), 9005.toChar(), 2881.toChar(), 3289.toChar(), 2013.toChar(), 9048.toChar(), 729.toChar(), 7901.toChar(), 1260.toChar(), 5755.toChar(), 4632.toChar(), 11955.toChar(), 2426.toChar(), 10593.toChar(), 1428.toChar(),
|
||||
4890.toChar(), 5911.toChar(), 3932.toChar(), 9558.toChar(), 8830.toChar(), 3637.toChar(), 5542.toChar(), 145.toChar(), 5179.toChar(), 8595.toChar(), 3707.toChar(), 10530.toChar(), 355.toChar(), 3382.toChar(), 4231.toChar(), 9741.toChar(),
|
||||
1207.toChar(), 9041.toChar(), 7012.toChar(), 1168.toChar(), 10146.toChar(), 11224.toChar(), 4645.toChar(), 11885.toChar(), 10911.toChar(), 10377.toChar(), 435.toChar(), 7952.toChar(), 4096.toChar(), 493.toChar(), 9908.toChar(), 6845.toChar(),
|
||||
6039.toChar(), 2422.toChar(), 2187.toChar(), 9723.toChar(), 8643.toChar(), 9852.toChar(), 9302.toChar(), 6022.toChar(), 7278.toChar(), 1002.toChar(), 4284.toChar(), 5088.toChar(), 1607.toChar(), 7313.toChar(), 875.toChar(), 8509.toChar(),
|
||||
9430.toChar(), 1045.toChar(), 2481.toChar(), 5012.toChar(), 7428.toChar(), 354.toChar(), 6591.toChar(), 9377.toChar(), 11847.toChar(), 2401.toChar(), 1067.toChar(), 7188.toChar(), 11516.toChar(), 390.toChar(), 8511.toChar(), 8456.toChar(),
|
||||
7270.toChar(), 545.toChar(), 8585.toChar(), 9611.toChar(), 12047.toChar(), 1537.toChar(), 4143.toChar(), 4714.toChar(), 4885.toChar(), 1017.toChar(), 5084.toChar(), 1632.toChar(), 3066.toChar(), 27.toChar(), 1440.toChar(), 8526.toChar(),
|
||||
9273.toChar(), 12046.toChar(), 11618.toChar(), 9289.toChar(), 3400.toChar(), 9890.toChar(), 3136.toChar(), 7098.toChar(), 8758.toChar(), 11813.toChar(), 7384.toChar(), 3985.toChar(), 11869.toChar(), 6730.toChar(), 10745.toChar(), 10111.toChar(),
|
||||
2249.toChar(), 4048.toChar(), 2884.toChar(), 11136.toChar(), 2126.toChar(), 1630.toChar(), 9103.toChar(), 5407.toChar(), 2686.toChar(), 9042.toChar(), 2969.toChar(), 8311.toChar(), 9424.toChar(), 9919.toChar(), 8779.toChar(), 5332.toChar(),
|
||||
10626.toChar(), 1777.toChar(), 4654.toChar(), 10863.toChar(), 7351.toChar(), 3636.toChar(), 9585.toChar(), 5291.toChar(), 8374.toChar(), 2166.toChar(), 4919.toChar(), 12176.toChar(), 9140.toChar(), 12129.toChar(), 7852.toChar(), 12286.toChar(),
|
||||
4895.toChar(), 10805.toChar(), 2780.toChar(), 5195.toChar(), 2305.toChar(), 7247.toChar(), 9644.toChar(), 4053.toChar(), 10600.toChar(), 3364.toChar(), 3271.toChar(), 4057.toChar(), 4414.toChar(), 9442.toChar(), 7917.toChar(), 2174.toChar()
|
||||
)
|
||||
private val omegas_inv_montgomery = charArrayOf(
|
||||
4075.toChar(), 5315.toChar(), 4324.toChar(), 4916.toChar(), 10120.toChar(), 11767.toChar(), 7210.toChar(), 9027.toChar(), 10316.toChar(), 6715.toChar(), 1278.toChar(), 9945.toChar(), 3514.toChar(), 11248.toChar(), 11271.toChar(), 5925.toChar(),
|
||||
147.toChar(), 8500.toChar(), 7840.toChar(), 6833.toChar(), 5537.toChar(), 4749.toChar(), 4467.toChar(), 7500.toChar(), 11099.toChar(), 9606.toChar(), 6171.toChar(), 8471.toChar(), 8429.toChar(), 5445.toChar(), 11239.toChar(), 7753.toChar(),
|
||||
9090.toChar(), 12233.toChar(), 5529.toChar(), 5206.toChar(), 10587.toChar(), 1987.toChar(), 11635.toChar(), 3565.toChar(), 5415.toChar(), 8646.toChar(), 6153.toChar(), 6427.toChar(), 7341.toChar(), 6152.toChar(), 10561.toChar(), 400.toChar(),
|
||||
8410.toChar(), 1922.toChar(), 2033.toChar(), 8291.toChar(), 1359.toChar(), 6854.toChar(), 11035.toChar(), 973.toChar(), 8579.toChar(), 6093.toChar(), 6950.toChar(), 5446.toChar(), 11821.toChar(), 8301.toChar(), 11907.toChar(), 316.toChar(),
|
||||
52.toChar(), 3174.toChar(), 10966.toChar(), 9523.toChar(), 6055.toChar(), 8953.toChar(), 11612.toChar(), 6415.toChar(), 2505.toChar(), 5906.toChar(), 10710.toChar(), 11858.toChar(), 8332.toChar(), 9450.toChar(), 10162.toChar(), 151.toChar(),
|
||||
3482.toChar(), 787.toChar(), 5468.toChar(), 1010.toChar(), 4169.toChar(), 9162.toChar(), 5241.toChar(), 9369.toChar(), 7509.toChar(), 8844.toChar(), 7232.toChar(), 4698.toChar(), 192.toChar(), 1321.toChar(), 10240.toChar(), 4912.toChar(),
|
||||
885.toChar(), 6281.toChar(), 10333.toChar(), 7280.toChar(), 8757.toChar(), 11286.toChar(), 58.toChar(), 12048.toChar(), 12147.toChar(), 11184.toChar(), 8812.toChar(), 6608.toChar(), 2844.toChar(), 3438.toChar(), 4212.toChar(), 11314.toChar(),
|
||||
8687.toChar(), 6068.toChar(), 421.toChar(), 8209.toChar(), 3600.toChar(), 3263.toChar(), 7665.toChar(), 6077.toChar(), 7507.toChar(), 5886.toChar(), 3029.toChar(), 6695.toChar(), 4213.toChar(), 504.toChar(), 11684.toChar(), 2302.toChar(),
|
||||
1962.toChar(), 1594.toChar(), 6328.toChar(), 7183.toChar(), 168.toChar(), 2692.toChar(), 8960.toChar(), 4298.toChar(), 5184.toChar(), 11089.toChar(), 6122.toChar(), 9734.toChar(), 10929.toChar(), 3956.toChar(), 5297.toChar(), 6170.toChar(),
|
||||
3762.toChar(), 9370.toChar(), 4016.toChar(), 4077.toChar(), 6523.toChar(), 652.toChar(), 11994.toChar(), 6099.toChar(), 1146.toChar(), 11341.toChar(), 11964.toChar(), 10885.toChar(), 6299.toChar(), 1159.toChar(), 8240.toChar(), 8561.toChar(),
|
||||
11177.toChar(), 2078.toChar(), 10331.toChar(), 4322.toChar(), 11367.toChar(), 441.toChar(), 4079.toChar(), 11231.toChar(), 3150.toChar(), 1319.toChar(), 8243.toChar(), 709.toChar(), 8049.toChar(), 8719.toChar(), 11454.toChar(), 6224.toChar(),
|
||||
3054.toChar(), 6803.toChar(), 3123.toChar(), 10542.toChar(), 4433.toChar(), 6370.toChar(), 7032.toChar(), 3834.toChar(), 8633.toChar(), 12225.toChar(), 9830.toChar(), 683.toChar(), 1566.toChar(), 5782.toChar(), 9786.toChar(), 9341.toChar(),
|
||||
12115.toChar(), 723.toChar(), 3009.toChar(), 1693.toChar(), 5735.toChar(), 2655.toChar(), 2738.toChar(), 6421.toChar(), 11942.toChar(), 2925.toChar(), 1975.toChar(), 8532.toChar(), 3315.toChar(), 11863.toChar(), 4754.toChar(), 1858.toChar(),
|
||||
1583.toChar(), 6347.toChar(), 2500.toChar(), 10800.toChar(), 6374.toChar(), 1483.toChar(), 12240.toChar(), 1263.toChar(), 1815.toChar(), 5383.toChar(), 10777.toChar(), 350.toChar(), 6920.toChar(), 10232.toChar(), 4493.toChar(), 9087.toChar(),
|
||||
8855.toChar(), 8760.toChar(), 9381.toChar(), 218.toChar(), 9928.toChar(), 10446.toChar(), 9259.toChar(), 4115.toChar(), 6147.toChar(), 9842.toChar(), 8326.toChar(), 576.toChar(), 10335.toChar(), 10238.toChar(), 10484.toChar(), 9407.toChar(),
|
||||
6381.toChar(), 11836.toChar(), 8517.toChar(), 418.toChar(), 6860.toChar(), 7515.toChar(), 1293.toChar(), 7552.toChar(), 2767.toChar(), 156.toChar(), 8298.toChar(), 8320.toChar(), 10008.toChar(), 5876.toChar(), 5333.toChar(), 10258.toChar(),
|
||||
10115.toChar(), 4372.toChar(), 2847.toChar(), 7875.toChar(), 8232.toChar(), 9018.toChar(), 8925.toChar(), 1689.toChar(), 8236.toChar(), 2645.toChar(), 5042.toChar(), 9984.toChar(), 7094.toChar(), 9509.toChar(), 1484.toChar(), 7394.toChar(),
|
||||
3.toChar(), 4437.toChar(), 160.toChar(), 3149.toChar(), 113.toChar(), 7370.toChar(), 10123.toChar(), 3915.toChar(), 6998.toChar(), 2704.toChar(), 8653.toChar(), 4938.toChar(), 1426.toChar(), 7635.toChar(), 10512.toChar(), 1663.toChar(),
|
||||
6957.toChar(), 3510.toChar(), 2370.toChar(), 2865.toChar(), 3978.toChar(), 9320.toChar(), 3247.toChar(), 9603.toChar(), 6882.toChar(), 3186.toChar(), 10659.toChar(), 10163.toChar(), 1153.toChar(), 9405.toChar(), 8241.toChar(), 10040.toChar(),
|
||||
2178.toChar(), 1544.toChar(), 5559.toChar(), 420.toChar(), 8304.toChar(), 4905.toChar(), 476.toChar(), 3531.toChar(), 5191.toChar(), 9153.toChar(), 2399.toChar(), 8889.toChar(), 3000.toChar(), 671.toChar(), 243.toChar(), 3016.toChar(),
|
||||
3763.toChar(), 10849.toChar(), 12262.toChar(), 9223.toChar(), 10657.toChar(), 7205.toChar(), 11272.toChar(), 7404.toChar(), 7575.toChar(), 8146.toChar(), 10752.toChar(), 242.toChar(), 2678.toChar(), 3704.toChar(), 11744.toChar(), 5019.toChar(),
|
||||
3833.toChar(), 3778.toChar(), 11899.toChar(), 773.toChar(), 5101.toChar(), 11222.toChar(), 9888.toChar(), 442.toChar(), 2912.toChar(), 5698.toChar(), 11935.toChar(), 4861.toChar(), 7277.toChar(), 9808.toChar(), 11244.toChar(), 2859.toChar(),
|
||||
3780.toChar(), 11414.toChar(), 4976.toChar(), 10682.toChar(), 7201.toChar(), 8005.toChar(), 11287.toChar(), 5011.toChar(), 6267.toChar(), 2987.toChar(), 2437.toChar(), 3646.toChar(), 2566.toChar(), 10102.toChar(), 9867.toChar(), 6250.toChar(),
|
||||
5444.toChar(), 2381.toChar(), 11796.toChar(), 8193.toChar(), 4337.toChar(), 11854.toChar(), 1912.toChar(), 1378.toChar(), 404.toChar(), 7644.toChar(), 1065.toChar(), 2143.toChar(), 11121.toChar(), 5277.toChar(), 3248.toChar(), 11082.toChar(),
|
||||
2548.toChar(), 8058.toChar(), 8907.toChar(), 11934.toChar(), 1759.toChar(), 8582.toChar(), 3694.toChar(), 7110.toChar(), 12144.toChar(), 6747.toChar(), 8652.toChar(), 3459.toChar(), 2731.toChar(), 8357.toChar(), 6378.toChar(), 7399.toChar(),
|
||||
10861.toChar(), 1696.toChar(), 9863.toChar(), 334.toChar(), 7657.toChar(), 6534.toChar(), 11029.toChar(), 4388.toChar(), 11560.toChar(), 3241.toChar(), 10276.toChar(), 9000.toChar(), 9408.toChar(), 3284.toChar(), 10200.toChar(), 7197.toChar(),
|
||||
6498.toChar(), 544.toChar(), 2468.toChar(), 339.toChar(), 11267.toChar(), 9.toChar(), 2842.toChar(), 480.toChar(), 5331.toChar(), 7300.toChar(), 1673.toChar(), 4278.toChar(), 4177.toChar(), 8705.toChar(), 9764.toChar(), 1381.toChar(),
|
||||
7837.toChar(), 2396.toChar(), 8340.toChar(), 8993.toChar(), 4354.toChar(), 130.toChar(), 6915.toChar(), 2837.toChar(), 11462.toChar(), 5767.toChar(), 953.toChar(), 8541.toChar(), 9813.toChar(), 118.toChar(), 7222.toChar(), 2197.toChar(),
|
||||
3006.toChar(), 9545.toChar(), 563.toChar(), 9314.toChar(), 2625.toChar(), 11340.toChar(), 4821.toChar(), 2639.toChar(), 7266.toChar(), 5828.toChar(), 6561.toChar(), 7698.toChar(), 3328.toChar(), 6512.toChar(), 1351.toChar(), 7311.toChar(),
|
||||
6553.toChar(), 8155.toChar(), 1305.toChar(), 722.toChar(), 5146.toChar(), 4043.toChar(), 12288.toChar(), 10810.toChar(), 2545.toChar(), 3621.toChar(), 8747.toChar(), 8785.toChar(), 1646.toChar(), 1212.toChar(), 5860.toChar(), 3195.toChar(),
|
||||
7203.toChar(), 10963.toChar(), 3201.toChar(), 3014.toChar(), 955.toChar(), 11499.toChar(), 9970.toChar(), 11119.toChar(), 3135.toChar(), 3712.toChar(), 7443.toChar(), 9542.toChar(), 7484.toChar(), 8736.toChar(), 9995.toChar(), 11227.toChar(),
|
||||
1635.toChar(), 9521.toChar(), 1177.toChar(), 8034.toChar(), 140.toChar(), 10436.toChar(), 11563.toChar(), 7678.toChar(), 4320.toChar(), 11289.toChar(), 9198.toChar(), 12208.toChar(), 2963.toChar(), 7393.toChar(), 2366.toChar(), 9238.toChar()
|
||||
)
|
||||
private val psis_bitrev_montgomery = charArrayOf(
|
||||
4075.toChar(), 6974.toChar(), 7373.toChar(), 7965.toChar(), 3262.toChar(), 5079.toChar(), 522.toChar(), 2169.toChar(), 6364.toChar(), 1018.toChar(), 1041.toChar(), 8775.toChar(), 2344.toChar(), 11011.toChar(), 5574.toChar(), 1973.toChar(),
|
||||
4536.toChar(), 1050.toChar(), 6844.toChar(), 3860.toChar(), 3818.toChar(), 6118.toChar(), 2683.toChar(), 1190.toChar(), 4789.toChar(), 7822.toChar(), 7540.toChar(), 6752.toChar(), 5456.toChar(), 4449.toChar(), 3789.toChar(), 12142.toChar(),
|
||||
11973.toChar(), 382.toChar(), 3988.toChar(), 468.toChar(), 6843.toChar(), 5339.toChar(), 6196.toChar(), 3710.toChar(), 11316.toChar(), 1254.toChar(), 5435.toChar(), 10930.toChar(), 3998.toChar(), 10256.toChar(), 10367.toChar(), 3879.toChar(),
|
||||
11889.toChar(), 1728.toChar(), 6137.toChar(), 4948.toChar(), 5862.toChar(), 6136.toChar(), 3643.toChar(), 6874.toChar(), 8724.toChar(), 654.toChar(), 10302.toChar(), 1702.toChar(), 7083.toChar(), 6760.toChar(), 56.toChar(), 3199.toChar(),
|
||||
9987.toChar(), 605.toChar(), 11785.toChar(), 8076.toChar(), 5594.toChar(), 9260.toChar(), 6403.toChar(), 4782.toChar(), 6212.toChar(), 4624.toChar(), 9026.toChar(), 8689.toChar(), 4080.toChar(), 11868.toChar(), 6221.toChar(), 3602.toChar(),
|
||||
975.toChar(), 8077.toChar(), 8851.toChar(), 9445.toChar(), 5681.toChar(), 3477.toChar(), 1105.toChar(), 142.toChar(), 241.toChar(), 12231.toChar(), 1003.toChar(), 3532.toChar(), 5009.toChar(), 1956.toChar(), 6008.toChar(), 11404.toChar(),
|
||||
7377.toChar(), 2049.toChar(), 10968.toChar(), 12097.toChar(), 7591.toChar(), 5057.toChar(), 3445.toChar(), 4780.toChar(), 2920.toChar(), 7048.toChar(), 3127.toChar(), 8120.toChar(), 11279.toChar(), 6821.toChar(), 11502.toChar(), 8807.toChar(),
|
||||
12138.toChar(), 2127.toChar(), 2839.toChar(), 3957.toChar(), 431.toChar(), 1579.toChar(), 6383.toChar(), 9784.toChar(), 5874.toChar(), 677.toChar(), 3336.toChar(), 6234.toChar(), 2766.toChar(), 1323.toChar(), 9115.toChar(), 12237.toChar(),
|
||||
2031.toChar(), 6956.toChar(), 6413.toChar(), 2281.toChar(), 3969.toChar(), 3991.toChar(), 12133.toChar(), 9522.toChar(), 4737.toChar(), 10996.toChar(), 4774.toChar(), 5429.toChar(), 11871.toChar(), 3772.toChar(), 453.toChar(), 5908.toChar(),
|
||||
2882.toChar(), 1805.toChar(), 2051.toChar(), 1954.toChar(), 11713.toChar(), 3963.toChar(), 2447.toChar(), 6142.toChar(), 8174.toChar(), 3030.toChar(), 1843.toChar(), 2361.toChar(), 12071.toChar(), 2908.toChar(), 3529.toChar(), 3434.toChar(),
|
||||
3202.toChar(), 7796.toChar(), 2057.toChar(), 5369.toChar(), 11939.toChar(), 1512.toChar(), 6906.toChar(), 10474.toChar(), 11026.toChar(), 49.toChar(), 10806.toChar(), 5915.toChar(), 1489.toChar(), 9789.toChar(), 5942.toChar(), 10706.toChar(),
|
||||
10431.toChar(), 7535.toChar(), 426.toChar(), 8974.toChar(), 3757.toChar(), 10314.toChar(), 9364.toChar(), 347.toChar(), 5868.toChar(), 9551.toChar(), 9634.toChar(), 6554.toChar(), 10596.toChar(), 9280.toChar(), 11566.toChar(), 174.toChar(),
|
||||
2948.toChar(), 2503.toChar(), 6507.toChar(), 10723.toChar(), 11606.toChar(), 2459.toChar(), 64.toChar(), 3656.toChar(), 8455.toChar(), 5257.toChar(), 5919.toChar(), 7856.toChar(), 1747.toChar(), 9166.toChar(), 5486.toChar(), 9235.toChar(),
|
||||
6065.toChar(), 835.toChar(), 3570.toChar(), 4240.toChar(), 11580.toChar(), 4046.toChar(), 10970.toChar(), 9139.toChar(), 1058.toChar(), 8210.toChar(), 11848.toChar(), 922.toChar(), 7967.toChar(), 1958.toChar(), 10211.toChar(), 1112.toChar(),
|
||||
3728.toChar(), 4049.toChar(), 11130.toChar(), 5990.toChar(), 1404.toChar(), 325.toChar(), 948.toChar(), 11143.toChar(), 6190.toChar(), 295.toChar(), 11637.toChar(), 5766.toChar(), 8212.toChar(), 8273.toChar(), 2919.toChar(), 8527.toChar(),
|
||||
6119.toChar(), 6992.toChar(), 8333.toChar(), 1360.toChar(), 2555.toChar(), 6167.toChar(), 1200.toChar(), 7105.toChar(), 7991.toChar(), 3329.toChar(), 9597.toChar(), 12121.toChar(), 5106.toChar(), 5961.toChar(), 10695.toChar(), 10327.toChar(),
|
||||
3051.toChar(), 9923.toChar(), 4896.toChar(), 9326.toChar(), 81.toChar(), 3091.toChar(), 1000.toChar(), 7969.toChar(), 4611.toChar(), 726.toChar(), 1853.toChar(), 12149.toChar(), 4255.toChar(), 11112.toChar(), 2768.toChar(), 10654.toChar(),
|
||||
1062.toChar(), 2294.toChar(), 3553.toChar(), 4805.toChar(), 2747.toChar(), 4846.toChar(), 8577.toChar(), 9154.toChar(), 1170.toChar(), 2319.toChar(), 790.toChar(), 11334.toChar(), 9275.toChar(), 9088.toChar(), 1326.toChar(), 5086.toChar(),
|
||||
9094.toChar(), 6429.toChar(), 11077.toChar(), 10643.toChar(), 3504.toChar(), 3542.toChar(), 8668.toChar(), 9744.toChar(), 1479.toChar(), 1.toChar(), 8246.toChar(), 7143.toChar(), 11567.toChar(), 10984.toChar(), 4134.toChar(), 5736.toChar(),
|
||||
4978.toChar(), 10938.toChar(), 5777.toChar(), 8961.toChar(), 4591.toChar(), 5728.toChar(), 6461.toChar(), 5023.toChar(), 9650.toChar(), 7468.toChar(), 949.toChar(), 9664.toChar(), 2975.toChar(), 11726.toChar(), 2744.toChar(), 9283.toChar(),
|
||||
10092.toChar(), 5067.toChar(), 12171.toChar(), 2476.toChar(), 3748.toChar(), 11336.toChar(), 6522.toChar(), 827.toChar(), 9452.toChar(), 5374.toChar(), 12159.toChar(), 7935.toChar(), 3296.toChar(), 3949.toChar(), 9893.toChar(), 4452.toChar(),
|
||||
10908.toChar(), 2525.toChar(), 3584.toChar(), 8112.toChar(), 8011.toChar(), 10616.toChar(), 4989.toChar(), 6958.toChar(), 11809.toChar(), 9447.toChar(), 12280.toChar(), 1022.toChar(), 11950.toChar(), 9821.toChar(), 11745.toChar(), 5791.toChar(),
|
||||
5092.toChar(), 2089.toChar(), 9005.toChar(), 2881.toChar(), 3289.toChar(), 2013.toChar(), 9048.toChar(), 729.toChar(), 7901.toChar(), 1260.toChar(), 5755.toChar(), 4632.toChar(), 11955.toChar(), 2426.toChar(), 10593.toChar(), 1428.toChar(),
|
||||
4890.toChar(), 5911.toChar(), 3932.toChar(), 9558.toChar(), 8830.toChar(), 3637.toChar(), 5542.toChar(), 145.toChar(), 5179.toChar(), 8595.toChar(), 3707.toChar(), 10530.toChar(), 355.toChar(), 3382.toChar(), 4231.toChar(), 9741.toChar(),
|
||||
1207.toChar(), 9041.toChar(), 7012.toChar(), 1168.toChar(), 10146.toChar(), 11224.toChar(), 4645.toChar(), 11885.toChar(), 10911.toChar(), 10377.toChar(), 435.toChar(), 7952.toChar(), 4096.toChar(), 493.toChar(), 9908.toChar(), 6845.toChar(),
|
||||
6039.toChar(), 2422.toChar(), 2187.toChar(), 9723.toChar(), 8643.toChar(), 9852.toChar(), 9302.toChar(), 6022.toChar(), 7278.toChar(), 1002.toChar(), 4284.toChar(), 5088.toChar(), 1607.toChar(), 7313.toChar(), 875.toChar(), 8509.toChar(),
|
||||
9430.toChar(), 1045.toChar(), 2481.toChar(), 5012.toChar(), 7428.toChar(), 354.toChar(), 6591.toChar(), 9377.toChar(), 11847.toChar(), 2401.toChar(), 1067.toChar(), 7188.toChar(), 11516.toChar(), 390.toChar(), 8511.toChar(), 8456.toChar(),
|
||||
7270.toChar(), 545.toChar(), 8585.toChar(), 9611.toChar(), 12047.toChar(), 1537.toChar(), 4143.toChar(), 4714.toChar(), 4885.toChar(), 1017.toChar(), 5084.toChar(), 1632.toChar(), 3066.toChar(), 27.toChar(), 1440.toChar(), 8526.toChar(),
|
||||
9273.toChar(), 12046.toChar(), 11618.toChar(), 9289.toChar(), 3400.toChar(), 9890.toChar(), 3136.toChar(), 7098.toChar(), 8758.toChar(), 11813.toChar(), 7384.toChar(), 3985.toChar(), 11869.toChar(), 6730.toChar(), 10745.toChar(), 10111.toChar(),
|
||||
2249.toChar(), 4048.toChar(), 2884.toChar(), 11136.toChar(), 2126.toChar(), 1630.toChar(), 9103.toChar(), 5407.toChar(), 2686.toChar(), 9042.toChar(), 2969.toChar(), 8311.toChar(), 9424.toChar(), 9919.toChar(), 8779.toChar(), 5332.toChar(),
|
||||
10626.toChar(), 1777.toChar(), 4654.toChar(), 10863.toChar(), 7351.toChar(), 3636.toChar(), 9585.toChar(), 5291.toChar(), 8374.toChar(), 2166.toChar(), 4919.toChar(), 12176.toChar(), 9140.toChar(), 12129.toChar(), 7852.toChar(), 12286.toChar(),
|
||||
4895.toChar(), 10805.toChar(), 2780.toChar(), 5195.toChar(), 2305.toChar(), 7247.toChar(), 9644.toChar(), 4053.toChar(), 10600.toChar(), 3364.toChar(), 3271.toChar(), 4057.toChar(), 4414.toChar(), 9442.toChar(), 7917.toChar(), 2174.toChar(),
|
||||
3947.toChar(), 11951.toChar(), 2455.toChar(), 6599.toChar(), 10545.toChar(), 10975.toChar(), 3654.toChar(), 2894.toChar(), 7681.toChar(), 7126.toChar(), 7287.toChar(), 12269.toChar(), 4119.toChar(), 3343.toChar(), 2151.toChar(), 1522.toChar(),
|
||||
7174.toChar(), 7350.toChar(), 11041.toChar(), 2442.toChar(), 2148.toChar(), 5959.toChar(), 6492.toChar(), 8330.toChar(), 8945.toChar(), 5598.toChar(), 3624.toChar(), 10397.toChar(), 1325.toChar(), 6565.toChar(), 1945.toChar(), 11260.toChar(),
|
||||
10077.toChar(), 2674.toChar(), 3338.toChar(), 3276.toChar(), 11034.toChar(), 506.toChar(), 6505.toChar(), 1392.toChar(), 5478.toChar(), 8778.toChar(), 1178.toChar(), 2776.toChar(), 3408.toChar(), 10347.toChar(), 11124.toChar(), 2575.toChar(),
|
||||
9489.toChar(), 12096.toChar(), 6092.toChar(), 10058.toChar(), 4167.toChar(), 6085.toChar(), 923.toChar(), 11251.toChar(), 11912.toChar(), 4578.toChar(), 10669.toChar(), 11914.toChar(), 425.toChar(), 10453.toChar(), 392.toChar(), 10104.toChar(),
|
||||
8464.toChar(), 4235.toChar(), 8761.toChar(), 7376.toChar(), 2291.toChar(), 3375.toChar(), 7954.toChar(), 8896.toChar(), 6617.toChar(), 7790.toChar(), 1737.toChar(), 11667.toChar(), 3982.toChar(), 9342.toChar(), 6680.toChar(), 636.toChar(),
|
||||
6825.toChar(), 7383.toChar(), 512.toChar(), 4670.toChar(), 2900.toChar(), 12050.toChar(), 7735.toChar(), 994.toChar(), 1687.toChar(), 11883.toChar(), 7021.toChar(), 146.toChar(), 10485.toChar(), 1403.toChar(), 5189.toChar(), 6094.toChar(),
|
||||
2483.toChar(), 2054.toChar(), 3042.toChar(), 10945.toChar(), 3981.toChar(), 10821.toChar(), 11826.toChar(), 8882.toChar(), 8151.toChar(), 180.toChar(), 9600.toChar(), 7684.toChar(), 5219.toChar(), 10880.toChar(), 6780.toChar(), 204.toChar(),
|
||||
11232.toChar(), 2600.toChar(), 7584.toChar(), 3121.toChar(), 3017.toChar(), 11053.toChar(), 7814.toChar(), 7043.toChar(), 4251.toChar(), 4739.toChar(), 11063.toChar(), 6771.toChar(), 7073.toChar(), 9261.toChar(), 2360.toChar(), 11925.toChar(),
|
||||
1928.toChar(), 11825.toChar(), 8024.toChar(), 3678.toChar(), 3205.toChar(), 3359.toChar(), 11197.toChar(), 5209.toChar(), 8581.toChar(), 3238.toChar(), 8840.toChar(), 1136.toChar(), 9363.toChar(), 1826.toChar(), 3171.toChar(), 4489.toChar(),
|
||||
7885.toChar(), 346.toChar(), 2068.toChar(), 1389.toChar(), 8257.toChar(), 3163.toChar(), 4840.toChar(), 6127.toChar(), 8062.toChar(), 8921.toChar(), 612.toChar(), 4238.toChar(), 10763.toChar(), 8067.toChar(), 125.toChar(), 11749.toChar(),
|
||||
10125.toChar(), 5416.toChar(), 2110.toChar(), 716.toChar(), 9839.toChar(), 10584.toChar(), 11475.toChar(), 11873.toChar(), 3448.toChar(), 343.toChar(), 1908.toChar(), 4538.toChar(), 10423.toChar(), 7078.toChar(), 4727.toChar(), 1208.toChar(),
|
||||
11572.toChar(), 3589.toChar(), 2982.toChar(), 1373.toChar(), 1721.toChar(), 10753.toChar(), 4103.toChar(), 2429.toChar(), 4209.toChar(), 5412.toChar(), 5993.toChar(), 9011.toChar(), 438.toChar(), 3515.toChar(), 7228.toChar(), 1218.toChar(),
|
||||
8347.toChar(), 5232.toChar(), 8682.toChar(), 1327.toChar(), 7508.toChar(), 4924.toChar(), 448.toChar(), 1014.toChar(), 10029.toChar(), 12221.toChar(), 4566.toChar(), 5836.toChar(), 12229.toChar(), 2717.toChar(), 1535.toChar(), 3200.toChar(),
|
||||
5588.toChar(), 5845.toChar(), 412.toChar(), 5102.toChar(), 7326.toChar(), 3744.toChar(), 3056.toChar(), 2528.toChar(), 7406.toChar(), 8314.toChar(), 9202.toChar(), 6454.toChar(), 6613.toChar(), 1417.toChar(), 10032.toChar(), 7784.toChar(),
|
||||
1518.toChar(), 3765.toChar(), 4176.toChar(), 5063.toChar(), 9828.toChar(), 2275.toChar(), 6636.toChar(), 4267.toChar(), 6463.toChar(), 2065.toChar(), 7725.toChar(), 3495.toChar(), 8328.toChar(), 8755.toChar(), 8144.toChar(), 10533.toChar(),
|
||||
5966.toChar(), 12077.toChar(), 9175.toChar(), 9520.toChar(), 5596.toChar(), 6302.toChar(), 8400.toChar(), 579.toChar(), 6781.toChar(), 11014.toChar(), 5734.toChar(), 11113.toChar(), 11164.toChar(), 4860.toChar(), 1131.toChar(), 10844.toChar(),
|
||||
9068.toChar(), 8016.toChar(), 9694.toChar(), 3837.toChar(), 567.toChar(), 9348.toChar(), 7000.toChar(), 6627.toChar(), 7699.toChar(), 5082.toChar(), 682.toChar(), 11309.toChar(), 5207.toChar(), 4050.toChar(), 7087.toChar(), 844.toChar(),
|
||||
7434.toChar(), 3769.toChar(), 293.toChar(), 9057.toChar(), 6940.toChar(), 9344.toChar(), 10883.toChar(), 2633.toChar(), 8190.toChar(), 3944.toChar(), 5530.toChar(), 5604.toChar(), 3480.toChar(), 2171.toChar(), 9282.toChar(), 11024.toChar(),
|
||||
2213.toChar(), 8136.toChar(), 3805.toChar(), 767.toChar(), 12239.toChar(), 216.toChar(), 11520.toChar(), 6763.toChar(), 10353.toChar(), 7.toChar(), 8566.toChar(), 845.toChar(), 7235.toChar(), 3154.toChar(), 4360.toChar(), 3285.toChar(),
|
||||
10268.toChar(), 2832.toChar(), 3572.toChar(), 1282.toChar(), 7559.toChar(), 3229.toChar(), 8360.toChar(), 10583.toChar(), 6105.toChar(), 3120.toChar(), 6643.toChar(), 6203.toChar(), 8536.toChar(), 8348.toChar(), 6919.toChar(), 3536.toChar(),
|
||||
9199.toChar(), 10891.toChar(), 11463.toChar(), 5043.toChar(), 1658.toChar(), 5618.toChar(), 8787.toChar(), 5789.toChar(), 4719.toChar(), 751.toChar(), 11379.toChar(), 6389.toChar(), 10783.toChar(), 3065.toChar(), 7806.toChar(), 6586.toChar(),
|
||||
2622.toChar(), 5386.toChar(), 510.toChar(), 7628.toChar(), 6921.toChar(), 578.toChar(), 10345.toChar(), 11839.toChar(), 8929.toChar(), 4684.toChar(), 12226.toChar(), 7154.toChar(), 9916.toChar(), 7302.toChar(), 8481.toChar(), 3670.toChar(),
|
||||
11066.toChar(), 2334.toChar(), 1590.toChar(), 7878.toChar(), 10734.toChar(), 1802.toChar(), 1891.toChar(), 5103.toChar(), 6151.toChar(), 8820.toChar(), 3418.toChar(), 7846.toChar(), 9951.toChar(), 4693.toChar(), 417.toChar(), 9996.toChar(),
|
||||
9652.toChar(), 4510.toChar(), 2946.toChar(), 5461.toChar(), 365.toChar(), 881.toChar(), 1927.toChar(), 1015.toChar(), 11675.toChar(), 11009.toChar(), 1371.toChar(), 12265.toChar(), 2485.toChar(), 11385.toChar(), 5039.toChar(), 6742.toChar(),
|
||||
8449.toChar(), 1842.toChar(), 12217.toChar(), 8176.toChar(), 9577.toChar(), 4834.toChar(), 7937.toChar(), 9461.toChar(), 2643.toChar(), 11194.toChar(), 3045.toChar(), 6508.toChar(), 4094.toChar(), 3451.toChar(), 7911.toChar(), 11048.toChar(),
|
||||
5406.toChar(), 4665.toChar(), 3020.toChar(), 6616.toChar(), 11345.toChar(), 7519.toChar(), 3669.toChar(), 5287.toChar(), 1790.toChar(), 7014.toChar(), 5410.toChar(), 11038.toChar(), 11249.toChar(), 2035.toChar(), 6125.toChar(), 10407.toChar(),
|
||||
4565.toChar(), 7315.toChar(), 5078.toChar(), 10506.toChar(), 2840.toChar(), 2478.toChar(), 9270.toChar(), 4194.toChar(), 9195.toChar(), 4518.toChar(), 7469.toChar(), 1160.toChar(), 6878.toChar(), 2730.toChar(), 10421.toChar(), 10036.toChar(),
|
||||
1734.toChar(), 3815.toChar(), 10939.toChar(), 5832.toChar(), 10595.toChar(), 10759.toChar(), 4423.toChar(), 8420.toChar(), 9617.toChar(), 7119.toChar(), 11010.toChar(), 11424.toChar(), 9173.toChar(), 189.toChar(), 10080.toChar(), 10526.toChar(),
|
||||
3466.toChar(), 10588.toChar(), 7592.toChar(), 3578.toChar(), 11511.toChar(), 7785.toChar(), 9663.toChar(), 530.toChar(), 12150.toChar(), 8957.toChar(), 2532.toChar(), 3317.toChar(), 9349.toChar(), 10243.toChar(), 1481.toChar(), 9332.toChar(),
|
||||
3454.toChar(), 3758.toChar(), 7899.toChar(), 4218.toChar(), 2593.toChar(), 11410.toChar(), 2276.toChar(), 982.toChar(), 6513.toChar(), 1849.toChar(), 8494.toChar(), 9021.toChar(), 4523.toChar(), 7988.toChar(), 8.toChar(), 457.toChar(),
|
||||
648.toChar(), 150.toChar(), 8000.toChar(), 2307.toChar(), 2301.toChar(), 874.toChar(), 5650.toChar(), 170.toChar(), 9462.toChar(), 2873.toChar(), 9855.toChar(), 11498.toChar(), 2535.toChar(), 11169.toChar(), 5808.toChar(), 12268.toChar(),
|
||||
9687.toChar(), 1901.toChar(), 7171.toChar(), 11787.toChar(), 3846.toChar(), 1573.toChar(), 6063.toChar(), 3793.toChar(), 466.toChar(), 11259.toChar(), 10608.toChar(), 3821.toChar(), 6320.toChar(), 4649.toChar(), 6263.toChar(), 2929.toChar()
|
||||
)
|
||||
private val psis_inv_montgomery = charArrayOf(
|
||||
256.toChar(), 10570.toChar(), 1510.toChar(), 7238.toChar(), 1034.toChar(), 7170.toChar(), 6291.toChar(), 7921.toChar(), 11665.toChar(), 3422.toChar(), 4000.toChar(), 2327.toChar(), 2088.toChar(), 5565.toChar(), 795.toChar(), 10647.toChar(),
|
||||
1521.toChar(), 5484.toChar(), 2539.toChar(), 7385.toChar(), 1055.toChar(), 7173.toChar(), 8047.toChar(), 11683.toChar(), 1669.toChar(), 1994.toChar(), 3796.toChar(), 5809.toChar(), 4341.toChar(), 9398.toChar(), 11876.toChar(), 12230.toChar(),
|
||||
10525.toChar(), 12037.toChar(), 12253.toChar(), 3506.toChar(), 4012.toChar(), 9351.toChar(), 4847.toChar(), 2448.toChar(), 7372.toChar(), 9831.toChar(), 3160.toChar(), 2207.toChar(), 5582.toChar(), 2553.toChar(), 7387.toChar(), 6322.toChar(),
|
||||
9681.toChar(), 1383.toChar(), 10731.toChar(), 1533.toChar(), 219.toChar(), 5298.toChar(), 4268.toChar(), 7632.toChar(), 6357.toChar(), 9686.toChar(), 8406.toChar(), 4712.toChar(), 9451.toChar(), 10128.toChar(), 4958.toChar(), 5975.toChar(),
|
||||
11387.toChar(), 8649.toChar(), 11769.toChar(), 6948.toChar(), 11526.toChar(), 12180.toChar(), 1740.toChar(), 10782.toChar(), 6807.toChar(), 2728.toChar(), 7412.toChar(), 4570.toChar(), 4164.toChar(), 4106.toChar(), 11120.toChar(), 12122.toChar(),
|
||||
8754.toChar(), 11784.toChar(), 3439.toChar(), 5758.toChar(), 11356.toChar(), 6889.toChar(), 9762.toChar(), 11928.toChar(), 1704.toChar(), 1999.toChar(), 10819.toChar(), 12079.toChar(), 12259.toChar(), 7018.toChar(), 11536.toChar(), 1648.toChar(),
|
||||
1991.toChar(), 2040.toChar(), 2047.toChar(), 2048.toChar(), 10826.toChar(), 12080.toChar(), 8748.toChar(), 8272.toChar(), 8204.toChar(), 1172.toChar(), 1923.toChar(), 7297.toChar(), 2798.toChar(), 7422.toChar(), 6327.toChar(), 4415.toChar(),
|
||||
7653.toChar(), 6360.toChar(), 11442.toChar(), 12168.toChar(), 7005.toChar(), 8023.toChar(), 9924.toChar(), 8440.toChar(), 8228.toChar(), 2931.toChar(), 7441.toChar(), 1063.toChar(), 3663.toChar(), 5790.toChar(), 9605.toChar(), 10150.toChar(),
|
||||
1450.toChar(), 8985.toChar(), 11817.toChar(), 10466.toChar(), 10273.toChar(), 12001.toChar(), 3470.toChar(), 7518.toChar(), 1074.toChar(), 1909.toChar(), 7295.toChar(), 9820.toChar(), 4914.toChar(), 702.toChar(), 5367.toChar(), 7789.toChar(),
|
||||
8135.toChar(), 9940.toChar(), 1420.toChar(), 3714.toChar(), 11064.toChar(), 12114.toChar(), 12264.toChar(), 1752.toChar(), 5517.toChar(), 9566.toChar(), 11900.toChar(), 1700.toChar(), 3754.toChar(), 5803.toChar(), 829.toChar(), 1874.toChar(),
|
||||
7290.toChar(), 2797.toChar(), 10933.toChar(), 5073.toChar(), 7747.toChar(), 8129.toChar(), 6428.toChar(), 6185.toChar(), 11417.toChar(), 1631.toChar(), 233.toChar(), 5300.toChar(), 9535.toChar(), 10140.toChar(), 11982.toChar(), 8734.toChar(),
|
||||
8270.toChar(), 2937.toChar(), 10953.toChar(), 8587.toChar(), 8249.toChar(), 2934.toChar(), 9197.toChar(), 4825.toChar(), 5956.toChar(), 4362.toChar(), 9401.toChar(), 1343.toChar(), 3703.toChar(), 529.toChar(), 10609.toChar(), 12049.toChar(),
|
||||
6988.toChar(), 6265.toChar(), 895.toChar(), 3639.toChar(), 4031.toChar(), 4087.toChar(), 4095.toChar(), 585.toChar(), 10617.toChar(), 8539.toChar(), 4731.toChar(), 4187.toChar(), 9376.toChar(), 3095.toChar(), 9220.toChar(), 10095.toChar(),
|
||||
10220.toChar(), 1460.toChar(), 10742.toChar(), 12068.toChar(), 1724.toChar(), 5513.toChar(), 11321.toChar(), 6884.toChar(), 2739.toChar(), 5658.toChar(), 6075.toChar(), 4379.toChar(), 11159.toChar(), 10372.toChar(), 8504.toChar(), 4726.toChar(),
|
||||
9453.toChar(), 3106.toChar(), 7466.toChar(), 11600.toChar(), 10435.toChar(), 8513.toChar(), 9994.toChar(), 8450.toChar(), 9985.toChar(), 3182.toChar(), 10988.toChar(), 8592.toChar(), 2983.toChar(), 9204.toChar(), 4826.toChar(), 2445.toChar(),
|
||||
5616.toChar(), 6069.toChar(), 867.toChar(), 3635.toChar(), 5786.toChar(), 11360.toChar(), 5134.toChar(), 2489.toChar(), 10889.toChar(), 12089.toChar(), 1727.toChar(), 7269.toChar(), 2794.toChar(), 9177.toChar(), 1311.toChar(), 5454.toChar(),
|
||||
9557.toChar(), 6632.toChar(), 2703.toChar(), 9164.toChar(), 10087.toChar(), 1441.toChar(), 3717.toChar(), 531.toChar(), 3587.toChar(), 2268.toChar(), 324.toChar(), 5313.toChar(), 759.toChar(), 1864.toChar(), 5533.toChar(), 2546.toChar(),
|
||||
7386.toChar(), 9833.toChar(), 8427.toChar(), 4715.toChar(), 11207.toChar(), 1601.toChar(), 7251.toChar(), 4547.toChar(), 11183.toChar(), 12131.toChar(), 1733.toChar(), 10781.toChar(), 10318.toChar(), 1474.toChar(), 10744.toChar(), 5046.toChar(),
|
||||
4232.toChar(), 11138.toChar(), 10369.toChar(), 6748.toChar(), 964.toChar(), 7160.toChar(), 4534.toChar(), 7670.toChar(), 8118.toChar(), 8182.toChar(), 4680.toChar(), 11202.toChar(), 6867.toChar(), 981.toChar(), 8918.toChar(), 1274.toChar(),
|
||||
182.toChar(), 26.toChar(), 7026.toChar(), 8026.toChar(), 11680.toChar(), 12202.toChar(), 10521.toChar(), 1503.toChar(), 7237.toChar(), 4545.toChar(), 5916.toChar(), 9623.toChar(), 8397.toChar(), 11733.toChar(), 10454.toChar(), 3249.toChar(),
|
||||
9242.toChar(), 6587.toChar(), 941.toChar(), 1890.toChar(), 270.toChar(), 10572.toChar(), 6777.toChar(), 9746.toChar(), 6659.toChar(), 6218.toChar(), 6155.toChar(), 6146.toChar(), 878.toChar(), 1881.toChar(), 7291.toChar(), 11575.toChar(),
|
||||
12187.toChar(), 1741.toChar(), 7271.toChar(), 8061.toChar(), 11685.toChar(), 6936.toChar(), 4502.toChar(), 9421.toChar(), 4857.toChar(), 4205.toChar(), 7623.toChar(), 1089.toChar(), 10689.toChar(), 1527.toChar(), 8996.toChar(), 10063.toChar(),
|
||||
11971.toChar(), 10488.toChar(), 6765.toChar(), 2722.toChar(), 3900.toChar(), 9335.toChar(), 11867.toChar(), 6962.toChar(), 11528.toChar(), 5158.toChar(), 4248.toChar(), 4118.toChar(), 5855.toChar(), 2592.toChar(), 5637.toChar(), 6072.toChar(),
|
||||
2623.toChar(), 7397.toChar(), 8079.toChar(), 9932.toChar(), 4930.toChar(), 5971.toChar(), 853.toChar(), 3633.toChar(), 519.toChar(), 8852.toChar(), 11798.toChar(), 3441.toChar(), 11025.toChar(), 1575.toChar(), 225.toChar(), 8810.toChar(),
|
||||
11792.toChar(), 12218.toChar(), 3501.toChar(), 9278.toChar(), 3081.toChar(), 9218.toChar(), 4828.toChar(), 7712.toChar(), 8124.toChar(), 11694.toChar(), 12204.toChar(), 3499.toChar(), 4011.toChar(), 573.toChar(), 3593.toChar(), 5780.toChar(),
|
||||
7848.toChar(), 9899.toChar(), 10192.toChar(), 1456.toChar(), 208.toChar(), 7052.toChar(), 2763.toChar(), 7417.toChar(), 11593.toChar(), 10434.toChar(), 12024.toChar(), 8740.toChar(), 11782.toChar(), 10461.toChar(), 3250.toChar(), 5731.toChar(),
|
||||
7841.toChar(), 9898.toChar(), 1414.toChar(), 202.toChar(), 3540.toChar(), 7528.toChar(), 2831.toChar(), 2160.toChar(), 10842.toChar(), 5060.toChar(), 4234.toChar(), 4116.toChar(), 588.toChar(), 84.toChar(), 12.toChar(), 7024.toChar(),
|
||||
2759.toChar(), 9172.toChar(), 6577.toChar(), 11473.toChar(), 1639.toChar(), 9012.toChar(), 3043.toChar(), 7457.toChar(), 6332.toChar(), 11438.toChar(), 1634.toChar(), 1989.toChar(), 9062.toChar(), 11828.toChar(), 8712.toChar(), 11778.toChar(),
|
||||
12216.toChar(), 10523.toChar(), 6770.toChar(), 9745.toChar(), 10170.toChar(), 4964.toChar(), 9487.toChar(), 6622.toChar(), 946.toChar(), 8913.toChar(), 6540.toChar(), 6201.toChar(), 4397.toChar(), 9406.toChar(), 8366.toChar(), 9973.toChar(),
|
||||
8447.toChar(), 8229.toChar(), 11709.toChar(), 8695.toChar(), 10020.toChar(), 3187.toChar(), 5722.toChar(), 2573.toChar(), 10901.toChar(), 6824.toChar(), 4486.toChar(), 4152.toChar(), 9371.toChar(), 8361.toChar(), 2950.toChar(), 2177.toChar(),
|
||||
311.toChar(), 1800.toChar(), 9035.toChar(), 8313.toChar(), 11721.toChar(), 3430.toChar(), 490.toChar(), 70.toChar(), 10.toChar(), 1757.toChar(), 251.toChar(), 3547.toChar(), 7529.toChar(), 11609.toChar(), 3414.toChar(), 7510.toChar(),
|
||||
4584.toChar(), 4166.toChar(), 9373.toChar(), 1339.toChar(), 5458.toChar(), 7802.toChar(), 11648.toChar(), 1664.toChar(), 7260.toChar(), 9815.toChar(), 10180.toChar(), 6721.toChar(), 9738.toChar(), 10169.toChar(), 8475.toChar(), 8233.toChar(),
|
||||
9954.toChar(), 1422.toChar(), 8981.toChar(), 1283.toChar(), 5450.toChar(), 11312.toChar(), 1616.toChar(), 3742.toChar(), 11068.toChar(), 10359.toChar(), 4991.toChar(), 713.toChar(), 3613.toChar(), 9294.toChar(), 8350.toChar(), 4704.toChar(),
|
||||
672.toChar(), 96.toChar(), 7036.toChar(), 9783.toChar(), 11931.toChar(), 3460.toChar(), 5761.toChar(), 823.toChar(), 10651.toChar(), 12055.toChar(), 10500.toChar(), 1500.toChar(), 5481.toChar(), 783.toChar(), 3623.toChar(), 11051.toChar(),
|
||||
8601.toChar(), 8251.toChar(), 8201.toChar(), 11705.toChar(), 10450.toChar(), 5004.toChar(), 4226.toChar(), 7626.toChar(), 2845.toChar(), 2162.toChar(), 3820.toChar(), 7568.toChar(), 9859.toChar(), 3164.toChar(), 452.toChar(), 10598.toChar(),
|
||||
1514.toChar(), 5483.toChar(), 6050.toChar(), 6131.toChar(), 4387.toChar(), 7649.toChar(), 8115.toChar(), 6426.toChar(), 918.toChar(), 8909.toChar(), 8295.toChar(), 1185.toChar(), 5436.toChar(), 11310.toChar(), 8638.toChar(), 1234.toChar(),
|
||||
5443.toChar(), 11311.toChar(), 5127.toChar(), 2488.toChar(), 2111.toChar(), 10835.toChar(), 5059.toChar(), 7745.toChar(), 2862.toChar(), 3920.toChar(), 560.toChar(), 80.toChar(), 1767.toChar(), 2008.toChar(), 3798.toChar(), 11076.toChar(),
|
||||
6849.toChar(), 2734.toChar(), 10924.toChar(), 12094.toChar(), 8750.toChar(), 1250.toChar(), 10712.toChar(), 6797.toChar(), 971.toChar(), 7161.toChar(), 1023.toChar(), 8924.toChar(), 4786.toChar(), 7706.toChar(), 4612.toChar(), 4170.toChar(),
|
||||
7618.toChar(), 6355.toChar(), 4419.toChar(), 5898.toChar(), 11376.toChar(), 10403.toChar(), 10264.toChar(), 6733.toChar(), 4473.toChar(), 639.toChar(), 5358.toChar(), 2521.toChar(), 9138.toChar(), 3061.toChar(), 5704.toChar(), 4326.toChar(),
|
||||
618.toChar(), 5355.toChar(), 765.toChar(), 5376.toChar(), 768.toChar(), 7132.toChar(), 4530.toChar(), 9425.toChar(), 3102.toChar(), 9221.toChar(), 6584.toChar(), 11474.toChar(), 10417.toChar(), 10266.toChar(), 12000.toChar(), 6981.toChar(),
|
||||
6264.toChar(), 4406.toChar(), 2385.toChar(), 7363.toChar(), 4563.toChar(), 4163.toChar(), 7617.toChar(), 9866.toChar(), 3165.toChar(), 9230.toChar(), 11852.toChar(), 10471.toChar(), 5007.toChar(), 5982.toChar(), 11388.toChar(), 5138.toChar(),
|
||||
734.toChar(), 3616.toChar(), 11050.toChar(), 12112.toChar(), 6997.toChar(), 11533.toChar(), 12181.toChar(), 10518.toChar(), 12036.toChar(), 3475.toChar(), 2252.toChar(), 7344.toChar(), 9827.toChar(), 4915.toChar(), 9480.toChar(), 6621.toChar(),
|
||||
4457.toChar(), 7659.toChar(), 9872.toChar(), 6677.toChar(), 4465.toChar(), 4149.toChar(), 7615.toChar(), 4599.toChar(), 657.toChar(), 3605.toChar(), 515.toChar(), 10607.toChar(), 6782.toChar(), 4480.toChar(), 640.toChar(), 1847.toChar(),
|
||||
3775.toChar(), 5806.toChar(), 2585.toChar(), 5636.toChar(), 9583.toChar(), 1369.toChar(), 10729.toChar(), 8555.toChar(), 10000.toChar(), 11962.toChar(), 5220.toChar(), 7768.toChar(), 8132.toChar(), 8184.toChar(), 9947.toChar(), 1421.toChar(),
|
||||
203.toChar(), 29.toChar(), 8782.toChar(), 11788.toChar(), 1684.toChar(), 10774.toChar(), 10317.toChar(), 4985.toChar(), 9490.toChar(), 8378.toChar(), 4708.toChar(), 11206.toChar(), 5112.toChar(), 5997.toChar(), 7879.toChar(), 11659.toChar(),
|
||||
12199.toChar(), 8765.toChar(), 10030.toChar(), 4944.toChar(), 5973.toChar(), 6120.toChar(), 6141.toChar(), 6144.toChar(), 7900.toChar(), 11662.toChar(), 1666.toChar(), 238.toChar(), 34.toChar(), 3516.toChar(), 5769.toChar(), 9602.toChar(),
|
||||
8394.toChar(), 9977.toChar(), 6692.toChar(), 956.toChar(), 10670.toChar(), 6791.toChar(), 9748.toChar(), 11926.toChar(), 8726.toChar(), 11780.toChar(), 5194.toChar(), 742.toChar(), 106.toChar(), 8793.toChar(), 10034.toChar(), 3189.toChar(),
|
||||
10989.toChar(), 5081.toChar(), 4237.toChar(), 5872.toChar(), 4350.toChar(), 2377.toChar(), 10873.toChar(), 6820.toChar(), 6241.toChar(), 11425.toChar(), 10410.toChar(), 10265.toChar(), 3222.toChar(), 5727.toChar(), 9596.toChar(), 4882.toChar(),
|
||||
2453.toChar(), 2106.toChar(), 3812.toChar(), 11078.toChar(), 12116.toChar(), 5242.toChar(), 4260.toChar(), 11142.toChar(), 8614.toChar(), 11764.toChar(), 12214.toChar(), 5256.toChar(), 4262.toChar(), 4120.toChar(), 11122.toChar(), 5100.toChar(),
|
||||
11262.toChar(), 5120.toChar(), 2487.toChar(), 5622.toChar(), 9581.toChar(), 8391.toChar(), 8221.toChar(), 2930.toChar(), 10952.toChar(), 12098.toChar(), 6995.toChar(), 6266.toChar(), 9673.toChar(), 4893.toChar(), 699.toChar(), 3611.toChar(),
|
||||
4027.toChar(), 5842.toChar(), 11368.toChar(), 1624.toChar(), 232.toChar(), 8811.toChar(), 8281.toChar(), 1183.toChar(), 169.toChar(), 8802.toChar(), 3013.toChar(), 2186.toChar(), 5579.toChar(), 797.toChar(), 3625.toChar(), 4029.toChar(),
|
||||
11109.toChar(), 1587.toChar(), 7249.toChar(), 11569.toChar(), 8675.toChar(), 6506.toChar(), 2685.toChar(), 10917.toChar(), 12093.toChar(), 12261.toChar(), 12285.toChar(), 1755.toChar(), 7273.toChar(), 1039.toChar(), 1904.toChar(), 272.toChar(),
|
||||
3550.toChar(), 9285.toChar(), 3082.toChar(), 5707.toChar(), 6082.toChar(), 4380.toChar(), 7648.toChar(), 11626.toChar(), 5172.toChar(), 4250.toChar(), 9385.toChar(), 8363.toChar(), 8217.toChar(), 4685.toChar(), 5936.toChar(), 848.toChar(),
|
||||
8899.toChar(), 6538.toChar(), 934.toChar(), 1889.toChar(), 3781.toChar(), 9318.toChar(), 10109.toChar(), 10222.toChar(), 6727.toChar(), 961.toChar(), 5404.toChar(), 772.toChar(), 5377.toChar(), 9546.toChar(), 8386.toChar(), 1198.toChar(),
|
||||
8949.toChar(), 3034.toChar(), 2189.toChar(), 7335.toChar(), 4559.toChar(), 5918.toChar(), 2601.toChar(), 10905.toChar(), 5069.toChar(), 9502.toChar(), 3113.toChar(), 7467.toChar(), 8089.toChar(), 11689.toChar(), 5181.toChar(), 9518.toChar(),
|
||||
8382.toChar(), 2953.toChar(), 3933.toChar(), 4073.toChar(), 4093.toChar(), 7607.toChar(), 8109.toChar(), 2914.toChar(), 5683.toChar(), 4323.toChar(), 11151.toChar(), 1593.toChar(), 10761.toChar(), 6804.toChar(), 972.toChar(), 3650.toChar(),
|
||||
2277.toChar(), 5592.toChar(), 4310.toChar(), 7638.toChar(), 9869.toChar(), 4921.toChar(), 703.toChar(), 1856.toChar(), 9043.toChar(), 4803.toChar(), 9464.toChar(), 1352.toChar(), 8971.toChar(), 11815.toChar(), 5199.toChar(), 7765.toChar(),
|
||||
6376.toChar(), 4422.toChar(), 7654.toChar(), 2849.toChar(), 407.toChar(), 8836.toChar(), 6529.toChar(), 7955.toChar(), 2892.toChar(), 9191.toChar(), 1313.toChar(), 10721.toChar(), 12065.toChar(), 12257.toChar(), 1751.toChar(), 9028.toChar(),
|
||||
8312.toChar(), 2943.toChar(), 2176.toChar(), 3822.toChar(), 546.toChar(), 78.toChar(), 8789.toChar(), 11789.toChar(), 10462.toChar(), 12028.toChar(), 6985.toChar(), 4509.toChar(), 9422.toChar(), 1346.toChar(), 5459.toChar(), 4291.toChar(),
|
||||
613.toChar(), 10621.toChar(), 6784.toChar(), 9747.toChar(), 3148.toChar(), 7472.toChar(), 2823.toChar(), 5670.toChar(), 810.toChar(), 7138.toChar(), 8042.toChar(), 4660.toChar(), 7688.toChar(), 6365.toChar(), 6176.toChar(), 6149.toChar(),
|
||||
2634.toChar(), 5643.toChar(), 9584.toChar(), 10147.toChar(), 11983.toChar(), 5223.toChar(), 9524.toChar(), 11894.toChar(), 10477.toChar(), 8519.toChar(), 1217.toChar(), 3685.toChar(), 2282.toChar(), 326.toChar(), 10580.toChar(), 3267.toChar(),
|
||||
7489.toChar(), 4581.toChar(), 2410.toChar(), 5611.toChar(), 11335.toChar(), 6886.toChar(), 8006.toChar(), 8166.toChar(), 11700.toChar(), 3427.toChar(), 11023.toChar(), 8597.toChar(), 10006.toChar(), 3185.toChar(), 455.toChar(), 65.toChar(),
|
||||
5276.toChar(), 7776.toChar(), 4622.toChar(), 5927.toChar(), 7869.toChar(), 9902.toChar(), 11948.toChar(), 5218.toChar(), 2501.toChar(), 5624.toChar(), 2559.toChar(), 10899.toChar(), 1557.toChar(), 1978.toChar(), 10816.toChar(), 10323.toChar(),
|
||||
8497.toChar(), 4725.toChar(), 675.toChar(), 1852.toChar(), 10798.toChar(), 12076.toChar(), 10503.toChar(), 3256.toChar(), 9243.toChar(), 3076.toChar(), 2195.toChar(), 10847.toChar(), 12083.toChar(), 10504.toChar(), 12034.toChar(), 10497.toChar()
|
||||
)
|
||||
private val bitrev_table_combined = intArrayOf(
|
||||
524289, 262146, 786435, 131076, 655365, 393222, 917511, 65544, 589833, 327690, 851979, 196620, 720909, 458766, 983055, 32784,
|
||||
557073, 294930, 819219, 163860, 688149, 426006, 950295, 98328, 622617, 360474, 884763, 229404, 753693, 491550, 1015839, 540705,
|
||||
278562, 802851, 147492, 671781, 409638, 933927, 81960, 606249, 344106, 868395, 213036, 737325, 475182, 999471, 573489, 311346,
|
||||
835635, 180276, 704565, 442422, 966711, 114744, 639033, 376890, 901179, 245820, 770109, 507966, 1032255, 532545, 270402, 794691,
|
||||
139332, 663621, 401478, 925767, 598089, 335946, 860235, 204876, 729165, 467022, 991311, 565329, 303186, 827475, 172116, 696405,
|
||||
434262, 958551, 106584, 630873, 368730, 893019, 237660, 761949, 499806, 1024095, 548961, 286818, 811107, 155748, 680037, 417894,
|
||||
942183, 614505, 352362, 876651, 221292, 745581, 483438, 1007727, 581745, 319602, 843891, 188532, 712821, 450678, 974967, 647289,
|
||||
385146, 909435, 254076, 778365, 516222, 1040511, 528513, 266370, 790659, 659589, 397446, 921735, 594057, 331914, 856203, 200844,
|
||||
725133, 462990, 987279, 561297, 299154, 823443, 168084, 692373, 430230, 954519, 626841, 364698, 888987, 233628, 757917, 495774,
|
||||
1020063, 544929, 282786, 807075, 676005, 413862, 938151, 610473, 348330, 872619, 217260, 741549, 479406, 1003695, 577713, 315570,
|
||||
839859, 708789, 446646, 970935, 643257, 381114, 905403, 250044, 774333, 512190, 1036479, 536769, 274626, 798915, 667845, 405702,
|
||||
929991, 602313, 340170, 864459, 733389, 471246, 995535, 569553, 307410, 831699, 700629, 438486, 962775, 635097, 372954, 897243,
|
||||
241884, 766173, 504030, 1028319, 553185, 291042, 815331, 684261, 422118, 946407, 618729, 356586, 880875, 749805, 487662, 1011951,
|
||||
585969, 323826, 848115, 717045, 454902, 979191, 651513, 389370, 913659, 782589, 520446, 1044735, 526593, 788739, 657669, 395526,
|
||||
919815, 592137, 329994, 854283, 723213, 461070, 985359, 559377, 297234, 821523, 690453, 428310, 952599, 624921, 362778, 887067,
|
||||
755997, 493854, 1018143, 543009, 805155, 674085, 411942, 936231, 608553, 346410, 870699, 739629, 477486, 1001775, 575793, 837939,
|
||||
706869, 444726, 969015, 641337, 379194, 903483, 772413, 510270, 1034559, 534849, 796995, 665925, 403782, 928071, 600393, 862539,
|
||||
731469, 469326, 993615, 567633, 829779, 698709, 436566, 960855, 633177, 371034, 895323, 764253, 502110, 1026399, 551265, 813411,
|
||||
682341, 420198, 944487, 616809, 878955, 747885, 485742, 1010031, 584049, 846195, 715125, 452982, 977271, 649593, 911739, 780669,
|
||||
518526, 1042815, 530817, 792963, 661893, 924039, 596361, 858507, 727437, 465294, 989583, 563601, 825747, 694677, 432534, 956823,
|
||||
629145, 891291, 760221, 498078, 1022367, 547233, 809379, 678309, 940455, 612777, 874923, 743853, 481710, 1005999, 580017, 842163,
|
||||
711093, 973239, 645561, 907707, 776637, 514494, 1038783, 539073, 801219, 670149, 932295, 604617, 866763, 735693, 997839, 571857,
|
||||
834003, 702933, 965079, 637401, 899547, 768477, 506334, 1030623, 555489, 817635, 686565, 948711, 621033, 883179, 752109, 1014255,
|
||||
588273, 850419, 719349, 981495, 653817, 915963, 784893, 1047039, 787971, 656901, 919047, 591369, 853515, 722445, 984591, 558609,
|
||||
820755, 689685, 951831, 624153, 886299, 755229, 1017375, 804387, 673317, 935463, 607785, 869931, 738861, 1001007, 837171, 706101,
|
||||
968247, 640569, 902715, 771645, 1033791, 796227, 665157, 927303, 861771, 730701, 992847, 829011, 697941, 960087, 632409, 894555,
|
||||
763485, 1025631, 812643, 681573, 943719, 878187, 747117, 1009263, 845427, 714357, 976503, 910971, 779901, 1042047, 792195, 923271,
|
||||
857739, 726669, 988815, 824979, 693909, 956055, 890523, 759453, 1021599, 808611, 939687, 874155, 743085, 1005231, 841395, 972471,
|
||||
906939, 775869, 1038015, 800451, 931527, 865995, 997071, 833235, 964311, 898779, 767709, 1029855, 816867, 947943, 882411, 1013487,
|
||||
849651, 980727, 915195, 1046271, 921351, 855819, 986895, 823059, 954135, 888603, 1019679, 937767, 872235, 1003311, 970551, 905019,
|
||||
1036095, 929607, 995151, 962391, 896859, 1027935, 946023, 1011567, 978807, 1044351, 991119, 958359, 1023903, 1007535, 1040319, 1032159
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,982 +0,0 @@
|
||||
/*
|
||||
* Based on the public domain C reference code for New Hope.
|
||||
* This Java version is also placed into the public domain.
|
||||
*
|
||||
* Original authors: Erdem Alkim, Léo Ducas, Thomas Pöppelmann, Peter Schwabe
|
||||
* Java port: Rhys Weatherley
|
||||
*/
|
||||
|
||||
package com.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* New Hope key exchange algorithm, "torref" variant.
|
||||
*
|
||||
* This version of New Hope implements the alternative constant-time
|
||||
* method for generating the public "a" value for anonymity networks
|
||||
* like Tor. It is not binary-compatible with the standard New Hope
|
||||
* implementation in the NewHope class.
|
||||
*
|
||||
* Reference: https://cryptojedi.org/papers/newhope-20160803.pdf
|
||||
*
|
||||
* @see NewHope
|
||||
*/
|
||||
public class NewHopeTor extends NewHope {
|
||||
|
||||
public NewHopeTor() {}
|
||||
|
||||
@Override
|
||||
protected void uniform(char[] coeffs, byte[] seed)
|
||||
{
|
||||
long[] state = new long [25];
|
||||
int nblocks=16;
|
||||
byte[] buf = new byte [SHAKE128_RATE*nblocks];
|
||||
char[] x = new char [buf.length / 2];
|
||||
|
||||
try {
|
||||
shake128_absorb(state, seed, 0, SEEDBYTES);
|
||||
do
|
||||
{
|
||||
shake128_squeezeblocks(buf, 0, nblocks, state);
|
||||
for (int i = buf.length - 2; i >= 0; i -= 2)
|
||||
{
|
||||
x[i / 2] = (char)((buf[i] & 0xff) | ((buf[i+1] & 0xff) << 8));
|
||||
}
|
||||
}
|
||||
while (discardtopoly(coeffs, x));
|
||||
} finally {
|
||||
Arrays.fill(state, 0);
|
||||
Arrays.fill(buf, (byte)0);
|
||||
Arrays.fill(x, (char)0);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean discardtopoly(char[] coeffs, char[] x)
|
||||
{
|
||||
int i, r=0;
|
||||
|
||||
for(i=0;i<16;i++)
|
||||
batcher84(x, i);
|
||||
|
||||
// Check whether we're safe:
|
||||
for(i=1008;i<1024;i++)
|
||||
r |= 61444 - x[i];
|
||||
if((r >>= 31) != 0) return true;
|
||||
|
||||
// If we are, copy coefficients to polynomial:
|
||||
for(i=0;i<PARAM_N;i++)
|
||||
coeffs[i] = x[i];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void batcher84(char[] x, int offset)
|
||||
{
|
||||
int c, t;
|
||||
c = 61444 - x[offset + 0]; t = (x[offset + 0] ^ x[offset + 16]) & (c >> 31); x[offset + 0] ^= t; x[offset + 16] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 48]) & (c >> 31); x[offset + 32] ^= t; x[offset + 48] ^= t;
|
||||
c = 61444 - x[offset + 0]; t = (x[offset + 0] ^ x[offset + 32]) & (c >> 31); x[offset + 0] ^= t; x[offset + 32] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 48]) & (c >> 31); x[offset + 16] ^= t; x[offset + 48] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 32]) & (c >> 31); x[offset + 16] ^= t; x[offset + 32] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 80]) & (c >> 31); x[offset + 64] ^= t; x[offset + 80] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 112]) & (c >> 31); x[offset + 96] ^= t; x[offset + 112] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 96]) & (c >> 31); x[offset + 64] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 112]) & (c >> 31); x[offset + 80] ^= t; x[offset + 112] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 96]) & (c >> 31); x[offset + 80] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 0]; t = (x[offset + 0] ^ x[offset + 64]) & (c >> 31); x[offset + 0] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 96]) & (c >> 31); x[offset + 32] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 64]) & (c >> 31); x[offset + 32] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 80]) & (c >> 31); x[offset + 16] ^= t; x[offset + 80] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 112]) & (c >> 31); x[offset + 48] ^= t; x[offset + 112] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 80]) & (c >> 31); x[offset + 48] ^= t; x[offset + 80] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 32]) & (c >> 31); x[offset + 16] ^= t; x[offset + 32] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 64]) & (c >> 31); x[offset + 48] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 96]) & (c >> 31); x[offset + 80] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 144]) & (c >> 31); x[offset + 128] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 176]) & (c >> 31); x[offset + 160] ^= t; x[offset + 176] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 160]) & (c >> 31); x[offset + 128] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 176]) & (c >> 31); x[offset + 144] ^= t; x[offset + 176] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 160]) & (c >> 31); x[offset + 144] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 208]) & (c >> 31); x[offset + 192] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 240]) & (c >> 31); x[offset + 224] ^= t; x[offset + 240] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 224]) & (c >> 31); x[offset + 192] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 240]) & (c >> 31); x[offset + 208] ^= t; x[offset + 240] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 224]) & (c >> 31); x[offset + 208] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 192]) & (c >> 31); x[offset + 128] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 224]) & (c >> 31); x[offset + 160] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 192]) & (c >> 31); x[offset + 160] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 208]) & (c >> 31); x[offset + 144] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 240]) & (c >> 31); x[offset + 176] ^= t; x[offset + 240] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 208]) & (c >> 31); x[offset + 176] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 160]) & (c >> 31); x[offset + 144] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 192]) & (c >> 31); x[offset + 176] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 224]) & (c >> 31); x[offset + 208] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 0]; t = (x[offset + 0] ^ x[offset + 128]) & (c >> 31); x[offset + 0] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 192]) & (c >> 31); x[offset + 64] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 128]) & (c >> 31); x[offset + 64] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 160]) & (c >> 31); x[offset + 32] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 224]) & (c >> 31); x[offset + 96] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 160]) & (c >> 31); x[offset + 96] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 64]) & (c >> 31); x[offset + 32] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 128]) & (c >> 31); x[offset + 96] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 192]) & (c >> 31); x[offset + 160] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 144]) & (c >> 31); x[offset + 16] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 208]) & (c >> 31); x[offset + 80] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 144]) & (c >> 31); x[offset + 80] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 176]) & (c >> 31); x[offset + 48] ^= t; x[offset + 176] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 240]) & (c >> 31); x[offset + 112] ^= t; x[offset + 240] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 176]) & (c >> 31); x[offset + 112] ^= t; x[offset + 176] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 80]) & (c >> 31); x[offset + 48] ^= t; x[offset + 80] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 144]) & (c >> 31); x[offset + 112] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 208]) & (c >> 31); x[offset + 176] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 32]) & (c >> 31); x[offset + 16] ^= t; x[offset + 32] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 64]) & (c >> 31); x[offset + 48] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 96]) & (c >> 31); x[offset + 80] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 128]) & (c >> 31); x[offset + 112] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 160]) & (c >> 31); x[offset + 144] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 192]) & (c >> 31); x[offset + 176] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 224]) & (c >> 31); x[offset + 208] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 272]) & (c >> 31); x[offset + 256] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 304]) & (c >> 31); x[offset + 288] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 288]) & (c >> 31); x[offset + 256] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 304]) & (c >> 31); x[offset + 272] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 288]) & (c >> 31); x[offset + 272] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 336]) & (c >> 31); x[offset + 320] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 368]) & (c >> 31); x[offset + 352] ^= t; x[offset + 368] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 352]) & (c >> 31); x[offset + 320] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 368]) & (c >> 31); x[offset + 336] ^= t; x[offset + 368] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 352]) & (c >> 31); x[offset + 336] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 320]) & (c >> 31); x[offset + 256] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 352]) & (c >> 31); x[offset + 288] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 320]) & (c >> 31); x[offset + 288] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 336]) & (c >> 31); x[offset + 272] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 368]) & (c >> 31); x[offset + 304] ^= t; x[offset + 368] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 336]) & (c >> 31); x[offset + 304] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 288]) & (c >> 31); x[offset + 272] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 320]) & (c >> 31); x[offset + 304] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 352]) & (c >> 31); x[offset + 336] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 400]) & (c >> 31); x[offset + 384] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 432]) & (c >> 31); x[offset + 416] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 416]) & (c >> 31); x[offset + 384] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 432]) & (c >> 31); x[offset + 400] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 416]) & (c >> 31); x[offset + 400] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 464]) & (c >> 31); x[offset + 448] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 496]) & (c >> 31); x[offset + 480] ^= t; x[offset + 496] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 480]) & (c >> 31); x[offset + 448] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 496]) & (c >> 31); x[offset + 464] ^= t; x[offset + 496] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 480]) & (c >> 31); x[offset + 464] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 448]) & (c >> 31); x[offset + 384] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 480]) & (c >> 31); x[offset + 416] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 448]) & (c >> 31); x[offset + 416] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 464]) & (c >> 31); x[offset + 400] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 496]) & (c >> 31); x[offset + 432] ^= t; x[offset + 496] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 464]) & (c >> 31); x[offset + 432] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 416]) & (c >> 31); x[offset + 400] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 448]) & (c >> 31); x[offset + 432] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 480]) & (c >> 31); x[offset + 464] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 384]) & (c >> 31); x[offset + 256] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 448]) & (c >> 31); x[offset + 320] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 384]) & (c >> 31); x[offset + 320] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 416]) & (c >> 31); x[offset + 288] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 480]) & (c >> 31); x[offset + 352] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 416]) & (c >> 31); x[offset + 352] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 320]) & (c >> 31); x[offset + 288] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 384]) & (c >> 31); x[offset + 352] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 448]) & (c >> 31); x[offset + 416] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 400]) & (c >> 31); x[offset + 272] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 464]) & (c >> 31); x[offset + 336] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 400]) & (c >> 31); x[offset + 336] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 432]) & (c >> 31); x[offset + 304] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 496]) & (c >> 31); x[offset + 368] ^= t; x[offset + 496] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 432]) & (c >> 31); x[offset + 368] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 336]) & (c >> 31); x[offset + 304] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 400]) & (c >> 31); x[offset + 368] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 464]) & (c >> 31); x[offset + 432] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 288]) & (c >> 31); x[offset + 272] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 320]) & (c >> 31); x[offset + 304] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 352]) & (c >> 31); x[offset + 336] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 384]) & (c >> 31); x[offset + 368] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 416]) & (c >> 31); x[offset + 400] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 448]) & (c >> 31); x[offset + 432] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 480]) & (c >> 31); x[offset + 464] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 0]; t = (x[offset + 0] ^ x[offset + 256]) & (c >> 31); x[offset + 0] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 384]) & (c >> 31); x[offset + 128] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 256]) & (c >> 31); x[offset + 128] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 320]) & (c >> 31); x[offset + 64] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 448]) & (c >> 31); x[offset + 192] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 320]) & (c >> 31); x[offset + 192] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 128]) & (c >> 31); x[offset + 64] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 256]) & (c >> 31); x[offset + 192] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 384]) & (c >> 31); x[offset + 320] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 288]) & (c >> 31); x[offset + 32] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 416]) & (c >> 31); x[offset + 160] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 288]) & (c >> 31); x[offset + 160] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 352]) & (c >> 31); x[offset + 96] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 480]) & (c >> 31); x[offset + 224] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 352]) & (c >> 31); x[offset + 224] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 160]) & (c >> 31); x[offset + 96] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 288]) & (c >> 31); x[offset + 224] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 416]) & (c >> 31); x[offset + 352] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 64]) & (c >> 31); x[offset + 32] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 128]) & (c >> 31); x[offset + 96] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 192]) & (c >> 31); x[offset + 160] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 256]) & (c >> 31); x[offset + 224] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 320]) & (c >> 31); x[offset + 288] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 384]) & (c >> 31); x[offset + 352] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 448]) & (c >> 31); x[offset + 416] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 272]) & (c >> 31); x[offset + 16] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 400]) & (c >> 31); x[offset + 144] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 272]) & (c >> 31); x[offset + 144] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 336]) & (c >> 31); x[offset + 80] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 464]) & (c >> 31); x[offset + 208] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 336]) & (c >> 31); x[offset + 208] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 144]) & (c >> 31); x[offset + 80] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 272]) & (c >> 31); x[offset + 208] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 400]) & (c >> 31); x[offset + 336] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 304]) & (c >> 31); x[offset + 48] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 432]) & (c >> 31); x[offset + 176] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 304]) & (c >> 31); x[offset + 176] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 368]) & (c >> 31); x[offset + 112] ^= t; x[offset + 368] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 496]) & (c >> 31); x[offset + 240] ^= t; x[offset + 496] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 368]) & (c >> 31); x[offset + 240] ^= t; x[offset + 368] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 176]) & (c >> 31); x[offset + 112] ^= t; x[offset + 176] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 304]) & (c >> 31); x[offset + 240] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 432]) & (c >> 31); x[offset + 368] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 80]) & (c >> 31); x[offset + 48] ^= t; x[offset + 80] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 144]) & (c >> 31); x[offset + 112] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 208]) & (c >> 31); x[offset + 176] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 272]) & (c >> 31); x[offset + 240] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 336]) & (c >> 31); x[offset + 304] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 400]) & (c >> 31); x[offset + 368] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 464]) & (c >> 31); x[offset + 432] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 32]) & (c >> 31); x[offset + 16] ^= t; x[offset + 32] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 64]) & (c >> 31); x[offset + 48] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 96]) & (c >> 31); x[offset + 80] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 128]) & (c >> 31); x[offset + 112] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 160]) & (c >> 31); x[offset + 144] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 192]) & (c >> 31); x[offset + 176] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 224]) & (c >> 31); x[offset + 208] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 256]) & (c >> 31); x[offset + 240] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 288]) & (c >> 31); x[offset + 272] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 320]) & (c >> 31); x[offset + 304] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 352]) & (c >> 31); x[offset + 336] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 384]) & (c >> 31); x[offset + 368] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 416]) & (c >> 31); x[offset + 400] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 448]) & (c >> 31); x[offset + 432] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 480]) & (c >> 31); x[offset + 464] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 512]; t = (x[offset + 512] ^ x[offset + 528]) & (c >> 31); x[offset + 512] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 560]) & (c >> 31); x[offset + 544] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 512]; t = (x[offset + 512] ^ x[offset + 544]) & (c >> 31); x[offset + 512] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 560]) & (c >> 31); x[offset + 528] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 544]) & (c >> 31); x[offset + 528] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 592]) & (c >> 31); x[offset + 576] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 624]) & (c >> 31); x[offset + 608] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 608]) & (c >> 31); x[offset + 576] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 624]) & (c >> 31); x[offset + 592] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 608]) & (c >> 31); x[offset + 592] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 512]; t = (x[offset + 512] ^ x[offset + 576]) & (c >> 31); x[offset + 512] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 608]) & (c >> 31); x[offset + 544] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 576]) & (c >> 31); x[offset + 544] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 592]) & (c >> 31); x[offset + 528] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 624]) & (c >> 31); x[offset + 560] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 592]) & (c >> 31); x[offset + 560] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 544]) & (c >> 31); x[offset + 528] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 576]) & (c >> 31); x[offset + 560] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 608]) & (c >> 31); x[offset + 592] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 656]) & (c >> 31); x[offset + 640] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 688]) & (c >> 31); x[offset + 672] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 672]) & (c >> 31); x[offset + 640] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 688]) & (c >> 31); x[offset + 656] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 672]) & (c >> 31); x[offset + 656] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 720]) & (c >> 31); x[offset + 704] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 752]) & (c >> 31); x[offset + 736] ^= t; x[offset + 752] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 736]) & (c >> 31); x[offset + 704] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 752]) & (c >> 31); x[offset + 720] ^= t; x[offset + 752] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 736]) & (c >> 31); x[offset + 720] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 704]) & (c >> 31); x[offset + 640] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 736]) & (c >> 31); x[offset + 672] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 704]) & (c >> 31); x[offset + 672] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 720]) & (c >> 31); x[offset + 656] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 752]) & (c >> 31); x[offset + 688] ^= t; x[offset + 752] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 720]) & (c >> 31); x[offset + 688] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 672]) & (c >> 31); x[offset + 656] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 704]) & (c >> 31); x[offset + 688] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 736]) & (c >> 31); x[offset + 720] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 512]; t = (x[offset + 512] ^ x[offset + 640]) & (c >> 31); x[offset + 512] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 704]) & (c >> 31); x[offset + 576] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 640]) & (c >> 31); x[offset + 576] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 672]) & (c >> 31); x[offset + 544] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 736]) & (c >> 31); x[offset + 608] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 672]) & (c >> 31); x[offset + 608] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 576]) & (c >> 31); x[offset + 544] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 640]) & (c >> 31); x[offset + 608] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 704]) & (c >> 31); x[offset + 672] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 656]) & (c >> 31); x[offset + 528] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 720]) & (c >> 31); x[offset + 592] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 656]) & (c >> 31); x[offset + 592] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 688]) & (c >> 31); x[offset + 560] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 752]) & (c >> 31); x[offset + 624] ^= t; x[offset + 752] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 688]) & (c >> 31); x[offset + 624] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 592]) & (c >> 31); x[offset + 560] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 656]) & (c >> 31); x[offset + 624] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 720]) & (c >> 31); x[offset + 688] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 544]) & (c >> 31); x[offset + 528] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 576]) & (c >> 31); x[offset + 560] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 608]) & (c >> 31); x[offset + 592] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 640]) & (c >> 31); x[offset + 624] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 672]) & (c >> 31); x[offset + 656] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 704]) & (c >> 31); x[offset + 688] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 736]) & (c >> 31); x[offset + 720] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 768]; t = (x[offset + 768] ^ x[offset + 784]) & (c >> 31); x[offset + 768] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 816]) & (c >> 31); x[offset + 800] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 768]; t = (x[offset + 768] ^ x[offset + 800]) & (c >> 31); x[offset + 768] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 816]) & (c >> 31); x[offset + 784] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 800]) & (c >> 31); x[offset + 784] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 848]) & (c >> 31); x[offset + 832] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 880]) & (c >> 31); x[offset + 864] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 864]) & (c >> 31); x[offset + 832] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 880]) & (c >> 31); x[offset + 848] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 864]) & (c >> 31); x[offset + 848] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 768]; t = (x[offset + 768] ^ x[offset + 832]) & (c >> 31); x[offset + 768] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 864]) & (c >> 31); x[offset + 800] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 832]) & (c >> 31); x[offset + 800] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 848]) & (c >> 31); x[offset + 784] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 880]) & (c >> 31); x[offset + 816] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 848]) & (c >> 31); x[offset + 816] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 800]) & (c >> 31); x[offset + 784] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 832]) & (c >> 31); x[offset + 816] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 864]) & (c >> 31); x[offset + 848] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 896]; t = (x[offset + 896] ^ x[offset + 912]) & (c >> 31); x[offset + 896] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 944]) & (c >> 31); x[offset + 928] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 896]; t = (x[offset + 896] ^ x[offset + 928]) & (c >> 31); x[offset + 896] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 944]) & (c >> 31); x[offset + 912] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 928]) & (c >> 31); x[offset + 912] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 960]; t = (x[offset + 960] ^ x[offset + 976]) & (c >> 31); x[offset + 960] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 992]; t = (x[offset + 992] ^ x[offset + 1008]) & (c >> 31); x[offset + 992] ^= t; x[offset + 1008] ^= t;
|
||||
c = 61444 - x[offset + 960]; t = (x[offset + 960] ^ x[offset + 992]) & (c >> 31); x[offset + 960] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 1008]) & (c >> 31); x[offset + 976] ^= t; x[offset + 1008] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 992]) & (c >> 31); x[offset + 976] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 896]; t = (x[offset + 896] ^ x[offset + 960]) & (c >> 31); x[offset + 896] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 992]) & (c >> 31); x[offset + 928] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 960]) & (c >> 31); x[offset + 928] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 976]) & (c >> 31); x[offset + 912] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 1008]) & (c >> 31); x[offset + 944] ^= t; x[offset + 1008] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 976]) & (c >> 31); x[offset + 944] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 928]) & (c >> 31); x[offset + 912] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 960]) & (c >> 31); x[offset + 944] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 992]) & (c >> 31); x[offset + 976] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 768]; t = (x[offset + 768] ^ x[offset + 896]) & (c >> 31); x[offset + 768] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 960]) & (c >> 31); x[offset + 832] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 896]) & (c >> 31); x[offset + 832] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 928]) & (c >> 31); x[offset + 800] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 992]) & (c >> 31); x[offset + 864] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 928]) & (c >> 31); x[offset + 864] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 832]) & (c >> 31); x[offset + 800] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 896]) & (c >> 31); x[offset + 864] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 960]) & (c >> 31); x[offset + 928] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 912]) & (c >> 31); x[offset + 784] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 976]) & (c >> 31); x[offset + 848] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 912]) & (c >> 31); x[offset + 848] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 944]) & (c >> 31); x[offset + 816] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 1008]) & (c >> 31); x[offset + 880] ^= t; x[offset + 1008] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 944]) & (c >> 31); x[offset + 880] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 848]) & (c >> 31); x[offset + 816] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 912]) & (c >> 31); x[offset + 880] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 976]) & (c >> 31); x[offset + 944] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 800]) & (c >> 31); x[offset + 784] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 832]) & (c >> 31); x[offset + 816] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 864]) & (c >> 31); x[offset + 848] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 896]) & (c >> 31); x[offset + 880] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 928]) & (c >> 31); x[offset + 912] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 960]) & (c >> 31); x[offset + 944] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 992]) & (c >> 31); x[offset + 976] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 512]; t = (x[offset + 512] ^ x[offset + 768]) & (c >> 31); x[offset + 512] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 896]) & (c >> 31); x[offset + 640] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 768]) & (c >> 31); x[offset + 640] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 832]) & (c >> 31); x[offset + 576] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 960]) & (c >> 31); x[offset + 704] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 832]) & (c >> 31); x[offset + 704] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 640]) & (c >> 31); x[offset + 576] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 768]) & (c >> 31); x[offset + 704] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 896]) & (c >> 31); x[offset + 832] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 800]) & (c >> 31); x[offset + 544] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 928]) & (c >> 31); x[offset + 672] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 800]) & (c >> 31); x[offset + 672] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 864]) & (c >> 31); x[offset + 608] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 992]) & (c >> 31); x[offset + 736] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 864]) & (c >> 31); x[offset + 736] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 672]) & (c >> 31); x[offset + 608] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 800]) & (c >> 31); x[offset + 736] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 928]) & (c >> 31); x[offset + 864] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 576]) & (c >> 31); x[offset + 544] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 640]) & (c >> 31); x[offset + 608] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 704]) & (c >> 31); x[offset + 672] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 768]) & (c >> 31); x[offset + 736] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 832]) & (c >> 31); x[offset + 800] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 896]) & (c >> 31); x[offset + 864] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 960]) & (c >> 31); x[offset + 928] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 784]) & (c >> 31); x[offset + 528] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 912]) & (c >> 31); x[offset + 656] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 784]) & (c >> 31); x[offset + 656] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 848]) & (c >> 31); x[offset + 592] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 976]) & (c >> 31); x[offset + 720] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 848]) & (c >> 31); x[offset + 720] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 656]) & (c >> 31); x[offset + 592] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 784]) & (c >> 31); x[offset + 720] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 912]) & (c >> 31); x[offset + 848] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 816]) & (c >> 31); x[offset + 560] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 944]) & (c >> 31); x[offset + 688] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 816]) & (c >> 31); x[offset + 688] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 880]) & (c >> 31); x[offset + 624] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 1008]) & (c >> 31); x[offset + 752] ^= t; x[offset + 1008] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 880]) & (c >> 31); x[offset + 752] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 688]) & (c >> 31); x[offset + 624] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 816]) & (c >> 31); x[offset + 752] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 944]) & (c >> 31); x[offset + 880] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 592]) & (c >> 31); x[offset + 560] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 656]) & (c >> 31); x[offset + 624] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 720]) & (c >> 31); x[offset + 688] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 784]) & (c >> 31); x[offset + 752] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 848]) & (c >> 31); x[offset + 816] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 912]) & (c >> 31); x[offset + 880] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 976]) & (c >> 31); x[offset + 944] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 544]) & (c >> 31); x[offset + 528] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 576]) & (c >> 31); x[offset + 560] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 608]) & (c >> 31); x[offset + 592] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 640]) & (c >> 31); x[offset + 624] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 672]) & (c >> 31); x[offset + 656] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 704]) & (c >> 31); x[offset + 688] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 736]) & (c >> 31); x[offset + 720] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 768]) & (c >> 31); x[offset + 752] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 800]) & (c >> 31); x[offset + 784] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 832]) & (c >> 31); x[offset + 816] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 864]) & (c >> 31); x[offset + 848] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 896]) & (c >> 31); x[offset + 880] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 928]) & (c >> 31); x[offset + 912] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 960]) & (c >> 31); x[offset + 944] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 992]) & (c >> 31); x[offset + 976] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 0]; t = (x[offset + 0] ^ x[offset + 512]) & (c >> 31); x[offset + 0] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 768]) & (c >> 31); x[offset + 256] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 512]) & (c >> 31); x[offset + 256] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 640]) & (c >> 31); x[offset + 128] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 896]) & (c >> 31); x[offset + 384] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 640]) & (c >> 31); x[offset + 384] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 256]) & (c >> 31); x[offset + 128] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 512]) & (c >> 31); x[offset + 384] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 768]) & (c >> 31); x[offset + 640] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 576]) & (c >> 31); x[offset + 64] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 832]) & (c >> 31); x[offset + 320] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 576]) & (c >> 31); x[offset + 320] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 704]) & (c >> 31); x[offset + 192] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 960]) & (c >> 31); x[offset + 448] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 704]) & (c >> 31); x[offset + 448] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 320]) & (c >> 31); x[offset + 192] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 576]) & (c >> 31); x[offset + 448] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 832]) & (c >> 31); x[offset + 704] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 128]) & (c >> 31); x[offset + 64] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 256]) & (c >> 31); x[offset + 192] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 384]) & (c >> 31); x[offset + 320] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 512]) & (c >> 31); x[offset + 448] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 640]) & (c >> 31); x[offset + 576] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 768]) & (c >> 31); x[offset + 704] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 896]) & (c >> 31); x[offset + 832] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 544]) & (c >> 31); x[offset + 32] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 800]) & (c >> 31); x[offset + 288] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 544]) & (c >> 31); x[offset + 288] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 672]) & (c >> 31); x[offset + 160] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 928]) & (c >> 31); x[offset + 416] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 672]) & (c >> 31); x[offset + 416] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 288]) & (c >> 31); x[offset + 160] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 544]) & (c >> 31); x[offset + 416] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 800]) & (c >> 31); x[offset + 672] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 608]) & (c >> 31); x[offset + 96] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 864]) & (c >> 31); x[offset + 352] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 608]) & (c >> 31); x[offset + 352] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 736]) & (c >> 31); x[offset + 224] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 992]) & (c >> 31); x[offset + 480] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 736]) & (c >> 31); x[offset + 480] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 352]) & (c >> 31); x[offset + 224] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 608]) & (c >> 31); x[offset + 480] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 864]) & (c >> 31); x[offset + 736] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 160]) & (c >> 31); x[offset + 96] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 288]) & (c >> 31); x[offset + 224] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 416]) & (c >> 31); x[offset + 352] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 544]) & (c >> 31); x[offset + 480] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 672]) & (c >> 31); x[offset + 608] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 800]) & (c >> 31); x[offset + 736] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 928]) & (c >> 31); x[offset + 864] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 64]) & (c >> 31); x[offset + 32] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 128]) & (c >> 31); x[offset + 96] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 192]) & (c >> 31); x[offset + 160] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 256]) & (c >> 31); x[offset + 224] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 320]) & (c >> 31); x[offset + 288] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 384]) & (c >> 31); x[offset + 352] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 448]) & (c >> 31); x[offset + 416] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 512]) & (c >> 31); x[offset + 480] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 576]) & (c >> 31); x[offset + 544] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 640]) & (c >> 31); x[offset + 608] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 704]) & (c >> 31); x[offset + 672] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 768]) & (c >> 31); x[offset + 736] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 832]) & (c >> 31); x[offset + 800] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 896]) & (c >> 31); x[offset + 864] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 960]) & (c >> 31); x[offset + 928] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 528]) & (c >> 31); x[offset + 16] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 784]) & (c >> 31); x[offset + 272] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 528]) & (c >> 31); x[offset + 272] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 656]) & (c >> 31); x[offset + 144] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 912]) & (c >> 31); x[offset + 400] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 656]) & (c >> 31); x[offset + 400] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 272]) & (c >> 31); x[offset + 144] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 528]) & (c >> 31); x[offset + 400] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 784]) & (c >> 31); x[offset + 656] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 592]) & (c >> 31); x[offset + 80] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 848]) & (c >> 31); x[offset + 336] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 592]) & (c >> 31); x[offset + 336] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 720]) & (c >> 31); x[offset + 208] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 976]) & (c >> 31); x[offset + 464] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 720]) & (c >> 31); x[offset + 464] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 336]) & (c >> 31); x[offset + 208] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 592]) & (c >> 31); x[offset + 464] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 848]) & (c >> 31); x[offset + 720] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 144]) & (c >> 31); x[offset + 80] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 272]) & (c >> 31); x[offset + 208] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 400]) & (c >> 31); x[offset + 336] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 528]) & (c >> 31); x[offset + 464] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 656]) & (c >> 31); x[offset + 592] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 784]) & (c >> 31); x[offset + 720] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 912]) & (c >> 31); x[offset + 848] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 560]) & (c >> 31); x[offset + 48] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 816]) & (c >> 31); x[offset + 304] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 560]) & (c >> 31); x[offset + 304] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 688]) & (c >> 31); x[offset + 176] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 944]) & (c >> 31); x[offset + 432] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 688]) & (c >> 31); x[offset + 432] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 304]) & (c >> 31); x[offset + 176] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 560]) & (c >> 31); x[offset + 432] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 816]) & (c >> 31); x[offset + 688] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 624]) & (c >> 31); x[offset + 112] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 880]) & (c >> 31); x[offset + 368] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 624]) & (c >> 31); x[offset + 368] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 752]) & (c >> 31); x[offset + 240] ^= t; x[offset + 752] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 1008]) & (c >> 31); x[offset + 496] ^= t; x[offset + 1008] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 752]) & (c >> 31); x[offset + 496] ^= t; x[offset + 752] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 368]) & (c >> 31); x[offset + 240] ^= t; x[offset + 368] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 624]) & (c >> 31); x[offset + 496] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 880]) & (c >> 31); x[offset + 752] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 176]) & (c >> 31); x[offset + 112] ^= t; x[offset + 176] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 304]) & (c >> 31); x[offset + 240] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 432]) & (c >> 31); x[offset + 368] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 560]) & (c >> 31); x[offset + 496] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 688]) & (c >> 31); x[offset + 624] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 816]) & (c >> 31); x[offset + 752] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 944]) & (c >> 31); x[offset + 880] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 80]) & (c >> 31); x[offset + 48] ^= t; x[offset + 80] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 144]) & (c >> 31); x[offset + 112] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 208]) & (c >> 31); x[offset + 176] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 272]) & (c >> 31); x[offset + 240] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 336]) & (c >> 31); x[offset + 304] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 400]) & (c >> 31); x[offset + 368] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 464]) & (c >> 31); x[offset + 432] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 528]) & (c >> 31); x[offset + 496] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 592]) & (c >> 31); x[offset + 560] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 656]) & (c >> 31); x[offset + 624] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 720]) & (c >> 31); x[offset + 688] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 784]) & (c >> 31); x[offset + 752] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 848]) & (c >> 31); x[offset + 816] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 912]) & (c >> 31); x[offset + 880] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 976]) & (c >> 31); x[offset + 944] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 32]) & (c >> 31); x[offset + 16] ^= t; x[offset + 32] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 64]) & (c >> 31); x[offset + 48] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 96]) & (c >> 31); x[offset + 80] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 128]) & (c >> 31); x[offset + 112] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 160]) & (c >> 31); x[offset + 144] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 192]) & (c >> 31); x[offset + 176] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 224]) & (c >> 31); x[offset + 208] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 256]) & (c >> 31); x[offset + 240] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 288]) & (c >> 31); x[offset + 272] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 320]) & (c >> 31); x[offset + 304] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 352]) & (c >> 31); x[offset + 336] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 384]) & (c >> 31); x[offset + 368] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 416]) & (c >> 31); x[offset + 400] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 448]) & (c >> 31); x[offset + 432] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 480]) & (c >> 31); x[offset + 464] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 512]) & (c >> 31); x[offset + 496] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 544]) & (c >> 31); x[offset + 528] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 576]) & (c >> 31); x[offset + 560] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 608]) & (c >> 31); x[offset + 592] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 640]) & (c >> 31); x[offset + 624] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 672]) & (c >> 31); x[offset + 656] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 704]) & (c >> 31); x[offset + 688] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 736]) & (c >> 31); x[offset + 720] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 768]) & (c >> 31); x[offset + 752] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 800]) & (c >> 31); x[offset + 784] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 832]) & (c >> 31); x[offset + 816] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 864]) & (c >> 31); x[offset + 848] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 896]) & (c >> 31); x[offset + 880] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 928]) & (c >> 31); x[offset + 912] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 960]) & (c >> 31); x[offset + 944] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 992]) & (c >> 31); x[offset + 976] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 1024]; t = (x[offset + 1024] ^ x[offset + 1040]) & (c >> 31); x[offset + 1024] ^= t; x[offset + 1040] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1072]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1072] ^= t;
|
||||
c = 61444 - x[offset + 1024]; t = (x[offset + 1024] ^ x[offset + 1056]) & (c >> 31); x[offset + 1024] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1072]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1072] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1056]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1088]; t = (x[offset + 1088] ^ x[offset + 1104]) & (c >> 31); x[offset + 1088] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1136]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1136] ^= t;
|
||||
c = 61444 - x[offset + 1088]; t = (x[offset + 1088] ^ x[offset + 1120]) & (c >> 31); x[offset + 1088] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1136]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1136] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1120]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1024]; t = (x[offset + 1024] ^ x[offset + 1088]) & (c >> 31); x[offset + 1024] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1120]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1088]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1104]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1136]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1136] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1104]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1056]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1088]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1120]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1152]; t = (x[offset + 1152] ^ x[offset + 1168]) & (c >> 31); x[offset + 1152] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1200]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 1152]; t = (x[offset + 1152] ^ x[offset + 1184]) & (c >> 31); x[offset + 1152] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1200]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1184]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1216]; t = (x[offset + 1216] ^ x[offset + 1232]) & (c >> 31); x[offset + 1216] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1248]; t = (x[offset + 1248] ^ x[offset + 1264]) & (c >> 31); x[offset + 1248] ^= t; x[offset + 1264] ^= t;
|
||||
c = 61444 - x[offset + 1216]; t = (x[offset + 1216] ^ x[offset + 1248]) & (c >> 31); x[offset + 1216] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1264]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1264] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1248]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1152]; t = (x[offset + 1152] ^ x[offset + 1216]) & (c >> 31); x[offset + 1152] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1248]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1216]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1232]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1264]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1264] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1232]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1184]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1216]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1248]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1024]; t = (x[offset + 1024] ^ x[offset + 1152]) & (c >> 31); x[offset + 1024] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1088]; t = (x[offset + 1088] ^ x[offset + 1216]) & (c >> 31); x[offset + 1088] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1088]; t = (x[offset + 1088] ^ x[offset + 1152]) & (c >> 31); x[offset + 1088] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1184]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1248]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1184]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1088]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1152]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1216]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1168]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1232]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1168]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1200]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1264]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1264] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1200]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1104]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1168]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1232]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1056]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1088]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1120]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1152]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1184]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1216]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1248]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1280]; t = (x[offset + 1280] ^ x[offset + 1296]) & (c >> 31); x[offset + 1280] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1312]; t = (x[offset + 1312] ^ x[offset + 1328]) & (c >> 31); x[offset + 1312] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 1280]; t = (x[offset + 1280] ^ x[offset + 1312]) & (c >> 31); x[offset + 1280] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1296]; t = (x[offset + 1296] ^ x[offset + 1328]) & (c >> 31); x[offset + 1296] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 1296]; t = (x[offset + 1296] ^ x[offset + 1312]) & (c >> 31); x[offset + 1296] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1296]; t = (x[offset + 1296] ^ x[offset + 1312]) & (c >> 31); x[offset + 1296] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1296]; t = (x[offset + 1296] ^ x[offset + 1312]) & (c >> 31); x[offset + 1296] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1024]; t = (x[offset + 1024] ^ x[offset + 1280]) & (c >> 31); x[offset + 1024] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1152]; t = (x[offset + 1152] ^ x[offset + 1280]) & (c >> 31); x[offset + 1152] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1088]; t = (x[offset + 1088] ^ x[offset + 1152]) & (c >> 31); x[offset + 1088] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1216]; t = (x[offset + 1216] ^ x[offset + 1280]) & (c >> 31); x[offset + 1216] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1312]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1312]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1184]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1248]; t = (x[offset + 1248] ^ x[offset + 1312]) & (c >> 31); x[offset + 1248] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1088]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1152]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1216]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1248]; t = (x[offset + 1248] ^ x[offset + 1280]) & (c >> 31); x[offset + 1248] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1296]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1296]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1168]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1296]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1328]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1328]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1200]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1328]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1104]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1168]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1232]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1296]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1056]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1088]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1120]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1152]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1184]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1216]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1248]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1280]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1296]; t = (x[offset + 1296] ^ x[offset + 1312]) & (c >> 31); x[offset + 1296] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1152]; t = (x[offset + 1152] ^ x[offset + 1280]) & (c >> 31); x[offset + 1152] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1088]; t = (x[offset + 1088] ^ x[offset + 1152]) & (c >> 31); x[offset + 1088] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1216]; t = (x[offset + 1216] ^ x[offset + 1280]) & (c >> 31); x[offset + 1216] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1312]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1184]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1248]; t = (x[offset + 1248] ^ x[offset + 1312]) & (c >> 31); x[offset + 1248] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1088]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1152]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1216]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1248]; t = (x[offset + 1248] ^ x[offset + 1280]) & (c >> 31); x[offset + 1248] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1296]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1168]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1296]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1328]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1200]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1328]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1104]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1168]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1232]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1296]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1056]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1088]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1120]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1152]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1184]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1216]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1248]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1280]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1296]; t = (x[offset + 1296] ^ x[offset + 1312]) & (c >> 31); x[offset + 1296] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 0]; t = (x[offset + 0] ^ x[offset + 1024]) & (c >> 31); x[offset + 0] ^= t; x[offset + 1024] ^= t;
|
||||
c = 61444 - x[offset + 512]; t = (x[offset + 512] ^ x[offset + 1024]) & (c >> 31); x[offset + 512] ^= t; x[offset + 1024] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 1280]) & (c >> 31); x[offset + 256] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 768]; t = (x[offset + 768] ^ x[offset + 1280]) & (c >> 31); x[offset + 768] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 256]; t = (x[offset + 256] ^ x[offset + 512]) & (c >> 31); x[offset + 256] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 768]; t = (x[offset + 768] ^ x[offset + 1024]) & (c >> 31); x[offset + 768] ^= t; x[offset + 1024] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 1152]) & (c >> 31); x[offset + 128] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 1152]) & (c >> 31); x[offset + 640] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 640]) & (c >> 31); x[offset + 384] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 896]; t = (x[offset + 896] ^ x[offset + 1152]) & (c >> 31); x[offset + 896] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 128]; t = (x[offset + 128] ^ x[offset + 256]) & (c >> 31); x[offset + 128] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 384]; t = (x[offset + 384] ^ x[offset + 512]) & (c >> 31); x[offset + 384] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 640]; t = (x[offset + 640] ^ x[offset + 768]) & (c >> 31); x[offset + 640] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 896]; t = (x[offset + 896] ^ x[offset + 1024]) & (c >> 31); x[offset + 896] ^= t; x[offset + 1024] ^= t;
|
||||
c = 61444 - x[offset + 1152]; t = (x[offset + 1152] ^ x[offset + 1280]) & (c >> 31); x[offset + 1152] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 1088]) & (c >> 31); x[offset + 64] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 1088]) & (c >> 31); x[offset + 576] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 576]) & (c >> 31); x[offset + 320] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 1088]) & (c >> 31); x[offset + 832] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 1216]) & (c >> 31); x[offset + 192] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 1216]) & (c >> 31); x[offset + 704] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 704]) & (c >> 31); x[offset + 448] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 960]; t = (x[offset + 960] ^ x[offset + 1216]) & (c >> 31); x[offset + 960] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 320]) & (c >> 31); x[offset + 192] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 576]) & (c >> 31); x[offset + 448] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 832]) & (c >> 31); x[offset + 704] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 960]; t = (x[offset + 960] ^ x[offset + 1088]) & (c >> 31); x[offset + 960] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 64]; t = (x[offset + 64] ^ x[offset + 128]) & (c >> 31); x[offset + 64] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 192]; t = (x[offset + 192] ^ x[offset + 256]) & (c >> 31); x[offset + 192] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 320]; t = (x[offset + 320] ^ x[offset + 384]) & (c >> 31); x[offset + 320] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 448]; t = (x[offset + 448] ^ x[offset + 512]) & (c >> 31); x[offset + 448] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 576]; t = (x[offset + 576] ^ x[offset + 640]) & (c >> 31); x[offset + 576] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 704]; t = (x[offset + 704] ^ x[offset + 768]) & (c >> 31); x[offset + 704] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 832]; t = (x[offset + 832] ^ x[offset + 896]) & (c >> 31); x[offset + 832] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 960]; t = (x[offset + 960] ^ x[offset + 1024]) & (c >> 31); x[offset + 960] ^= t; x[offset + 1024] ^= t;
|
||||
c = 61444 - x[offset + 1088]; t = (x[offset + 1088] ^ x[offset + 1152]) & (c >> 31); x[offset + 1088] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1216]; t = (x[offset + 1216] ^ x[offset + 1280]) & (c >> 31); x[offset + 1216] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 1056]) & (c >> 31); x[offset + 32] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 1056]) & (c >> 31); x[offset + 544] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 1312]) & (c >> 31); x[offset + 288] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 1312]) & (c >> 31); x[offset + 800] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 544]) & (c >> 31); x[offset + 288] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 1056]) & (c >> 31); x[offset + 800] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 1184]) & (c >> 31); x[offset + 160] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 1184]) & (c >> 31); x[offset + 672] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 672]) & (c >> 31); x[offset + 416] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 1184]) & (c >> 31); x[offset + 928] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 288]) & (c >> 31); x[offset + 160] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 544]) & (c >> 31); x[offset + 416] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 800]) & (c >> 31); x[offset + 672] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 1056]) & (c >> 31); x[offset + 928] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1312]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 1120]) & (c >> 31); x[offset + 96] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 1120]) & (c >> 31); x[offset + 608] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 608]) & (c >> 31); x[offset + 352] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 1120]) & (c >> 31); x[offset + 864] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 1248]) & (c >> 31); x[offset + 224] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 1248]) & (c >> 31); x[offset + 736] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 736]) & (c >> 31); x[offset + 480] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 992]; t = (x[offset + 992] ^ x[offset + 1248]) & (c >> 31); x[offset + 992] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 352]) & (c >> 31); x[offset + 224] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 608]) & (c >> 31); x[offset + 480] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 864]) & (c >> 31); x[offset + 736] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 992]; t = (x[offset + 992] ^ x[offset + 1120]) & (c >> 31); x[offset + 992] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 160]) & (c >> 31); x[offset + 96] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 288]) & (c >> 31); x[offset + 224] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 416]) & (c >> 31); x[offset + 352] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 544]) & (c >> 31); x[offset + 480] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 672]) & (c >> 31); x[offset + 608] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 800]) & (c >> 31); x[offset + 736] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 928]) & (c >> 31); x[offset + 864] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 992]; t = (x[offset + 992] ^ x[offset + 1056]) & (c >> 31); x[offset + 992] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1184]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1248]; t = (x[offset + 1248] ^ x[offset + 1312]) & (c >> 31); x[offset + 1248] ^= t; x[offset + 1312] ^= t;
|
||||
c = 61444 - x[offset + 32]; t = (x[offset + 32] ^ x[offset + 64]) & (c >> 31); x[offset + 32] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 96]; t = (x[offset + 96] ^ x[offset + 128]) & (c >> 31); x[offset + 96] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 160]; t = (x[offset + 160] ^ x[offset + 192]) & (c >> 31); x[offset + 160] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 224]; t = (x[offset + 224] ^ x[offset + 256]) & (c >> 31); x[offset + 224] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 288]; t = (x[offset + 288] ^ x[offset + 320]) & (c >> 31); x[offset + 288] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 352]; t = (x[offset + 352] ^ x[offset + 384]) & (c >> 31); x[offset + 352] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 416]; t = (x[offset + 416] ^ x[offset + 448]) & (c >> 31); x[offset + 416] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 480]; t = (x[offset + 480] ^ x[offset + 512]) & (c >> 31); x[offset + 480] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 544]; t = (x[offset + 544] ^ x[offset + 576]) & (c >> 31); x[offset + 544] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 608]; t = (x[offset + 608] ^ x[offset + 640]) & (c >> 31); x[offset + 608] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 672]; t = (x[offset + 672] ^ x[offset + 704]) & (c >> 31); x[offset + 672] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 736]; t = (x[offset + 736] ^ x[offset + 768]) & (c >> 31); x[offset + 736] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 800]; t = (x[offset + 800] ^ x[offset + 832]) & (c >> 31); x[offset + 800] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 864]; t = (x[offset + 864] ^ x[offset + 896]) & (c >> 31); x[offset + 864] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 928]; t = (x[offset + 928] ^ x[offset + 960]) & (c >> 31); x[offset + 928] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 992]; t = (x[offset + 992] ^ x[offset + 1024]) & (c >> 31); x[offset + 992] ^= t; x[offset + 1024] ^= t;
|
||||
c = 61444 - x[offset + 1056]; t = (x[offset + 1056] ^ x[offset + 1088]) & (c >> 31); x[offset + 1056] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1120]; t = (x[offset + 1120] ^ x[offset + 1152]) & (c >> 31); x[offset + 1120] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1184]; t = (x[offset + 1184] ^ x[offset + 1216]) & (c >> 31); x[offset + 1184] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1248]; t = (x[offset + 1248] ^ x[offset + 1280]) & (c >> 31); x[offset + 1248] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 1040]) & (c >> 31); x[offset + 16] ^= t; x[offset + 1040] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 1040]) & (c >> 31); x[offset + 528] ^= t; x[offset + 1040] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 1296]) & (c >> 31); x[offset + 272] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 1296]) & (c >> 31); x[offset + 784] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 528]) & (c >> 31); x[offset + 272] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 1040]) & (c >> 31); x[offset + 784] ^= t; x[offset + 1040] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 1168]) & (c >> 31); x[offset + 144] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 1168]) & (c >> 31); x[offset + 656] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 656]) & (c >> 31); x[offset + 400] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 1168]) & (c >> 31); x[offset + 912] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 272]) & (c >> 31); x[offset + 144] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 528]) & (c >> 31); x[offset + 400] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 784]) & (c >> 31); x[offset + 656] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 1040]) & (c >> 31); x[offset + 912] ^= t; x[offset + 1040] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1296]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 1104]) & (c >> 31); x[offset + 80] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 1104]) & (c >> 31); x[offset + 592] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 592]) & (c >> 31); x[offset + 336] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 1104]) & (c >> 31); x[offset + 848] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 1232]) & (c >> 31); x[offset + 208] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 1232]) & (c >> 31); x[offset + 720] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 720]) & (c >> 31); x[offset + 464] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 1232]) & (c >> 31); x[offset + 976] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 336]) & (c >> 31); x[offset + 208] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 592]) & (c >> 31); x[offset + 464] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 848]) & (c >> 31); x[offset + 720] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 1104]) & (c >> 31); x[offset + 976] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 144]) & (c >> 31); x[offset + 80] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 272]) & (c >> 31); x[offset + 208] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 400]) & (c >> 31); x[offset + 336] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 528]) & (c >> 31); x[offset + 464] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 656]) & (c >> 31); x[offset + 592] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 784]) & (c >> 31); x[offset + 720] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 912]) & (c >> 31); x[offset + 848] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 1040]) & (c >> 31); x[offset + 976] ^= t; x[offset + 1040] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1168]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1296]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 1072]) & (c >> 31); x[offset + 48] ^= t; x[offset + 1072] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 1072]) & (c >> 31); x[offset + 560] ^= t; x[offset + 1072] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 1328]) & (c >> 31); x[offset + 304] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 1328]) & (c >> 31); x[offset + 816] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 560]) & (c >> 31); x[offset + 304] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 1072]) & (c >> 31); x[offset + 816] ^= t; x[offset + 1072] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 1200]) & (c >> 31); x[offset + 176] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 1200]) & (c >> 31); x[offset + 688] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 688]) & (c >> 31); x[offset + 432] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 1200]) & (c >> 31); x[offset + 944] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 304]) & (c >> 31); x[offset + 176] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 560]) & (c >> 31); x[offset + 432] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 816]) & (c >> 31); x[offset + 688] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 1072]) & (c >> 31); x[offset + 944] ^= t; x[offset + 1072] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1328]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 1136]) & (c >> 31); x[offset + 112] ^= t; x[offset + 1136] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 1136]) & (c >> 31); x[offset + 624] ^= t; x[offset + 1136] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 624]) & (c >> 31); x[offset + 368] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 1136]) & (c >> 31); x[offset + 880] ^= t; x[offset + 1136] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 1264]) & (c >> 31); x[offset + 240] ^= t; x[offset + 1264] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 1264]) & (c >> 31); x[offset + 752] ^= t; x[offset + 1264] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 752]) & (c >> 31); x[offset + 496] ^= t; x[offset + 752] ^= t;
|
||||
c = 61444 - x[offset + 1008]; t = (x[offset + 1008] ^ x[offset + 1264]) & (c >> 31); x[offset + 1008] ^= t; x[offset + 1264] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 368]) & (c >> 31); x[offset + 240] ^= t; x[offset + 368] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 624]) & (c >> 31); x[offset + 496] ^= t; x[offset + 624] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 880]) & (c >> 31); x[offset + 752] ^= t; x[offset + 880] ^= t;
|
||||
c = 61444 - x[offset + 1008]; t = (x[offset + 1008] ^ x[offset + 1136]) & (c >> 31); x[offset + 1008] ^= t; x[offset + 1136] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 176]) & (c >> 31); x[offset + 112] ^= t; x[offset + 176] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 304]) & (c >> 31); x[offset + 240] ^= t; x[offset + 304] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 432]) & (c >> 31); x[offset + 368] ^= t; x[offset + 432] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 560]) & (c >> 31); x[offset + 496] ^= t; x[offset + 560] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 688]) & (c >> 31); x[offset + 624] ^= t; x[offset + 688] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 816]) & (c >> 31); x[offset + 752] ^= t; x[offset + 816] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 944]) & (c >> 31); x[offset + 880] ^= t; x[offset + 944] ^= t;
|
||||
c = 61444 - x[offset + 1008]; t = (x[offset + 1008] ^ x[offset + 1072]) & (c >> 31); x[offset + 1008] ^= t; x[offset + 1072] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1200]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1200] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1328]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1328] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 80]) & (c >> 31); x[offset + 48] ^= t; x[offset + 80] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 144]) & (c >> 31); x[offset + 112] ^= t; x[offset + 144] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 208]) & (c >> 31); x[offset + 176] ^= t; x[offset + 208] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 272]) & (c >> 31); x[offset + 240] ^= t; x[offset + 272] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 336]) & (c >> 31); x[offset + 304] ^= t; x[offset + 336] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 400]) & (c >> 31); x[offset + 368] ^= t; x[offset + 400] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 464]) & (c >> 31); x[offset + 432] ^= t; x[offset + 464] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 528]) & (c >> 31); x[offset + 496] ^= t; x[offset + 528] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 592]) & (c >> 31); x[offset + 560] ^= t; x[offset + 592] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 656]) & (c >> 31); x[offset + 624] ^= t; x[offset + 656] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 720]) & (c >> 31); x[offset + 688] ^= t; x[offset + 720] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 784]) & (c >> 31); x[offset + 752] ^= t; x[offset + 784] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 848]) & (c >> 31); x[offset + 816] ^= t; x[offset + 848] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 912]) & (c >> 31); x[offset + 880] ^= t; x[offset + 912] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 976]) & (c >> 31); x[offset + 944] ^= t; x[offset + 976] ^= t;
|
||||
c = 61444 - x[offset + 1008]; t = (x[offset + 1008] ^ x[offset + 1040]) & (c >> 31); x[offset + 1008] ^= t; x[offset + 1040] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1104]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1104] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1168]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1168] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1232]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1232] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1296]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1296] ^= t;
|
||||
c = 61444 - x[offset + 16]; t = (x[offset + 16] ^ x[offset + 32]) & (c >> 31); x[offset + 16] ^= t; x[offset + 32] ^= t;
|
||||
c = 61444 - x[offset + 48]; t = (x[offset + 48] ^ x[offset + 64]) & (c >> 31); x[offset + 48] ^= t; x[offset + 64] ^= t;
|
||||
c = 61444 - x[offset + 80]; t = (x[offset + 80] ^ x[offset + 96]) & (c >> 31); x[offset + 80] ^= t; x[offset + 96] ^= t;
|
||||
c = 61444 - x[offset + 112]; t = (x[offset + 112] ^ x[offset + 128]) & (c >> 31); x[offset + 112] ^= t; x[offset + 128] ^= t;
|
||||
c = 61444 - x[offset + 144]; t = (x[offset + 144] ^ x[offset + 160]) & (c >> 31); x[offset + 144] ^= t; x[offset + 160] ^= t;
|
||||
c = 61444 - x[offset + 176]; t = (x[offset + 176] ^ x[offset + 192]) & (c >> 31); x[offset + 176] ^= t; x[offset + 192] ^= t;
|
||||
c = 61444 - x[offset + 208]; t = (x[offset + 208] ^ x[offset + 224]) & (c >> 31); x[offset + 208] ^= t; x[offset + 224] ^= t;
|
||||
c = 61444 - x[offset + 240]; t = (x[offset + 240] ^ x[offset + 256]) & (c >> 31); x[offset + 240] ^= t; x[offset + 256] ^= t;
|
||||
c = 61444 - x[offset + 272]; t = (x[offset + 272] ^ x[offset + 288]) & (c >> 31); x[offset + 272] ^= t; x[offset + 288] ^= t;
|
||||
c = 61444 - x[offset + 304]; t = (x[offset + 304] ^ x[offset + 320]) & (c >> 31); x[offset + 304] ^= t; x[offset + 320] ^= t;
|
||||
c = 61444 - x[offset + 336]; t = (x[offset + 336] ^ x[offset + 352]) & (c >> 31); x[offset + 336] ^= t; x[offset + 352] ^= t;
|
||||
c = 61444 - x[offset + 368]; t = (x[offset + 368] ^ x[offset + 384]) & (c >> 31); x[offset + 368] ^= t; x[offset + 384] ^= t;
|
||||
c = 61444 - x[offset + 400]; t = (x[offset + 400] ^ x[offset + 416]) & (c >> 31); x[offset + 400] ^= t; x[offset + 416] ^= t;
|
||||
c = 61444 - x[offset + 432]; t = (x[offset + 432] ^ x[offset + 448]) & (c >> 31); x[offset + 432] ^= t; x[offset + 448] ^= t;
|
||||
c = 61444 - x[offset + 464]; t = (x[offset + 464] ^ x[offset + 480]) & (c >> 31); x[offset + 464] ^= t; x[offset + 480] ^= t;
|
||||
c = 61444 - x[offset + 496]; t = (x[offset + 496] ^ x[offset + 512]) & (c >> 31); x[offset + 496] ^= t; x[offset + 512] ^= t;
|
||||
c = 61444 - x[offset + 528]; t = (x[offset + 528] ^ x[offset + 544]) & (c >> 31); x[offset + 528] ^= t; x[offset + 544] ^= t;
|
||||
c = 61444 - x[offset + 560]; t = (x[offset + 560] ^ x[offset + 576]) & (c >> 31); x[offset + 560] ^= t; x[offset + 576] ^= t;
|
||||
c = 61444 - x[offset + 592]; t = (x[offset + 592] ^ x[offset + 608]) & (c >> 31); x[offset + 592] ^= t; x[offset + 608] ^= t;
|
||||
c = 61444 - x[offset + 624]; t = (x[offset + 624] ^ x[offset + 640]) & (c >> 31); x[offset + 624] ^= t; x[offset + 640] ^= t;
|
||||
c = 61444 - x[offset + 656]; t = (x[offset + 656] ^ x[offset + 672]) & (c >> 31); x[offset + 656] ^= t; x[offset + 672] ^= t;
|
||||
c = 61444 - x[offset + 688]; t = (x[offset + 688] ^ x[offset + 704]) & (c >> 31); x[offset + 688] ^= t; x[offset + 704] ^= t;
|
||||
c = 61444 - x[offset + 720]; t = (x[offset + 720] ^ x[offset + 736]) & (c >> 31); x[offset + 720] ^= t; x[offset + 736] ^= t;
|
||||
c = 61444 - x[offset + 752]; t = (x[offset + 752] ^ x[offset + 768]) & (c >> 31); x[offset + 752] ^= t; x[offset + 768] ^= t;
|
||||
c = 61444 - x[offset + 784]; t = (x[offset + 784] ^ x[offset + 800]) & (c >> 31); x[offset + 784] ^= t; x[offset + 800] ^= t;
|
||||
c = 61444 - x[offset + 816]; t = (x[offset + 816] ^ x[offset + 832]) & (c >> 31); x[offset + 816] ^= t; x[offset + 832] ^= t;
|
||||
c = 61444 - x[offset + 848]; t = (x[offset + 848] ^ x[offset + 864]) & (c >> 31); x[offset + 848] ^= t; x[offset + 864] ^= t;
|
||||
c = 61444 - x[offset + 880]; t = (x[offset + 880] ^ x[offset + 896]) & (c >> 31); x[offset + 880] ^= t; x[offset + 896] ^= t;
|
||||
c = 61444 - x[offset + 912]; t = (x[offset + 912] ^ x[offset + 928]) & (c >> 31); x[offset + 912] ^= t; x[offset + 928] ^= t;
|
||||
c = 61444 - x[offset + 944]; t = (x[offset + 944] ^ x[offset + 960]) & (c >> 31); x[offset + 944] ^= t; x[offset + 960] ^= t;
|
||||
c = 61444 - x[offset + 976]; t = (x[offset + 976] ^ x[offset + 992]) & (c >> 31); x[offset + 976] ^= t; x[offset + 992] ^= t;
|
||||
c = 61444 - x[offset + 1008]; t = (x[offset + 1008] ^ x[offset + 1024]) & (c >> 31); x[offset + 1008] ^= t; x[offset + 1024] ^= t;
|
||||
c = 61444 - x[offset + 1040]; t = (x[offset + 1040] ^ x[offset + 1056]) & (c >> 31); x[offset + 1040] ^= t; x[offset + 1056] ^= t;
|
||||
c = 61444 - x[offset + 1072]; t = (x[offset + 1072] ^ x[offset + 1088]) & (c >> 31); x[offset + 1072] ^= t; x[offset + 1088] ^= t;
|
||||
c = 61444 - x[offset + 1104]; t = (x[offset + 1104] ^ x[offset + 1120]) & (c >> 31); x[offset + 1104] ^= t; x[offset + 1120] ^= t;
|
||||
c = 61444 - x[offset + 1136]; t = (x[offset + 1136] ^ x[offset + 1152]) & (c >> 31); x[offset + 1136] ^= t; x[offset + 1152] ^= t;
|
||||
c = 61444 - x[offset + 1168]; t = (x[offset + 1168] ^ x[offset + 1184]) & (c >> 31); x[offset + 1168] ^= t; x[offset + 1184] ^= t;
|
||||
c = 61444 - x[offset + 1200]; t = (x[offset + 1200] ^ x[offset + 1216]) & (c >> 31); x[offset + 1200] ^= t; x[offset + 1216] ^= t;
|
||||
c = 61444 - x[offset + 1232]; t = (x[offset + 1232] ^ x[offset + 1248]) & (c >> 31); x[offset + 1232] ^= t; x[offset + 1248] ^= t;
|
||||
c = 61444 - x[offset + 1264]; t = (x[offset + 1264] ^ x[offset + 1280]) & (c >> 31); x[offset + 1264] ^= t; x[offset + 1280] ^= t;
|
||||
c = 61444 - x[offset + 1296]; t = (x[offset + 1296] ^ x[offset + 1312]) & (c >> 31); x[offset + 1296] ^= t; x[offset + 1312] ^= t;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Based on the public domain C reference code for New Hope.
|
||||
* This Java version is also placed into the public domain.
|
||||
*
|
||||
* Original authors: Erdem Alkim, Léo Ducas, Thomas Pöppelmann, Peter Schwabe
|
||||
* Java port: Rhys Weatherley
|
||||
*/
|
||||
package com.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
/**
|
||||
* New Hope key exchange algorithm, "torref" variant.
|
||||
*
|
||||
* This version of New Hope implements the alternative constant-time
|
||||
* method for generating the public "a" value for anonymity networks
|
||||
* like Tor.
|
||||
*/
|
||||
open class NewHopeTor : NewHope() {
|
||||
|
||||
override fun uniform(coeffs: CharArray, seed: ByteArray) {
|
||||
val state = LongArray(25)
|
||||
val nblocks = 16
|
||||
val buf = ByteArray(SHAKE128_RATE * nblocks)
|
||||
val x = CharArray(buf.size / 2)
|
||||
|
||||
try {
|
||||
shake128_absorb(state, seed, 0, SEEDBYTES)
|
||||
do {
|
||||
shake128_squeezeblocks(buf, 0, nblocks, state)
|
||||
for (i in 0 until buf.size step 2) {
|
||||
x[i / 2] = ((buf[i].toInt() and 0xff) or ((buf[i + 1].toInt() and 0xff) shl 8)).toChar()
|
||||
}
|
||||
} while (discardtopoly(coeffs, x))
|
||||
} finally {
|
||||
state.fill(0L)
|
||||
buf.fill(0)
|
||||
x.fill(0.toChar())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun discardtopoly(coeffs: CharArray, x: CharArray): Boolean {
|
||||
for (i in 0 until 16) {
|
||||
batcher84(x, i)
|
||||
}
|
||||
|
||||
// Check whether we're safe
|
||||
var r = 0
|
||||
for (i in 1008 until 1024) {
|
||||
r = r or (61444 - x[i].code)
|
||||
}
|
||||
if ((r shr 31) != 0) return true
|
||||
|
||||
// If we are, copy coefficients to polynomial
|
||||
x.copyInto(coeffs, destinationOffset = 0, startIndex = 0, endIndex = PARAM_N)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun batcher84(x: CharArray, offset: Int) {
|
||||
fun cmpSwap(idx1: Int, idx2: Int) {
|
||||
val off1 = offset + idx1
|
||||
val off2 = offset + idx2
|
||||
val c = 61444 - x[off1].code
|
||||
val t = (x[off1].code xor x[off2].code) and (c shr 31)
|
||||
x[off1] = (x[off1].code xor t).toChar()
|
||||
x[off2] = (x[off2].code xor t).toChar()
|
||||
}
|
||||
|
||||
cmpSwap(0, 16); cmpSwap(32, 48); cmpSwap(0, 32); cmpSwap(16, 48); cmpSwap(16, 32)
|
||||
cmpSwap(64, 80); cmpSwap(96, 112); cmpSwap(64, 96); cmpSwap(80, 112); cmpSwap(80, 96)
|
||||
cmpSwap(0, 64); cmpSwap(32, 96); cmpSwap(32, 64); cmpSwap(16, 80); cmpSwap(48, 112); cmpSwap(48, 80); cmpSwap(16, 32); cmpSwap(48, 64); cmpSwap(80, 96)
|
||||
cmpSwap(128, 144); cmpSwap(160, 176); cmpSwap(128, 160); cmpSwap(144, 176); cmpSwap(144, 160)
|
||||
cmpSwap(192, 208); cmpSwap(224, 240); cmpSwap(192, 224); cmpSwap(208, 240); cmpSwap(208, 224)
|
||||
cmpSwap(128, 192); cmpSwap(160, 224); cmpSwap(160, 192); cmpSwap(144, 208); cmpSwap(176, 240); cmpSwap(176, 208); cmpSwap(144, 160); cmpSwap(176, 192); cmpSwap(208, 224)
|
||||
cmpSwap(0, 128); cmpSwap(64, 192); cmpSwap(64, 128); cmpSwap(32, 160); cmpSwap(96, 224); cmpSwap(96, 160); cmpSwap(32, 64); cmpSwap(96, 128); cmpSwap(160, 192)
|
||||
cmpSwap(16, 144); cmpSwap(80, 208); cmpSwap(80, 144); cmpSwap(48, 176); cmpSwap(112, 240); cmpSwap(112, 176); cmpSwap(48, 80); cmpSwap(112, 144); cmpSwap(176, 208)
|
||||
cmpSwap(16, 32); cmpSwap(48, 64); cmpSwap(80, 96); cmpSwap(112, 128); cmpSwap(144, 160); cmpSwap(176, 192); cmpSwap(208, 224)
|
||||
cmpSwap(256, 272); cmpSwap(288, 304); cmpSwap(256, 288); cmpSwap(272, 304); cmpSwap(272, 288)
|
||||
cmpSwap(320, 336); cmpSwap(352, 368); cmpSwap(320, 352); cmpSwap(336, 368); cmpSwap(336, 352)
|
||||
cmpSwap(256, 320); cmpSwap(288, 352); cmpSwap(288, 320); cmpSwap(272, 336); cmpSwap(304, 368); cmpSwap(304, 336); cmpSwap(272, 288); cmpSwap(304, 320); cmpSwap(336, 352)
|
||||
cmpSwap(384, 400); cmpSwap(416, 432); cmpSwap(384, 416); cmpSwap(400, 432); cmpSwap(400, 416)
|
||||
cmpSwap(448, 464); cmpSwap(480, 496); cmpSwap(448, 480); cmpSwap(464, 496); cmpSwap(464, 480)
|
||||
cmpSwap(384, 448); cmpSwap(416, 480); cmpSwap(416, 448); cmpSwap(400, 464); cmpSwap(432, 496); cmpSwap(432, 464); cmpSwap(400, 416); cmpSwap(432, 448); cmpSwap(464, 480)
|
||||
cmpSwap(256, 384); cmpSwap(320, 448); cmpSwap(320, 384); cmpSwap(288, 416); cmpSwap(352, 480); cmpSwap(352, 416); cmpSwap(288, 320); cmpSwap(352, 384); cmpSwap(416, 448)
|
||||
cmpSwap(272, 400); cmpSwap(336, 464); cmpSwap(336, 400); cmpSwap(304, 432); cmpSwap(368, 496); cmpSwap(368, 432); cmpSwap(304, 336); cmpSwap(368, 400); cmpSwap(432, 464)
|
||||
cmpSwap(272, 288); cmpSwap(304, 320); cmpSwap(336, 352); cmpSwap(368, 384); cmpSwap(400, 416); cmpSwap(432, 448); cmpSwap(464, 480)
|
||||
cmpSwap(0, 256); cmpSwap(128, 384); cmpSwap(128, 256); cmpSwap(64, 320); cmpSwap(192, 448); cmpSwap(192, 320); cmpSwap(64, 128); cmpSwap(192, 256); cmpSwap(320, 384)
|
||||
cmpSwap(32, 288); cmpSwap(160, 416); cmpSwap(160, 288); cmpSwap(96, 352); cmpSwap(224, 480); cmpSwap(224, 352); cmpSwap(96, 160); cmpSwap(224, 288); cmpSwap(352, 416)
|
||||
cmpSwap(32, 64); cmpSwap(96, 128); cmpSwap(160, 192); cmpSwap(224, 256); cmpSwap(288, 320); cmpSwap(352, 384); cmpSwap(416, 448)
|
||||
cmpSwap(16, 272); cmpSwap(144, 400); cmpSwap(144, 272); cmpSwap(80, 336); cmpSwap(208, 464); cmpSwap(208, 336); cmpSwap(80, 144); cmpSwap(208, 272); cmpSwap(336, 400)
|
||||
cmpSwap(48, 304); cmpSwap(176, 432); cmpSwap(176, 304); cmpSwap(112, 368); cmpSwap(240, 496); cmpSwap(240, 368); cmpSwap(112, 176); cmpSwap(240, 304); cmpSwap(368, 432)
|
||||
cmpSwap(48, 80); cmpSwap(112, 144); cmpSwap(176, 208); cmpSwap(240, 272); cmpSwap(304, 336); cmpSwap(368, 400); cmpSwap(432, 464)
|
||||
cmpSwap(16, 32); cmpSwap(48, 64); cmpSwap(80, 96); cmpSwap(112, 128); cmpSwap(144, 160); cmpSwap(176, 192); cmpSwap(208, 224); cmpSwap(240, 256); cmpSwap(272, 288); cmpSwap(304, 320); cmpSwap(336, 352); cmpSwap(368, 384); cmpSwap(400, 416); cmpSwap(432, 448); cmpSwap(464, 480)
|
||||
cmpSwap(512, 528); cmpSwap(544, 560); cmpSwap(512, 544); cmpSwap(528, 560); cmpSwap(528, 544)
|
||||
cmpSwap(576, 592); cmpSwap(608, 624); cmpSwap(576, 608); cmpSwap(592, 624); cmpSwap(592, 608)
|
||||
cmpSwap(512, 576); cmpSwap(544, 608); cmpSwap(544, 576); cmpSwap(528, 592); cmpSwap(560, 624); cmpSwap(560, 592); cmpSwap(528, 544); cmpSwap(560, 576); cmpSwap(592, 608)
|
||||
cmpSwap(640, 656); cmpSwap(672, 688); cmpSwap(640, 672); cmpSwap(656, 688); cmpSwap(656, 672)
|
||||
cmpSwap(704, 720); cmpSwap(736, 752); cmpSwap(704, 736); cmpSwap(720, 752); cmpSwap(720, 736)
|
||||
cmpSwap(640, 704); cmpSwap(672, 736); cmpSwap(672, 704); cmpSwap(656, 720); cmpSwap(688, 752); cmpSwap(688, 720); cmpSwap(656, 672); cmpSwap(688, 704); cmpSwap(720, 736)
|
||||
cmpSwap(512, 640); cmpSwap(576, 704); cmpSwap(576, 640); cmpSwap(544, 672); cmpSwap(608, 736); cmpSwap(608, 672); cmpSwap(544, 576); cmpSwap(608, 640); cmpSwap(672, 704)
|
||||
cmpSwap(528, 656); cmpSwap(592, 720); cmpSwap(592, 656); cmpSwap(560, 688); cmpSwap(624, 752); cmpSwap(624, 688); cmpSwap(560, 592); cmpSwap(624, 656); cmpSwap(688, 720)
|
||||
cmpSwap(528, 544); cmpSwap(560, 576); cmpSwap(592, 608); cmpSwap(624, 640); cmpSwap(656, 672); cmpSwap(688, 704); cmpSwap(720, 736)
|
||||
cmpSwap(768, 784); cmpSwap(800, 816); cmpSwap(768, 800); cmpSwap(784, 816); cmpSwap(784, 800)
|
||||
cmpSwap(832, 848); cmpSwap(864, 880); cmpSwap(832, 864); cmpSwap(848, 880); cmpSwap(848, 864)
|
||||
cmpSwap(768, 832); cmpSwap(800, 864); cmpSwap(800, 832); cmpSwap(784, 848); cmpSwap(816, 880); cmpSwap(816, 848); cmpSwap(784, 800); cmpSwap(816, 832); cmpSwap(848, 864)
|
||||
cmpSwap(896, 912); cmpSwap(928, 944); cmpSwap(896, 928); cmpSwap(912, 944); cmpSwap(912, 928)
|
||||
cmpSwap(960, 976); cmpSwap(992, 1008); cmpSwap(960, 992); cmpSwap(976, 1008); cmpSwap(976, 992)
|
||||
cmpSwap(896, 960); cmpSwap(928, 992); cmpSwap(928, 960); cmpSwap(912, 976); cmpSwap(944, 1008); cmpSwap(944, 976); cmpSwap(912, 928); cmpSwap(944, 960); cmpSwap(976, 992)
|
||||
cmpSwap(768, 896); cmpSwap(832, 960); cmpSwap(832, 896); cmpSwap(800, 928); cmpSwap(864, 992); cmpSwap(864, 928); cmpSwap(800, 832); cmpSwap(864, 896); cmpSwap(928, 960)
|
||||
cmpSwap(784, 912); cmpSwap(848, 976); cmpSwap(848, 912); cmpSwap(816, 944); cmpSwap(880, 1008); cmpSwap(880, 944); cmpSwap(816, 848); cmpSwap(880, 912); cmpSwap(944, 976)
|
||||
cmpSwap(784, 800); cmpSwap(816, 832); cmpSwap(848, 864); cmpSwap(880, 896); cmpSwap(912, 928); cmpSwap(944, 960); cmpSwap(976, 992)
|
||||
cmpSwap(512, 768); cmpSwap(640, 896); cmpSwap(640, 768); cmpSwap(576, 832); cmpSwap(704, 960); cmpSwap(704, 832); cmpSwap(576, 640); cmpSwap(704, 768); cmpSwap(832, 896)
|
||||
cmpSwap(544, 800); cmpSwap(672, 928); cmpSwap(672, 800); cmpSwap(608, 864); cmpSwap(736, 992); cmpSwap(736, 864); cmpSwap(608, 672); cmpSwap(736, 800); cmpSwap(864, 928)
|
||||
cmpSwap(544, 576); cmpSwap(608, 640); cmpSwap(672, 704); cmpSwap(736, 768); cmpSwap(800, 832); cmpSwap(864, 896); cmpSwap(928, 960)
|
||||
cmpSwap(528, 784); cmpSwap(656, 912); cmpSwap(656, 784); cmpSwap(592, 848); cmpSwap(720, 976); cmpSwap(720, 848); cmpSwap(592, 656); cmpSwap(720, 784); cmpSwap(848, 912)
|
||||
cmpSwap(560, 816); cmpSwap(688, 944); cmpSwap(688, 816); cmpSwap(624, 880); cmpSwap(752, 1008); cmpSwap(752, 880); cmpSwap(624, 688); cmpSwap(752, 816); cmpSwap(880, 944)
|
||||
cmpSwap(560, 592); cmpSwap(624, 656); cmpSwap(688, 720); cmpSwap(752, 784); cmpSwap(816, 848); cmpSwap(880, 912); cmpSwap(944, 976)
|
||||
cmpSwap(528, 544); cmpSwap(560, 576); cmpSwap(592, 608); cmpSwap(624, 640); cmpSwap(656, 672); cmpSwap(688, 704); cmpSwap(720, 736); cmpSwap(752, 768); cmpSwap(784, 800); cmpSwap(816, 832); cmpSwap(848, 864); cmpSwap(880, 896); cmpSwap(912, 928); cmpSwap(944, 960); cmpSwap(976, 992)
|
||||
cmpSwap(0, 512); cmpSwap(256, 768); cmpSwap(256, 512); cmpSwap(128, 640); cmpSwap(384, 896); cmpSwap(384, 640); cmpSwap(128, 256); cmpSwap(384, 512); cmpSwap(640, 768)
|
||||
cmpSwap(64, 576); cmpSwap(320, 832); cmpSwap(320, 576); cmpSwap(192, 704); cmpSwap(448, 960); cmpSwap(448, 704); cmpSwap(192, 320); cmpSwap(448, 576); cmpSwap(704, 832)
|
||||
cmpSwap(64, 128); cmpSwap(192, 256); cmpSwap(320, 384); cmpSwap(448, 512); cmpSwap(576, 640); cmpSwap(704, 768); cmpSwap(832, 896)
|
||||
cmpSwap(32, 544); cmpSwap(288, 800); cmpSwap(288, 544); cmpSwap(160, 672); cmpSwap(416, 928); cmpSwap(416, 672); cmpSwap(160, 288); cmpSwap(416, 544); cmpSwap(672, 800)
|
||||
cmpSwap(96, 608); cmpSwap(352, 864); cmpSwap(352, 608); cmpSwap(224, 736); cmpSwap(480, 992); cmpSwap(480, 736); cmpSwap(224, 352); cmpSwap(480, 608); cmpSwap(736, 864)
|
||||
cmpSwap(96, 160); cmpSwap(224, 288); cmpSwap(352, 416); cmpSwap(480, 544); cmpSwap(608, 672); cmpSwap(736, 800); cmpSwap(864, 928)
|
||||
cmpSwap(32, 64); cmpSwap(96, 128); cmpSwap(160, 192); cmpSwap(224, 256); cmpSwap(288, 320); cmpSwap(352, 384); cmpSwap(416, 448); cmpSwap(480, 512); cmpSwap(544, 576); cmpSwap(608, 640); cmpSwap(672, 704); cmpSwap(736, 768); cmpSwap(800, 832); cmpSwap(864, 896); cmpSwap(928, 960)
|
||||
cmpSwap(16, 528); cmpSwap(272, 784); cmpSwap(272, 528); cmpSwap(144, 656); cmpSwap(400, 912); cmpSwap(400, 656); cmpSwap(144, 272); cmpSwap(400, 528); cmpSwap(656, 784)
|
||||
cmpSwap(80, 592); cmpSwap(336, 848); cmpSwap(336, 592); cmpSwap(208, 720); cmpSwap(464, 976); cmpSwap(464, 720); cmpSwap(208, 336); cmpSwap(464, 592); cmpSwap(720, 848)
|
||||
cmpSwap(80, 144); cmpSwap(208, 272); cmpSwap(336, 400); cmpSwap(464, 528); cmpSwap(592, 656); cmpSwap(720, 784); cmpSwap(848, 912)
|
||||
cmpSwap(48, 560); cmpSwap(304, 816); cmpSwap(304, 560); cmpSwap(176, 688); cmpSwap(432, 944); cmpSwap(432, 688); cmpSwap(176, 304); cmpSwap(432, 560); cmpSwap(688, 816)
|
||||
cmpSwap(112, 624); cmpSwap(368, 880); cmpSwap(368, 624); cmpSwap(240, 752); cmpSwap(496, 1008); cmpSwap(496, 752); cmpSwap(240, 368); cmpSwap(496, 624); cmpSwap(752, 880)
|
||||
cmpSwap(112, 176); cmpSwap(240, 304); cmpSwap(368, 432); cmpSwap(496, 560); cmpSwap(624, 688); cmpSwap(752, 816); cmpSwap(880, 944)
|
||||
cmpSwap(48, 80); cmpSwap(112, 144); cmpSwap(176, 208); cmpSwap(240, 272); cmpSwap(304, 336); cmpSwap(368, 400); cmpSwap(432, 464); cmpSwap(496, 528); cmpSwap(560, 592); cmpSwap(624, 656); cmpSwap(688, 720); cmpSwap(752, 784); cmpSwap(816, 848); cmpSwap(880, 912); cmpSwap(944, 976)
|
||||
cmpSwap(16, 32); cmpSwap(48, 64); cmpSwap(80, 96); cmpSwap(112, 128); cmpSwap(144, 160); cmpSwap(176, 192); cmpSwap(208, 224); cmpSwap(240, 256); cmpSwap(272, 288); cmpSwap(304, 320); cmpSwap(336, 352); cmpSwap(368, 384); cmpSwap(400, 416); cmpSwap(432, 448); cmpSwap(464, 480); cmpSwap(496, 512); cmpSwap(528, 544); cmpSwap(560, 576); cmpSwap(592, 608); cmpSwap(624, 640); cmpSwap(656, 672); cmpSwap(688, 704); cmpSwap(720, 736); cmpSwap(752, 768); cmpSwap(784, 800); cmpSwap(816, 832); cmpSwap(848, 864); cmpSwap(880, 896); cmpSwap(912, 928); cmpSwap(944, 960); cmpSwap(976, 992)
|
||||
cmpSwap(0, 1024); cmpSwap(512, 1024); cmpSwap(256, 1280); cmpSwap(768, 1280); cmpSwap(256, 512); cmpSwap(768, 1024); cmpSwap(128, 1152); cmpSwap(640, 1152); cmpSwap(384, 640); cmpSwap(896, 1152); cmpSwap(128, 256); cmpSwap(384, 512); cmpSwap(640, 768); cmpSwap(896, 1024); cmpSwap(1152, 1280)
|
||||
cmpSwap(64, 1088); cmpSwap(576, 1088); cmpSwap(320, 576); cmpSwap(832, 1088); cmpSwap(192, 1216); cmpSwap(704, 1216); cmpSwap(448, 704); cmpSwap(960, 1216); cmpSwap(192, 320); cmpSwap(448, 576); cmpSwap(704, 832); cmpSwap(960, 1088); cmpSwap(64, 128); cmpSwap(192, 256); cmpSwap(320, 384); cmpSwap(448, 512); cmpSwap(576, 640); cmpSwap(704, 768); cmpSwap(832, 896); cmpSwap(960, 1024); cmpSwap(1088, 1152); cmpSwap(1216, 1280)
|
||||
cmpSwap(32, 1056); cmpSwap(544, 1056); cmpSwap(288, 1312); cmpSwap(800, 1312); cmpSwap(288, 544); cmpSwap(800, 1056); cmpSwap(160, 1184); cmpSwap(672, 1184); cmpSwap(416, 672); cmpSwap(928, 1184); cmpSwap(160, 288); cmpSwap(416, 544); cmpSwap(672, 800); cmpSwap(928, 1056); cmpSwap(1184, 1312)
|
||||
cmpSwap(96, 1120); cmpSwap(608, 1120); cmpSwap(352, 608); cmpSwap(864, 1120); cmpSwap(224, 1248); cmpSwap(736, 1248); cmpSwap(480, 736); cmpSwap(992, 1248); cmpSwap(224, 352); cmpSwap(480, 608); cmpSwap(736, 864); cmpSwap(992, 1120); cmpSwap(96, 160); cmpSwap(224, 288); cmpSwap(352, 416); cmpSwap(480, 544); cmpSwap(608, 672); cmpSwap(736, 800); cmpSwap(864, 928); cmpSwap(992, 1056); cmpSwap(1120, 1184); cmpSwap(1248, 1312)
|
||||
cmpSwap(32, 64); cmpSwap(96, 128); cmpSwap(160, 192); cmpSwap(224, 256); cmpSwap(288, 320); cmpSwap(352, 384); cmpSwap(416, 448); cmpSwap(480, 512); cmpSwap(544, 576); cmpSwap(608, 640); cmpSwap(672, 704); cmpSwap(736, 768); cmpSwap(800, 832); cmpSwap(864, 896); cmpSwap(928, 960); cmpSwap(992, 1024); cmpSwap(1056, 1088); cmpSwap(1120, 1152); cmpSwap(1184, 1216); cmpSwap(1248, 1280); cmpSwap(1312, 1344)
|
||||
cmpSwap(16, 1040); cmpSwap(528, 1040); cmpSwap(272, 1296); cmpSwap(784, 1296); cmpSwap(272, 528); cmpSwap(784, 1040); cmpSwap(144, 1168); cmpSwap(656, 1168); cmpSwap(400, 656); cmpSwap(912, 1168); cmpSwap(144, 272); cmpSwap(400, 528); cmpSwap(656, 784); cmpSwap(912, 1040); cmpSwap(1168, 1296)
|
||||
cmpSwap(80, 1104); cmpSwap(592, 1104); cmpSwap(336, 592); cmpSwap(848, 1104); cmpSwap(208, 1232); cmpSwap(720, 1232); cmpSwap(464, 720); cmpSwap(976, 1232); cmpSwap(208, 336); cmpSwap(464, 592); cmpSwap(720, 848); cmpSwap(976, 1104); cmpSwap(80, 144); cmpSwap(208, 272); cmpSwap(336, 400); cmpSwap(464, 528); cmpSwap(592, 656); cmpSwap(720, 784); cmpSwap(848, 912); cmpSwap(976, 1040); cmpSwap(1104, 1168); cmpSwap(1232, 1296)
|
||||
cmpSwap(48, 1072); cmpSwap(560, 1072); cmpSwap(304, 1328); cmpSwap(816, 1328); cmpSwap(304, 560); cmpSwap(816, 1072); cmpSwap(176, 1200); cmpSwap(688, 1200); cmpSwap(432, 688); cmpSwap(944, 1200); cmpSwap(176, 304); cmpSwap(432, 560); cmpSwap(688, 816); cmpSwap(944, 1072); cmpSwap(1200, 1328)
|
||||
cmpSwap(112, 1136); cmpSwap(624, 1136); cmpSwap(368, 624); cmpSwap(880, 1136); cmpSwap(240, 1264); cmpSwap(752, 1264); cmpSwap(496, 752); cmpSwap(1008, 1264); cmpSwap(240, 368); cmpSwap(496, 624); cmpSwap(752, 880); cmpSwap(1008, 1136); cmpSwap(112, 176); cmpSwap(240, 304); cmpSwap(368, 432); cmpSwap(496, 560); cmpSwap(624, 688); cmpSwap(752, 816); cmpSwap(880, 944); cmpSwap(1008, 1072); cmpSwap(1136, 1200); cmpSwap(1264, 1328)
|
||||
cmpSwap(48, 80); cmpSwap(112, 144); cmpSwap(176, 208); cmpSwap(240, 272); cmpSwap(304, 336); cmpSwap(368, 400); cmpSwap(432, 464); cmpSwap(496, 528); cmpSwap(560, 592); cmpSwap(624, 656); cmpSwap(688, 720); cmpSwap(752, 784); cmpSwap(816, 848); cmpSwap(880, 912); cmpSwap(944, 976); cmpSwap(1008, 1040); cmpSwap(1072, 1104); cmpSwap(1136, 1168); cmpSwap(1200, 1232); cmpSwap(1264, 1296); cmpSwap(1328, 1360)
|
||||
cmpSwap(16, 32); cmpSwap(48, 64); cmpSwap(80, 96); cmpSwap(112, 128); cmpSwap(144, 160); cmpSwap(176, 192); cmpSwap(208, 224); cmpSwap(240, 256); cmpSwap(272, 288); cmpSwap(304, 320); cmpSwap(336, 352); cmpSwap(368, 384); cmpSwap(400, 416); cmpSwap(432, 448); cmpSwap(464, 480); cmpSwap(496, 512); cmpSwap(528, 544); cmpSwap(560, 576); cmpSwap(592, 608); cmpSwap(624, 640); cmpSwap(656, 672); cmpSwap(688, 704); cmpSwap(720, 736); cmpSwap(752, 768); cmpSwap(784, 800); cmpSwap(816, 832); cmpSwap(848, 864); cmpSwap(880, 896); cmpSwap(912, 928); cmpSwap(944, 960); cmpSwap(976, 992); cmpSwap(1008, 1024); cmpSwap(1040, 1056); cmpSwap(1072, 1088); cmpSwap(1104, 1120); cmpSwap(1136, 1152); cmpSwap(1168, 1184); cmpSwap(1200, 1216); cmpSwap(1232, 1248); cmpSwap(1264, 1280); cmpSwap(1296, 1312); cmpSwap(1328, 1344); cmpSwap(1360, 1376)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,327 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable;
|
||||
|
||||
/**
|
||||
* Simple implementation of the Poly1305 message authenticator.
|
||||
*/
|
||||
public final class Poly1305 implements Destroyable {
|
||||
|
||||
// The 130-bit intermediate values are broken up into five 26-bit words.
|
||||
private byte[] nonce;
|
||||
private byte[] block;
|
||||
private int[] h;
|
||||
private int[] r;
|
||||
private int[] c;
|
||||
private long[] t;
|
||||
private int posn;
|
||||
|
||||
/**
|
||||
* Constructs a new Poly1305 message authenticator.
|
||||
*/
|
||||
public Poly1305()
|
||||
{
|
||||
nonce = new byte [16];
|
||||
block = new byte [16];
|
||||
h = new int [5];
|
||||
r = new int [5];
|
||||
c = new int [5];
|
||||
t = new long [10];
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the message authenticator with a new key.
|
||||
*
|
||||
* @param key The buffer containing the 32 byte key.
|
||||
* @param offset The offset into the buffer of the first key byte.
|
||||
*/
|
||||
public void reset(byte[] key, int offset)
|
||||
{
|
||||
System.arraycopy(key, offset + 16, nonce, 0, 16);
|
||||
Arrays.fill(h, 0);
|
||||
posn = 0;
|
||||
|
||||
// Convert the first 16 bytes of the key into a 130-bit
|
||||
// "r" value while masking off the bits that we don't need.
|
||||
r[0] = ((key[offset] & 0xFF)) |
|
||||
((key[offset + 1] & 0xFF) << 8) |
|
||||
((key[offset + 2] & 0xFF) << 16) |
|
||||
((key[offset + 3] & 0x03) << 24);
|
||||
r[1] = ((key[offset + 3] & 0x0C) >> 2) |
|
||||
((key[offset + 4] & 0xFC) << 6) |
|
||||
((key[offset + 5] & 0xFF) << 14) |
|
||||
((key[offset + 6] & 0x0F) << 22);
|
||||
r[2] = ((key[offset + 6] & 0xF0) >> 4) |
|
||||
((key[offset + 7] & 0x0F) << 4) |
|
||||
((key[offset + 8] & 0xFC) << 12) |
|
||||
((key[offset + 9] & 0x3F) << 20);
|
||||
r[3] = ((key[offset + 9] & 0xC0) >> 6) |
|
||||
((key[offset + 10] & 0xFF) << 2) |
|
||||
((key[offset + 11] & 0x0F) << 10) |
|
||||
((key[offset + 12] & 0xFC) << 18);
|
||||
r[4] = ((key[offset + 13] & 0xFF)) |
|
||||
((key[offset + 14] & 0xFF) << 8) |
|
||||
((key[offset + 15] & 0x0F) << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the message authenticator with more input data.
|
||||
*
|
||||
* @param data The buffer containing the input data.
|
||||
* @param offset The offset of the first byte of input.
|
||||
* @param length The number of bytes of input.
|
||||
*/
|
||||
public void update(byte[] data, int offset, int length)
|
||||
{
|
||||
while (length > 0) {
|
||||
if (posn == 0 && length >= 16) {
|
||||
// We can process the chunk directly out of the input buffer.
|
||||
processChunk(data, offset, false);
|
||||
offset += 16;
|
||||
length -= 16;
|
||||
} else {
|
||||
// Collect up partial bytes in the block buffer.
|
||||
int temp = 16 - posn;
|
||||
if (temp > length)
|
||||
temp = length;
|
||||
System.arraycopy(data, offset, block, posn, temp);
|
||||
offset += temp;
|
||||
length -= temp;
|
||||
posn += temp;
|
||||
if (posn >= 16) {
|
||||
processChunk(block, 0, false);
|
||||
posn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the input with zeroes to a multiple of 16 bytes.
|
||||
*/
|
||||
public void pad()
|
||||
{
|
||||
if (posn != 0) {
|
||||
Arrays.fill(block, posn, 16, (byte)0);
|
||||
processChunk(block, 0, false);
|
||||
posn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the message authenticator and returns the 16-byte token.
|
||||
*
|
||||
* @param token The buffer to receive the token.
|
||||
* @param offset The offset of the token in the buffer.
|
||||
*/
|
||||
public void finish(byte[] token, int offset)
|
||||
{
|
||||
// Pad and flush the final chunk.
|
||||
if (posn != 0) {
|
||||
block[posn] = (byte)1;
|
||||
Arrays.fill(block, posn + 1, 16, (byte)0);
|
||||
processChunk(block, 0, true);
|
||||
}
|
||||
|
||||
// At this point, processChunk() has left h as a partially reduced
|
||||
// result that is less than (2^130 - 5) * 6. Perform one more
|
||||
// reduction and a trial subtraction to produce the final result.
|
||||
|
||||
// Multiply the high bits of h by 5 and add them to the 130 low bits.
|
||||
int carry = (h[4] >> 26) * 5 + h[0];
|
||||
h[0] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[1];
|
||||
h[1] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[2];
|
||||
h[2] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[3];
|
||||
h[3] = carry & 0x03FFFFFF;
|
||||
h[4] = (carry >> 26) + (h[4] & 0x03FFFFFF);
|
||||
|
||||
// Subtract (2^130 - 5) from h by computing c = h + 5 - 2^130.
|
||||
// The "minus 2^130" step is implicit.
|
||||
carry = 5 + h[0];
|
||||
c[0] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[1];
|
||||
c[1] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[2];
|
||||
c[2] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[3];
|
||||
c[3] = carry & 0x03FFFFFF;
|
||||
c[4] = (carry >> 26) + h[4];
|
||||
|
||||
// Borrow occurs if bit 2^130 of the previous c result is zero.
|
||||
// Carefully turn this into a selection mask so we can select either
|
||||
// h or c as the final result.
|
||||
int mask = -((c[4] >> 26) & 0x01);
|
||||
int nmask = ~mask;
|
||||
h[0] = (h[0] & nmask) | (c[0] & mask);
|
||||
h[1] = (h[1] & nmask) | (c[1] & mask);
|
||||
h[2] = (h[2] & nmask) | (c[2] & mask);
|
||||
h[3] = (h[3] & nmask) | (c[3] & mask);
|
||||
h[4] = (h[4] & nmask) | (c[4] & mask);
|
||||
|
||||
// Convert h into little-endian in the block buffer.
|
||||
block[0] = (byte)(h[0]);
|
||||
block[1] = (byte)(h[0] >> 8);
|
||||
block[2] = (byte)(h[0] >> 16);
|
||||
block[3] = (byte)((h[0] >> 24) | (h[1] << 2));
|
||||
block[4] = (byte)(h[1] >> 6);
|
||||
block[5] = (byte)(h[1] >> 14);
|
||||
block[6] = (byte)((h[1] >> 22) | (h[2] << 4));
|
||||
block[7] = (byte)(h[2] >> 4);
|
||||
block[8] = (byte)(h[2] >> 12);
|
||||
block[9] = (byte)((h[2] >> 20) | (h[3] << 6));
|
||||
block[10] = (byte)(h[3] >> 2);
|
||||
block[11] = (byte)(h[3] >> 10);
|
||||
block[12] = (byte)(h[3] >> 18);
|
||||
block[13] = (byte)(h[4]);
|
||||
block[14] = (byte)(h[4] >> 8);
|
||||
block[15] = (byte)(h[4] >> 16);
|
||||
|
||||
// Add the nonce and write the final result to the token.
|
||||
carry = (nonce[0] & 0xFF) + (block[0] & 0xFF);
|
||||
token[offset] = (byte)carry;
|
||||
for (int x = 1; x < 16; ++x) {
|
||||
carry = (carry >> 8) + (nonce[x] & 0xFF) + (block[x] & 0xFF);
|
||||
token[offset + x] = (byte)carry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the next chunk of input data.
|
||||
*
|
||||
* @param chunk Buffer containing the input data chunk.
|
||||
* @param offset Offset of the first byte of the 16-byte chunk.
|
||||
* @param finalChunk Set to true if this is the final chunk.
|
||||
*/
|
||||
private void processChunk(byte[] chunk, int offset, boolean finalChunk)
|
||||
{
|
||||
int x;
|
||||
|
||||
// Unpack the 128-bit chunk into a 130-bit value in "c".
|
||||
c[0] = ((chunk[offset] & 0xFF)) |
|
||||
((chunk[offset + 1] & 0xFF) << 8) |
|
||||
((chunk[offset + 2] & 0xFF) << 16) |
|
||||
((chunk[offset + 3] & 0x03) << 24);
|
||||
c[1] = ((chunk[offset + 3] & 0xFC) >> 2) |
|
||||
((chunk[offset + 4] & 0xFF) << 6) |
|
||||
((chunk[offset + 5] & 0xFF) << 14) |
|
||||
((chunk[offset + 6] & 0x0F) << 22);
|
||||
c[2] = ((chunk[offset + 6] & 0xF0) >> 4) |
|
||||
((chunk[offset + 7] & 0xFF) << 4) |
|
||||
((chunk[offset + 8] & 0xFF) << 12) |
|
||||
((chunk[offset + 9] & 0x3F) << 20);
|
||||
c[3] = ((chunk[offset + 9] & 0xC0) >> 6) |
|
||||
((chunk[offset + 10] & 0xFF) << 2) |
|
||||
((chunk[offset + 11] & 0xFF) << 10) |
|
||||
((chunk[offset + 12] & 0xFF) << 18);
|
||||
c[4] = ((chunk[offset + 13] & 0xFF)) |
|
||||
((chunk[offset + 14] & 0xFF) << 8) |
|
||||
((chunk[offset + 15] & 0xFF) << 16);
|
||||
if (!finalChunk)
|
||||
c[4] |= (1 << 24);
|
||||
|
||||
// Compute h = ((h + c) * r) mod (2^130 - 5)
|
||||
|
||||
// Start with h += c. We assume that h is less than (2^130 - 5) * 6
|
||||
// and that c is less than 2^129, so the result will be less than 2^133.
|
||||
h[0] += c[0];
|
||||
h[1] += c[1];
|
||||
h[2] += c[2];
|
||||
h[3] += c[3];
|
||||
h[4] += c[4];
|
||||
|
||||
// Multiply h by r. We know that r is less than 2^124 because the
|
||||
// top 4 bits were AND-ed off by reset(). That makes h * r less
|
||||
// than 2^257. Which is less than the (2^130 - 6)^2 we want for
|
||||
// the modulo reduction step that follows. The intermediate limbs
|
||||
// are 52 bits in size, which allows us to collect up carries in the
|
||||
// extra bits of the 64 bit longs and propagate them later.
|
||||
long hv = h[0];
|
||||
t[0] = hv * r[0];
|
||||
t[1] = hv * r[1];
|
||||
t[2] = hv * r[2];
|
||||
t[3] = hv * r[3];
|
||||
t[4] = hv * r[4];
|
||||
for (x = 1; x < 5; ++x) {
|
||||
hv = h[x];
|
||||
t[x] += hv * r[0];
|
||||
t[x + 1] += hv * r[1];
|
||||
t[x + 2] += hv * r[2];
|
||||
t[x + 3] += hv * r[3];
|
||||
t[x + 4] = hv * r[4];
|
||||
}
|
||||
|
||||
// Propagate carries to convert the t limbs from 52-bit back to 26-bit.
|
||||
// The low bits are placed into h and the high bits are placed into c.
|
||||
h[0] = ((int)t[0]) & 0x03FFFFFF;
|
||||
hv = t[1] + (t[0] >> 26);
|
||||
h[1] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[2] + (hv >> 26);
|
||||
h[2] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[3] + (hv >> 26);
|
||||
h[3] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[4] + (hv >> 26);
|
||||
h[4] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[5] + (hv >> 26);
|
||||
c[0] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[6] + (hv >> 26);
|
||||
c[1] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[7] + (hv >> 26);
|
||||
c[2] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[8] + (hv >> 26);
|
||||
c[3] = ((int)hv) & 0x03FFFFFF;
|
||||
hv = t[9] + (hv >> 26);
|
||||
c[4] = ((int)hv);
|
||||
|
||||
// Reduce h * r modulo (2^130 - 5) by multiplying the high 130 bits by 5
|
||||
// and adding them to the low 130 bits. This will leave the result at
|
||||
// most 5 subtractions away from the answer we want.
|
||||
int carry = h[0] + c[0] * 5;
|
||||
h[0] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[1] + c[1] * 5;
|
||||
h[1] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[2] + c[2] * 5;
|
||||
h[2] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[3] + c[3] * 5;
|
||||
h[3] = carry & 0x03FFFFFF;
|
||||
carry = (carry >> 26) + h[4] + c[4] * 5;
|
||||
h[4] = carry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Arrays.fill(nonce, (byte)0);
|
||||
Arrays.fill(block, (byte)0);
|
||||
Arrays.fill(h, (int)0);
|
||||
Arrays.fill(r, (int)0);
|
||||
Arrays.fill(c, (int)0);
|
||||
Arrays.fill(t, (long)0);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable
|
||||
|
||||
|
||||
/**
|
||||
* Simple implementation of the Poly1305 message authenticator.
|
||||
*/
|
||||
class Poly1305 : Destroyable {
|
||||
// The 130-bit intermediate values are broken up into five 26-bit words.
|
||||
private val nonce = ByteArray(16)
|
||||
private val block = ByteArray(16)
|
||||
private val h = IntArray(5)
|
||||
private val r = IntArray(5)
|
||||
private val c = IntArray(5)
|
||||
private val t = LongArray(10)
|
||||
private var posn = 0
|
||||
|
||||
|
||||
/**
|
||||
* Resets the message authenticator with a new key.
|
||||
*
|
||||
* @param key The buffer containing the 32 byte key.
|
||||
* @param offset The offset into the buffer of the first key byte.
|
||||
*/
|
||||
fun reset(key: ByteArray, offset: Int) {
|
||||
|
||||
// Kotlin KMP Array Copy
|
||||
key.copyInto(destination = nonce, destinationOffset = 0, startIndex = offset + 16, endIndex = offset + 32)
|
||||
|
||||
h.fill(0)
|
||||
posn = 0
|
||||
|
||||
|
||||
// Convert the first 16 bytes of the key into a 130-bit
|
||||
// "r" value while masking off the bits that we don't need.
|
||||
r[0] = ((key[offset].toInt() and 0xFF)) or
|
||||
((key[offset + 1].toInt() and 0xFF) shl 8) or
|
||||
((key[offset + 2].toInt() and 0xFF) shl 16) or
|
||||
((key[offset + 3].toInt() and 0x03) shl 24)
|
||||
r[1] = ((key[offset + 3].toInt() and 0x0C) shr 2) or
|
||||
((key[offset + 4].toInt() and 0xFC) shl 6) or
|
||||
((key[offset + 5].toInt() and 0xFF) shl 14) or
|
||||
((key[offset + 6].toInt() and 0x0F) shl 22)
|
||||
r[2] = ((key[offset + 6].toInt() and 0xF0) shr 4) or
|
||||
((key[offset + 7].toInt() and 0x0F) shl 4) or
|
||||
((key[offset + 8].toInt() and 0xFC) shl 12) or
|
||||
((key[offset + 9].toInt() and 0x3F) shl 20)
|
||||
r[3] = ((key[offset + 9].toInt() and 0xC0) shr 6) or
|
||||
((key[offset + 10].toInt() and 0xFF) shl 2) or
|
||||
((key[offset + 11].toInt() and 0x0F) shl 10) or
|
||||
((key[offset + 12].toInt() and 0xFC) shl 18)
|
||||
r[4] = ((key[offset + 13].toInt() and 0xFF)) or
|
||||
((key[offset + 14].toInt() and 0xFF) shl 8) or
|
||||
((key[offset + 15].toInt() and 0x0F) shl 16)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the message authenticator with more input data.
|
||||
*
|
||||
* @param data The buffer containing the input data.
|
||||
* @param offset The offset of the first byte of input.
|
||||
* @param length The number of bytes of input.
|
||||
*/
|
||||
fun update(data: ByteArray, offset: Int, length: Int) {
|
||||
var offset = offset
|
||||
var length = length
|
||||
while (length > 0) {
|
||||
if (posn == 0 && length >= 16) {
|
||||
// We can process the chunk directly out of the input buffer.
|
||||
processChunk(data, offset, false)
|
||||
offset += 16
|
||||
length -= 16
|
||||
} else {
|
||||
// Collect up partial bytes in the block buffer.
|
||||
var temp = 16 - posn
|
||||
if (temp > length) temp = length
|
||||
System.arraycopy(data, offset, block, posn, temp)
|
||||
offset += temp
|
||||
length -= temp
|
||||
posn += temp
|
||||
if (posn >= 16) {
|
||||
processChunk(block, 0, false)
|
||||
posn = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the input with zeroes to a multiple of 16 bytes.
|
||||
*/
|
||||
fun pad() {
|
||||
if (posn != 0) {
|
||||
// Kotlin Array Fill
|
||||
block.fill(0.toByte(), fromIndex = posn, toIndex = 16)
|
||||
processChunk(block, 0, false)
|
||||
posn = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the message authenticator and returns the 16-byte token.
|
||||
*
|
||||
* @param token The buffer to receive the token.
|
||||
* @param offset The offset of the token in the buffer.
|
||||
*/
|
||||
fun finish(token: ByteArray, offset: Int) {
|
||||
// Pad and flush the final chunk.
|
||||
if (posn != 0) {
|
||||
block[posn] = 1.toByte()
|
||||
block.fill(0.toByte(), fromIndex = posn + 1, toIndex = 16)
|
||||
processChunk(block, 0, true)
|
||||
}
|
||||
|
||||
|
||||
// At this point, processChunk() has left h as a partially reduced
|
||||
// result that is less than (2^130 - 5) * 6. Perform one more
|
||||
// reduction and a trial subtraction to produce the final result.
|
||||
|
||||
// Multiply the high bits of h by 5 and add them to the 130 low bits.
|
||||
var carry = (h[4] shr 26) * 5 + h[0]
|
||||
h[0] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[1]
|
||||
h[1] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[2]
|
||||
h[2] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[3]
|
||||
h[3] = carry and 0x03FFFFFF
|
||||
h[4] = (carry shr 26) + (h[4] and 0x03FFFFFF)
|
||||
|
||||
// Subtract (2^130 - 5) from h by computing c = h + 5 - 2^130.
|
||||
// The "minus 2^130" step is implicit.
|
||||
carry = 5 + h[0]
|
||||
c[0] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[1]
|
||||
c[1] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[2]
|
||||
c[2] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[3]
|
||||
c[3] = carry and 0x03FFFFFF
|
||||
c[4] = (carry shr 26) + h[4]
|
||||
|
||||
// Borrow occurs if bit 2^130 of the previous c result is zero.
|
||||
// Carefully turn this into a selection mask so we can select either
|
||||
// h or c as the final result.
|
||||
val mask = -((c[4] shr 26) and 0x01)
|
||||
val nmask = mask.inv()
|
||||
h[0] = (h[0] and nmask) or (c[0] and mask)
|
||||
h[1] = (h[1] and nmask) or (c[1] and mask)
|
||||
h[2] = (h[2] and nmask) or (c[2] and mask)
|
||||
h[3] = (h[3] and nmask) or (c[3] and mask)
|
||||
h[4] = (h[4] and nmask) or (c[4] and mask)
|
||||
|
||||
|
||||
// Convert h into little-endian in the block buffer.
|
||||
block[0] = (h[0]).toByte()
|
||||
block[1] = (h[0] shr 8).toByte()
|
||||
block[2] = (h[0] shr 16).toByte()
|
||||
block[3] = ((h[0] shr 24) or (h[1] shl 2)).toByte()
|
||||
block[4] = (h[1] shr 6).toByte()
|
||||
block[5] = (h[1] shr 14).toByte()
|
||||
block[6] = ((h[1] shr 22) or (h[2] shl 4)).toByte()
|
||||
block[7] = (h[2] shr 4).toByte()
|
||||
block[8] = (h[2] shr 12).toByte()
|
||||
block[9] = ((h[2] shr 20) or (h[3] shl 6)).toByte()
|
||||
block[10] = (h[3] shr 2).toByte()
|
||||
block[11] = (h[3] shr 10).toByte()
|
||||
block[12] = (h[3] shr 18).toByte()
|
||||
block[13] = (h[4]).toByte()
|
||||
block[14] = (h[4] shr 8).toByte()
|
||||
block[15] = (h[4] shr 16).toByte()
|
||||
|
||||
|
||||
// Add the nonce and write the final result to the token.
|
||||
carry = (nonce[0].toInt() and 0xFF) + (block[0].toInt() and 0xFF)
|
||||
token[offset] = carry.toByte()
|
||||
for (x in 1..15) {
|
||||
carry = (carry shr 8) + (nonce[x].toInt() and 0xFF) + (block[x].toInt() and 0xFF)
|
||||
token[offset + x] = carry.toByte()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the next chunk of input data.
|
||||
*
|
||||
* @param chunk Buffer containing the input data chunk.
|
||||
* @param offset Offset of the first byte of the 16-byte chunk.
|
||||
* @param finalChunk Set to true if this is the final chunk.
|
||||
*/
|
||||
private fun processChunk(chunk: ByteArray, offset: Int, finalChunk: Boolean) {
|
||||
|
||||
// Unpack the 128-bit chunk into a 130-bit value in "c".
|
||||
c[0] = ((chunk[offset].toInt() and 0xFF)) or
|
||||
((chunk[offset + 1].toInt() and 0xFF) shl 8) or
|
||||
((chunk[offset + 2].toInt() and 0xFF) shl 16) or
|
||||
((chunk[offset + 3].toInt() and 0x03) shl 24)
|
||||
c[1] = ((chunk[offset + 3].toInt() and 0xFC) shr 2) or
|
||||
((chunk[offset + 4].toInt() and 0xFF) shl 6) or
|
||||
((chunk[offset + 5].toInt() and 0xFF) shl 14) or
|
||||
((chunk[offset + 6].toInt() and 0x0F) shl 22)
|
||||
c[2] = ((chunk[offset + 6].toInt() and 0xF0) shr 4) or
|
||||
((chunk[offset + 7].toInt() and 0xFF) shl 4) or
|
||||
((chunk[offset + 8].toInt() and 0xFF) shl 12) or
|
||||
((chunk[offset + 9].toInt() and 0x3F) shl 20)
|
||||
c[3] = ((chunk[offset + 9].toInt() and 0xC0) shr 6) or
|
||||
((chunk[offset + 10].toInt() and 0xFF) shl 2) or
|
||||
((chunk[offset + 11].toInt() and 0xFF) shl 10) or
|
||||
((chunk[offset + 12].toInt() and 0xFF) shl 18)
|
||||
c[4] = ((chunk[offset + 13].toInt() and 0xFF)) or
|
||||
((chunk[offset + 14].toInt() and 0xFF) shl 8) or
|
||||
((chunk[offset + 15].toInt() and 0xFF) shl 16)
|
||||
if (!finalChunk) c[4] = c[4] or (1 shl 24)
|
||||
|
||||
|
||||
// Compute h = ((h + c) * r) mod (2^130 - 5)
|
||||
|
||||
// Start with h += c. We assume that h is less than (2^130 - 5) * 6
|
||||
// and that c is less than 2^129, so the result will be less than 2^133.
|
||||
h[0] += c[0]
|
||||
h[1] += c[1]
|
||||
h[2] += c[2]
|
||||
h[3] += c[3]
|
||||
h[4] += c[4]
|
||||
|
||||
// Multiply h by r. We know that r is less than 2^124 because the
|
||||
// top 4 bits were AND-ed off by reset(). That makes h * r less
|
||||
// than 2^257. Which is less than the (2^130 - 6)^2 we want for
|
||||
// the modulo reduction step that follows. The intermediate limbs
|
||||
// are 52 bits in size, which allows us to collect up carries in the
|
||||
// extra bits of the 64 bit longs and propagate them later.
|
||||
var hv = h[0].toLong()
|
||||
t[0] = hv * r[0]
|
||||
t[1] = hv * r[1]
|
||||
t[2] = hv * r[2]
|
||||
t[3] = hv * r[3]
|
||||
t[4] = hv * r[4]
|
||||
|
||||
for (x in 1 until 5) {
|
||||
hv = h[x].toLong()
|
||||
t[x] += hv * r[0]
|
||||
t[x + 1] += hv * r[1]
|
||||
t[x + 2] += hv * r[2]
|
||||
t[x + 3] += hv * r[3]
|
||||
t[x + 4] = hv * r[4]
|
||||
}
|
||||
|
||||
|
||||
// Propagate carries to convert the t limbs from 52-bit back to 26-bit.
|
||||
// The low bits are placed into h and the high bits are placed into c.
|
||||
h[0] = (t[0].toInt()) and 0x03FFFFFF
|
||||
hv = t[1] + (t[0] shr 26)
|
||||
h[1] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[2] + (hv shr 26)
|
||||
h[2] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[3] + (hv shr 26)
|
||||
h[3] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[4] + (hv shr 26)
|
||||
h[4] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[5] + (hv shr 26)
|
||||
c[0] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[6] + (hv shr 26)
|
||||
c[1] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[7] + (hv shr 26)
|
||||
c[2] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[8] + (hv shr 26)
|
||||
c[3] = (hv.toInt()) and 0x03FFFFFF
|
||||
hv = t[9] + (hv shr 26)
|
||||
c[4] = (hv.toInt())
|
||||
|
||||
|
||||
// Reduce h * r modulo (2^130 - 5) by multiplying the high 130 bits by 5
|
||||
// and adding them to the low 130 bits. This will leave the result at
|
||||
// most 5 subtractions away from the answer we want.
|
||||
var carry = h[0] + c[0] * 5
|
||||
h[0] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[1] + c[1] * 5
|
||||
h[1] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[2] + c[2] * 5
|
||||
h[2] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[3] + c[3] * 5
|
||||
h[3] = carry and 0x03FFFFFF
|
||||
carry = (carry shr 26) + h[4] + c[4] * 5
|
||||
h[4] = carry
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
// Kotlin Array Fill
|
||||
nonce.fill(0.toByte())
|
||||
block.fill(0.toByte())
|
||||
h.fill(0)
|
||||
r.fill(0)
|
||||
c.fill(0)
|
||||
t.fill(0L)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable;
|
||||
|
||||
/**
|
||||
* Fallback implementation of SHA256.
|
||||
*/
|
||||
public class SHA256MessageDigest extends MessageDigest implements Destroyable {
|
||||
|
||||
private int[] h;
|
||||
private byte[] block;
|
||||
private int[] w;
|
||||
private long length;
|
||||
private int posn;
|
||||
|
||||
/**
|
||||
* Constructs a new SHA256 message digest object.
|
||||
*/
|
||||
public SHA256MessageDigest() {
|
||||
super("SHA-256");
|
||||
h = new int [8];
|
||||
block = new byte [64];
|
||||
w = new int [64];
|
||||
engineReset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Arrays.fill(h, (int)0);
|
||||
Arrays.fill(block, (byte)0);
|
||||
Arrays.fill(w, (int)0);
|
||||
}
|
||||
|
||||
private static void writeBE32(byte[] buf, int offset, int value)
|
||||
{
|
||||
buf[offset] = (byte)(value >> 24);
|
||||
buf[offset + 1] = (byte)(value >> 16);
|
||||
buf[offset + 2] = (byte)(value >> 8);
|
||||
buf[offset + 3] = (byte)value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineDigest() {
|
||||
byte[] digest = new byte [32];
|
||||
try {
|
||||
engineDigest(digest, 0, 32);
|
||||
} catch (DigestException e) {
|
||||
// Shouldn't happen, but just in case.
|
||||
Arrays.fill(digest, (byte)0);
|
||||
}
|
||||
return digest;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineDigest(byte[] buf, int offset, int len) throws DigestException
|
||||
{
|
||||
if (len < 32)
|
||||
throw new DigestException("Invalid digest length for SHA256");
|
||||
if (posn <= (64 - 9)) {
|
||||
block[posn] = (byte)0x80;
|
||||
Arrays.fill(block, posn + 1, 64 - 8, (byte)0);
|
||||
} else {
|
||||
block[posn] = (byte)0x80;
|
||||
Arrays.fill(block, posn + 1, 64, (byte)0);
|
||||
transform(block, 0);
|
||||
Arrays.fill(block, 0, 64 - 8, (byte)0);
|
||||
}
|
||||
writeBE32(block, 64 - 8, (int)(length >> 32));
|
||||
writeBE32(block, 64 - 4, (int)length);
|
||||
transform(block, 0);
|
||||
posn = 0;
|
||||
for (int index = 0; index < 8; ++index)
|
||||
writeBE32(buf, offset + index * 4, h[index]);
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineGetDigestLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineReset() {
|
||||
h[0] = 0x6A09E667;
|
||||
h[1] = 0xBB67AE85;
|
||||
h[2] = 0x3C6EF372;
|
||||
h[3] = 0xA54FF53A;
|
||||
h[4] = 0x510E527F;
|
||||
h[5] = 0x9B05688C;
|
||||
h[6] = 0x1F83D9AB;
|
||||
h[7] = 0x5BE0CD19;
|
||||
length = 0;
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte input) {
|
||||
block[posn++] = input;
|
||||
length += 8;
|
||||
if (posn >= 64) {
|
||||
transform(block, 0);
|
||||
posn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte[] input, int offset, int len) {
|
||||
while (len > 0) {
|
||||
if (posn == 0 && len >= 64) {
|
||||
transform(input, offset);
|
||||
offset += 64;
|
||||
len -= 64;
|
||||
length += 64 * 8;
|
||||
} else {
|
||||
int temp = 64 - posn;
|
||||
if (temp > len)
|
||||
temp = len;
|
||||
System.arraycopy(input, offset, block, posn, temp);
|
||||
posn += temp;
|
||||
length += temp * 8;
|
||||
if (posn >= 64) {
|
||||
transform(block, 0);
|
||||
posn = 0;
|
||||
}
|
||||
offset += temp;
|
||||
len -= temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int[] k = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
private static int rightRotate(int value, int n)
|
||||
{
|
||||
return (value >>> n) | (value << (32 - n));
|
||||
}
|
||||
|
||||
private void transform(byte[] m, int offset)
|
||||
{
|
||||
int a, b, c, d, e, f, g, h;
|
||||
int temp1, temp2;
|
||||
int index;
|
||||
|
||||
// Initialize working variables to the current hash value.
|
||||
a = this.h[0];
|
||||
b = this.h[1];
|
||||
c = this.h[2];
|
||||
d = this.h[3];
|
||||
e = this.h[4];
|
||||
f = this.h[5];
|
||||
g = this.h[6];
|
||||
h = this.h[7];
|
||||
|
||||
// Convert the 16 input message words from big endian to host byte order.
|
||||
for (index = 0; index < 16; ++index) {
|
||||
w[index] = ((m[offset] & 0xFF) << 24) |
|
||||
((m[offset + 1] & 0xFF) << 16) |
|
||||
((m[offset + 2] & 0xFF) << 8) |
|
||||
(m[offset + 3] & 0xFF);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
// Extend the first 16 words to 64.
|
||||
for (index = 16; index < 64; ++index) {
|
||||
w[index] = w[index - 16] + w[index - 7] +
|
||||
(rightRotate(w[index - 15], 7) ^
|
||||
rightRotate(w[index - 15], 18) ^
|
||||
(w[index - 15] >>> 3)) +
|
||||
(rightRotate(w[index - 2], 17) ^
|
||||
rightRotate(w[index - 2], 19) ^
|
||||
(w[index - 2] >>> 10));
|
||||
}
|
||||
|
||||
// Compression function main loop.
|
||||
for (index = 0; index < 64; ++index) {
|
||||
temp1 = (h) + k[index] + w[index] +
|
||||
(rightRotate((e), 6) ^ rightRotate((e), 11) ^ rightRotate((e), 25)) +
|
||||
(((e) & (f)) ^ ((~(e)) & (g)));
|
||||
temp2 = (rightRotate((a), 2) ^ rightRotate((a), 13) ^ rightRotate((a), 22)) +
|
||||
(((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c)));
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + temp1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = temp1 + temp2;
|
||||
}
|
||||
|
||||
// Add the compressed chunk to the current hash value.
|
||||
this.h[0] += a;
|
||||
this.h[1] += b;
|
||||
this.h[2] += c;
|
||||
this.h[3] += d;
|
||||
this.h[4] += e;
|
||||
this.h[5] += f;
|
||||
this.h[6] += g;
|
||||
this.h[7] += h;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable
|
||||
import java.security.DigestException
|
||||
import java.security.MessageDigest
|
||||
|
||||
|
||||
/**
|
||||
* Fallback implementation of SHA256.
|
||||
*/
|
||||
class SHA256MessageDigest : MessageDigest("SHA-256"), Destroyable {
|
||||
private val h = IntArray(8)
|
||||
private val block = ByteArray(64)
|
||||
private val w = IntArray(64)
|
||||
private var length: Long = 0
|
||||
private var posn = 0
|
||||
|
||||
init {
|
||||
engineReset()
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
h.fill(0)
|
||||
block.fill(0.toByte())
|
||||
w.fill(0)
|
||||
}
|
||||
|
||||
override fun engineDigest(): ByteArray {
|
||||
val digest = ByteArray(32)
|
||||
try {
|
||||
engineDigest(digest, 0, 32)
|
||||
} catch (e: DigestException) {
|
||||
// Shouldn't happen, but just in case.
|
||||
digest.fill(0.toByte())
|
||||
}
|
||||
return digest
|
||||
}
|
||||
|
||||
@Throws(DigestException::class)
|
||||
override fun engineDigest(buf: ByteArray, offset: Int, len: Int): Int {
|
||||
if (len < 32) throw DigestException("Invalid digest length for SHA256")
|
||||
if (posn <= (64 - 9)) {
|
||||
block[posn] = 0x80.toByte()
|
||||
block.fill(0.toByte(), posn + 1, 64 - 8)
|
||||
} else {
|
||||
block[posn] = 0x80.toByte()
|
||||
block.fill(0.toByte(), posn + 1, 64)
|
||||
transform(block, 0)
|
||||
block.fill(0.toByte(), 0, 64 - 8)
|
||||
}
|
||||
writeBE32(block, 64 - 8, (length shr 32).toInt())
|
||||
writeBE32(block, 64 - 4, length.toInt())
|
||||
transform(block, 0)
|
||||
posn = 0
|
||||
for (index in 0..7) writeBE32(buf, offset + index * 4, h[index])
|
||||
return 32
|
||||
}
|
||||
|
||||
override fun engineGetDigestLength(): Int {
|
||||
return 32
|
||||
}
|
||||
|
||||
override fun engineReset() {
|
||||
h[0] = 0x6A09E667
|
||||
h[1] = -0x4498517b
|
||||
h[2] = 0x3C6EF372
|
||||
h[3] = -0x5ab00ac6
|
||||
h[4] = 0x510E527F
|
||||
h[5] = -0x64fa9774
|
||||
h[6] = 0x1F83D9AB
|
||||
h[7] = 0x5BE0CD19
|
||||
length = 0
|
||||
posn = 0
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: Byte) {
|
||||
block[posn++] = input
|
||||
length += 8
|
||||
if (posn >= 64) {
|
||||
transform(block, 0)
|
||||
posn = 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: ByteArray, offset: Int, len: Int) {
|
||||
var offset = offset
|
||||
var len = len
|
||||
while (len > 0) {
|
||||
if (posn == 0 && len >= 64) {
|
||||
transform(input, offset)
|
||||
offset += 64
|
||||
len -= 64
|
||||
length += (64 * 8).toLong()
|
||||
} else {
|
||||
var temp = 64 - posn
|
||||
if (temp > len) temp = len
|
||||
System.arraycopy(input, offset, block, posn, temp)
|
||||
posn += temp
|
||||
length += (temp * 8).toLong()
|
||||
if (posn >= 64) {
|
||||
transform(block, 0)
|
||||
posn = 0
|
||||
}
|
||||
offset += temp
|
||||
len -= temp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transform(m: ByteArray, offset: Int) {
|
||||
var currentOffset = offset
|
||||
|
||||
// Initialize working variables to the current hash value.
|
||||
var a = this.h[0]
|
||||
var b = this.h[1]
|
||||
var c = this.h[2]
|
||||
var d = this.h[3]
|
||||
var e = this.h[4]
|
||||
var f = this.h[5]
|
||||
var g = this.h[6]
|
||||
var h = this.h[7]
|
||||
|
||||
// Convert the 16 input message words from big endian to host byte order.
|
||||
for (index in 0 until 16) {
|
||||
w[index] = ((m[currentOffset].toInt() and 0xFF) shl 24) or
|
||||
((m[currentOffset + 1].toInt() and 0xFF) shl 16) or
|
||||
((m[currentOffset + 2].toInt() and 0xFF) shl 8) or
|
||||
(m[currentOffset + 3].toInt() and 0xFF)
|
||||
currentOffset += 4
|
||||
}
|
||||
|
||||
|
||||
// Extend the first 16 words to 64.
|
||||
for (index in 16 until 64) {
|
||||
w[index] = w[index - 16] + w[index - 7] +
|
||||
(rightRotate(w[index - 15], 7) xor
|
||||
rightRotate(w[index - 15], 18) xor
|
||||
(w[index - 15] ushr 3)) +
|
||||
(rightRotate(w[index - 2], 17) xor
|
||||
rightRotate(w[index - 2], 19) xor
|
||||
(w[index - 2] ushr 10))
|
||||
}
|
||||
|
||||
|
||||
// Compression function main loop.
|
||||
for (index in 0 until 64) {
|
||||
val temp1 = h + k[index] + w[index] +
|
||||
(rightRotate(e, 6) xor rightRotate(e, 11) xor rightRotate(e, 25)) +
|
||||
((e and f) xor (e.inv() and g))
|
||||
val temp2 = (rightRotate(a, 2) xor rightRotate(a, 13) xor rightRotate(a, 22)) +
|
||||
((a and b) xor (a and c) xor (b and c))
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = d + temp1
|
||||
d = c
|
||||
c = b
|
||||
b = a
|
||||
a = temp1 + temp2
|
||||
}
|
||||
|
||||
// Add the compressed chunk to the current hash value.
|
||||
this.h[0] += a
|
||||
this.h[1] += b
|
||||
this.h[2] += c
|
||||
this.h[3] += d
|
||||
this.h[4] += e
|
||||
this.h[5] += f
|
||||
this.h[6] += g
|
||||
this.h[7] += h
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun writeBE32(buf: ByteArray, offset: Int, value: Int) {
|
||||
buf[offset] = (value shr 24).toByte()
|
||||
buf[offset + 1] = (value shr 16).toByte()
|
||||
buf[offset + 2] = (value shr 8).toByte()
|
||||
buf[offset + 3] = value.toByte()
|
||||
}
|
||||
|
||||
private val k = intArrayOf(
|
||||
0x428a2f98, 0x71374491, -0x4a3f0431, -0x164a245b,
|
||||
0x3956c25b, 0x59f111f1, -0x6dc07d5c, -0x54e3a12b,
|
||||
-0x27f85568, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, -0x7f214e02, -0x6423f959, -0x3e640e8c,
|
||||
-0x1b64963f, -0x1041b87a, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
-0x67c1aeae, -0x57ce3993, -0x4ffcd838, -0x40a68039,
|
||||
-0x391ff40d, -0x2a586eb9, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, -0x7e3d36d2, -0x6d8dd37b,
|
||||
-0x5d40175f, -0x57e599b5, -0x3db47490, -0x3893ae5d,
|
||||
-0x2e6d17e7, -0x2966f9dc, -0xbf1ca7b, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, -0x7b3787ec, -0x7338fdf8,
|
||||
-0x6f410006, -0x5baf9315, -0x41065c09, -0x398e870e
|
||||
)
|
||||
|
||||
private fun rightRotate(value: Int, n: Int): Int {
|
||||
return (value ushr n) or (value shl (32 - n))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto;
|
||||
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable;
|
||||
|
||||
/**
|
||||
* Fallback implementation of SHA512.
|
||||
*
|
||||
* Note: This implementation is limited to a maximum 2^56 - 1 bytes of input.
|
||||
* That is, we don't bother trying to implement 128-bit length values.
|
||||
*/
|
||||
public class SHA512MessageDigest extends MessageDigest implements Destroyable {
|
||||
|
||||
private long[] h;
|
||||
private byte[] block;
|
||||
private long[] w;
|
||||
private long length;
|
||||
private int posn;
|
||||
|
||||
/**
|
||||
* Constructs a new SHA512 message digest object.
|
||||
*/
|
||||
public SHA512MessageDigest() {
|
||||
super("SHA-512");
|
||||
h = new long [8];
|
||||
block = new byte [128];
|
||||
w = new long [80];
|
||||
engineReset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Arrays.fill(h, (long)0);
|
||||
Arrays.fill(block, (byte)0);
|
||||
Arrays.fill(w, (long)0);
|
||||
}
|
||||
|
||||
private static void writeBE64(byte[] buf, int offset, long value)
|
||||
{
|
||||
buf[offset] = (byte)(value >> 56);
|
||||
buf[offset + 1] = (byte)(value >> 48);
|
||||
buf[offset + 2] = (byte)(value >> 40);
|
||||
buf[offset + 3] = (byte)(value >> 32);
|
||||
buf[offset + 4] = (byte)(value >> 24);
|
||||
buf[offset + 5] = (byte)(value >> 16);
|
||||
buf[offset + 6] = (byte)(value >> 8);
|
||||
buf[offset + 7] = (byte)value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineDigest() {
|
||||
byte[] digest = new byte [64];
|
||||
try {
|
||||
engineDigest(digest, 0, 64);
|
||||
} catch (DigestException e) {
|
||||
// Shouldn't happen, but just in case.
|
||||
Arrays.fill(digest, (byte)0);
|
||||
}
|
||||
return digest;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineDigest(byte[] buf, int offset, int len) throws DigestException
|
||||
{
|
||||
if (len < 64)
|
||||
throw new DigestException("Invalid digest length for SHA512");
|
||||
if (posn <= (128 - 17)) {
|
||||
block[posn] = (byte)0x80;
|
||||
Arrays.fill(block, posn + 1, 128 - 8, (byte)0);
|
||||
} else {
|
||||
block[posn] = (byte)0x80;
|
||||
Arrays.fill(block, posn + 1, 128, (byte)0);
|
||||
transform(block, 0);
|
||||
Arrays.fill(block, 0, 128 - 8, (byte)0);
|
||||
}
|
||||
writeBE64(block, 128 - 8, length);
|
||||
transform(block, 0);
|
||||
posn = 0;
|
||||
for (int index = 0; index < 8; ++index)
|
||||
writeBE64(buf, offset + index * 8, h[index]);
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int engineGetDigestLength() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineReset() {
|
||||
h[0] = 0x6a09e667f3bcc908L;
|
||||
h[1] = 0xbb67ae8584caa73bL;
|
||||
h[2] = 0x3c6ef372fe94f82bL;
|
||||
h[3] = 0xa54ff53a5f1d36f1L;
|
||||
h[4] = 0x510e527fade682d1L;
|
||||
h[5] = 0x9b05688c2b3e6c1fL;
|
||||
h[6] = 0x1f83d9abfb41bd6bL;
|
||||
h[7] = 0x5be0cd19137e2179L;
|
||||
length = 0;
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte input) {
|
||||
block[posn++] = input;
|
||||
length += 8;
|
||||
if (posn >= 128) {
|
||||
transform(block, 0);
|
||||
posn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte[] input, int offset, int len) {
|
||||
while (len > 0) {
|
||||
if (posn == 0 && len >= 128) {
|
||||
transform(input, offset);
|
||||
offset += 128;
|
||||
len -= 128;
|
||||
length += 128 * 8;
|
||||
} else {
|
||||
int temp = 128 - posn;
|
||||
if (temp > len)
|
||||
temp = len;
|
||||
System.arraycopy(input, offset, block, posn, temp);
|
||||
posn += temp;
|
||||
length += temp * 8;
|
||||
if (posn >= 128) {
|
||||
transform(block, 0);
|
||||
posn = 0;
|
||||
}
|
||||
offset += temp;
|
||||
len -= temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final long[] k = {
|
||||
0x428A2F98D728AE22L, 0x7137449123EF65CDL, 0xB5C0FBCFEC4D3B2FL,
|
||||
0xE9B5DBA58189DBBCL, 0x3956C25BF348B538L, 0x59F111F1B605D019L,
|
||||
0x923F82A4AF194F9BL, 0xAB1C5ED5DA6D8118L, 0xD807AA98A3030242L,
|
||||
0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L,
|
||||
0x72BE5D74F27B896FL, 0x80DEB1FE3B1696B1L, 0x9BDC06A725C71235L,
|
||||
0xC19BF174CF692694L, 0xE49B69C19EF14AD2L, 0xEFBE4786384F25E3L,
|
||||
0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L, 0x2DE92C6F592B0275L,
|
||||
0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L,
|
||||
0x983E5152EE66DFABL, 0xA831C66D2DB43210L, 0xB00327C898FB213FL,
|
||||
0xBF597FC7BEEF0EE4L, 0xC6E00BF33DA88FC2L, 0xD5A79147930AA725L,
|
||||
0x06CA6351E003826FL, 0x142929670A0E6E70L, 0x27B70A8546D22FFCL,
|
||||
0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL,
|
||||
0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, 0x81C2C92E47EDAEE6L,
|
||||
0x92722C851482353BL, 0xA2BFE8A14CF10364L, 0xA81A664BBC423001L,
|
||||
0xC24B8B70D0F89791L, 0xC76C51A30654BE30L, 0xD192E819D6EF5218L,
|
||||
0xD69906245565A910L, 0xF40E35855771202AL, 0x106AA07032BBD1B8L,
|
||||
0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L,
|
||||
0x34B0BCB5E19B48A8L, 0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL,
|
||||
0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L, 0x748F82EE5DEFB2FCL,
|
||||
0x78A5636F43172F60L, 0x84C87814A1F0AB72L, 0x8CC702081A6439ECL,
|
||||
0x90BEFFFA23631E28L, 0xA4506CEBDE82BDE9L, 0xBEF9A3F7B2C67915L,
|
||||
0xC67178F2E372532BL, 0xCA273ECEEA26619CL, 0xD186B8C721C0C207L,
|
||||
0xEADA7DD6CDE0EB1EL, 0xF57D4F7FEE6ED178L, 0x06F067AA72176FBAL,
|
||||
0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL,
|
||||
0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL,
|
||||
0x431D67C49C100D4CL, 0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL,
|
||||
0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L
|
||||
};
|
||||
|
||||
private static long rightRotate(long value, int n)
|
||||
{
|
||||
return (value >>> n) | (value << (64 - n));
|
||||
}
|
||||
|
||||
private void transform(byte[] m, int offset)
|
||||
{
|
||||
long a, b, c, d, e, f, g, h;
|
||||
long temp1, temp2;
|
||||
int index;
|
||||
|
||||
// Initialize working variables to the current hash value.
|
||||
a = this.h[0];
|
||||
b = this.h[1];
|
||||
c = this.h[2];
|
||||
d = this.h[3];
|
||||
e = this.h[4];
|
||||
f = this.h[5];
|
||||
g = this.h[6];
|
||||
h = this.h[7];
|
||||
|
||||
// Convert the 16 input message words from big endian to host byte order.
|
||||
for (index = 0; index < 16; ++index) {
|
||||
w[index] = ((m[offset] & 0xFFL) << 56) |
|
||||
((m[offset + 1] & 0xFFL) << 48) |
|
||||
((m[offset + 2] & 0xFFL) << 40) |
|
||||
((m[offset + 3] & 0xFFL) << 32) |
|
||||
((m[offset + 4] & 0xFFL) << 24) |
|
||||
((m[offset + 5] & 0xFFL) << 16) |
|
||||
((m[offset + 6] & 0xFFL) << 8) |
|
||||
(m[offset + 7] & 0xFFL);
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
// Extend the first 16 words to 80.
|
||||
for (index = 16; index < 80; ++index) {
|
||||
w[index] = w[index - 16] + w[index - 7] +
|
||||
(rightRotate(w[index - 15], 1) ^
|
||||
rightRotate(w[index - 15], 8) ^
|
||||
(w[index - 15] >>> 7)) +
|
||||
(rightRotate(w[index - 2], 19) ^
|
||||
rightRotate(w[index - 2], 61) ^
|
||||
(w[index - 2] >>> 6));
|
||||
}
|
||||
|
||||
// Compression function main loop.
|
||||
for (index = 0; index < 80; ++index) {
|
||||
temp1 = (h) + k[index] + w[index] +
|
||||
(rightRotate((e), 14) ^ rightRotate((e), 18) ^ rightRotate((e), 41)) +
|
||||
(((e) & (f)) ^ ((~(e)) & (g)));
|
||||
temp2 = (rightRotate((a), 28) ^ rightRotate((a), 34) ^ rightRotate((a), 39)) +
|
||||
(((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c)));
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + temp1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = temp1 + temp2;
|
||||
}
|
||||
|
||||
// Add the compressed chunk to the current hash value.
|
||||
this.h[0] += a;
|
||||
this.h[1] += b;
|
||||
this.h[2] += c;
|
||||
this.h[3] += d;
|
||||
this.h[4] += e;
|
||||
this.h[5] += f;
|
||||
this.h[6] += g;
|
||||
this.h[7] += h;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.crypto
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Destroyable
|
||||
import java.security.DigestException
|
||||
import java.security.MessageDigest
|
||||
|
||||
/**
|
||||
* Fallback implementation of SHA512.
|
||||
*
|
||||
* Note: This implementation is limited to a maximum 2^56 - 1 bytes of input.
|
||||
* That is, we don't bother trying to implement 128-bit length values.
|
||||
*/
|
||||
class SHA512MessageDigest : MessageDigest("SHA-512"), Destroyable {
|
||||
private val h = LongArray(8)
|
||||
private val block = ByteArray(128)
|
||||
private val w = LongArray(80)
|
||||
private var length: Long = 0
|
||||
private var posn = 0
|
||||
|
||||
init {
|
||||
engineReset()
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
h.fill(0L)
|
||||
block.fill(0.toByte())
|
||||
w.fill(0L)
|
||||
}
|
||||
|
||||
|
||||
override fun engineDigest(): ByteArray {
|
||||
val digest = ByteArray(64)
|
||||
try {
|
||||
engineDigest(digest, 0, 64)
|
||||
} catch (e: DigestException) {
|
||||
// Shouldn't happen, but just in case.
|
||||
digest.fill(0.toByte())
|
||||
}
|
||||
return digest
|
||||
}
|
||||
|
||||
@Throws(DigestException::class)
|
||||
override fun engineDigest(buf: ByteArray, offset: Int, len: Int): Int {
|
||||
if (len < 64) throw DigestException("Invalid digest length for SHA512")
|
||||
if (posn <= (128 - 17)) {
|
||||
block[posn] = 0x80.toByte()
|
||||
block.fill(0.toByte(), posn + 1, 128 - 8)
|
||||
} else {
|
||||
block[posn] = 0x80.toByte()
|
||||
block.fill(0.toByte(), posn + 1, 128)
|
||||
transform(block, 0)
|
||||
block.fill(0.toByte(), 0, 128 - 8)
|
||||
}
|
||||
writeBE64(block, 128 - 8, length)
|
||||
transform(block, 0)
|
||||
posn = 0
|
||||
for (index in 0..7) writeBE64(buf, offset + index * 8, h[index])
|
||||
return 64
|
||||
}
|
||||
|
||||
override fun engineGetDigestLength(): Int = 64
|
||||
|
||||
|
||||
override fun engineReset() {
|
||||
h[0] = 0x6a09e667f3bcc908L
|
||||
h[1] = -0x4498517a7b3558c5L
|
||||
h[2] = 0x3c6ef372fe94f82bL
|
||||
h[3] = -0x5ab00ac5a0e2c90fL
|
||||
h[4] = 0x510e527fade682d1L
|
||||
h[5] = -0x64fa9773d4c193e1L
|
||||
h[6] = 0x1f83d9abfb41bd6bL
|
||||
h[7] = 0x5be0cd19137e2179L
|
||||
length = 0
|
||||
posn = 0
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: Byte) {
|
||||
block[posn++] = input
|
||||
length += 8
|
||||
if (posn >= 128) {
|
||||
transform(block, 0)
|
||||
posn = 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun engineUpdate(input: ByteArray, offset: Int, len: Int) {
|
||||
var offset = offset
|
||||
var len = len
|
||||
while (len > 0) {
|
||||
if (posn == 0 && len >= 128) {
|
||||
transform(input, offset)
|
||||
offset += 128
|
||||
len -= 128
|
||||
length += (128 * 8).toLong()
|
||||
} else {
|
||||
var temp = 128 - posn
|
||||
if (temp > len) temp = len
|
||||
System.arraycopy(input, offset, block, posn, temp)
|
||||
posn += temp
|
||||
length += (temp * 8).toLong()
|
||||
if (posn >= 128) {
|
||||
transform(block, 0)
|
||||
posn = 0
|
||||
}
|
||||
offset += temp
|
||||
len -= temp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transform(m: ByteArray, offset: Int) {
|
||||
var currentOffset = offset
|
||||
|
||||
// Initialize working variables to the current hash value.
|
||||
var a = this.h[0]
|
||||
var b = this.h[1]
|
||||
var c = this.h[2]
|
||||
var d = this.h[3]
|
||||
var e = this.h[4]
|
||||
var f = this.h[5]
|
||||
var g = this.h[6]
|
||||
var h = this.h[7]
|
||||
|
||||
for (index in 0 until 16) {
|
||||
w[index] = ((m[currentOffset].toLong() and 0xFFL) shl 56) or
|
||||
((m[currentOffset + 1].toLong() and 0xFFL) shl 48) or
|
||||
((m[currentOffset + 2].toLong() and 0xFFL) shl 40) or
|
||||
((m[currentOffset + 3].toLong() and 0xFFL) shl 32) or
|
||||
((m[currentOffset + 4].toLong() and 0xFFL) shl 24) or
|
||||
((m[currentOffset + 5].toLong() and 0xFFL) shl 16) or
|
||||
((m[currentOffset + 6].toLong() and 0xFFL) shl 8) or
|
||||
(m[currentOffset + 7].toLong() and 0xFFL)
|
||||
currentOffset += 8
|
||||
}
|
||||
|
||||
|
||||
// Extend the first 16 words to 80.
|
||||
for (index in 16 until 80) {
|
||||
w[index] = w[index - 16] + w[index - 7] +
|
||||
(rightRotate(w[index - 15], 1) xor
|
||||
rightRotate(w[index - 15], 8) xor
|
||||
(w[index - 15] ushr 7)) +
|
||||
(rightRotate(w[index - 2], 19) xor
|
||||
rightRotate(w[index - 2], 61) xor
|
||||
(w[index - 2] ushr 6))
|
||||
}
|
||||
|
||||
// Compression function main loop.
|
||||
for (index in 0 until 80) {
|
||||
val temp1 = h + k[index] + w[index] +
|
||||
(rightRotate(e, 14) xor rightRotate(e, 18) xor rightRotate(e, 41)) +
|
||||
((e and f) xor (e.inv() and g))
|
||||
val temp2 = (rightRotate(a, 28) xor rightRotate(a, 34) xor rightRotate(a, 39)) +
|
||||
((a and b) xor (a and c) xor (b and c))
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = d + temp1
|
||||
d = c
|
||||
c = b
|
||||
b = a
|
||||
a = temp1 + temp2
|
||||
}
|
||||
|
||||
// Add the compressed chunk to the current hash value.
|
||||
this.h[0] += a
|
||||
this.h[1] += b
|
||||
this.h[2] += c
|
||||
this.h[3] += d
|
||||
this.h[4] += e
|
||||
this.h[5] += f
|
||||
this.h[6] += g
|
||||
this.h[7] += h
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun writeBE64(buf: ByteArray, offset: Int, value: Long) {
|
||||
buf[offset] = (value shr 56).toByte()
|
||||
buf[offset + 1] = (value shr 48).toByte()
|
||||
buf[offset + 2] = (value shr 40).toByte()
|
||||
buf[offset + 3] = (value shr 32).toByte()
|
||||
buf[offset + 4] = (value shr 24).toByte()
|
||||
buf[offset + 5] = (value shr 16).toByte()
|
||||
buf[offset + 6] = (value shr 8).toByte()
|
||||
buf[offset + 7] = value.toByte()
|
||||
}
|
||||
|
||||
private val k = longArrayOf(
|
||||
0x428A2F98D728AE22L, 0x7137449123EF65CDL, -0x4a3f043013b2c4d1L,
|
||||
-0x164a245a7e762444L, 0x3956C25BF348B538L, 0x59F111F1B605D019L,
|
||||
-0x6dc07d5b50e6b065L, -0x54e3a12a25927ee8L, -0x27f855675cfcfdbeL,
|
||||
0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L,
|
||||
0x72BE5D74F27B896FL, -0x7f214e01c4e9694fL, -0x6423f958da38edcbL,
|
||||
-0x3e640e8b3096d96cL, -0x1b64963e610eb52eL, -0x1041b879c7b0da1dL,
|
||||
0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L, 0x2DE92C6F592B0275L,
|
||||
0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L,
|
||||
-0x67c1aead11992055L, -0x57ce3992d24bcdf0L, -0x4ffcd8376704dec1L,
|
||||
-0x40a680384110f11cL, -0x391ff40cc257703eL, -0x2a586eb86cf558dbL,
|
||||
0x06CA6351E003826FL, 0x142929670A0E6E70L, 0x27B70A8546D22FFCL,
|
||||
0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL,
|
||||
0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, -0x7e3d36d1b812511aL,
|
||||
-0x6d8dd37aeb7dcac5L, -0x5d40175eb30efc9cL, -0x57e599b443bdcfffL,
|
||||
-0x3db4748f2f07686fL, -0x3893ae5cf9ab41d0L, -0x2e6d17e62910ade8L,
|
||||
-0x2966f9dbaa9a56f0L, -0xbf1ca7aa88edfd6L, 0x106AA07032BBD1B8L,
|
||||
0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L,
|
||||
0x34B0BCB5E19B48A8L, 0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL,
|
||||
0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L, 0x748F82EE5DEFB2FCL,
|
||||
0x78A5636F43172F60L, -0x7b3787eb5e0f548eL, -0x7338fdf7e59bc614L,
|
||||
-0x6f410005dc9ce1d8L, -0x5baf9314217d4217L, -0x41065c084d3986ebL,
|
||||
-0x398e870d1c8dacd5L, -0x35d8c13115d99e64L, -0x2e794738de3f3df9L,
|
||||
-0x15258229321f14e2L, -0xa82b08011912e88L, 0x06F067AA72176FBAL,
|
||||
0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL,
|
||||
0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL,
|
||||
0x431D67C49C100D4CL, 0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL,
|
||||
0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L
|
||||
)
|
||||
|
||||
private fun rightRotate(value: Long, n: Int): Long {
|
||||
return (value ushr n) or (value shl (64 - n))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
|
||||
/**
|
||||
* Fallback implementations of cryptographic primitives.
|
||||
*
|
||||
* This package provides plain Java implementations of the
|
||||
* cryptographic primitives that Noise requires which do not
|
||||
* normally come with standard JDK's.
|
||||
*
|
||||
* Applications that use Noise won't normally use these classes
|
||||
* directly.
|
||||
*/
|
||||
package com.bitchat.android.noise.southernstorm.crypto;
|
||||
@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.GHASH;
|
||||
import com.bitchat.android.noise.southernstorm.crypto.RijndaelAES;
|
||||
|
||||
/**
|
||||
* Fallback implementation of "AESGCM" on platforms where
|
||||
* the JCA/JCE does not have a suitable GCM or CTR provider.
|
||||
*/
|
||||
class AESGCMFallbackCipherState implements CipherState {
|
||||
|
||||
private RijndaelAES aes;
|
||||
private long n;
|
||||
private byte[] iv;
|
||||
private byte[] enciv;
|
||||
private byte[] hashKey;
|
||||
private GHASH ghash;
|
||||
private boolean haskey;
|
||||
|
||||
/**
|
||||
* Constructs a new cipher state for the "AESGCM" algorithm.
|
||||
*/
|
||||
public AESGCMFallbackCipherState()
|
||||
{
|
||||
aes = new RijndaelAES();
|
||||
n = 0;
|
||||
iv = new byte [16];
|
||||
enciv = new byte [16];
|
||||
hashKey = new byte [16];
|
||||
ghash = new GHASH();
|
||||
haskey = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
aes.destroy();
|
||||
ghash.destroy();
|
||||
Noise.destroy(hashKey);
|
||||
Noise.destroy(iv);
|
||||
Noise.destroy(enciv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCipherName() {
|
||||
return "AESGCM";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getKeyLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMACLength() {
|
||||
return haskey ? 16 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeKey(byte[] key, int offset) {
|
||||
// Set up the AES key.
|
||||
aes.setupEnc(key, offset, 256);
|
||||
haskey = true;
|
||||
|
||||
// Generate the hashing key by encrypting a block of zeroes.
|
||||
Arrays.fill(hashKey, (byte)0);
|
||||
aes.encrypt(hashKey, 0, hashKey, 0);
|
||||
ghash.reset(hashKey, 0);
|
||||
|
||||
// Reset the nonce.
|
||||
n = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey() {
|
||||
return haskey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up to encrypt or decrypt the next packet.
|
||||
*
|
||||
* @param ad The associated data for the packet.
|
||||
*/
|
||||
private void setup(byte[] ad)
|
||||
{
|
||||
// Check for nonce wrap-around.
|
||||
if (n == -1L)
|
||||
throw new IllegalStateException("Nonce has wrapped around");
|
||||
|
||||
// Format the counter/IV block.
|
||||
iv[0] = 0;
|
||||
iv[1] = 0;
|
||||
iv[2] = 0;
|
||||
iv[3] = 0;
|
||||
iv[4] = (byte)(n >> 56);
|
||||
iv[5] = (byte)(n >> 48);
|
||||
iv[6] = (byte)(n >> 40);
|
||||
iv[7] = (byte)(n >> 32);
|
||||
iv[8] = (byte)(n >> 24);
|
||||
iv[9] = (byte)(n >> 16);
|
||||
iv[10] = (byte)(n >> 8);
|
||||
iv[11] = (byte)n;
|
||||
iv[12] = 0;
|
||||
iv[13] = 0;
|
||||
iv[14] = 0;
|
||||
iv[15] = 1;
|
||||
++n;
|
||||
|
||||
// Encrypt a block of zeroes to generate the hash key to XOR
|
||||
// the GHASH tag with at the end of the encrypt/decrypt operation.
|
||||
Arrays.fill(hashKey, (byte)0);
|
||||
aes.encrypt(iv, 0, hashKey, 0);
|
||||
|
||||
// Initialize the GHASH with the associated data value.
|
||||
ghash.reset();
|
||||
if (ad != null) {
|
||||
ghash.update(ad, 0, ad.length);
|
||||
ghash.pad();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a block in CTR mode.
|
||||
*
|
||||
* @param plaintext The plaintext to encrypt.
|
||||
* @param plaintextOffset Offset of the first plaintext byte.
|
||||
* @param ciphertext The resulting ciphertext.
|
||||
* @param ciphertextOffset Offset of the first ciphertext byte.
|
||||
* @param length The number of bytes to encrypt.
|
||||
*
|
||||
* This function can also be used to decrypt.
|
||||
*/
|
||||
private void encryptCTR(byte[] plaintext, int plaintextOffset, byte[] ciphertext, int ciphertextOffset, int length)
|
||||
{
|
||||
while (length > 0) {
|
||||
// Increment the IV and encrypt it to get the next keystream block.
|
||||
if (++(iv[15]) == 0)
|
||||
if (++(iv[14]) == 0)
|
||||
if (++(iv[13]) == 0)
|
||||
++(iv[12]);
|
||||
aes.encrypt(iv, 0, enciv, 0);
|
||||
|
||||
// XOR the keystream block with the plaintext to create the ciphertext.
|
||||
int temp = length;
|
||||
if (temp > 16)
|
||||
temp = 16;
|
||||
for (int index = 0; index < temp; ++index)
|
||||
ciphertext[ciphertextOffset + index] = (byte)(plaintext[plaintextOffset + index] ^ enciv[index]);
|
||||
|
||||
// Advance to the next block.
|
||||
plaintextOffset += temp;
|
||||
ciphertextOffset += temp;
|
||||
length -= temp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
|
||||
byte[] ciphertext, int ciphertextOffset, int length)
|
||||
throws ShortBufferException {
|
||||
int space;
|
||||
if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length || length > plaintext.length || (plaintext.length - plaintextOffset) < length)
|
||||
throw new IllegalArgumentException();
|
||||
space = ciphertext.length - ciphertextOffset;
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the plaintext as-is.
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
|
||||
System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
|
||||
return length;
|
||||
}
|
||||
if (space < 16 || length > (space - 16))
|
||||
throw new ShortBufferException();
|
||||
setup(ad);
|
||||
encryptCTR(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
|
||||
ghash.update(ciphertext, ciphertextOffset, length);
|
||||
ghash.pad(ad != null ? ad.length : 0, length);
|
||||
ghash.finish(ciphertext, ciphertextOffset + length, 16);
|
||||
for (int index = 0; index < 16; ++index)
|
||||
ciphertext[ciphertextOffset + length + index] ^= hashKey[index];
|
||||
return length + 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decryptWithAd(byte[] ad, byte[] ciphertext,
|
||||
int ciphertextOffset, byte[] plaintext, int plaintextOffset,
|
||||
int length) throws ShortBufferException, BadPaddingException {
|
||||
int space;
|
||||
if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
|
||||
throw new IllegalArgumentException();
|
||||
else
|
||||
space = ciphertext.length - ciphertextOffset;
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length || length > ciphertext.length || (ciphertext.length - ciphertextOffset) < length)
|
||||
throw new IllegalArgumentException();
|
||||
space = plaintext.length - plaintextOffset;
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the ciphertext as-is.
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
|
||||
System.arraycopy(ciphertext, ciphertextOffset, plaintext, plaintextOffset, length);
|
||||
return length;
|
||||
}
|
||||
if (length < 16)
|
||||
Noise.throwBadTagException();
|
||||
int dataLen = length - 16;
|
||||
if (dataLen > space)
|
||||
throw new ShortBufferException();
|
||||
setup(ad);
|
||||
ghash.update(ciphertext, ciphertextOffset, dataLen);
|
||||
ghash.pad(ad != null ? ad.length : 0, dataLen);
|
||||
ghash.finish(enciv, 0, 16);
|
||||
int temp = 0;
|
||||
for (int index = 0; index < 16; ++index)
|
||||
temp |= (hashKey[index] ^ enciv[index] ^ ciphertext[ciphertextOffset + dataLen + index]);
|
||||
if ((temp & 0xFF) != 0)
|
||||
Noise.throwBadTagException();
|
||||
encryptCTR(ciphertext, ciphertextOffset, plaintext, plaintextOffset, dataLen);
|
||||
return dataLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CipherState fork(byte[] key, int offset) {
|
||||
CipherState cipher;
|
||||
cipher = new AESGCMFallbackCipherState();
|
||||
cipher.initializeKey(key, offset);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonce(long nonce) {
|
||||
n = nonce;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.GHASH
|
||||
import com.bitchat.android.noise.southernstorm.crypto.RijndaelAES
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.destroy
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.throwBadTagException
|
||||
import javax.crypto.BadPaddingException
|
||||
import javax.crypto.ShortBufferException
|
||||
|
||||
/**
|
||||
* Fallback implementation of "AESGCM" on platforms where
|
||||
* the JCA/JCE does not have a suitable GCM or CTR provider.
|
||||
*/
|
||||
internal class AESGCMFallbackCipherState : CipherState {
|
||||
private val aes: RijndaelAES = RijndaelAES()
|
||||
private var n: Long = 0
|
||||
private val iv: ByteArray = ByteArray(16)
|
||||
private val enciv: ByteArray = ByteArray(16)
|
||||
private val hashKey: ByteArray = ByteArray(16)
|
||||
private val ghash: GHASH = GHASH()
|
||||
private var haskey: Boolean = false
|
||||
|
||||
override fun destroy() {
|
||||
aes.destroy()
|
||||
ghash.destroy()
|
||||
destroy(hashKey)
|
||||
destroy(iv)
|
||||
destroy(enciv)
|
||||
}
|
||||
|
||||
override val cipherName: String get() = "AESGCM"
|
||||
override val keyLength: Int get() = 32
|
||||
override val macLength: Int get() = if (haskey) 16 else 0
|
||||
|
||||
override fun initializeKey(key: ByteArray, offset: Int) {
|
||||
// Set up the AES key.
|
||||
aes.setupEnc(key, offset, 256)
|
||||
haskey = true
|
||||
|
||||
// Generate the hashing key by encrypting a block of zeroes.
|
||||
hashKey.fill(0)
|
||||
aes.encrypt(hashKey, 0, hashKey, 0)
|
||||
ghash.reset(hashKey, 0)
|
||||
|
||||
|
||||
// Reset the nonce.
|
||||
n = 0
|
||||
}
|
||||
|
||||
override fun hasKey(): Boolean {
|
||||
return haskey
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up to encrypt or decrypt the next packet.
|
||||
*
|
||||
* @param ad The associated data for the packet.
|
||||
*/
|
||||
private fun setup(ad: ByteArray?) {
|
||||
// Check for nonce wrap-around.
|
||||
check(n != -1L) { "Nonce has wrapped around" }
|
||||
|
||||
|
||||
// Format the counter/IV block.
|
||||
iv[0] = 0
|
||||
iv[1] = 0
|
||||
iv[2] = 0
|
||||
iv[3] = 0
|
||||
iv[4] = (n shr 56).toByte()
|
||||
iv[5] = (n shr 48).toByte()
|
||||
iv[6] = (n shr 40).toByte()
|
||||
iv[7] = (n shr 32).toByte()
|
||||
iv[8] = (n shr 24).toByte()
|
||||
iv[9] = (n shr 16).toByte()
|
||||
iv[10] = (n shr 8).toByte()
|
||||
iv[11] = n.toByte()
|
||||
iv[12] = 0
|
||||
iv[13] = 0
|
||||
iv[14] = 0
|
||||
iv[15] = 1
|
||||
++n
|
||||
|
||||
|
||||
// Encrypt a block of zeroes to generate the hash key to XOR
|
||||
// the GHASH tag with at the end of the encrypt/decrypt operation.
|
||||
hashKey.fill(0)
|
||||
aes.encrypt(iv, 0, hashKey, 0)
|
||||
|
||||
|
||||
// Initialize the GHASH with the associated data value.
|
||||
ghash.reset()
|
||||
if (ad != null) {
|
||||
ghash.update(ad, 0, ad.size)
|
||||
ghash.pad()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a block in CTR mode.
|
||||
*
|
||||
* @param plaintext The plaintext to encrypt.
|
||||
* @param plaintextOffset Offset of the first plaintext byte.
|
||||
* @param ciphertext The resulting ciphertext.
|
||||
* @param ciphertextOffset Offset of the first ciphertext byte.
|
||||
* @param length The number of bytes to encrypt.
|
||||
*
|
||||
* This function can also be used to decrypt.
|
||||
*/
|
||||
private fun encryptCTR(
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
length: Int
|
||||
) {
|
||||
var plaintextOffset = plaintextOffset
|
||||
var ciphertextOffset = ciphertextOffset
|
||||
var length = length
|
||||
while (length > 0) {
|
||||
// Increment the IV (big-endian 4-byte counter at iv[12..15])
|
||||
// and encrypt it to get the next keystream block.
|
||||
iv[15] = (iv[15] + 1).toByte()
|
||||
if (iv[15].toInt() == 0) {
|
||||
iv[14] = (iv[14] + 1).toByte()
|
||||
if (iv[14].toInt() == 0) {
|
||||
iv[13] = (iv[13] + 1).toByte()
|
||||
if (iv[13].toInt() == 0) {
|
||||
iv[12] = (iv[12] + 1).toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
aes.encrypt(iv, 0, enciv, 0)
|
||||
|
||||
|
||||
// XOR the keystream block with the plaintext to create the ciphertext.
|
||||
var temp = length
|
||||
if (temp > 16) temp = 16
|
||||
for (index in 0..<temp) ciphertext[ciphertextOffset + index] =
|
||||
(plaintext[plaintextOffset + index].toInt() xor enciv[index].toInt()).toByte()
|
||||
|
||||
|
||||
// Advance to the next block.
|
||||
plaintextOffset += temp
|
||||
ciphertextOffset += temp
|
||||
length -= temp
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ShortBufferException::class)
|
||||
override fun encryptWithAd(
|
||||
ad: ByteArray?, plaintext: ByteArray, plaintextOffset: Int,
|
||||
ciphertext: ByteArray, ciphertextOffset: Int, length: Int
|
||||
): Int {
|
||||
require(!(ciphertextOffset < 0 || ciphertextOffset > ciphertext.size))
|
||||
require(!(length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.size || length > plaintext.size || (plaintext.size - plaintextOffset) < length))
|
||||
val space: Int = ciphertext.size - ciphertextOffset
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the plaintext as-is.
|
||||
if (length > space) throw ShortBufferException()
|
||||
if (plaintext !== ciphertext || plaintextOffset != ciphertextOffset) System.arraycopy(
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
length
|
||||
)
|
||||
return length
|
||||
}
|
||||
if (space < 16 || length > (space - 16)) throw ShortBufferException()
|
||||
setup(ad)
|
||||
encryptCTR(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length)
|
||||
ghash.update(ciphertext, ciphertextOffset, length)
|
||||
ghash.pad((if (ad != null) ad.size else 0).toLong(), length.toLong())
|
||||
ghash.finish(ciphertext, ciphertextOffset + length, 16)
|
||||
for (index in 0..15) {
|
||||
ciphertext[ciphertextOffset + length + index] =
|
||||
(ciphertext[ciphertextOffset + length + index].toInt() xor hashKey[index].toInt()).toByte()
|
||||
}
|
||||
return length + 16
|
||||
}
|
||||
|
||||
@Throws(ShortBufferException::class, BadPaddingException::class)
|
||||
override fun decryptWithAd(
|
||||
ad: ByteArray?,
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
length: Int
|
||||
): Int {
|
||||
var space: Int
|
||||
require(!(ciphertextOffset < 0 || ciphertextOffset > ciphertext.size))
|
||||
space = ciphertext.size - ciphertextOffset
|
||||
if (length > space) throw ShortBufferException()
|
||||
require(!(length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.size || length > ciphertext.size || (ciphertext.size - ciphertextOffset) < length))
|
||||
space = plaintext.size - plaintextOffset
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the ciphertext as-is.
|
||||
if (length > space) throw ShortBufferException()
|
||||
if (plaintext !== ciphertext || plaintextOffset != ciphertextOffset) System.arraycopy(
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
length
|
||||
)
|
||||
return length
|
||||
}
|
||||
if (length < 16) throwBadTagException()
|
||||
val dataLen = length - 16
|
||||
if (dataLen > space) throw ShortBufferException()
|
||||
setup(ad)
|
||||
ghash.update(ciphertext, ciphertextOffset, dataLen)
|
||||
ghash.pad((if (ad != null) ad.size else 0).toLong(), dataLen.toLong())
|
||||
ghash.finish(enciv, 0, 16)
|
||||
var temp = 0
|
||||
for (index in 0..15) temp =
|
||||
temp or (hashKey[index].toInt() xor enciv[index].toInt() xor ciphertext[ciphertextOffset + dataLen + index].toInt())
|
||||
if ((temp and 0xFF) != 0) throwBadTagException()
|
||||
encryptCTR(ciphertext, ciphertextOffset, plaintext, plaintextOffset, dataLen)
|
||||
return dataLen
|
||||
}
|
||||
|
||||
override fun fork(key: ByteArray, offset: Int): CipherState {
|
||||
val cipher: CipherState = AESGCMFallbackCipherState()
|
||||
cipher.initializeKey(key, offset)
|
||||
return cipher
|
||||
}
|
||||
|
||||
override fun setNonce(nonce: Long) {
|
||||
n = nonce
|
||||
}
|
||||
}
|
||||
@ -1,335 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.GHASH;
|
||||
|
||||
/**
|
||||
* Emulates the "AESGCM" cipher for Noise using the "AES/CTR/NoPadding"
|
||||
* transformation from JCA/JCE.
|
||||
*
|
||||
* This class is used on platforms that don't have "AES/GCM/NoPadding",
|
||||
* but which do have the older "AES/CTR/NoPadding".
|
||||
*/
|
||||
class AESGCMOnCtrCipherState implements CipherState {
|
||||
|
||||
private Cipher cipher;
|
||||
private SecretKeySpec keySpec;
|
||||
private long n;
|
||||
private byte[] iv;
|
||||
private byte[] hashKey;
|
||||
private GHASH ghash;
|
||||
|
||||
/**
|
||||
* Constructs a new cipher state for the "AESGCM" algorithm.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The system does not have a
|
||||
* provider for this algorithm.
|
||||
*/
|
||||
public AESGCMOnCtrCipherState() throws NoSuchAlgorithmException
|
||||
{
|
||||
try {
|
||||
cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
} catch (NoSuchPaddingException e) {
|
||||
// AES/CTR is available, but not the unpadded version? Huh?
|
||||
throw new NoSuchAlgorithmException("AES/CTR/NoPadding not available", e);
|
||||
}
|
||||
keySpec = null;
|
||||
n = 0;
|
||||
iv = new byte [16];
|
||||
hashKey = new byte [16];
|
||||
ghash = new GHASH();
|
||||
|
||||
// Try to set a 256-bit key on the cipher. Some JCE's are
|
||||
// configured to disallow 256-bit AES if an extra policy
|
||||
// file has not been installed.
|
||||
try {
|
||||
SecretKeySpec spec = new SecretKeySpec(new byte [32], "AES");
|
||||
IvParameterSpec params = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, spec, params);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new NoSuchAlgorithmException("AES/CTR/NoPadding does not support 256-bit keys", e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new NoSuchAlgorithmException("AES/CTR/NoPadding does not support 256-bit keys", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// There doesn't seem to be a standard API to clean out a Cipher.
|
||||
// So we instead set the key and IV to all-zeroes to hopefully
|
||||
// destroy the sensitive data in the cipher instance.
|
||||
ghash.destroy();
|
||||
Noise.destroy(hashKey);
|
||||
Noise.destroy(iv);
|
||||
keySpec = new SecretKeySpec(new byte [32], "AES");
|
||||
IvParameterSpec params = new IvParameterSpec(iv);
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, params);
|
||||
} catch (InvalidKeyException e) {
|
||||
// Shouldn't happen.
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
// Shouldn't happen.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCipherName() {
|
||||
return "AESGCM";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getKeyLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMACLength() {
|
||||
return keySpec != null ? 16 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeKey(byte[] key, int offset) {
|
||||
// Set the encryption key.
|
||||
keySpec = new SecretKeySpec(key, offset, 32, "AES");
|
||||
|
||||
// Generate the hashing key by encrypting a block of zeroes.
|
||||
Arrays.fill(iv, (byte)0);
|
||||
Arrays.fill(hashKey, (byte)0);
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
|
||||
} catch (InvalidKeyException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
try {
|
||||
int result = cipher.update(hashKey, 0, 16, hashKey, 0);
|
||||
cipher.doFinal(hashKey, result);
|
||||
} catch (ShortBufferException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (BadPaddingException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
ghash.reset(hashKey, 0);
|
||||
|
||||
// Reset the nonce.
|
||||
n = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey() {
|
||||
return keySpec != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up to encrypt or decrypt the next packet.
|
||||
*
|
||||
* @param ad The associated data for the packet.
|
||||
*/
|
||||
private void setup(byte[] ad) throws InvalidKeyException, InvalidAlgorithmParameterException
|
||||
{
|
||||
// Check for nonce wrap-around.
|
||||
if (n == -1L)
|
||||
throw new IllegalStateException("Nonce has wrapped around");
|
||||
|
||||
// Format the counter/IV block for AES/CTR/NoPadding.
|
||||
iv[0] = 0;
|
||||
iv[1] = 0;
|
||||
iv[2] = 0;
|
||||
iv[3] = 0;
|
||||
iv[4] = (byte)(n >> 56);
|
||||
iv[5] = (byte)(n >> 48);
|
||||
iv[6] = (byte)(n >> 40);
|
||||
iv[7] = (byte)(n >> 32);
|
||||
iv[8] = (byte)(n >> 24);
|
||||
iv[9] = (byte)(n >> 16);
|
||||
iv[10] = (byte)(n >> 8);
|
||||
iv[11] = (byte)n;
|
||||
iv[12] = 0;
|
||||
iv[13] = 0;
|
||||
iv[14] = 0;
|
||||
iv[15] = 1;
|
||||
++n;
|
||||
|
||||
// Initialize the CTR mode cipher with the key and IV.
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
|
||||
|
||||
// Encrypt a block of zeroes to generate the hash key to XOR
|
||||
// the GHASH tag with at the end of the encrypt/decrypt operation.
|
||||
Arrays.fill(hashKey, (byte)0);
|
||||
try {
|
||||
cipher.update(hashKey, 0, 16, hashKey, 0);
|
||||
} catch (ShortBufferException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
// Initialize the GHASH with the associated data value.
|
||||
ghash.reset();
|
||||
if (ad != null) {
|
||||
ghash.update(ad, 0, ad.length);
|
||||
ghash.pad();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
|
||||
byte[] ciphertext, int ciphertextOffset, int length)
|
||||
throws ShortBufferException {
|
||||
int space;
|
||||
if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length || length > plaintext.length || (plaintext.length - plaintextOffset) < length)
|
||||
throw new IllegalArgumentException();
|
||||
space = ciphertext.length - ciphertextOffset;
|
||||
if (keySpec == null) {
|
||||
// The key is not set yet - return the plaintext as-is.
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
|
||||
System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
|
||||
return length;
|
||||
}
|
||||
if (space < 16 || length > (space - 16))
|
||||
throw new ShortBufferException();
|
||||
try {
|
||||
setup(ad);
|
||||
int result = cipher.update(plaintext, plaintextOffset, length, ciphertext, ciphertextOffset);
|
||||
cipher.doFinal(ciphertext, ciphertextOffset + result);
|
||||
} catch (InvalidKeyException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (BadPaddingException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
ghash.update(ciphertext, ciphertextOffset, length);
|
||||
ghash.pad(ad != null ? ad.length : 0, length);
|
||||
ghash.finish(ciphertext, ciphertextOffset + length, 16);
|
||||
for (int index = 0; index < 16; ++index)
|
||||
ciphertext[ciphertextOffset + length + index] ^= hashKey[index];
|
||||
return length + 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decryptWithAd(byte[] ad, byte[] ciphertext,
|
||||
int ciphertextOffset, byte[] plaintext, int plaintextOffset,
|
||||
int length) throws ShortBufferException, BadPaddingException {
|
||||
int space;
|
||||
if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
|
||||
throw new IllegalArgumentException();
|
||||
else
|
||||
space = ciphertext.length - ciphertextOffset;
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length || length > ciphertext.length || (ciphertext.length - ciphertextOffset) < length)
|
||||
throw new IllegalArgumentException();
|
||||
space = plaintext.length - plaintextOffset;
|
||||
if (keySpec == null) {
|
||||
// The key is not set yet - return the ciphertext as-is.
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
|
||||
System.arraycopy(ciphertext, ciphertextOffset, plaintext, plaintextOffset, length);
|
||||
return length;
|
||||
}
|
||||
if (length < 16)
|
||||
Noise.throwBadTagException();
|
||||
int dataLen = length - 16;
|
||||
if (dataLen > space)
|
||||
throw new ShortBufferException();
|
||||
try {
|
||||
setup(ad);
|
||||
} catch (InvalidKeyException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
ghash.update(ciphertext, ciphertextOffset, dataLen);
|
||||
ghash.pad(ad != null ? ad.length : 0, dataLen);
|
||||
ghash.finish(iv, 0, 16);
|
||||
int temp = 0;
|
||||
for (int index = 0; index < 16; ++index)
|
||||
temp |= (hashKey[index] ^ iv[index] ^ ciphertext[ciphertextOffset + dataLen + index]);
|
||||
if ((temp & 0xFF) != 0)
|
||||
Noise.throwBadTagException();
|
||||
try {
|
||||
int result = cipher.update(ciphertext, ciphertextOffset, dataLen, plaintext, plaintextOffset);
|
||||
cipher.doFinal(plaintext, plaintextOffset + result);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
} catch (BadPaddingException e) {
|
||||
// Shouldn't happen.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return dataLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CipherState fork(byte[] key, int offset) {
|
||||
CipherState cipher;
|
||||
try {
|
||||
cipher = new AESGCMOnCtrCipherState();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Shouldn't happen.
|
||||
return null;
|
||||
}
|
||||
cipher.initializeKey(key, offset);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonce(long nonce) {
|
||||
n = nonce;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.GHASH
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.destroy
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.throwBadTagException
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import javax.crypto.BadPaddingException
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.IllegalBlockSizeException
|
||||
import javax.crypto.NoSuchPaddingException
|
||||
import javax.crypto.ShortBufferException
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
/**
|
||||
* Emulates the "AESGCM" cipher for Noise using the "AES/CTR/NoPadding"
|
||||
* transformation from JCA/JCE.
|
||||
*
|
||||
* This class is used on platforms that don't have "AES/GCM/NoPadding",
|
||||
* but which do have the older "AES/CTR/NoPadding".
|
||||
*/
|
||||
internal class AESGCMOnCtrCipherState
|
||||
@Throws(NoSuchAlgorithmException::class)
|
||||
constructor() : CipherState {
|
||||
private val cipher: Cipher = try {
|
||||
Cipher.getInstance("AES/CTR/NoPadding")
|
||||
} catch (e: NoSuchPaddingException) {
|
||||
// AES/CTR is available, but not the unpadded version? Huh?
|
||||
throw NoSuchAlgorithmException("AES/CTR/NoPadding not available", e)
|
||||
}
|
||||
private var keySpec: SecretKeySpec? = null
|
||||
private var n: Long = 0
|
||||
private val iv: ByteArray = ByteArray(16)
|
||||
private val hashKey: ByteArray = ByteArray(16)
|
||||
private val ghash: GHASH = GHASH()
|
||||
|
||||
init {
|
||||
// Try to set a 256-bit key on the cipher. Some JCE's are
|
||||
// configured to disallow 256-bit AES if an extra policy
|
||||
// file has not been installed.
|
||||
try {
|
||||
val spec = SecretKeySpec(ByteArray(32), "AES")
|
||||
val params = IvParameterSpec(iv)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, spec, params)
|
||||
} catch (e: InvalidKeyException) {
|
||||
throw NoSuchAlgorithmException("AES/CTR/NoPadding does not support 256-bit keys", e)
|
||||
} catch (e: InvalidAlgorithmParameterException) {
|
||||
throw NoSuchAlgorithmException("AES/CTR/NoPadding does not support 256-bit keys", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
// There doesn't seem to be a standard API to clean out a Cipher.
|
||||
// So we instead set the key and IV to all-zeroes to hopefully
|
||||
// destroy the sensitive data in the cipher instance.
|
||||
ghash.destroy()
|
||||
destroy(hashKey)
|
||||
destroy(iv)
|
||||
keySpec = SecretKeySpec(ByteArray(32), "AES")
|
||||
val params = IvParameterSpec(iv)
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, params)
|
||||
} catch (_: InvalidKeyException) {
|
||||
// Shouldn't happen.
|
||||
} catch (_: InvalidAlgorithmParameterException) {
|
||||
// Shouldn't happen.
|
||||
}
|
||||
}
|
||||
|
||||
override val cipherName: String get() = "AESGCM"
|
||||
override val keyLength: Int get() = 32
|
||||
override val macLength: Int get() = if (keySpec != null) 16 else 0
|
||||
|
||||
override fun initializeKey(key: ByteArray, offset: Int) {
|
||||
// Set the encryption key.
|
||||
keySpec = SecretKeySpec(key, offset, 32, "AES")
|
||||
|
||||
|
||||
// Generate the hashing key by encrypting a block of zeroes.
|
||||
iv.fill(0)
|
||||
hashKey.fill(0)
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, IvParameterSpec(iv))
|
||||
} catch (e: InvalidKeyException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: InvalidAlgorithmParameterException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
try {
|
||||
val result = cipher.update(hashKey, 0, 16, hashKey, 0)
|
||||
cipher.doFinal(hashKey, result)
|
||||
} catch (e: ShortBufferException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: IllegalBlockSizeException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: BadPaddingException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
ghash.reset(hashKey, 0)
|
||||
|
||||
|
||||
// Reset the nonce.
|
||||
n = 0
|
||||
}
|
||||
|
||||
override fun hasKey(): Boolean {
|
||||
return keySpec != null
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up to encrypt or decrypt the next packet.
|
||||
*
|
||||
* @param ad The associated data for the packet.
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, InvalidAlgorithmParameterException::class)
|
||||
private fun setup(ad: ByteArray?) {
|
||||
// Check for nonce wrap-around.
|
||||
check(n != -1L) { "Nonce has wrapped around" }
|
||||
|
||||
|
||||
// Format the counter/IV block for AES/CTR/NoPadding.
|
||||
iv[0] = 0
|
||||
iv[1] = 0
|
||||
iv[2] = 0
|
||||
iv[3] = 0
|
||||
iv[4] = (n shr 56).toByte()
|
||||
iv[5] = (n shr 48).toByte()
|
||||
iv[6] = (n shr 40).toByte()
|
||||
iv[7] = (n shr 32).toByte()
|
||||
iv[8] = (n shr 24).toByte()
|
||||
iv[9] = (n shr 16).toByte()
|
||||
iv[10] = (n shr 8).toByte()
|
||||
iv[11] = n.toByte()
|
||||
iv[12] = 0
|
||||
iv[13] = 0
|
||||
iv[14] = 0
|
||||
iv[15] = 1
|
||||
++n
|
||||
|
||||
|
||||
// Initialize the CTR mode cipher with the key and IV.
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, IvParameterSpec(iv))
|
||||
|
||||
|
||||
// Encrypt a block of zeroes to generate the hash key to XOR
|
||||
// the GHASH tag with at the end of the encrypt/decrypt operation.
|
||||
hashKey.fill(0)
|
||||
try {
|
||||
cipher.update(hashKey, 0, 16, hashKey, 0)
|
||||
} catch (e: ShortBufferException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
|
||||
|
||||
// Initialize the GHASH with the associated data value.
|
||||
ghash.reset()
|
||||
if (ad != null) {
|
||||
ghash.update(ad, 0, ad.size)
|
||||
ghash.pad()
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ShortBufferException::class)
|
||||
override fun encryptWithAd(
|
||||
ad: ByteArray?, plaintext: ByteArray, plaintextOffset: Int,
|
||||
ciphertext: ByteArray, ciphertextOffset: Int, length: Int
|
||||
): Int {
|
||||
require(!(ciphertextOffset < 0 || ciphertextOffset > ciphertext.size))
|
||||
require(!(length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.size || length > plaintext.size || (plaintext.size - plaintextOffset) < length))
|
||||
val space: Int = ciphertext.size - ciphertextOffset
|
||||
if (keySpec == null) {
|
||||
// The key is not set yet - return the plaintext as-is.
|
||||
if (length > space) throw ShortBufferException()
|
||||
if (plaintext !== ciphertext || plaintextOffset != ciphertextOffset) System.arraycopy(
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
length
|
||||
)
|
||||
return length
|
||||
}
|
||||
if (space < 16 || length > (space - 16)) throw ShortBufferException()
|
||||
try {
|
||||
setup(ad)
|
||||
val result =
|
||||
cipher.update(plaintext, plaintextOffset, length, ciphertext, ciphertextOffset)
|
||||
cipher.doFinal(ciphertext, ciphertextOffset + result)
|
||||
} catch (e: InvalidKeyException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: InvalidAlgorithmParameterException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: IllegalBlockSizeException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: BadPaddingException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
ghash.update(ciphertext, ciphertextOffset, length)
|
||||
ghash.pad((if (ad != null) ad.size else 0).toLong(), length.toLong())
|
||||
ghash.finish(ciphertext, ciphertextOffset + length, 16)
|
||||
for (index in 0..15) {
|
||||
ciphertext[ciphertextOffset + length + index] =
|
||||
(ciphertext[ciphertextOffset + length + index].toInt() xor hashKey[index].toInt()).toByte()
|
||||
}
|
||||
return length + 16
|
||||
}
|
||||
|
||||
@Throws(ShortBufferException::class, BadPaddingException::class)
|
||||
override fun decryptWithAd(
|
||||
ad: ByteArray?,
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
length: Int
|
||||
): Int {
|
||||
var space: Int
|
||||
require(!(ciphertextOffset < 0 || ciphertextOffset > ciphertext.size))
|
||||
space = ciphertext.size - ciphertextOffset
|
||||
if (length > space) throw ShortBufferException()
|
||||
require(!(length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.size || length > ciphertext.size || (ciphertext.size - ciphertextOffset) < length))
|
||||
space = plaintext.size - plaintextOffset
|
||||
if (keySpec == null) {
|
||||
// The key is not set yet - return the ciphertext as-is.
|
||||
if (length > space) throw ShortBufferException()
|
||||
if (plaintext !== ciphertext || plaintextOffset != ciphertextOffset) System.arraycopy(
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
length
|
||||
)
|
||||
return length
|
||||
}
|
||||
if (length < 16) throwBadTagException()
|
||||
val dataLen = length - 16
|
||||
if (dataLen > space) throw ShortBufferException()
|
||||
try {
|
||||
setup(ad)
|
||||
} catch (e: InvalidKeyException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: InvalidAlgorithmParameterException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
ghash.update(ciphertext, ciphertextOffset, dataLen)
|
||||
ghash.pad((ad?.size ?: 0).toLong(), dataLen.toLong())
|
||||
ghash.finish(iv, 0, 16)
|
||||
var temp = 0
|
||||
for (index in 0..15) temp =
|
||||
temp or (hashKey[index].toInt() xor iv[index].toInt() xor ciphertext[ciphertextOffset + dataLen + index].toInt())
|
||||
if ((temp and 0xFF) != 0) throwBadTagException()
|
||||
try {
|
||||
val result =
|
||||
cipher.update(ciphertext, ciphertextOffset, dataLen, plaintext, plaintextOffset)
|
||||
cipher.doFinal(plaintext, plaintextOffset + result)
|
||||
} catch (e: IllegalBlockSizeException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
} catch (e: BadPaddingException) {
|
||||
// Shouldn't happen.
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
return dataLen
|
||||
}
|
||||
|
||||
override fun fork(key: ByteArray, offset: Int): CipherState {
|
||||
val cipher: CipherState = try {
|
||||
AESGCMOnCtrCipherState()
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
// Shouldn't happen — this state already exists, so the algorithm is available.
|
||||
throw IllegalStateException(e)
|
||||
}
|
||||
cipher.initializeKey(key, offset)
|
||||
return cipher
|
||||
}
|
||||
|
||||
override fun setNonce(nonce: Long) {
|
||||
n = nonce
|
||||
}
|
||||
}
|
||||
@ -1,290 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.ChaChaCore;
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Poly1305;
|
||||
|
||||
/**
|
||||
* Implements the ChaChaPoly cipher for Noise.
|
||||
*/
|
||||
class ChaChaPolyCipherState implements CipherState {
|
||||
|
||||
private Poly1305 poly;
|
||||
private int[] input;
|
||||
private int[] output;
|
||||
private byte[] polyKey;
|
||||
long n;
|
||||
private boolean haskey;
|
||||
|
||||
/**
|
||||
* Constructs a new cipher state for the "ChaChaPoly" algorithm.
|
||||
*/
|
||||
public ChaChaPolyCipherState()
|
||||
{
|
||||
poly = new Poly1305();
|
||||
input = new int [16];
|
||||
output = new int [16];
|
||||
polyKey = new byte [32];
|
||||
n = 0;
|
||||
haskey = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
poly.destroy();
|
||||
Arrays.fill(input, 0);
|
||||
Arrays.fill(output, 0);
|
||||
Noise.destroy(polyKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCipherName() {
|
||||
return "ChaChaPoly";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getKeyLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMACLength() {
|
||||
return haskey ? 16 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeKey(byte[] key, int offset) {
|
||||
ChaChaCore.initKey256(input, key, offset);
|
||||
n = 0;
|
||||
haskey = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey() {
|
||||
return haskey;
|
||||
}
|
||||
|
||||
/**
|
||||
* XOR's the output of ChaCha20 with a byte buffer.
|
||||
*
|
||||
* @param input The input byte buffer.
|
||||
* @param inputOffset The offset of the first input byte.
|
||||
* @param output The output byte buffer (can be the same as the input).
|
||||
* @param outputOffset The offset of the first output byte.
|
||||
* @param length The number of bytes to XOR between 1 and 64.
|
||||
* @param block The ChaCha20 output block.
|
||||
*/
|
||||
private static void xorBlock(byte[] input, int inputOffset, byte[] output, int outputOffset, int length, int[] block)
|
||||
{
|
||||
int posn = 0;
|
||||
int value;
|
||||
while (length >= 4) {
|
||||
value = block[posn++];
|
||||
output[outputOffset] = (byte)(input[inputOffset] ^ value);
|
||||
output[outputOffset + 1] = (byte)(input[inputOffset + 1] ^ (value >> 8));
|
||||
output[outputOffset + 2] = (byte)(input[inputOffset + 2] ^ (value >> 16));
|
||||
output[outputOffset + 3] = (byte)(input[inputOffset + 3] ^ (value >> 24));
|
||||
inputOffset += 4;
|
||||
outputOffset += 4;
|
||||
length -= 4;
|
||||
}
|
||||
if (length == 3) {
|
||||
value = block[posn];
|
||||
output[outputOffset] = (byte)(input[inputOffset] ^ value);
|
||||
output[outputOffset + 1] = (byte)(input[inputOffset + 1] ^ (value >> 8));
|
||||
output[outputOffset + 2] = (byte)(input[inputOffset + 2] ^ (value >> 16));
|
||||
} else if (length == 2) {
|
||||
value = block[posn];
|
||||
output[outputOffset] = (byte)(input[inputOffset] ^ value);
|
||||
output[outputOffset + 1] = (byte)(input[inputOffset + 1] ^ (value >> 8));
|
||||
} else if (length == 1) {
|
||||
value = block[posn];
|
||||
output[outputOffset] = (byte)(input[inputOffset] ^ value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up to encrypt or decrypt the next packet.
|
||||
*
|
||||
* @param ad The associated data for the packet.
|
||||
*/
|
||||
private void setup(byte[] ad)
|
||||
{
|
||||
if (n == -1L)
|
||||
throw new IllegalStateException("Nonce has wrapped around");
|
||||
ChaChaCore.initIV(input, n++);
|
||||
ChaChaCore.hash(output, input);
|
||||
Arrays.fill(polyKey, (byte)0);
|
||||
xorBlock(polyKey, 0, polyKey, 0, 32, output);
|
||||
poly.reset(polyKey, 0);
|
||||
if (ad != null) {
|
||||
poly.update(ad, 0, ad.length);
|
||||
poly.pad();
|
||||
}
|
||||
if (++(input[12]) == 0)
|
||||
++(input[13]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a 64-bit integer into a buffer in little-endian order.
|
||||
*
|
||||
* @param output The output buffer.
|
||||
* @param offset The offset into the output buffer.
|
||||
* @param value The 64-bit integer value.
|
||||
*/
|
||||
private static void putLittleEndian64(byte[] output, int offset, long value)
|
||||
{
|
||||
output[offset] = (byte)value;
|
||||
output[offset + 1] = (byte)(value >> 8);
|
||||
output[offset + 2] = (byte)(value >> 16);
|
||||
output[offset + 3] = (byte)(value >> 24);
|
||||
output[offset + 4] = (byte)(value >> 32);
|
||||
output[offset + 5] = (byte)(value >> 40);
|
||||
output[offset + 6] = (byte)(value >> 48);
|
||||
output[offset + 7] = (byte)(value >> 56);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes up the authentication tag for a packet.
|
||||
*
|
||||
* @param ad The associated data.
|
||||
* @param length The length of the plaintext data.
|
||||
*/
|
||||
private void finish(byte[] ad, int length)
|
||||
{
|
||||
poly.pad();
|
||||
putLittleEndian64(polyKey, 0, ad != null ? ad.length : 0);
|
||||
putLittleEndian64(polyKey, 8, length);
|
||||
poly.update(polyKey, 0, 16);
|
||||
poly.finish(polyKey, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts or decrypts a buffer of bytes for the active packet.
|
||||
*
|
||||
* @param plaintext The plaintext data to be encrypted.
|
||||
* @param plaintextOffset The offset to the first plaintext byte.
|
||||
* @param ciphertext The ciphertext data that results from encryption.
|
||||
* @param ciphertextOffset The offset to the first ciphertext byte.
|
||||
* @param length The number of bytes to encrypt.
|
||||
*/
|
||||
private void encrypt(byte[] plaintext, int plaintextOffset,
|
||||
byte[] ciphertext, int ciphertextOffset, int length) {
|
||||
while (length > 0) {
|
||||
int tempLen = 64;
|
||||
if (tempLen > length)
|
||||
tempLen = length;
|
||||
ChaChaCore.hash(output, input);
|
||||
xorBlock(plaintext, plaintextOffset, ciphertext, ciphertextOffset, tempLen, output);
|
||||
if (++(input[12]) == 0)
|
||||
++(input[13]);
|
||||
plaintextOffset += tempLen;
|
||||
ciphertextOffset += tempLen;
|
||||
length -= tempLen;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
|
||||
byte[] ciphertext, int ciphertextOffset, int length) throws ShortBufferException {
|
||||
int space;
|
||||
if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length || length > plaintext.length || (plaintext.length - plaintextOffset) < length)
|
||||
throw new IllegalArgumentException();
|
||||
space = ciphertext.length - ciphertextOffset;
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the plaintext as-is.
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
|
||||
System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
|
||||
return length;
|
||||
}
|
||||
if (space < 16 || length > (space - 16))
|
||||
throw new ShortBufferException();
|
||||
setup(ad);
|
||||
encrypt(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
|
||||
poly.update(ciphertext, ciphertextOffset, length);
|
||||
finish(ad, length);
|
||||
System.arraycopy(polyKey, 0, ciphertext, ciphertextOffset + length, 16);
|
||||
return length + 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decryptWithAd(byte[] ad, byte[] ciphertext,
|
||||
int ciphertextOffset, byte[] plaintext, int plaintextOffset,
|
||||
int length) throws ShortBufferException, BadPaddingException {
|
||||
int space;
|
||||
if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
|
||||
throw new IllegalArgumentException();
|
||||
else
|
||||
space = ciphertext.length - ciphertextOffset;
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length || length > ciphertext.length || (ciphertext.length - ciphertextOffset) < length)
|
||||
throw new IllegalArgumentException();
|
||||
space = plaintext.length - plaintextOffset;
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the ciphertext as-is.
|
||||
if (length > space)
|
||||
throw new ShortBufferException();
|
||||
if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
|
||||
System.arraycopy(ciphertext, ciphertextOffset, plaintext, plaintextOffset, length);
|
||||
return length;
|
||||
}
|
||||
if (length < 16)
|
||||
Noise.throwBadTagException();
|
||||
int dataLen = length - 16;
|
||||
if (dataLen > space)
|
||||
throw new ShortBufferException();
|
||||
setup(ad);
|
||||
poly.update(ciphertext, ciphertextOffset, dataLen);
|
||||
finish(ad, dataLen);
|
||||
int temp = 0;
|
||||
for (int index = 0; index < 16; ++index)
|
||||
temp |= (polyKey[index] ^ ciphertext[ciphertextOffset + dataLen + index]);
|
||||
if ((temp & 0xFF) != 0)
|
||||
Noise.throwBadTagException();
|
||||
encrypt(ciphertext, ciphertextOffset, plaintext, plaintextOffset, dataLen);
|
||||
return dataLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CipherState fork(byte[] key, int offset) {
|
||||
CipherState cipher = new ChaChaPolyCipherState();
|
||||
cipher.initializeKey(key, offset);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonce(long nonce) {
|
||||
n = nonce;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.ChaChaCore.hash
|
||||
import com.bitchat.android.noise.southernstorm.crypto.ChaChaCore.initIV
|
||||
import com.bitchat.android.noise.southernstorm.crypto.ChaChaCore.initKey256
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Poly1305
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.destroy
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.throwBadTagException
|
||||
import javax.crypto.BadPaddingException
|
||||
import javax.crypto.ShortBufferException
|
||||
|
||||
/**
|
||||
* Implements the ChaChaPoly cipher for Noise.
|
||||
*/
|
||||
internal class ChaChaPolyCipherState : CipherState {
|
||||
private val poly: Poly1305 = Poly1305()
|
||||
private val input: IntArray = IntArray(16)
|
||||
private val output: IntArray = IntArray(16)
|
||||
private val polyKey: ByteArray = ByteArray(32)
|
||||
private var n: Long = 0
|
||||
private var haskey = false
|
||||
|
||||
override fun destroy() {
|
||||
poly.destroy()
|
||||
input.fill(0)
|
||||
output.fill(0)
|
||||
destroy(polyKey)
|
||||
}
|
||||
|
||||
override val cipherName: String get() = "ChaChaPoly"
|
||||
override val keyLength: Int get() = 32
|
||||
override val macLength: Int get() = if (haskey) 16 else 0
|
||||
|
||||
override fun initializeKey(key: ByteArray, offset: Int) {
|
||||
initKey256(input, key, offset)
|
||||
n = 0
|
||||
haskey = true
|
||||
}
|
||||
|
||||
override fun hasKey(): Boolean {
|
||||
return haskey
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up to encrypt or decrypt the next packet.
|
||||
*
|
||||
* @param ad The associated data for the packet.
|
||||
*/
|
||||
private fun setup(ad: ByteArray?) {
|
||||
check(n != -1L) { "Nonce has wrapped around" }
|
||||
initIV(input, n++)
|
||||
hash(output, input)
|
||||
polyKey.fill(0)
|
||||
xorBlock(polyKey, 0, polyKey, 0, 32, output)
|
||||
poly.reset(polyKey, 0)
|
||||
if (ad != null) {
|
||||
poly.update(ad, 0, ad.size)
|
||||
poly.pad()
|
||||
}
|
||||
if (++input[12] == 0) ++input[13]
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes up the authentication tag for a packet.
|
||||
*
|
||||
* @param ad The associated data.
|
||||
* @param length The length of the plaintext data.
|
||||
*/
|
||||
private fun finish(ad: ByteArray?, length: Int) {
|
||||
poly.pad()
|
||||
putLittleEndian64(polyKey, 0, (ad?.size ?: 0).toLong())
|
||||
putLittleEndian64(polyKey, 8, length.toLong())
|
||||
poly.update(polyKey, 0, 16)
|
||||
poly.finish(polyKey, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts or decrypts a buffer of bytes for the active packet.
|
||||
*
|
||||
* @param plaintext The plaintext data to be encrypted.
|
||||
* @param plaintextOffset The offset to the first plaintext byte.
|
||||
* @param ciphertext The ciphertext data that results from encryption.
|
||||
* @param ciphertextOffset The offset to the first ciphertext byte.
|
||||
* @param length The number of bytes to encrypt.
|
||||
*/
|
||||
private fun encrypt(
|
||||
plaintext: ByteArray, plaintextOffset: Int,
|
||||
ciphertext: ByteArray, ciphertextOffset: Int, length: Int
|
||||
) {
|
||||
var plaintextOffset = plaintextOffset
|
||||
var ciphertextOffset = ciphertextOffset
|
||||
var length = length
|
||||
while (length > 0) {
|
||||
var tempLen = 64
|
||||
if (tempLen > length) tempLen = length
|
||||
hash(output, input)
|
||||
xorBlock(plaintext, plaintextOffset, ciphertext, ciphertextOffset, tempLen, output)
|
||||
if (++input[12] == 0) ++input[13]
|
||||
plaintextOffset += tempLen
|
||||
ciphertextOffset += tempLen
|
||||
length -= tempLen
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ShortBufferException::class)
|
||||
override fun encryptWithAd(
|
||||
ad: ByteArray?, plaintext: ByteArray, plaintextOffset: Int,
|
||||
ciphertext: ByteArray, ciphertextOffset: Int, length: Int
|
||||
): Int {
|
||||
require(!(ciphertextOffset < 0 || ciphertextOffset > ciphertext.size))
|
||||
require(!(length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.size || length > plaintext.size || (plaintext.size - plaintextOffset) < length))
|
||||
val space: Int = ciphertext.size - ciphertextOffset
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the plaintext as-is.
|
||||
if (length > space) throw ShortBufferException()
|
||||
if (plaintext !== ciphertext || plaintextOffset != ciphertextOffset) System.arraycopy(
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
length
|
||||
)
|
||||
return length
|
||||
}
|
||||
if (space < 16 || length > (space - 16)) throw ShortBufferException()
|
||||
setup(ad)
|
||||
encrypt(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length)
|
||||
poly.update(ciphertext, ciphertextOffset, length)
|
||||
finish(ad, length)
|
||||
System.arraycopy(polyKey, 0, ciphertext, ciphertextOffset + length, 16)
|
||||
return length + 16
|
||||
}
|
||||
|
||||
@Throws(ShortBufferException::class, BadPaddingException::class)
|
||||
override fun decryptWithAd(
|
||||
ad: ByteArray?,
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
length: Int
|
||||
): Int {
|
||||
require(!(ciphertextOffset < 0 || ciphertextOffset > ciphertext.size))
|
||||
var space: Int = ciphertext.size - ciphertextOffset
|
||||
if (length > space) throw ShortBufferException()
|
||||
require(!(length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.size || length > ciphertext.size || (ciphertext.size - ciphertextOffset) < length))
|
||||
space = plaintext.size - plaintextOffset
|
||||
if (!haskey) {
|
||||
// The key is not set yet - return the ciphertext as-is.
|
||||
if (length > space) throw ShortBufferException()
|
||||
if (plaintext !== ciphertext || plaintextOffset != ciphertextOffset) System.arraycopy(
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
length
|
||||
)
|
||||
return length
|
||||
}
|
||||
if (length < 16) throwBadTagException()
|
||||
val dataLen = length - 16
|
||||
if (dataLen > space) throw ShortBufferException()
|
||||
setup(ad)
|
||||
poly.update(ciphertext, ciphertextOffset, dataLen)
|
||||
finish(ad, dataLen)
|
||||
var temp = 0
|
||||
for (index in 0..15) temp =
|
||||
temp or (polyKey[index].toInt() xor ciphertext[ciphertextOffset + dataLen + index].toInt())
|
||||
if ((temp and 0xFF) != 0) throwBadTagException()
|
||||
encrypt(ciphertext, ciphertextOffset, plaintext, plaintextOffset, dataLen)
|
||||
return dataLen
|
||||
}
|
||||
|
||||
override fun fork(key: ByteArray, offset: Int): CipherState {
|
||||
val cipher: CipherState = ChaChaPolyCipherState()
|
||||
cipher.initializeKey(key, offset)
|
||||
return cipher
|
||||
}
|
||||
|
||||
override fun setNonce(nonce: Long) {
|
||||
n = nonce
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* XOR's the output of ChaCha20 with a byte buffer.
|
||||
*
|
||||
* @param input The input byte buffer.
|
||||
* @param inputOffset The offset of the first input byte.
|
||||
* @param output The output byte buffer (can be the same as the input).
|
||||
* @param outputOffset The offset of the first output byte.
|
||||
* @param length The number of bytes to XOR between 1 and 64.
|
||||
* @param block The ChaCha20 output block.
|
||||
*/
|
||||
private fun xorBlock(
|
||||
input: ByteArray,
|
||||
inputOffset: Int,
|
||||
output: ByteArray,
|
||||
outputOffset: Int,
|
||||
length: Int,
|
||||
block: IntArray
|
||||
) {
|
||||
var inputOffset = inputOffset
|
||||
var outputOffset = outputOffset
|
||||
var length = length
|
||||
var posn = 0
|
||||
var value: Int
|
||||
while (length >= 4) {
|
||||
value = block[posn++]
|
||||
output[outputOffset] = (input[inputOffset].toInt() xor value).toByte()
|
||||
output[outputOffset + 1] =
|
||||
(input[inputOffset + 1].toInt() xor (value shr 8)).toByte()
|
||||
output[outputOffset + 2] =
|
||||
(input[inputOffset + 2].toInt() xor (value shr 16)).toByte()
|
||||
output[outputOffset + 3] =
|
||||
(input[inputOffset + 3].toInt() xor (value shr 24)).toByte()
|
||||
inputOffset += 4
|
||||
outputOffset += 4
|
||||
length -= 4
|
||||
}
|
||||
when (length) {
|
||||
3 -> {
|
||||
value = block[posn]
|
||||
output[outputOffset] = (input[inputOffset].toInt() xor value).toByte()
|
||||
output[outputOffset + 1] =
|
||||
(input[inputOffset + 1].toInt() xor (value shr 8)).toByte()
|
||||
output[outputOffset + 2] =
|
||||
(input[inputOffset + 2].toInt() xor (value shr 16)).toByte()
|
||||
}
|
||||
2 -> {
|
||||
value = block[posn]
|
||||
output[outputOffset] = (input[inputOffset].toInt() xor value).toByte()
|
||||
output[outputOffset + 1] =
|
||||
(input[inputOffset + 1].toInt() xor (value shr 8)).toByte()
|
||||
}
|
||||
1 -> {
|
||||
value = block[posn]
|
||||
output[outputOffset] = (input[inputOffset].toInt() xor value).toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a 64-bit integer into a buffer in little-endian order.
|
||||
*
|
||||
* @param output The output buffer.
|
||||
* @param offset The offset into the output buffer.
|
||||
* @param value The 64-bit integer value.
|
||||
*/
|
||||
private fun putLittleEndian64(output: ByteArray, offset: Int, value: Long) {
|
||||
output[offset] = value.toByte()
|
||||
output[offset + 1] = (value shr 8).toByte()
|
||||
output[offset + 2] = (value shr 16).toByte()
|
||||
output[offset + 3] = (value shr 24).toByte()
|
||||
output[offset + 4] = (value shr 32).toByte()
|
||||
output[offset + 5] = (value shr 40).toByte()
|
||||
output[offset + 6] = (value shr 48).toByte()
|
||||
output[offset + 7] = (value shr 56).toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
/**
|
||||
* Interface to an authenticated cipher for use in the Noise protocol.
|
||||
*
|
||||
* CipherState objects are used to encrypt or decrypt data during a
|
||||
* session. Once the handshake has completed, HandshakeState.split()
|
||||
* will create two CipherState objects for encrypting packets sent to
|
||||
* the other party, and decrypting packets received from the other party.
|
||||
*/
|
||||
public interface CipherState extends Destroyable {
|
||||
|
||||
/**
|
||||
* Gets the Noise protocol name for this cipher.
|
||||
*
|
||||
* @return The cipher name.
|
||||
*/
|
||||
String getCipherName();
|
||||
|
||||
/**
|
||||
* Gets the length of the key values for this cipher.
|
||||
*
|
||||
* @return The length of the key in bytes; usually 32.
|
||||
*/
|
||||
int getKeyLength();
|
||||
|
||||
/**
|
||||
* Gets the length of the MAC values for this cipher.
|
||||
*
|
||||
* @return The length of MAC values in bytes, or zero if the
|
||||
* key has not yet been initialized.
|
||||
*/
|
||||
int getMACLength();
|
||||
|
||||
/**
|
||||
* Initializes the key on this cipher object.
|
||||
*
|
||||
* @param key Points to a buffer that contains the key.
|
||||
* @param offset The offset of the key in the key buffer.
|
||||
*
|
||||
* The key buffer must contain at least getKeyLength() bytes
|
||||
* starting at offset.
|
||||
*
|
||||
* @see #hasKey()
|
||||
*/
|
||||
void initializeKey(byte[] key, int offset);
|
||||
|
||||
/**
|
||||
* Determine if this cipher object has been configured with a key.
|
||||
*
|
||||
* @return true if this cipher object has a key; false if the
|
||||
* key has not yet been set with initializeKey().
|
||||
*
|
||||
* @see #initializeKey(byte[], int)
|
||||
*/
|
||||
boolean hasKey();
|
||||
|
||||
/**
|
||||
* Encrypts a plaintext buffer using the cipher and a block of associated data.
|
||||
*
|
||||
* @param ad The associated data, or null if there is none.
|
||||
* @param plaintext The buffer containing the plaintext to encrypt.
|
||||
* @param plaintextOffset The offset within the plaintext buffer of the
|
||||
* first byte or plaintext data.
|
||||
* @param ciphertext The buffer to place the ciphertext in. This can
|
||||
* be the same as the plaintext buffer.
|
||||
* @param ciphertextOffset The first offset within the ciphertext buffer
|
||||
* to place the ciphertext and the MAC tag.
|
||||
* @param length The length of the plaintext.
|
||||
* @return The length of the ciphertext plus the MAC tag, or -1 if the
|
||||
* ciphertext buffer is not large enough to hold the result.
|
||||
*
|
||||
* @throws ShortBufferException The ciphertext buffer does not have
|
||||
* enough space to hold the ciphertext plus MAC.
|
||||
*
|
||||
* @throws IllegalStateException The nonce has wrapped around.
|
||||
*
|
||||
* @throws IllegalArgumentException One of the parameters is out of range.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* encryption. In that case, plaintextOffset must be identical to
|
||||
* ciphertextOffset.
|
||||
*
|
||||
* There must be enough space in the ciphertext buffer to accomodate
|
||||
* length + getMACLength() bytes of data starting at ciphertextOffset.
|
||||
*/
|
||||
int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset, byte[] ciphertext, int ciphertextOffset, int length) throws ShortBufferException;
|
||||
|
||||
/**
|
||||
* Decrypts a ciphertext buffer using the cipher and a block of associated data.
|
||||
*
|
||||
* @param ad The associated data, or null if there is none.
|
||||
* @param ciphertext The buffer containing the ciphertext to decrypt.
|
||||
* @param ciphertextOffset The offset within the ciphertext buffer of
|
||||
* the first byte of ciphertext data.
|
||||
* @param plaintext The buffer to place the plaintext in. This can be
|
||||
* the same as the ciphertext buffer.
|
||||
* @param plaintextOffset The first offset within the plaintext buffer
|
||||
* to place the plaintext.
|
||||
* @param length The length of the incoming ciphertext plus the MAC tag.
|
||||
* @return The length of the plaintext with the MAC tag stripped off.
|
||||
*
|
||||
* @throws ShortBufferException The plaintext buffer does not have
|
||||
* enough space to store the decrypted data.
|
||||
*
|
||||
* @throws BadPaddingException The MAC value failed to verify.
|
||||
*
|
||||
* @throws IllegalStateException The nonce has wrapped around.
|
||||
*
|
||||
* @throws IllegalArgumentException One of the parameters is out of range.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* decryption. In that case, ciphertextOffset must be identical to
|
||||
* plaintextOffset.
|
||||
*/
|
||||
int decryptWithAd(byte[] ad, byte[] ciphertext, int ciphertextOffset, byte[] plaintext, int plaintextOffset, int length) throws ShortBufferException, BadPaddingException;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this cipher and initializes it with a key.
|
||||
*
|
||||
* @param key The buffer containing the key.
|
||||
* @param offset The offset into the key buffer of the first key byte.
|
||||
* @return A new CipherState of the same class as this one.
|
||||
*/
|
||||
CipherState fork(byte[] key, int offset);
|
||||
|
||||
/**
|
||||
* Sets the nonce value.
|
||||
*
|
||||
* @param nonce The new nonce value, which must be greater than or equal
|
||||
* to the current value.
|
||||
*
|
||||
* This function is intended for testing purposes only. If the nonce
|
||||
* value goes backwards then security may be compromised.
|
||||
*/
|
||||
void setNonce(long nonce);
|
||||
}
|
||||
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import javax.crypto.BadPaddingException
|
||||
import javax.crypto.ShortBufferException
|
||||
|
||||
/**
|
||||
* Interface to an authenticated cipher for use in the Noise protocol.
|
||||
*
|
||||
* CipherState objects are used to encrypt or decrypt data during a
|
||||
* session. Once the handshake has completed, HandshakeState.split()
|
||||
* will create two CipherState objects for encrypting packets sent to
|
||||
* the other party, and decrypting packets received from the other party.
|
||||
*/
|
||||
interface CipherState : Destroyable {
|
||||
/**
|
||||
* Gets the Noise protocol name for this cipher.
|
||||
*
|
||||
* @return The cipher name.
|
||||
*/
|
||||
val cipherName: String
|
||||
|
||||
/**
|
||||
* Gets the length of the key values for this cipher.
|
||||
*
|
||||
* @return The length of the key in bytes; usually 32.
|
||||
*/
|
||||
val keyLength: Int
|
||||
|
||||
/**
|
||||
* Gets the length of the MAC values for this cipher.
|
||||
*
|
||||
* @return The length of MAC values in bytes, or zero if the
|
||||
* key has not yet been initialized.
|
||||
*/
|
||||
val macLength: Int
|
||||
|
||||
/**
|
||||
* Initializes the key on this cipher object.
|
||||
*
|
||||
* @param key Points to a buffer that contains the key.
|
||||
* @param offset The offset of the key in the key buffer.
|
||||
*
|
||||
* The key buffer must contain at least getKeyLength() bytes
|
||||
* starting at offset.
|
||||
*
|
||||
* @see .hasKey
|
||||
*/
|
||||
fun initializeKey(key: ByteArray, offset: Int)
|
||||
|
||||
/**
|
||||
* Determine if this cipher object has been configured with a key.
|
||||
*
|
||||
* @return true if this cipher object has a key; false if the
|
||||
* key has not yet been set with initializeKey().
|
||||
*
|
||||
* @see .initializeKey
|
||||
*/
|
||||
fun hasKey(): Boolean
|
||||
|
||||
/**
|
||||
* Encrypts a plaintext buffer using the cipher and a block of associated data.
|
||||
*
|
||||
* @param ad The associated data, or null if there is none.
|
||||
* @param plaintext The buffer containing the plaintext to encrypt.
|
||||
* @param plaintextOffset The offset within the plaintext buffer of the
|
||||
* first byte or plaintext data.
|
||||
* @param ciphertext The buffer to place the ciphertext in. This can
|
||||
* be the same as the plaintext buffer.
|
||||
* @param ciphertextOffset The first offset within the ciphertext buffer
|
||||
* to place the ciphertext and the MAC tag.
|
||||
* @param length The length of the plaintext.
|
||||
* @return The length of the ciphertext plus the MAC tag, or -1 if the
|
||||
* ciphertext buffer is not large enough to hold the result.
|
||||
*
|
||||
* @throws ShortBufferException The ciphertext buffer does not have
|
||||
* enough space to hold the ciphertext plus MAC.
|
||||
*
|
||||
* @throws IllegalStateException The nonce has wrapped around.
|
||||
*
|
||||
* @throws IllegalArgumentException One of the parameters is out of range.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* encryption. In that case, plaintextOffset must be identical to
|
||||
* ciphertextOffset.
|
||||
*
|
||||
* There must be enough space in the ciphertext buffer to accomodate
|
||||
* length + getMACLength() bytes of data starting at ciphertextOffset.
|
||||
*/
|
||||
@Throws(ShortBufferException::class)
|
||||
fun encryptWithAd(
|
||||
ad: ByteArray?,
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
length: Int
|
||||
): Int
|
||||
|
||||
/**
|
||||
* Decrypts a ciphertext buffer using the cipher and a block of associated data.
|
||||
*
|
||||
* @param ad The associated data, or null if there is none.
|
||||
* @param ciphertext The buffer containing the ciphertext to decrypt.
|
||||
* @param ciphertextOffset The offset within the ciphertext buffer of
|
||||
* the first byte of ciphertext data.
|
||||
* @param plaintext The buffer to place the plaintext in. This can be
|
||||
* the same as the ciphertext buffer.
|
||||
* @param plaintextOffset The first offset within the plaintext buffer
|
||||
* to place the plaintext.
|
||||
* @param length The length of the incoming ciphertext plus the MAC tag.
|
||||
* @return The length of the plaintext with the MAC tag stripped off.
|
||||
*
|
||||
* @throws ShortBufferException The plaintext buffer does not have
|
||||
* enough space to store the decrypted data.
|
||||
*
|
||||
* @throws BadPaddingException The MAC value failed to verify.
|
||||
*
|
||||
* @throws IllegalStateException The nonce has wrapped around.
|
||||
*
|
||||
* @throws IllegalArgumentException One of the parameters is out of range.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* decryption. In that case, ciphertextOffset must be identical to
|
||||
* plaintextOffset.
|
||||
*/
|
||||
@Throws(ShortBufferException::class, BadPaddingException::class)
|
||||
fun decryptWithAd(
|
||||
ad: ByteArray?,
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
length: Int
|
||||
): Int
|
||||
|
||||
/**
|
||||
* Creates a new instance of this cipher and initializes it with a key.
|
||||
*
|
||||
* @param key The buffer containing the key.
|
||||
* @param offset The offset into the key buffer of the first key byte.
|
||||
* @return A new CipherState of the same class as this one.
|
||||
*/
|
||||
fun fork(key: ByteArray, offset: Int): CipherState
|
||||
|
||||
/**
|
||||
* Sets the nonce value.
|
||||
*
|
||||
* @param nonce The new nonce value, which must be greater than or equal
|
||||
* to the current value.
|
||||
*
|
||||
* This function is intended for testing purposes only. If the nonce
|
||||
* value goes backwards then security may be compromised.
|
||||
*/
|
||||
fun setNonce(nonce: Long)
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
/**
|
||||
* Class that contains a pair of CipherState objects.
|
||||
*
|
||||
* CipherState pairs typically arise when HandshakeState.split() is called.
|
||||
*/
|
||||
public final class CipherStatePair implements Destroyable {
|
||||
|
||||
private CipherState send;
|
||||
private CipherState recv;
|
||||
|
||||
/**
|
||||
* Constructs a pair of CipherState objects.
|
||||
*
|
||||
* @param sender The CipherState to use to send packets to the remote party.
|
||||
* @param receiver The CipherState to use to receive packets from the remote party.
|
||||
*/
|
||||
public CipherStatePair(CipherState sender, CipherState receiver)
|
||||
{
|
||||
send = sender;
|
||||
recv = receiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CipherState to use to send packets to the remote party.
|
||||
*
|
||||
* @return The sending CipherState.
|
||||
*/
|
||||
public CipherState getSender() {
|
||||
return send;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CipherState to use to receive packets from the remote party.
|
||||
*
|
||||
* @return The receiving CipherState.
|
||||
*/
|
||||
public CipherState getReceiver() {
|
||||
return recv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the receiving CipherState and retains only the sending CipherState.
|
||||
*
|
||||
* This function is intended for use with one-way handshake patterns.
|
||||
*/
|
||||
public void senderOnly()
|
||||
{
|
||||
if (recv != null) {
|
||||
recv.destroy();
|
||||
recv = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the sending CipherState and retains only the receiving CipherState.
|
||||
*
|
||||
* This function is intended for use with one-way handshake patterns.
|
||||
*/
|
||||
public void receiverOnly()
|
||||
{
|
||||
if (send != null) {
|
||||
send.destroy();
|
||||
send = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the sender and receiver.
|
||||
*/
|
||||
public void swap()
|
||||
{
|
||||
CipherState temp = send;
|
||||
send = recv;
|
||||
recv = temp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
senderOnly();
|
||||
receiverOnly();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
/**
|
||||
* Class that contains a pair of CipherState objects.
|
||||
*
|
||||
* CipherState pairs typically arise when HandshakeState.split() is called.
|
||||
*
|
||||
* @param sender The CipherState to use to send packets to the remote party.
|
||||
* @param receiver The CipherState to use to receive packets from the remote party.
|
||||
*/
|
||||
class CipherStatePair(
|
||||
var sender: CipherState?,
|
||||
var receiver: CipherState?,
|
||||
) : Destroyable {
|
||||
|
||||
/**
|
||||
* Destroys the receiving CipherState and retains only the sending CipherState.
|
||||
*
|
||||
* This function is intended for use with one-way handshake patterns.
|
||||
*/
|
||||
fun senderOnly() {
|
||||
receiver?.destroy()
|
||||
receiver = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the sending CipherState and retains only the receiving CipherState.
|
||||
*
|
||||
* This function is intended for use with one-way handshake patterns.
|
||||
*/
|
||||
fun receiverOnly() {
|
||||
sender?.destroy()
|
||||
sender = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the sender and receiver.
|
||||
*/
|
||||
fun swap() {
|
||||
sender = receiver.also { receiver = sender }
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
senderOnly()
|
||||
receiverOnly()
|
||||
}
|
||||
}
|
||||
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Curve25519;
|
||||
|
||||
/**
|
||||
* Implementation of the Curve25519 algorithm for the Noise protocol.
|
||||
*/
|
||||
class Curve25519DHState implements DHState {
|
||||
|
||||
private byte[] publicKey;
|
||||
private byte[] privateKey;
|
||||
private int mode;
|
||||
|
||||
/**
|
||||
* Constructs a new Diffie-Hellman object for Curve25519.
|
||||
*/
|
||||
public Curve25519DHState()
|
||||
{
|
||||
publicKey = new byte [32];
|
||||
privateKey = new byte [32];
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
clearKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDHName() {
|
||||
return "25519";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPublicKeyLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrivateKeyLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSharedKeyLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateKeyPair() {
|
||||
Noise.random(privateKey);
|
||||
Curve25519.eval(publicKey, 0, privateKey, null);
|
||||
mode = 0x03;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPublicKey(byte[] key, int offset) {
|
||||
System.arraycopy(publicKey, 0, key, offset, 32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPublicKey(byte[] key, int offset) {
|
||||
System.arraycopy(key, offset, publicKey, 0, 32);
|
||||
Arrays.fill(privateKey, (byte)0);
|
||||
mode = 0x01;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPrivateKey(byte[] key, int offset) {
|
||||
System.arraycopy(privateKey, 0, key, offset, 32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrivateKey(byte[] key, int offset) {
|
||||
System.arraycopy(key, offset, privateKey, 0, 32);
|
||||
Curve25519.eval(publicKey, 0, privateKey, null);
|
||||
mode = 0x03;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToNullPublicKey() {
|
||||
Arrays.fill(publicKey, (byte)0);
|
||||
Arrays.fill(privateKey, (byte)0);
|
||||
mode = 0x01;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearKey() {
|
||||
Noise.destroy(publicKey);
|
||||
Noise.destroy(privateKey);
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPublicKey() {
|
||||
return (mode & 0x01) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivateKey() {
|
||||
return (mode & 0x02) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullPublicKey() {
|
||||
if ((mode & 0x01) == 0)
|
||||
return false;
|
||||
int temp = 0;
|
||||
for (int index = 0; index < 32; ++index)
|
||||
temp |= publicKey[index];
|
||||
return temp == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(byte[] sharedKey, int offset, DHState publicDH) {
|
||||
if (!(publicDH instanceof Curve25519DHState))
|
||||
throw new IllegalArgumentException("Incompatible DH algorithms");
|
||||
Curve25519.eval(sharedKey, offset, privateKey, ((Curve25519DHState)publicDH).publicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(DHState other) {
|
||||
if (!(other instanceof Curve25519DHState))
|
||||
throw new IllegalStateException("Mismatched DH key objects");
|
||||
if (other == this)
|
||||
return;
|
||||
Curve25519DHState dh = (Curve25519DHState)other;
|
||||
System.arraycopy(dh.privateKey, 0, privateKey, 0, 32);
|
||||
System.arraycopy(dh.publicKey, 0, publicKey, 0, 32);
|
||||
mode = dh.mode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Curve25519
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.destroy
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.random
|
||||
|
||||
/**
|
||||
* Implementation of the Curve25519 algorithm for the Noise protocol.
|
||||
*/
|
||||
internal class Curve25519DHState : DHState {
|
||||
private val publicKey: ByteArray = ByteArray(32)
|
||||
private val privateKey: ByteArray = ByteArray(32)
|
||||
private var mode = 0
|
||||
|
||||
override fun destroy() {
|
||||
clearKey()
|
||||
}
|
||||
|
||||
override val dhName: String get() = "25519"
|
||||
override val publicKeyLength: Int get() = 32
|
||||
override val privateKeyLength: Int get() = 32
|
||||
override val sharedKeyLength: Int get() = 32
|
||||
|
||||
override fun generateKeyPair() {
|
||||
random(privateKey)
|
||||
Curve25519.eval(publicKey, 0, privateKey, null)
|
||||
mode = 0x03
|
||||
}
|
||||
|
||||
override fun getPublicKey(key: ByteArray, offset: Int) {
|
||||
publicKey.copyInto(key, offset, 0, 32)
|
||||
}
|
||||
|
||||
override fun setPublicKey(key: ByteArray, offset: Int) {
|
||||
key.copyInto(publicKey, 0, offset, offset + 32)
|
||||
privateKey.fill(0)
|
||||
mode = 0x01
|
||||
}
|
||||
|
||||
override fun getPrivateKey(key: ByteArray, offset: Int) {
|
||||
privateKey.copyInto(key, offset, 0, 32)
|
||||
}
|
||||
|
||||
override fun setPrivateKey(key: ByteArray, offset: Int) {
|
||||
key.copyInto(privateKey, 0, offset, offset + 32)
|
||||
Curve25519.eval(publicKey, 0, privateKey, null)
|
||||
mode = 0x03
|
||||
}
|
||||
|
||||
override fun setToNullPublicKey() {
|
||||
publicKey.fill(0)
|
||||
privateKey.fill(0)
|
||||
mode = 0x01
|
||||
}
|
||||
|
||||
override fun clearKey() {
|
||||
destroy(publicKey)
|
||||
destroy(privateKey)
|
||||
mode = 0
|
||||
}
|
||||
|
||||
override fun hasPublicKey(): Boolean = (mode and 0x01) != 0
|
||||
|
||||
override fun hasPrivateKey(): Boolean = (mode and 0x02) != 0
|
||||
|
||||
override fun isNullPublicKey(): Boolean {
|
||||
if ((mode and 0x01) == 0) return false
|
||||
var temp = 0
|
||||
for (index in 0..31) temp = temp or publicKey[index].toInt()
|
||||
return temp == 0
|
||||
}
|
||||
|
||||
override fun calculate(sharedKey: ByteArray, offset: Int, publicDH: DHState) {
|
||||
require(publicDH is Curve25519DHState) { "Incompatible DH algorithms" }
|
||||
Curve25519.eval(sharedKey, offset, privateKey, publicDH.publicKey)
|
||||
}
|
||||
|
||||
override fun copyFrom(other: DHState) {
|
||||
check(other is Curve25519DHState) { "Mismatched DH key objects" }
|
||||
if (other === this) return
|
||||
other.privateKey.copyInto(privateKey, 0, 0, 32)
|
||||
other.publicKey.copyInto(publicKey, 0, 0, 32)
|
||||
mode = other.mode
|
||||
}
|
||||
}
|
||||
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Curve448;
|
||||
|
||||
/**
|
||||
* Implementation of the Curve448 algorithm for the Noise protocol.
|
||||
*/
|
||||
class Curve448DHState implements DHState {
|
||||
|
||||
private byte[] publicKey;
|
||||
private byte[] privateKey;
|
||||
private int mode;
|
||||
|
||||
/**
|
||||
* Constructs a new Diffie-Hellman object for Curve448.
|
||||
*/
|
||||
public Curve448DHState()
|
||||
{
|
||||
publicKey = new byte [56];
|
||||
privateKey = new byte [56];
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
clearKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDHName() {
|
||||
return "448";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPublicKeyLength() {
|
||||
return 56;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrivateKeyLength() {
|
||||
return 56;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSharedKeyLength() {
|
||||
return 56;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateKeyPair() {
|
||||
Noise.random(privateKey);
|
||||
Curve448.eval(publicKey, 0, privateKey, null);
|
||||
mode = 0x03;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPublicKey(byte[] key, int offset) {
|
||||
System.arraycopy(publicKey, 0, key, offset, 56);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPublicKey(byte[] key, int offset) {
|
||||
System.arraycopy(key, offset, publicKey, 0, 56);
|
||||
Arrays.fill(privateKey, (byte)0);
|
||||
mode = 0x01;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPrivateKey(byte[] key, int offset) {
|
||||
System.arraycopy(privateKey, 0, key, offset, 56);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrivateKey(byte[] key, int offset) {
|
||||
System.arraycopy(key, offset, privateKey, 0, 56);
|
||||
Curve448.eval(publicKey, 0, privateKey, null);
|
||||
mode = 0x03;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToNullPublicKey() {
|
||||
Arrays.fill(publicKey, (byte)0);
|
||||
Arrays.fill(privateKey, (byte)0);
|
||||
mode = 0x01;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearKey() {
|
||||
Noise.destroy(publicKey);
|
||||
Noise.destroy(privateKey);
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPublicKey() {
|
||||
return (mode & 0x01) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivateKey() {
|
||||
return (mode & 0x02) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullPublicKey() {
|
||||
if ((mode & 0x01) == 0)
|
||||
return false;
|
||||
int temp = 0;
|
||||
for (int index = 0; index < 56; ++index)
|
||||
temp |= publicKey[index];
|
||||
return temp == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(byte[] sharedKey, int offset, DHState publicDH) {
|
||||
if (!(publicDH instanceof Curve448DHState))
|
||||
throw new IllegalArgumentException("Incompatible DH algorithms");
|
||||
Curve448.eval(sharedKey, offset, privateKey, ((Curve448DHState)publicDH).publicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(DHState other) {
|
||||
if (!(other instanceof Curve448DHState))
|
||||
throw new IllegalStateException("Mismatched DH key objects");
|
||||
if (other == this)
|
||||
return;
|
||||
Curve448DHState dh = (Curve448DHState)other;
|
||||
System.arraycopy(dh.privateKey, 0, privateKey, 0, 56);
|
||||
System.arraycopy(dh.publicKey, 0, publicKey, 0, 56);
|
||||
mode = dh.mode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Curve448
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.destroy
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.random
|
||||
|
||||
/**
|
||||
* Implementation of the Curve448 algorithm for the Noise protocol.
|
||||
*/
|
||||
internal class Curve448DHState : DHState {
|
||||
private val publicKey: ByteArray = ByteArray(56)
|
||||
private val privateKey: ByteArray = ByteArray(56)
|
||||
private var mode = 0
|
||||
|
||||
override fun destroy() {
|
||||
clearKey()
|
||||
}
|
||||
|
||||
override val dhName: String get() = "448"
|
||||
override val publicKeyLength: Int get() = 56
|
||||
override val privateKeyLength: Int get() = 56
|
||||
override val sharedKeyLength: Int get() = 56
|
||||
|
||||
override fun generateKeyPair() {
|
||||
random(privateKey)
|
||||
Curve448.eval(publicKey, 0, privateKey, null)
|
||||
mode = 0x03
|
||||
}
|
||||
|
||||
override fun getPublicKey(key: ByteArray, offset: Int) {
|
||||
publicKey.copyInto(key, offset, 0, 56)
|
||||
}
|
||||
|
||||
override fun setPublicKey(key: ByteArray, offset: Int) {
|
||||
key.copyInto(publicKey, 0, offset, offset + 56)
|
||||
privateKey.fill(0)
|
||||
mode = 0x01
|
||||
}
|
||||
|
||||
override fun getPrivateKey(key: ByteArray, offset: Int) {
|
||||
privateKey.copyInto(key, offset, 0, 56)
|
||||
}
|
||||
|
||||
override fun setPrivateKey(key: ByteArray, offset: Int) {
|
||||
key.copyInto(privateKey, 0, offset, offset + 56)
|
||||
Curve448.eval(publicKey, 0, privateKey, null)
|
||||
mode = 0x03
|
||||
}
|
||||
|
||||
override fun setToNullPublicKey() {
|
||||
publicKey.fill(0)
|
||||
privateKey.fill(0)
|
||||
mode = 0x01
|
||||
}
|
||||
|
||||
override fun clearKey() {
|
||||
destroy(publicKey)
|
||||
destroy(privateKey)
|
||||
mode = 0
|
||||
}
|
||||
|
||||
override fun hasPublicKey(): Boolean = (mode and 0x01) != 0
|
||||
|
||||
override fun hasPrivateKey(): Boolean = (mode and 0x02) != 0
|
||||
|
||||
override fun isNullPublicKey(): Boolean {
|
||||
if ((mode and 0x01) == 0) return false
|
||||
var temp = 0
|
||||
for (index in 0..55) temp = temp or publicKey[index].toInt()
|
||||
return temp == 0
|
||||
}
|
||||
|
||||
override fun calculate(sharedKey: ByteArray, offset: Int, publicDH: DHState) {
|
||||
require(publicDH is Curve448DHState) { "Incompatible DH algorithms" }
|
||||
Curve448.eval(sharedKey, offset, privateKey, publicDH.publicKey)
|
||||
}
|
||||
|
||||
override fun copyFrom(other: DHState) {
|
||||
check(other is Curve448DHState) { "Mismatched DH key objects" }
|
||||
if (other === this) return
|
||||
other.privateKey.copyInto(privateKey, 0, 0, 56)
|
||||
other.publicKey.copyInto(publicKey, 0, 0, 56)
|
||||
mode = other.mode
|
||||
}
|
||||
}
|
||||
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
/**
|
||||
* Interface to a Diffie-Hellman algorithm for the Noise protocol.
|
||||
*/
|
||||
public interface DHState extends Destroyable {
|
||||
|
||||
/**
|
||||
* Gets the Noise protocol name for this Diffie-Hellman algorithm.
|
||||
*
|
||||
* @return The algorithm name.
|
||||
*/
|
||||
String getDHName();
|
||||
|
||||
/**
|
||||
* Gets the length of public keys for this algorithm.
|
||||
*
|
||||
* @return The length of public keys in bytes.
|
||||
*/
|
||||
int getPublicKeyLength();
|
||||
|
||||
/**
|
||||
* Gets the length of private keys for this algorithm.
|
||||
*
|
||||
* @return The length of private keys in bytes.
|
||||
*/
|
||||
int getPrivateKeyLength();
|
||||
|
||||
/**
|
||||
* Gets the length of shared keys for this algorithm.
|
||||
*
|
||||
* @return The length of shared keys in bytes.
|
||||
*/
|
||||
int getSharedKeyLength();
|
||||
|
||||
/**
|
||||
* Generates a new random keypair.
|
||||
*/
|
||||
void generateKeyPair();
|
||||
|
||||
/**
|
||||
* Gets the public key associated with this object.
|
||||
*
|
||||
* @param key The buffer to copy the public key to.
|
||||
* @param offset The first offset in the key buffer to copy to.
|
||||
*/
|
||||
void getPublicKey(byte[] key, int offset);
|
||||
|
||||
/**
|
||||
* Sets the public key for this object.
|
||||
*
|
||||
* @param key The buffer containing the public key.
|
||||
* @param offset The first offset in the buffer that contains the key.
|
||||
*
|
||||
* If this object previously held a key pair, then this function
|
||||
* will change it into a public key only object.
|
||||
*/
|
||||
void setPublicKey(byte[] key, int offset);
|
||||
|
||||
/**
|
||||
* Gets the private key associated with this object.
|
||||
*
|
||||
* @param key The buffer to copy the private key to.
|
||||
* @param offset The first offset in the key buffer to copy to.
|
||||
*/
|
||||
void getPrivateKey(byte[] key, int offset);
|
||||
|
||||
/**
|
||||
* Sets the private key for this object.
|
||||
*
|
||||
* @param key The buffer containing the [rivate key.
|
||||
* @param offset The first offset in the buffer that contains the key.
|
||||
*
|
||||
* If this object previously held only a public key, then
|
||||
* this function will change it into a key pair.
|
||||
*/
|
||||
void setPrivateKey(byte[] key, int offset);
|
||||
|
||||
/**
|
||||
* Sets this object to the null public key and clears the private key.
|
||||
*/
|
||||
void setToNullPublicKey();
|
||||
|
||||
/**
|
||||
* Clears the key pair.
|
||||
*/
|
||||
void clearKey();
|
||||
|
||||
/**
|
||||
* Determine if this object contains a public key.
|
||||
*
|
||||
* @return Returns true if this object contains a public key,
|
||||
* or false if the public key has not yet been set.
|
||||
*/
|
||||
boolean hasPublicKey();
|
||||
|
||||
/**
|
||||
* Determine if this object contains a private key.
|
||||
*
|
||||
* @return Returns true if this object contains a private key,
|
||||
* or false if the private key has not yet been set.
|
||||
*/
|
||||
boolean hasPrivateKey();
|
||||
|
||||
/**
|
||||
* Determine if the public key in this object is the special null value.
|
||||
*
|
||||
* @return Returns true if the public key is the special null value,
|
||||
* or false otherwise.
|
||||
*/
|
||||
boolean isNullPublicKey();
|
||||
|
||||
/**
|
||||
* Performs a Diffie-Hellman calculation with this object as the private key.
|
||||
*
|
||||
* @param sharedKey Buffer to put the shared key into.
|
||||
* @param offset Offset of the first byte for the shared key.
|
||||
* @param publicDH Object that contains the public key for the calculation.
|
||||
*
|
||||
* @throws IllegalArgumentException The publicDH object is not the same
|
||||
* type as this object, or one of the objects does not contain a valid key.
|
||||
*/
|
||||
void calculate(byte[] sharedKey, int offset, DHState publicDH);
|
||||
|
||||
/**
|
||||
* Copies the key values from another DH object of the same type.
|
||||
*
|
||||
* @param other The other DH object to copy from
|
||||
*
|
||||
* @throws IllegalStateException The other DH object does not have
|
||||
* the same type as this object.
|
||||
*/
|
||||
void copyFrom(DHState other);
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
/**
|
||||
* Interface to a Diffie-Hellman algorithm for the Noise protocol.
|
||||
*/
|
||||
interface DHState : Destroyable {
|
||||
/** The Noise protocol name for this Diffie-Hellman algorithm. */
|
||||
val dhName: String
|
||||
|
||||
/** Length of public keys for this algorithm, in bytes. */
|
||||
val publicKeyLength: Int
|
||||
|
||||
/** Length of private keys for this algorithm, in bytes. */
|
||||
val privateKeyLength: Int
|
||||
|
||||
/** Length of shared keys for this algorithm, in bytes. */
|
||||
val sharedKeyLength: Int
|
||||
|
||||
/**
|
||||
* Generates a new random keypair.
|
||||
*/
|
||||
fun generateKeyPair()
|
||||
|
||||
/**
|
||||
* Gets the public key associated with this object.
|
||||
*
|
||||
* @param key The buffer to copy the public key to.
|
||||
* @param offset The first offset in the key buffer to copy to.
|
||||
*/
|
||||
fun getPublicKey(key: ByteArray, offset: Int)
|
||||
|
||||
/**
|
||||
* Sets the public key for this object.
|
||||
*
|
||||
* @param key The buffer containing the public key.
|
||||
* @param offset The first offset in the buffer that contains the key.
|
||||
*
|
||||
* If this object previously held a key pair, then this function
|
||||
* will change it into a public key only object.
|
||||
*/
|
||||
fun setPublicKey(key: ByteArray, offset: Int)
|
||||
|
||||
/**
|
||||
* Gets the private key associated with this object.
|
||||
*
|
||||
* @param key The buffer to copy the private key to.
|
||||
* @param offset The first offset in the key buffer to copy to.
|
||||
*/
|
||||
fun getPrivateKey(key: ByteArray, offset: Int)
|
||||
|
||||
/**
|
||||
* Sets the private key for this object.
|
||||
*
|
||||
* @param key The buffer containing the private key.
|
||||
* @param offset The first offset in the buffer that contains the key.
|
||||
*
|
||||
* If this object previously held only a public key, then
|
||||
* this function will change it into a key pair.
|
||||
*/
|
||||
fun setPrivateKey(key: ByteArray, offset: Int)
|
||||
|
||||
/**
|
||||
* Sets this object to the null public key and clears the private key.
|
||||
*/
|
||||
fun setToNullPublicKey()
|
||||
|
||||
/**
|
||||
* Clears the key pair.
|
||||
*/
|
||||
fun clearKey()
|
||||
|
||||
/**
|
||||
* Determine if this object contains a public key.
|
||||
*/
|
||||
fun hasPublicKey(): Boolean
|
||||
|
||||
/**
|
||||
* Determine if this object contains a private key.
|
||||
*/
|
||||
fun hasPrivateKey(): Boolean
|
||||
|
||||
/**
|
||||
* Determine if the public key in this object is the special null value.
|
||||
*/
|
||||
fun isNullPublicKey(): Boolean
|
||||
|
||||
/**
|
||||
* Performs a Diffie-Hellman calculation with this object as the private key.
|
||||
*
|
||||
* @param sharedKey Buffer to put the shared key into.
|
||||
* @param offset Offset of the first byte for the shared key.
|
||||
* @param publicDH Object that contains the public key for the calculation.
|
||||
*
|
||||
* @throws IllegalArgumentException The publicDH object is not the same
|
||||
* type as this object, or one of the objects does not contain a valid key.
|
||||
*/
|
||||
fun calculate(sharedKey: ByteArray, offset: Int, publicDH: DHState)
|
||||
|
||||
/**
|
||||
* Copies the key values from another DH object of the same type.
|
||||
*
|
||||
* @param other The other DH object to copy from.
|
||||
*
|
||||
* @throws IllegalStateException The other DH object does not have
|
||||
* the same type as this object.
|
||||
*/
|
||||
fun copyFrom(other: DHState)
|
||||
}
|
||||
@ -19,42 +19,43 @@
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.bitchat.android.noise.southernstorm.protocol;
|
||||
package com.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
/**
|
||||
* Additional API for DH objects that need special handling for
|
||||
* hybrid operations.
|
||||
*/
|
||||
public interface DHStateHybrid extends DHState {
|
||||
interface DHStateHybrid : DHState {
|
||||
/**
|
||||
* Generates a new random keypair relative to the parameters
|
||||
* in another object.
|
||||
*
|
||||
* @param remote The remote party in this communication to obtain parameters.
|
||||
*
|
||||
* @throws IllegalStateException The other or remote DH object does not have
|
||||
* the same type as this object.
|
||||
*/
|
||||
fun generateKeyPair(remote: DHState?)
|
||||
|
||||
/**
|
||||
* Generates a new random keypair relative to the parameters
|
||||
* in another object.
|
||||
*
|
||||
* @param remote The remote party in this communication to obtain parameters.
|
||||
*
|
||||
* @throws IllegalStateException The other or remote DH object does not have
|
||||
* the same type as this object.
|
||||
*/
|
||||
void generateKeyPair(DHState remote);
|
||||
// Note: copyFrom(other) is inherited from DHState; the two-arg overload
|
||||
// below adds the remote-peer parameter required by hybrid algorithms.
|
||||
|
||||
/**
|
||||
* Copies the key values from another DH object of the same type.
|
||||
*
|
||||
* @param other The other DH object to copy from
|
||||
* @param remote The remote party in this communication to obtain parameters.
|
||||
*
|
||||
* @throws IllegalStateException The other or remote DH object does not have
|
||||
* the same type as this object.
|
||||
*/
|
||||
void copyFrom(DHState other, DHState remote);
|
||||
|
||||
/**
|
||||
* Specifies the local peer object prior to setting a public key
|
||||
* on a remote object.
|
||||
*
|
||||
* @param local The local peer object.
|
||||
*/
|
||||
void specifyPeer(DHState local);
|
||||
/**
|
||||
* Copies the key values from another DH object of the same type.
|
||||
*
|
||||
* @param other The other DH object to copy from
|
||||
* @param remote The remote party in this communication to obtain parameters.
|
||||
*
|
||||
* @throws IllegalStateException The other or remote DH object does not have
|
||||
* the same type as this object.
|
||||
*/
|
||||
fun copyFrom(other: DHState, remote: DHState?)
|
||||
|
||||
/**
|
||||
* Specifies the local peer object prior to setting a public key
|
||||
* on a remote object.
|
||||
*
|
||||
* @param local The local peer object.
|
||||
*/
|
||||
fun specifyPeer(local: DHState?)
|
||||
}
|
||||
@ -20,7 +20,7 @@
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.bitchat.android.noise.southernstorm.protocol;
|
||||
package com.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
/**
|
||||
* Interface for objects that implement destroying.
|
||||
@ -34,10 +34,9 @@ package com.bitchat.android.noise.southernstorm.protocol;
|
||||
* The Noise.destroy() function can help with destroying byte arrays
|
||||
* that hold sensitive values.
|
||||
*/
|
||||
public interface Destroyable {
|
||||
|
||||
/**
|
||||
* Destroys all sensitive state in the current object.
|
||||
*/
|
||||
void destroy();
|
||||
interface Destroyable {
|
||||
/**
|
||||
* Destroys all sensitive state in the current object.
|
||||
*/
|
||||
fun destroy()
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,340 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.NewHope;
|
||||
import com.bitchat.android.noise.southernstorm.crypto.NewHopeTor;
|
||||
|
||||
/**
|
||||
* Implementation of the New Hope post-quantum algorithm for the Noise protocol.
|
||||
*/
|
||||
final class NewHopeDHState implements DHStateHybrid {
|
||||
|
||||
enum KeyType
|
||||
{
|
||||
None,
|
||||
AlicePrivate,
|
||||
AlicePublic,
|
||||
BobPrivate,
|
||||
BobPublic,
|
||||
BobCalculated;
|
||||
}
|
||||
|
||||
private NewHopeTor nh;
|
||||
private byte[] publicKey;
|
||||
private byte[] privateKey;
|
||||
private KeyType keyType;
|
||||
|
||||
/**
|
||||
* Special version of NewHopeTor that allows explicit random data
|
||||
* to be specified for test vectors.
|
||||
*/
|
||||
private class NewHopeWithPrivateKey extends NewHopeTor {
|
||||
|
||||
byte[] randomData;
|
||||
|
||||
public NewHopeWithPrivateKey(byte[] randomData)
|
||||
{
|
||||
this.randomData = randomData;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void randombytes(byte[] buffer)
|
||||
{
|
||||
System.arraycopy(randomData, 0, buffer, 0, buffer.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new key exchange object for New Hope.
|
||||
*/
|
||||
public NewHopeDHState() {
|
||||
nh = null;
|
||||
publicKey = null;
|
||||
privateKey = null;
|
||||
keyType = KeyType.None;
|
||||
}
|
||||
|
||||
private boolean isAlice() {
|
||||
return keyType == KeyType.AlicePrivate || keyType == KeyType.AlicePublic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
clearKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDHName() {
|
||||
return "NewHope";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPublicKeyLength() {
|
||||
if (isAlice())
|
||||
return NewHope.SENDABYTES;
|
||||
else
|
||||
return NewHope.SENDBBYTES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrivateKeyLength() {
|
||||
// New Hope doesn't have private keys in the same sense as
|
||||
// Curve25519 and Curve448. Instead return the number of
|
||||
// random bytes that we need to generate each key type.
|
||||
if (isAlice())
|
||||
return 64;
|
||||
else
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSharedKeyLength() {
|
||||
return NewHope.SHAREDBYTES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateKeyPair() {
|
||||
clearKey();
|
||||
keyType = KeyType.AlicePrivate;
|
||||
nh = new NewHopeTor();
|
||||
publicKey = new byte [NewHope.SENDABYTES];
|
||||
nh.keygen(publicKey, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateKeyPair(DHState remote) {
|
||||
if (remote == null) {
|
||||
// No remote public key, so always generate in Alice mode.
|
||||
generateKeyPair();
|
||||
return;
|
||||
} else if (!(remote instanceof NewHopeDHState)) {
|
||||
throw new IllegalStateException("Mismatched DH objects");
|
||||
}
|
||||
NewHopeDHState r = (NewHopeDHState)remote;
|
||||
if (r.isAlice() && r.publicKey != null) {
|
||||
// We have a remote public key for Alice, so generate in Bob mode.
|
||||
clearKey();
|
||||
keyType = KeyType.BobCalculated;
|
||||
nh = new NewHopeTor();
|
||||
publicKey = new byte [NewHope.SENDBBYTES];
|
||||
privateKey = new byte [NewHope.SHAREDBYTES];
|
||||
nh.sharedb(privateKey, 0, publicKey, 0, r.publicKey, 0);
|
||||
} else {
|
||||
generateKeyPair();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPublicKey(byte[] key, int offset) {
|
||||
if (publicKey != null)
|
||||
System.arraycopy(publicKey, 0, key, offset, getPublicKeyLength());
|
||||
else
|
||||
Arrays.fill(key, 0, getPublicKeyLength(), (byte)0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPublicKey(byte[] key, int offset) {
|
||||
if (publicKey != null)
|
||||
Noise.destroy(publicKey);
|
||||
publicKey = new byte [getPublicKeyLength()];
|
||||
System.arraycopy(key, 0, publicKey, 0, publicKey.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPrivateKey(byte[] key, int offset) {
|
||||
if (privateKey != null)
|
||||
System.arraycopy(privateKey, 0, key, offset, getPrivateKeyLength());
|
||||
else
|
||||
Arrays.fill(key, 0, getPrivateKeyLength(), (byte)0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrivateKey(byte[] key, int offset) {
|
||||
clearKey();
|
||||
// Guess the key type from the length of the test data.
|
||||
if (offset == 0 && key.length == 64)
|
||||
keyType = KeyType.AlicePrivate;
|
||||
else
|
||||
keyType = KeyType.BobPrivate;
|
||||
privateKey = new byte [getPrivateKeyLength()];
|
||||
System.arraycopy(key, 0, privateKey, 0, privateKey.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToNullPublicKey() {
|
||||
// Null public keys are not supported by New Hope.
|
||||
// Destroy the current values but otherwise ignore.
|
||||
clearKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearKey() {
|
||||
if (nh != null) {
|
||||
nh.destroy();
|
||||
nh = null;
|
||||
}
|
||||
if (publicKey != null) {
|
||||
Noise.destroy(publicKey);
|
||||
publicKey = null;
|
||||
}
|
||||
if (privateKey != null) {
|
||||
Noise.destroy(privateKey);
|
||||
privateKey = null;
|
||||
}
|
||||
keyType = KeyType.None;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPublicKey() {
|
||||
return publicKey != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrivateKey() {
|
||||
return privateKey != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullPublicKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(byte[] sharedKey, int offset, DHState publicDH) {
|
||||
if (!(publicDH instanceof NewHopeDHState))
|
||||
throw new IllegalArgumentException("Incompatible DH algorithms");
|
||||
NewHopeDHState other = (NewHopeDHState)publicDH;
|
||||
if (keyType == KeyType.AlicePrivate) {
|
||||
// Compute the shared key for Alice.
|
||||
nh.shareda(sharedKey, 0, other.publicKey, 0);
|
||||
} else if (keyType == KeyType.BobCalculated) {
|
||||
// The shared key for Bob was already computed when the key was generated.
|
||||
System.arraycopy(privateKey, 0, sharedKey, 0, NewHope.SHAREDBYTES);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot calculate with this DH object");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(DHState other) {
|
||||
if (!(other instanceof NewHopeDHState))
|
||||
throw new IllegalStateException("Mismatched DH key objects");
|
||||
if (other == this)
|
||||
return;
|
||||
NewHopeDHState dh = (NewHopeDHState)other;
|
||||
clearKey();
|
||||
switch (dh.keyType) {
|
||||
case None:
|
||||
break;
|
||||
|
||||
case AlicePrivate:
|
||||
if (dh.privateKey != null) {
|
||||
keyType = KeyType.AlicePrivate;
|
||||
privateKey = new byte [dh.privateKey.length];
|
||||
System.arraycopy(dh.privateKey, 0, privateKey, 0, privateKey.length);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot copy generated key for Alice");
|
||||
}
|
||||
break;
|
||||
|
||||
case BobPrivate:
|
||||
case BobCalculated:
|
||||
throw new IllegalStateException("Cannot copy private key for Bob without public key for Alice");
|
||||
|
||||
case AlicePublic:
|
||||
case BobPublic:
|
||||
keyType = dh.keyType;
|
||||
publicKey = new byte [dh.publicKey.length];
|
||||
System.arraycopy(dh.publicKey, 0, publicKey, 0, publicKey.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(DHState other, DHState remote) {
|
||||
if (remote == null) {
|
||||
copyFrom(other);
|
||||
return;
|
||||
}
|
||||
if (!(other instanceof NewHopeDHState) || !(remote instanceof NewHopeDHState))
|
||||
throw new IllegalStateException("Mismatched DH key objects");
|
||||
if (other == this)
|
||||
return;
|
||||
NewHopeDHState dh = (NewHopeDHState)other;
|
||||
NewHopeDHState remotedh = (NewHopeDHState)remote;
|
||||
clearKey();
|
||||
switch (dh.keyType) {
|
||||
case None:
|
||||
break;
|
||||
|
||||
case AlicePrivate:
|
||||
if (dh.privateKey != null) {
|
||||
// Generate Alice's public and private key now.
|
||||
keyType = KeyType.AlicePrivate;
|
||||
nh = new NewHopeWithPrivateKey(dh.privateKey);
|
||||
publicKey = new byte [NewHope.SENDABYTES];
|
||||
nh.keygen(publicKey, 0);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot copy generated key for Alice");
|
||||
}
|
||||
break;
|
||||
|
||||
case BobPrivate:
|
||||
if (dh.privateKey != null && remotedh.keyType == KeyType.AlicePublic) {
|
||||
// Now we know the public key for Alice, we can calculate Bob's public and shared keys.
|
||||
keyType = KeyType.BobCalculated;
|
||||
nh = new NewHopeWithPrivateKey(dh.privateKey);
|
||||
publicKey = new byte [NewHope.SENDBBYTES];
|
||||
privateKey = new byte [NewHope.SHAREDBYTES];
|
||||
nh.sharedb(privateKey, 0, publicKey, 0, remotedh.publicKey, 0);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot copy private key for Bob without public key for Alice");
|
||||
}
|
||||
break;
|
||||
|
||||
case BobCalculated:
|
||||
throw new IllegalStateException("Cannot copy generated key for Bob");
|
||||
|
||||
case AlicePublic:
|
||||
case BobPublic:
|
||||
keyType = dh.keyType;
|
||||
publicKey = new byte [dh.publicKey.length];
|
||||
System.arraycopy(dh.publicKey, 0, publicKey, 0, publicKey.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void specifyPeer(DHState local) {
|
||||
if (!(local instanceof NewHopeDHState))
|
||||
return;
|
||||
clearKey();
|
||||
if (((NewHopeDHState)local).keyType == KeyType.AlicePrivate)
|
||||
keyType = KeyType.BobPublic;
|
||||
else
|
||||
keyType = KeyType.AlicePublic;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.NewHope
|
||||
import com.bitchat.android.noise.southernstorm.crypto.NewHopeTor
|
||||
|
||||
/**
|
||||
* Implementation of the New Hope post-quantum algorithm for the Noise protocol.
|
||||
*/
|
||||
internal class NewHopeDHState : DHStateHybrid {
|
||||
internal enum class KeyType {
|
||||
None,
|
||||
AlicePrivate,
|
||||
AlicePublic,
|
||||
BobPrivate,
|
||||
BobPublic,
|
||||
BobCalculated
|
||||
}
|
||||
|
||||
private var nh: NewHopeTor? = null
|
||||
private var publicKey: ByteArray? = null
|
||||
private var privateKey: ByteArray? = null
|
||||
private var keyType: KeyType = KeyType.None
|
||||
|
||||
/**
|
||||
* Special version of NewHopeTor that allows explicit random data
|
||||
* to be specified for test vectors.
|
||||
*/
|
||||
private inner class NewHopeWithPrivateKey(private val randomData: ByteArray) : NewHopeTor() {
|
||||
override fun randombytes(buffer: ByteArray) {
|
||||
randomData.copyInto(buffer, 0, 0, buffer.size)
|
||||
}
|
||||
}
|
||||
|
||||
private val isAlice: Boolean
|
||||
get() = keyType == KeyType.AlicePrivate || keyType == KeyType.AlicePublic
|
||||
|
||||
override fun destroy() {
|
||||
clearKey()
|
||||
}
|
||||
|
||||
override val dhName: String get() = "NewHope"
|
||||
|
||||
override val publicKeyLength: Int
|
||||
get() = if (isAlice) NewHope.SENDABYTES else NewHope.SENDBBYTES
|
||||
|
||||
override val privateKeyLength: Int
|
||||
// New Hope doesn't have private keys in the same sense as
|
||||
// Curve25519 and Curve448. Instead return the number of
|
||||
// random bytes that we need to generate each key type.
|
||||
get() = if (isAlice) 64 else 32
|
||||
|
||||
override val sharedKeyLength: Int get() = NewHope.SHAREDBYTES
|
||||
|
||||
override fun generateKeyPair() {
|
||||
clearKey()
|
||||
keyType = KeyType.AlicePrivate
|
||||
nh = NewHopeTor()
|
||||
publicKey = ByteArray(NewHope.SENDABYTES)
|
||||
nh!!.keygen(publicKey!!, 0)
|
||||
}
|
||||
|
||||
override fun generateKeyPair(remote: DHState?) {
|
||||
if (remote == null) {
|
||||
// No remote public key, so always generate in Alice mode.
|
||||
generateKeyPair()
|
||||
return
|
||||
}
|
||||
check(remote is NewHopeDHState) { "Mismatched DH objects" }
|
||||
if (remote.isAlice && remote.publicKey != null) {
|
||||
// We have a remote public key for Alice, so generate in Bob mode.
|
||||
clearKey()
|
||||
keyType = KeyType.BobCalculated
|
||||
nh = NewHopeTor()
|
||||
publicKey = ByteArray(NewHope.SENDBBYTES)
|
||||
privateKey = ByteArray(NewHope.SHAREDBYTES)
|
||||
nh!!.sharedb(privateKey!!, 0, publicKey!!, 0, remote.publicKey!!, 0)
|
||||
} else {
|
||||
generateKeyPair()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPublicKey(key: ByteArray, offset: Int) {
|
||||
val pk = publicKey
|
||||
if (pk != null) pk.copyInto(key, offset, 0, publicKeyLength)
|
||||
else key.fill(0, offset, offset + publicKeyLength)
|
||||
}
|
||||
|
||||
override fun setPublicKey(key: ByteArray, offset: Int) {
|
||||
publicKey?.let { Noise.destroy(it) }
|
||||
val len = publicKeyLength
|
||||
publicKey = key.copyOfRange(offset, offset + len)
|
||||
}
|
||||
|
||||
override fun getPrivateKey(key: ByteArray, offset: Int) {
|
||||
val sk = privateKey
|
||||
if (sk != null) sk.copyInto(key, offset, 0, privateKeyLength)
|
||||
else key.fill(0, offset, offset + privateKeyLength)
|
||||
}
|
||||
|
||||
override fun setPrivateKey(key: ByteArray, offset: Int) {
|
||||
clearKey()
|
||||
// Guess the key type from the length of the test data.
|
||||
keyType = if (offset == 0 && key.size == 64) KeyType.AlicePrivate else KeyType.BobPrivate
|
||||
val len = privateKeyLength
|
||||
privateKey = key.copyOfRange(offset, offset + len)
|
||||
}
|
||||
|
||||
override fun setToNullPublicKey() {
|
||||
// Null public keys are not supported by New Hope.
|
||||
// Destroy the current values but otherwise ignore.
|
||||
clearKey()
|
||||
}
|
||||
|
||||
override fun clearKey() {
|
||||
nh?.let {
|
||||
it.destroy()
|
||||
nh = null
|
||||
}
|
||||
publicKey?.let {
|
||||
Noise.destroy(it)
|
||||
publicKey = null
|
||||
}
|
||||
privateKey?.let {
|
||||
Noise.destroy(it)
|
||||
privateKey = null
|
||||
}
|
||||
keyType = KeyType.None
|
||||
}
|
||||
|
||||
override fun hasPublicKey(): Boolean = publicKey != null
|
||||
|
||||
override fun hasPrivateKey(): Boolean = privateKey != null
|
||||
|
||||
override fun isNullPublicKey(): Boolean = false
|
||||
|
||||
override fun calculate(sharedKey: ByteArray, offset: Int, publicDH: DHState) {
|
||||
require(publicDH is NewHopeDHState) { "Incompatible DH algorithms" }
|
||||
when (keyType) {
|
||||
KeyType.AlicePrivate -> {
|
||||
// Compute the shared key for Alice.
|
||||
// Note: matches original Java — offset is intentionally unused;
|
||||
// the shared key is always written starting at index 0.
|
||||
nh!!.shareda(sharedKey, 0, publicDH.publicKey!!, 0)
|
||||
}
|
||||
KeyType.BobCalculated -> {
|
||||
// The shared key for Bob was already computed when the key was generated.
|
||||
privateKey!!.copyInto(sharedKey, 0, 0, NewHope.SHAREDBYTES)
|
||||
}
|
||||
else -> throw IllegalStateException("Cannot calculate with this DH object")
|
||||
}
|
||||
}
|
||||
|
||||
override fun copyFrom(other: DHState) {
|
||||
check(other is NewHopeDHState) { "Mismatched DH key objects" }
|
||||
if (other === this) return
|
||||
clearKey()
|
||||
when (other.keyType) {
|
||||
KeyType.None -> {}
|
||||
KeyType.AlicePrivate -> {
|
||||
val src = other.privateKey ?: throw IllegalStateException("Cannot copy generated key for Alice")
|
||||
keyType = KeyType.AlicePrivate
|
||||
privateKey = src.copyOf()
|
||||
}
|
||||
KeyType.BobPrivate, KeyType.BobCalculated ->
|
||||
throw IllegalStateException("Cannot copy private key for Bob without public key for Alice")
|
||||
KeyType.AlicePublic, KeyType.BobPublic -> {
|
||||
keyType = other.keyType
|
||||
publicKey = other.publicKey!!.copyOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun copyFrom(other: DHState, remote: DHState?) {
|
||||
if (remote == null) {
|
||||
copyFrom(other)
|
||||
return
|
||||
}
|
||||
check(other is NewHopeDHState && remote is NewHopeDHState) { "Mismatched DH key objects" }
|
||||
if (other === this) return
|
||||
clearKey()
|
||||
when (other.keyType) {
|
||||
KeyType.None -> {}
|
||||
KeyType.AlicePrivate -> {
|
||||
val src = other.privateKey ?: throw IllegalStateException("Cannot copy generated key for Alice")
|
||||
// Generate Alice's public and private key now.
|
||||
keyType = KeyType.AlicePrivate
|
||||
nh = NewHopeWithPrivateKey(src)
|
||||
publicKey = ByteArray(NewHope.SENDABYTES)
|
||||
nh!!.keygen(publicKey!!, 0)
|
||||
}
|
||||
KeyType.BobPrivate -> {
|
||||
val src = other.privateKey
|
||||
if (src != null && remote.keyType == KeyType.AlicePublic) {
|
||||
// Now we know the public key for Alice, we can calculate Bob's public and shared keys.
|
||||
keyType = KeyType.BobCalculated
|
||||
nh = NewHopeWithPrivateKey(src)
|
||||
publicKey = ByteArray(NewHope.SENDBBYTES)
|
||||
privateKey = ByteArray(NewHope.SHAREDBYTES)
|
||||
nh!!.sharedb(privateKey!!, 0, publicKey!!, 0, remote.publicKey!!, 0)
|
||||
} else {
|
||||
throw IllegalStateException("Cannot copy private key for Bob without public key for Alice")
|
||||
}
|
||||
}
|
||||
KeyType.BobCalculated -> throw IllegalStateException("Cannot copy generated key for Bob")
|
||||
KeyType.AlicePublic, KeyType.BobPublic -> {
|
||||
keyType = other.keyType
|
||||
publicKey = other.publicKey!!.copyOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun specifyPeer(local: DHState?) {
|
||||
if (local !is NewHopeDHState) return
|
||||
clearKey()
|
||||
keyType = if (local.keyType == KeyType.AlicePrivate) KeyType.BobPublic else KeyType.AlicePublic
|
||||
}
|
||||
}
|
||||
@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Blake2bMessageDigest;
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Blake2sMessageDigest;
|
||||
import com.bitchat.android.noise.southernstorm.crypto.SHA256MessageDigest;
|
||||
import com.bitchat.android.noise.southernstorm.crypto.SHA512MessageDigest;
|
||||
|
||||
/**
|
||||
* Utility functions for the Noise protocol library.
|
||||
*/
|
||||
public final class Noise {
|
||||
|
||||
/**
|
||||
* Maximum length for Noise packets.
|
||||
*/
|
||||
public static final int MAX_PACKET_LEN = 65535;
|
||||
|
||||
private static SecureRandom random = new SecureRandom();
|
||||
|
||||
/**
|
||||
* Generates random data using the system random number generator.
|
||||
*
|
||||
* @param data The data buffer to fill with random data.
|
||||
*/
|
||||
public static void random(byte[] data)
|
||||
{
|
||||
random.nextBytes(data);
|
||||
}
|
||||
|
||||
private static boolean forceFallbacks = false;
|
||||
|
||||
/**
|
||||
* Force the use of plain Java fallback crypto implementations.
|
||||
*
|
||||
* @param force Set to true for force fallbacks, false to
|
||||
* try to use the system implementation before falling back.
|
||||
*
|
||||
* This function is intended for testing purposes to toggle between
|
||||
* the system JCA/JCE implementations and the plain Java fallback
|
||||
* reference implementations.
|
||||
*/
|
||||
public static void setForceFallbacks(boolean force)
|
||||
{
|
||||
forceFallbacks = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Diffie-Hellman object from its Noise protocol name.
|
||||
*
|
||||
* @param name The name of the DH algorithm; e.g. "25519", "448", etc.
|
||||
*
|
||||
* @return The Diffie-Hellman object if the name is recognized.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The name is not recognized as a
|
||||
* valid Noise protocol name, or there is no cryptography provider
|
||||
* in the system that implements the algorithm.
|
||||
*/
|
||||
public static DHState createDH(String name) throws NoSuchAlgorithmException
|
||||
{
|
||||
if (name.equals("25519"))
|
||||
return new Curve25519DHState();
|
||||
if (name.equals("448"))
|
||||
return new Curve448DHState();
|
||||
if (name.equals("NewHope"))
|
||||
return new NewHopeDHState();
|
||||
throw new NoSuchAlgorithmException("Unknown Noise DH algorithm name: " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cipher object from its Noise protocol name.
|
||||
*
|
||||
* @param name The name of the cipher algorithm; e.g. "AESGCM", "ChaChaPoly", etc.
|
||||
*
|
||||
* @return The cipher object if the name is recognized.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The name is not recognized as a
|
||||
* valid Noise protocol name, or there is no cryptography provider
|
||||
* in the system that implements the algorithm.
|
||||
*/
|
||||
public static CipherState createCipher(String name) throws NoSuchAlgorithmException
|
||||
{
|
||||
if (name.equals("AESGCM")) {
|
||||
if (forceFallbacks)
|
||||
return new AESGCMFallbackCipherState();
|
||||
// "AES/GCM/NoPadding" exists in some recent JDK's but it is flaky
|
||||
// to use and not easily back-portable to older Android versions.
|
||||
// We instead emulate AESGCM on top of "AES/CTR/NoPadding".
|
||||
try {
|
||||
return new AESGCMOnCtrCipherState();
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
// Could not find anything useful in the JCA/JCE so
|
||||
// use the pure Java fallback implementation instead.
|
||||
return new AESGCMFallbackCipherState();
|
||||
}
|
||||
} else if (name.equals("ChaChaPoly")) {
|
||||
return new ChaChaPolyCipherState();
|
||||
}
|
||||
throw new NoSuchAlgorithmException("Unknown Noise cipher algorithm name: " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hash object from its Noise protocol name.
|
||||
*
|
||||
* @param name The name of the hash algorithm; e.g. "SHA256", "BLAKE2s", etc.
|
||||
*
|
||||
* @return The hash object if the name is recognized.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The name is not recognized as a
|
||||
* valid Noise protocol name, or there is no cryptography provider
|
||||
* in the system that implements the algorithm.
|
||||
*/
|
||||
public static MessageDigest createHash(String name) throws NoSuchAlgorithmException
|
||||
{
|
||||
// Look for a JCA/JCE provider first and if that doesn't work,
|
||||
// use the fallback implementations in this library instead.
|
||||
// The only algorithm that is required to be implemented by a
|
||||
// JDK is "SHA-256", although "SHA-512" is fairly common as well.
|
||||
if (name.equals("SHA256")) {
|
||||
if (forceFallbacks)
|
||||
return new SHA256MessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new SHA256MessageDigest();
|
||||
}
|
||||
} else if (name.equals("SHA512")) {
|
||||
if (forceFallbacks)
|
||||
return new SHA512MessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-512");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new SHA512MessageDigest();
|
||||
}
|
||||
} else if (name.equals("BLAKE2b")) {
|
||||
// Bouncy Castle registers the BLAKE2b variant we
|
||||
// want under the name "BLAKE2B-512".
|
||||
if (forceFallbacks)
|
||||
return new Blake2bMessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("BLAKE2B-512");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new Blake2bMessageDigest();
|
||||
}
|
||||
} else if (name.equals("BLAKE2s")) {
|
||||
// Bouncy Castle doesn't currently (June 2016) have an
|
||||
// implementation of BLAKE2s, but look for the most
|
||||
// obvious provider name in case one is added in the future.
|
||||
if (forceFallbacks)
|
||||
return new Blake2sMessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("BLAKE2S-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new Blake2sMessageDigest();
|
||||
}
|
||||
}
|
||||
throw new NoSuchAlgorithmException("Unknown Noise hash algorithm name: " + name);
|
||||
}
|
||||
|
||||
// The rest of this class consists of internal utility functions
|
||||
// that are not part of the public API.
|
||||
|
||||
/**
|
||||
* Destroys the contents of a byte array.
|
||||
*
|
||||
* @param array The array whose contents should be destroyed.
|
||||
*/
|
||||
static void destroy(byte[] array)
|
||||
{
|
||||
Arrays.fill(array, (byte)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a copy of part of an array.
|
||||
*
|
||||
* @param data The buffer containing the data to copy.
|
||||
* @param offset Offset of the first byte to copy.
|
||||
* @param length The number of bytes to copy.
|
||||
*
|
||||
* @return A new array with a copy of the sub-array.
|
||||
*/
|
||||
static byte[] copySubArray(byte[] data, int offset, int length)
|
||||
{
|
||||
byte[] copy = new byte [length];
|
||||
System.arraycopy(data, offset, copy, 0, length);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an instance of AEADBadTagException.
|
||||
*
|
||||
* @throws BadPaddingException The AEAD exception.
|
||||
*
|
||||
* If the underlying JDK does not have the AEADBadTagException
|
||||
* class, then this function will instead throw an instance of
|
||||
* the superclass BadPaddingException.
|
||||
*/
|
||||
static void throwBadTagException() throws BadPaddingException
|
||||
{
|
||||
try {
|
||||
Class<?> c = Class.forName("javax.crypto.AEADBadTagException");
|
||||
throw (BadPaddingException)(c.newInstance());
|
||||
} catch (ClassNotFoundException e) {
|
||||
} catch (InstantiationException e) {
|
||||
} catch (IllegalAccessException e) {
|
||||
}
|
||||
throw new BadPaddingException();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Blake2bMessageDigest
|
||||
import com.bitchat.android.noise.southernstorm.crypto.Blake2sMessageDigest
|
||||
import com.bitchat.android.noise.southernstorm.crypto.SHA256MessageDigest
|
||||
import com.bitchat.android.noise.southernstorm.crypto.SHA512MessageDigest
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.security.SecureRandom
|
||||
import javax.crypto.BadPaddingException
|
||||
|
||||
/**
|
||||
* Utility functions for the Noise protocol library.
|
||||
*/
|
||||
object Noise {
|
||||
/**
|
||||
* Maximum length for Noise packets.
|
||||
*/
|
||||
const val MAX_PACKET_LEN: Int = 65535
|
||||
|
||||
private val random = SecureRandom()
|
||||
|
||||
private var forceFallbacks = false
|
||||
|
||||
/**
|
||||
* Generates random data using the system random number generator.
|
||||
*
|
||||
* @param data The data buffer to fill with random data.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun random(data: ByteArray) {
|
||||
random.nextBytes(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the use of plain Java fallback crypto implementations.
|
||||
*
|
||||
* @param force Set to true for force fallbacks, false to
|
||||
* try to use the system implementation before falling back.
|
||||
*
|
||||
* This function is intended for testing purposes to toggle between
|
||||
* the system JCA/JCE implementations and the plain Java fallback
|
||||
* reference implementations.
|
||||
*/
|
||||
fun setForceFallbacks(force: Boolean) {
|
||||
forceFallbacks = force
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Diffie-Hellman object from its Noise protocol name.
|
||||
*
|
||||
* @param name The name of the DH algorithm; e.g. "25519", "448", etc.
|
||||
*
|
||||
* @return The Diffie-Hellman object if the name is recognized.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The name is not recognized as a
|
||||
* valid Noise protocol name, or there is no cryptography provider
|
||||
* in the system that implements the algorithm.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(NoSuchAlgorithmException::class)
|
||||
fun createDH(name: String): DHState = when (name) {
|
||||
"25519" -> Curve25519DHState()
|
||||
"448" -> Curve448DHState()
|
||||
"NewHope" -> NewHopeDHState()
|
||||
else -> throw NoSuchAlgorithmException("Unknown Noise DH algorithm name: $name")
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cipher object from its Noise protocol name.
|
||||
*
|
||||
* @param name The name of the cipher algorithm; e.g. "AESGCM", "ChaChaPoly", etc.
|
||||
*
|
||||
* @return The cipher object if the name is recognized.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The name is not recognized as a
|
||||
* valid Noise protocol name, or there is no cryptography provider
|
||||
* in the system that implements the algorithm.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(NoSuchAlgorithmException::class)
|
||||
fun createCipher(name: String): CipherState = when (name) {
|
||||
"AESGCM" -> {
|
||||
if (forceFallbacks) {
|
||||
AESGCMFallbackCipherState()
|
||||
} else {
|
||||
// "AES/GCM/NoPadding" exists in some recent JDK's but it is flaky
|
||||
// to use and not easily back-portable to older Android versions.
|
||||
// We instead emulate AESGCM on top of "AES/CTR/NoPadding".
|
||||
try {
|
||||
AESGCMOnCtrCipherState()
|
||||
} catch (_: NoSuchAlgorithmException) {
|
||||
AESGCMFallbackCipherState()
|
||||
}
|
||||
}
|
||||
}
|
||||
"ChaChaPoly" -> ChaChaPolyCipherState()
|
||||
else -> throw NoSuchAlgorithmException("Unknown Noise cipher algorithm name: $name")
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hash object from its Noise protocol name.
|
||||
*
|
||||
* @param name The name of the hash algorithm; e.g. "SHA256", "BLAKE2s", etc.
|
||||
*
|
||||
* @return The hash object if the name is recognized.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The name is not recognized as a
|
||||
* valid Noise protocol name, or there is no cryptography provider
|
||||
* in the system that implements the algorithm.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(NoSuchAlgorithmException::class)
|
||||
fun createHash(name: String): MessageDigest {
|
||||
// Look for a JCA/JCE provider first and if that doesn't work,
|
||||
// use the fallback implementations in this library instead.
|
||||
// The only algorithm that is required to be implemented by a
|
||||
// JDK is "SHA-256", although "SHA-512" is fairly common as well.
|
||||
val (jcaName, fallback) = when (name) {
|
||||
"SHA256" -> "SHA-256" to ::SHA256MessageDigest
|
||||
"SHA512" -> "SHA-512" to ::SHA512MessageDigest
|
||||
"BLAKE2b" -> "BLAKE2B-512" to ::Blake2bMessageDigest
|
||||
"BLAKE2s" -> "BLAKE2S-256" to ::Blake2sMessageDigest
|
||||
else -> throw NoSuchAlgorithmException("Unknown Noise hash algorithm name: $name")
|
||||
}
|
||||
if (forceFallbacks) return fallback()
|
||||
return try {
|
||||
MessageDigest.getInstance(jcaName)
|
||||
} catch (_: NoSuchAlgorithmException) {
|
||||
fallback()
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of this class consists of internal utility functions
|
||||
// that are not part of the public API.
|
||||
/**
|
||||
* Destroys the contents of a byte array.
|
||||
*
|
||||
* @param array The array whose contents should be destroyed.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun destroy(array: ByteArray) {
|
||||
array.fill(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a copy of part of an array.
|
||||
*
|
||||
* @param data The buffer containing the data to copy.
|
||||
* @param offset Offset of the first byte to copy.
|
||||
* @param length The number of bytes to copy.
|
||||
*
|
||||
* @return A new array with a copy of the sub-array.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun copySubArray(data: ByteArray, offset: Int, length: Int): ByteArray =
|
||||
data.copyOfRange(offset, offset + length)
|
||||
|
||||
/**
|
||||
* Throws an instance of AEADBadTagException.
|
||||
*
|
||||
* @throws BadPaddingException The AEAD exception.
|
||||
*
|
||||
* If the underlying JDK does not have the AEADBadTagException
|
||||
* class, then this function will instead throw an instance of
|
||||
* the superclass BadPaddingException.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(BadPaddingException::class)
|
||||
fun throwBadTagException() {
|
||||
val aead = try {
|
||||
val c = Class.forName("javax.crypto.AEADBadTagException")
|
||||
c.getDeclaredConstructor().newInstance() as BadPaddingException
|
||||
} catch (_: ReflectiveOperationException) {
|
||||
null
|
||||
}
|
||||
throw aead ?: BadPaddingException()
|
||||
}
|
||||
}
|
||||
@ -1,835 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
/**
|
||||
* Information about all supported handshake patterns.
|
||||
*/
|
||||
class Pattern {
|
||||
|
||||
private Pattern() {}
|
||||
|
||||
// Token codes.
|
||||
public static final short S = 1;
|
||||
public static final short E = 2;
|
||||
public static final short EE = 3;
|
||||
public static final short ES = 4;
|
||||
public static final short SE = 5;
|
||||
public static final short SS = 6;
|
||||
public static final short F = 7;
|
||||
public static final short FF = 8;
|
||||
public static final short FLIP_DIR = 255;
|
||||
|
||||
// Pattern flag bits.
|
||||
public static final short FLAG_LOCAL_STATIC = 0x0001;
|
||||
public static final short FLAG_LOCAL_EPHEMERAL = 0x0002;
|
||||
public static final short FLAG_LOCAL_REQUIRED = 0x0004;
|
||||
public static final short FLAG_LOCAL_EPHEM_REQ = 0x0008;
|
||||
public static final short FLAG_LOCAL_HYBRID = 0x0010;
|
||||
public static final short FLAG_LOCAL_HYBRID_REQ = 0x0020;
|
||||
public static final short FLAG_REMOTE_STATIC = 0x0100;
|
||||
public static final short FLAG_REMOTE_EPHEMERAL = 0x0200;
|
||||
public static final short FLAG_REMOTE_REQUIRED = 0x0400;
|
||||
public static final short FLAG_REMOTE_EPHEM_REQ = 0x0800;
|
||||
public static final short FLAG_REMOTE_HYBRID = 0x1000;
|
||||
public static final short FLAG_REMOTE_HYBRID_REQ = 0x2000;
|
||||
|
||||
private static final short[] noise_pattern_N = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_K = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
SS
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_X = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
S,
|
||||
SS
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NN = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NK = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NX = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XN = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XK = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XX = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
S,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KN = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KK = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KX = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IN = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IK = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
S,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IX = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXfallback = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEM_REQ,
|
||||
|
||||
E,
|
||||
EE,
|
||||
S,
|
||||
SE,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_Xnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
S,
|
||||
ES,
|
||||
SS
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NXnoidh = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KXnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IKnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
S,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IXnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NNhfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NKhfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NXhfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XNhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XKhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
S,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KNhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KKhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KXhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_INhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IKhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
S,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IXhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXfallback_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEM_REQ |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_HYBRID_REQ,
|
||||
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
S,
|
||||
SE,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NXnoidh_hfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KXnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IKnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IXnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
/**
|
||||
* Look up the description information for a pattern.
|
||||
*
|
||||
* @param name The name of the pattern.
|
||||
* @return The pattern description or null.
|
||||
*/
|
||||
public static short[] lookup(String name)
|
||||
{
|
||||
if (name.equals("N"))
|
||||
return noise_pattern_N;
|
||||
else if (name.equals("K"))
|
||||
return noise_pattern_K;
|
||||
else if (name.equals("X"))
|
||||
return noise_pattern_X;
|
||||
else if (name.equals("NN"))
|
||||
return noise_pattern_NN;
|
||||
else if (name.equals("NK"))
|
||||
return noise_pattern_NK;
|
||||
else if (name.equals("NX"))
|
||||
return noise_pattern_NX;
|
||||
else if (name.equals("XN"))
|
||||
return noise_pattern_XN;
|
||||
else if (name.equals("XK"))
|
||||
return noise_pattern_XK;
|
||||
else if (name.equals("XX"))
|
||||
return noise_pattern_XX;
|
||||
else if (name.equals("KN"))
|
||||
return noise_pattern_KN;
|
||||
else if (name.equals("KK"))
|
||||
return noise_pattern_KK;
|
||||
else if (name.equals("KX"))
|
||||
return noise_pattern_KX;
|
||||
else if (name.equals("IN"))
|
||||
return noise_pattern_IN;
|
||||
else if (name.equals("IK"))
|
||||
return noise_pattern_IK;
|
||||
else if (name.equals("IX"))
|
||||
return noise_pattern_IX;
|
||||
else if (name.equals("XXfallback"))
|
||||
return noise_pattern_XXfallback;
|
||||
else if (name.equals("Xnoidh"))
|
||||
return noise_pattern_Xnoidh;
|
||||
else if (name.equals("NXnoidh"))
|
||||
return noise_pattern_NXnoidh;
|
||||
else if (name.equals("XXnoidh"))
|
||||
return noise_pattern_XXnoidh;
|
||||
else if (name.equals("KXnoidh"))
|
||||
return noise_pattern_KXnoidh;
|
||||
else if (name.equals("IKnoidh"))
|
||||
return noise_pattern_IKnoidh;
|
||||
else if (name.equals("IXnoidh"))
|
||||
return noise_pattern_IXnoidh;
|
||||
else if (name.equals("NNhfs"))
|
||||
return noise_pattern_NNhfs;
|
||||
else if (name.equals("NKhfs"))
|
||||
return noise_pattern_NKhfs;
|
||||
else if (name.equals("NXhfs"))
|
||||
return noise_pattern_NXhfs;
|
||||
else if (name.equals("XNhfs"))
|
||||
return noise_pattern_XNhfs;
|
||||
else if (name.equals("XKhfs"))
|
||||
return noise_pattern_XKhfs;
|
||||
else if (name.equals("XXhfs"))
|
||||
return noise_pattern_XXhfs;
|
||||
else if (name.equals("KNhfs"))
|
||||
return noise_pattern_KNhfs;
|
||||
else if (name.equals("KKhfs"))
|
||||
return noise_pattern_KKhfs;
|
||||
else if (name.equals("KXhfs"))
|
||||
return noise_pattern_KXhfs;
|
||||
else if (name.equals("INhfs"))
|
||||
return noise_pattern_INhfs;
|
||||
else if (name.equals("IKhfs"))
|
||||
return noise_pattern_IKhfs;
|
||||
else if (name.equals("IXhfs"))
|
||||
return noise_pattern_IXhfs;
|
||||
else if (name.equals("XXfallback+hfs"))
|
||||
return noise_pattern_XXfallback_hfs;
|
||||
else if (name.equals("NXnoidh+hfs"))
|
||||
return noise_pattern_NXnoidh_hfs;
|
||||
else if (name.equals("XXnoidh+hfs"))
|
||||
return noise_pattern_XXnoidh_hfs;
|
||||
else if (name.equals("KXnoidh+hfs"))
|
||||
return noise_pattern_KXnoidh_hfs;
|
||||
else if (name.equals("IKnoidh+hfs"))
|
||||
return noise_pattern_IKnoidh_hfs;
|
||||
else if (name.equals("IXnoidh+hfs"))
|
||||
return noise_pattern_IXnoidh_hfs;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the local and remote flags for a pattern.
|
||||
*
|
||||
* @param flags The flags, assuming that the initiator is "local".
|
||||
* @return The reversed flags, with the responder now being "local".
|
||||
*/
|
||||
public static short reverseFlags(short flags)
|
||||
{
|
||||
return (short)(((flags >> 8) & 0x00FF) | ((flags << 8) & 0xFF00));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
/**
|
||||
* Information about all supported handshake patterns.
|
||||
*/
|
||||
internal object Pattern {
|
||||
// Token codes.
|
||||
const val S: Short = 1
|
||||
const val E: Short = 2
|
||||
const val EE: Short = 3
|
||||
const val ES: Short = 4
|
||||
const val SE: Short = 5
|
||||
const val SS: Short = 6
|
||||
const val F: Short = 7
|
||||
const val FF: Short = 8
|
||||
const val FLIP_DIR: Short = 255
|
||||
|
||||
// Pattern flag bits.
|
||||
const val FLAG_LOCAL_STATIC: Short = 0x0001
|
||||
const val FLAG_LOCAL_EPHEMERAL: Short = 0x0002
|
||||
const val FLAG_LOCAL_REQUIRED: Short = 0x0004
|
||||
const val FLAG_LOCAL_EPHEM_REQ: Short = 0x0008
|
||||
const val FLAG_LOCAL_HYBRID: Short = 0x0010
|
||||
const val FLAG_LOCAL_HYBRID_REQ: Short = 0x0020
|
||||
const val FLAG_REMOTE_STATIC: Short = 0x0100
|
||||
const val FLAG_REMOTE_EPHEMERAL: Short = 0x0200
|
||||
const val FLAG_REMOTE_REQUIRED: Short = 0x0400
|
||||
const val FLAG_REMOTE_EPHEM_REQ: Short = 0x0800
|
||||
const val FLAG_REMOTE_HYBRID: Short = 0x1000
|
||||
const val FLAG_REMOTE_HYBRID_REQ: Short = 0x2000
|
||||
|
||||
private fun flags(vararg bits: Short): Short {
|
||||
var v = 0
|
||||
for (b in bits) v = v or b.toInt()
|
||||
return v.toShort()
|
||||
}
|
||||
|
||||
private val patterns: Map<String, ShortArray> = mapOf(
|
||||
"N" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_REMOTE_STATIC, FLAG_REMOTE_REQUIRED),
|
||||
E, ES
|
||||
),
|
||||
"K" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_REQUIRED),
|
||||
E, ES, SS
|
||||
),
|
||||
"X" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_REQUIRED),
|
||||
E, ES, S, SS
|
||||
),
|
||||
"NN" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, EE
|
||||
),
|
||||
"NK" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL,
|
||||
FLAG_REMOTE_REQUIRED),
|
||||
E, ES, FLIP_DIR, E, EE
|
||||
),
|
||||
"NX" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, EE, S, ES
|
||||
),
|
||||
"XN" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, EE, FLIP_DIR, S, SE
|
||||
),
|
||||
"XK" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_REQUIRED),
|
||||
E, ES, FLIP_DIR, E, EE, FLIP_DIR, S, SE
|
||||
),
|
||||
"XX" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, EE, S, ES, FLIP_DIR, S, SE
|
||||
),
|
||||
"KN" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, EE, SE
|
||||
),
|
||||
"KK" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_REQUIRED),
|
||||
E, ES, SS, FLIP_DIR, E, EE, SE
|
||||
),
|
||||
"KX" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, EE, SE, S, ES
|
||||
),
|
||||
"IN" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_REMOTE_EPHEMERAL),
|
||||
E, S, FLIP_DIR, E, EE, SE
|
||||
),
|
||||
"IK" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_REQUIRED),
|
||||
E, ES, S, SS, FLIP_DIR, E, EE, SE
|
||||
),
|
||||
"IX" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, S, FLIP_DIR, E, EE, SE, S, ES
|
||||
),
|
||||
"XXfallback" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_EPHEM_REQ),
|
||||
E, EE, S, SE, FLIP_DIR, S, ES
|
||||
),
|
||||
"Xnoidh" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_REQUIRED),
|
||||
E, S, ES, SS
|
||||
),
|
||||
"NXnoidh" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, S, EE, ES
|
||||
),
|
||||
"XXnoidh" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, S, EE, ES, FLIP_DIR, S, SE
|
||||
),
|
||||
"KXnoidh" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, FLIP_DIR, E, S, EE, SE, ES
|
||||
),
|
||||
"IKnoidh" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_REQUIRED),
|
||||
E, S, ES, SS, FLIP_DIR, E, EE, SE
|
||||
),
|
||||
"IXnoidh" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL),
|
||||
E, S, FLIP_DIR, E, S, EE, SE, ES
|
||||
),
|
||||
"NNhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, EE, FF
|
||||
),
|
||||
"NKhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID,
|
||||
FLAG_REMOTE_REQUIRED),
|
||||
E, F, ES, FLIP_DIR, E, F, EE, FF
|
||||
),
|
||||
"NXhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, EE, FF, S, ES
|
||||
),
|
||||
"XNhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, EE, FF, FLIP_DIR, S, SE
|
||||
),
|
||||
"XKhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID,
|
||||
FLAG_REMOTE_REQUIRED),
|
||||
E, F, ES, FLIP_DIR, E, F, EE, FF, FLIP_DIR, S, SE
|
||||
),
|
||||
"XXhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, EE, FF, S, ES, FLIP_DIR, S, SE
|
||||
),
|
||||
"KNhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_LOCAL_HYBRID, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, EE, FF, SE
|
||||
),
|
||||
"KKhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_LOCAL_HYBRID, FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL,
|
||||
FLAG_REMOTE_HYBRID, FLAG_REMOTE_REQUIRED),
|
||||
E, F, ES, SS, FLIP_DIR, E, F, EE, FF, SE
|
||||
),
|
||||
"KXhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_LOCAL_HYBRID, FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL,
|
||||
FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, EE, FF, SE, S, ES
|
||||
),
|
||||
"INhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, S, FLIP_DIR, E, F, EE, FF, SE
|
||||
),
|
||||
"IKhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID,
|
||||
FLAG_REMOTE_REQUIRED),
|
||||
E, F, ES, S, SS, FLIP_DIR, E, F, EE, FF, SE
|
||||
),
|
||||
"IXhfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, S, FLIP_DIR, E, F, EE, FF, SE, S, ES
|
||||
),
|
||||
"XXfallback+hfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_EPHEM_REQ,
|
||||
FLAG_REMOTE_HYBRID, FLAG_REMOTE_HYBRID_REQ),
|
||||
E, F, EE, FF, S, SE, FLIP_DIR, S, ES
|
||||
),
|
||||
"NXnoidh+hfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, S, EE, FF, ES
|
||||
),
|
||||
"XXnoidh+hfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, S, EE, FF, ES, FLIP_DIR, S, SE
|
||||
),
|
||||
"KXnoidh+hfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_REQUIRED,
|
||||
FLAG_LOCAL_HYBRID, FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL,
|
||||
FLAG_REMOTE_HYBRID),
|
||||
E, F, FLIP_DIR, E, F, S, EE, FF, SE, ES
|
||||
),
|
||||
// Note: FLAG_REMOTE_EPHEMERAL is listed twice in the original Java
|
||||
// pattern definition. Kept here verbatim — the duplicate or-bit is a
|
||||
// no-op, so behavior matches the upstream implementation.
|
||||
"IKnoidh+hfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_EPHEMERAL,
|
||||
FLAG_REMOTE_HYBRID),
|
||||
E, F, S, ES, SS, FLIP_DIR, E, F, EE, FF, SE
|
||||
),
|
||||
"IXnoidh+hfs" to shortArrayOf(
|
||||
flags(FLAG_LOCAL_STATIC, FLAG_LOCAL_EPHEMERAL, FLAG_LOCAL_HYBRID,
|
||||
FLAG_REMOTE_STATIC, FLAG_REMOTE_EPHEMERAL, FLAG_REMOTE_HYBRID),
|
||||
E, F, S, FLIP_DIR, E, F, S, EE, FF, SE, ES
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Look up the description information for a pattern.
|
||||
*
|
||||
* @param name The name of the pattern.
|
||||
* @return The pattern description or null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun lookup(name: String): ShortArray? = patterns[name]
|
||||
|
||||
/**
|
||||
* Reverses the local and remote flags for a pattern.
|
||||
*
|
||||
* @param flags The flags, assuming that the initiator is "local".
|
||||
* @return The reversed flags, with the responder now being "local".
|
||||
*/
|
||||
@JvmStatic
|
||||
fun reverseFlags(flags: Short): Short {
|
||||
val v = flags.toInt() and 0xFFFF
|
||||
return (((v shr 8) and 0x00FF) or ((v shl 8) and 0xFF00)).toShort()
|
||||
}
|
||||
}
|
||||
@ -1,532 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
/**
|
||||
* Symmetric state for helping manage a Noise handshake.
|
||||
*/
|
||||
class SymmetricState implements Destroyable {
|
||||
|
||||
private static final String TAG = "AndroidSymmetric";
|
||||
|
||||
private String name;
|
||||
private CipherState cipher;
|
||||
private MessageDigest hash;
|
||||
private byte[] ck;
|
||||
private byte[] h;
|
||||
private byte[] prev_h;
|
||||
|
||||
/**
|
||||
* Converts a byte array to hex string for logging (matching iOS hex format)
|
||||
*/
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new symmetric state object.
|
||||
*
|
||||
* @param protocolName The name of the Noise protocol, which is assumed to be valid.
|
||||
* @param cipherName The name of the cipher within protocolName.
|
||||
* @param hashName The name of the hash within protocolName.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The cipher or hash algorithm in the
|
||||
* protocol name is not supported.
|
||||
*/
|
||||
public SymmetricState(String protocolName, String cipherName, String hashName) throws NoSuchAlgorithmException
|
||||
{
|
||||
name = protocolName;
|
||||
cipher = Noise.createCipher(cipherName);
|
||||
hash = Noise.createHash(hashName);
|
||||
int hashLength = hash.getDigestLength();
|
||||
ck = new byte [hashLength];
|
||||
h = new byte [hashLength];
|
||||
prev_h = new byte [hashLength];
|
||||
|
||||
byte[] protocolNameBytes;
|
||||
try {
|
||||
protocolNameBytes = protocolName.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// If UTF-8 is not supported, then we are definitely in trouble!
|
||||
throw new UnsupportedOperationException("UTF-8 encoding is not supported");
|
||||
}
|
||||
|
||||
if (protocolNameBytes.length <= hashLength) {
|
||||
System.arraycopy(protocolNameBytes, 0, h, 0, protocolNameBytes.length);
|
||||
Arrays.fill(h, protocolNameBytes.length, h.length, (byte)0);
|
||||
} else {
|
||||
hashOne(protocolNameBytes, 0, protocolNameBytes.length, h, 0, h.length);
|
||||
}
|
||||
|
||||
System.arraycopy(h, 0, ck, 0, hashLength);
|
||||
|
||||
// LOGGING: Initial symmetric state after protocol name initialization (matching iOS)
|
||||
Log.d(TAG, "=== ANDROID SYMMETRIC STATE INITIALIZED ===");
|
||||
Log.d(TAG, "Protocol: " + protocolName);
|
||||
Log.d(TAG, "Initial hash (h): " + bytesToHex(h));
|
||||
Log.d(TAG, "Initial chaining key (ck): " + bytesToHex(ck));
|
||||
Log.d(TAG, "Hash length: " + h.length);
|
||||
Log.d(TAG, "=========================================");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the Noise protocol.
|
||||
*
|
||||
* @return The protocol name.
|
||||
*/
|
||||
public String getProtocolName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of MAC values in the current state.
|
||||
*
|
||||
* @return The length of the MAC value for the underlying cipher
|
||||
* or zero if the cipher has not yet been initialized with a key.
|
||||
*/
|
||||
public int getMACLength()
|
||||
{
|
||||
return cipher.getMACLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes data into the chaining key.
|
||||
*
|
||||
* @param data The buffer containing the data to mix in.
|
||||
* @param offset The offset of the first data byte to mix in.
|
||||
* @param length The number of bytes to mix in.
|
||||
*/
|
||||
public void mixKey(byte[] data, int offset, int length)
|
||||
{
|
||||
// LOGGING: Before mixKey operation (matching iOS)
|
||||
byte[] inputData = new byte[length];
|
||||
System.arraycopy(data, offset, inputData, 0, length);
|
||||
Log.d(TAG, "*** Android mixKey() BEFORE ***");
|
||||
Log.d(TAG, "Input data (" + length + " bytes): " + bytesToHex(inputData));
|
||||
Log.d(TAG, "Current CK: " + bytesToHex(ck));
|
||||
Log.d(TAG, "Current Hash: " + bytesToHex(h));
|
||||
|
||||
int keyLength = cipher.getKeyLength();
|
||||
byte[] tempKey = new byte [keyLength];
|
||||
try {
|
||||
hkdf(ck, 0, ck.length, data, offset, length, ck, 0, ck.length, tempKey, 0, keyLength);
|
||||
cipher.initializeKey(tempKey, 0);
|
||||
} finally {
|
||||
Noise.destroy(tempKey);
|
||||
}
|
||||
|
||||
// LOGGING: After mixKey operation (matching iOS)
|
||||
Log.d(TAG, "*** Android mixKey() AFTER ***");
|
||||
Log.d(TAG, "New CK: " + bytesToHex(ck));
|
||||
Log.d(TAG, "Hash unchanged: " + bytesToHex(h));
|
||||
Log.d(TAG, "Cipher now has key: " + (cipher.getMACLength() > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes data into the handshake hash.
|
||||
*
|
||||
* @param data The buffer containing the data to mix in.
|
||||
* @param offset The offset of the first data byte to mix in.
|
||||
* @param length The number of bytes to mix in.
|
||||
*/
|
||||
public void mixHash(byte[] data, int offset, int length)
|
||||
{
|
||||
// LOGGING: Before mixHash operation (matching iOS)
|
||||
byte[] inputData = new byte[length];
|
||||
System.arraycopy(data, offset, inputData, 0, length);
|
||||
Log.d(TAG, "*** Android mixHash() BEFORE ***");
|
||||
Log.d(TAG, "Input data (" + length + " bytes): " + bytesToHex(inputData));
|
||||
Log.d(TAG, "Current Hash: " + bytesToHex(h));
|
||||
|
||||
hashTwo(h, 0, h.length, data, offset, length, h, 0, h.length);
|
||||
|
||||
// LOGGING: After mixHash operation (matching iOS)
|
||||
Log.d(TAG, "*** Android mixHash() AFTER ***");
|
||||
Log.d(TAG, "New Hash: " + bytesToHex(h));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes a pre-shared key into the chaining key and handshake hash.
|
||||
*
|
||||
* @param key The pre-shared key value.
|
||||
*/
|
||||
public void mixPreSharedKey(byte[] key)
|
||||
{
|
||||
byte[] temp = new byte [hash.getDigestLength()];
|
||||
try {
|
||||
hkdf(ck, 0, ck.length, key, 0, key.length, ck, 0, ck.length, temp, 0, temp.length);
|
||||
mixHash(temp, 0, temp.length);
|
||||
} finally {
|
||||
Noise.destroy(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes a pre-supplied public key into the handshake hash.
|
||||
*
|
||||
* @param dh The object containing the public key.
|
||||
*/
|
||||
public void mixPublicKey(DHState dh)
|
||||
{
|
||||
byte[] temp = new byte [dh.getPublicKeyLength()];
|
||||
try {
|
||||
dh.getPublicKey(temp, 0);
|
||||
mixHash(temp, 0, temp.length);
|
||||
} finally {
|
||||
Noise.destroy(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes a pre-supplied public key into the chaining key.
|
||||
*
|
||||
* @param dh The object containing the public key.
|
||||
*/
|
||||
public void mixPublicKeyIntoCK(DHState dh)
|
||||
{
|
||||
byte[] temp = new byte [dh.getPublicKeyLength()];
|
||||
try {
|
||||
dh.getPublicKey(temp, 0);
|
||||
mixKey(temp, 0, temp.length);
|
||||
} finally {
|
||||
Noise.destroy(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a block of plaintext and mixes the ciphertext into the handshake hash.
|
||||
*
|
||||
* @param plaintext The buffer containing the plaintext to encrypt.
|
||||
* @param plaintextOffset The offset within the plaintext buffer of the
|
||||
* first byte or plaintext data.
|
||||
* @param ciphertext The buffer to place the ciphertext in. This can
|
||||
* be the same as the plaintext buffer.
|
||||
* @param ciphertextOffset The first offset within the ciphertext buffer
|
||||
* to place the ciphertext and the MAC tag.
|
||||
* @param length The length of the plaintext.
|
||||
* @return The length of the ciphertext plus the MAC tag.
|
||||
*
|
||||
* @throws ShortBufferException There is not enough space in the
|
||||
* ciphertext buffer for the encrypted data plus MAC value.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* encryption. In that case, plaintextOffset must be identical to
|
||||
* ciphertextOffset.
|
||||
*
|
||||
* There must be enough space in the ciphertext buffer to accomodate
|
||||
* length + getMACLength() bytes of data starting at ciphertextOffset.
|
||||
*/
|
||||
public int encryptAndHash(byte[] plaintext, int plaintextOffset, byte[] ciphertext, int ciphertextOffset, int length) throws ShortBufferException
|
||||
{
|
||||
int ciphertextLength = cipher.encryptWithAd(h, plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
|
||||
mixHash(ciphertext, ciphertextOffset, ciphertextLength);
|
||||
return ciphertextLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a block of ciphertext and mixes it into the handshake hash.
|
||||
*
|
||||
* @param ciphertext The buffer containing the ciphertext to decrypt.
|
||||
* @param ciphertextOffset The offset within the ciphertext buffer of
|
||||
* the first byte of ciphertext data.
|
||||
* @param plaintext The buffer to place the plaintext in. This can be
|
||||
* the same as the ciphertext buffer.
|
||||
* @param plaintextOffset The first offset within the plaintext buffer
|
||||
* to place the plaintext.
|
||||
* @param length The length of the incoming ciphertext plus the MAC tag.
|
||||
* @return The length of the plaintext with the MAC tag stripped off.
|
||||
*
|
||||
* @throws ShortBufferException There is not enough space in the plaintext
|
||||
* buffer for the decrypted data.
|
||||
*
|
||||
* @throws BadPaddingException The MAC value failed to verify.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* decryption. In that case, ciphertextOffset must be identical to
|
||||
* plaintextOffset.
|
||||
*/
|
||||
public int decryptAndHash(byte[] ciphertext, int ciphertextOffset, byte[] plaintext, int plaintextOffset, int length) throws ShortBufferException, BadPaddingException
|
||||
{
|
||||
System.arraycopy(h, 0, prev_h, 0, h.length);
|
||||
mixHash(ciphertext, ciphertextOffset, length);
|
||||
return cipher.decryptWithAd(prev_h, ciphertext, ciphertextOffset, plaintext, plaintextOffset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the symmetric state into two ciphers for session encryption.
|
||||
*
|
||||
* @return The pair of ciphers for sending and receiving.
|
||||
*/
|
||||
public CipherStatePair split()
|
||||
{
|
||||
return split(new byte[0], 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the symmetric state into two ciphers for session encryption,
|
||||
* and optionally mixes in a secondary symmetric key.
|
||||
*
|
||||
* @param secondaryKey The buffer containing the secondary key.
|
||||
* @param offset The offset of the first secondary key byte.
|
||||
* @param length The length of the secondary key in bytes, which
|
||||
* must be either 0 or 32.
|
||||
* @return The pair of ciphers for sending and receiving.
|
||||
*
|
||||
* @throws IllegalArgumentException The length is not 0 or 32.
|
||||
*/
|
||||
public CipherStatePair split(byte[] secondaryKey, int offset, int length)
|
||||
{
|
||||
if (length != 0 && length != 32)
|
||||
throw new IllegalArgumentException("Secondary keys must be 0 or 32 bytes in length");
|
||||
int keyLength = cipher.getKeyLength();
|
||||
byte[] k1 = new byte [keyLength];
|
||||
byte[] k2 = new byte [keyLength];
|
||||
try {
|
||||
hkdf(ck, 0, ck.length, secondaryKey, offset, length, k1, 0, k1.length, k2, 0, k2.length);
|
||||
CipherState c1 = null;
|
||||
CipherState c2 = null;
|
||||
CipherStatePair pair = null;
|
||||
try {
|
||||
c1 = cipher.fork(k1, 0);
|
||||
c2 = cipher.fork(k2, 0);
|
||||
pair = new CipherStatePair(c1, c2);
|
||||
} finally {
|
||||
if (c1 == null || c2 == null || pair == null) {
|
||||
// Could not create some of the objects. Clean up the others
|
||||
// to avoid accidental leakage of k1 or k2.
|
||||
if (c1 != null)
|
||||
c1.destroy();
|
||||
if (c2 != null)
|
||||
c2.destroy();
|
||||
pair = null;
|
||||
}
|
||||
}
|
||||
return pair;
|
||||
} finally {
|
||||
Noise.destroy(k1);
|
||||
Noise.destroy(k2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current value of the handshake hash.
|
||||
*
|
||||
* @return The handshake hash. This must not be modified by the caller.
|
||||
*
|
||||
* The handshake hash value is only of use to the application after
|
||||
* split() has been called.
|
||||
*/
|
||||
public byte[] getHandshakeHash()
|
||||
{
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (cipher != null) {
|
||||
cipher.destroy();
|
||||
cipher = null;
|
||||
}
|
||||
if (hash != null) {
|
||||
// The built-in fallback implementations are destroyable.
|
||||
// JCA/JCE implementations aren't, so try reset() instead.
|
||||
if (hash instanceof Destroyable)
|
||||
((Destroyable)hash).destroy();
|
||||
else
|
||||
hash.reset();
|
||||
hash = null;
|
||||
}
|
||||
if (ck != null) {
|
||||
Noise.destroy(ck);
|
||||
ck = null;
|
||||
}
|
||||
if (h != null) {
|
||||
Noise.destroy(h);
|
||||
h = null;
|
||||
}
|
||||
if (prev_h != null) {
|
||||
Noise.destroy(prev_h);
|
||||
prev_h = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes a single data buffer.
|
||||
*
|
||||
* @param data The buffer containing the data to hash.
|
||||
* @param offset Offset into the data buffer of the first byte to hash.
|
||||
* @param length Length of the data to be hashed.
|
||||
* @param output The buffer to receive the output hash value.
|
||||
* @param outputOffset Offset into the output buffer to place the hash value.
|
||||
* @param outputLength The length of the hash output.
|
||||
*
|
||||
* The output buffer can be the same as the input data buffer.
|
||||
*/
|
||||
private void hashOne(byte[] data, int offset, int length, byte[] output, int outputOffset, int outputLength)
|
||||
{
|
||||
hash.reset();
|
||||
hash.update(data, offset, length);
|
||||
try {
|
||||
hash.digest(output, outputOffset, outputLength);
|
||||
} catch (DigestException e) {
|
||||
Arrays.fill(output, outputOffset, outputLength, (byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes two data buffers.
|
||||
*
|
||||
* @param data1 The buffer containing the first data to hash.
|
||||
* @param offset1 Offset into the first data buffer of the first byte to hash.
|
||||
* @param length1 Length of the first data to be hashed.
|
||||
* @param data2 The buffer containing the second data to hash.
|
||||
* @param offset2 Offset into the second data buffer of the first byte to hash.
|
||||
* @param length2 Length of the second data to be hashed.
|
||||
* @param output The buffer to receive the output hash value.
|
||||
* @param outputOffset Offset into the output buffer to place the hash value.
|
||||
* @param outputLength The length of the hash output.
|
||||
*
|
||||
* The output buffer can be same as either of the input buffers.
|
||||
*/
|
||||
private void hashTwo(byte[] data1, int offset1, int length1,
|
||||
byte[] data2, int offset2, int length2,
|
||||
byte[] output, int outputOffset, int outputLength)
|
||||
{
|
||||
hash.reset();
|
||||
hash.update(data1, offset1, length1);
|
||||
hash.update(data2, offset2, length2);
|
||||
try {
|
||||
hash.digest(output, outputOffset, outputLength);
|
||||
} catch (DigestException e) {
|
||||
Arrays.fill(output, outputOffset, outputLength, (byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a HMAC value using key and data values.
|
||||
*
|
||||
* @param key The buffer that contains the key.
|
||||
* @param keyOffset The offset of the key in the key buffer.
|
||||
* @param keyLength The length of the key in bytes.
|
||||
* @param data The buffer that contains the data.
|
||||
* @param dataOffset The offset of the data in the data buffer.
|
||||
* @param dataLength The length of the data in bytes.
|
||||
* @param output The output buffer to place the HMAC value in.
|
||||
* @param outputOffset Offset into the output buffer for the HMAC value.
|
||||
* @param outputLength The length of the HMAC output.
|
||||
*/
|
||||
private void hmac(byte[] key, int keyOffset, int keyLength,
|
||||
byte[] data, int dataOffset, int dataLength,
|
||||
byte[] output, int outputOffset, int outputLength)
|
||||
{
|
||||
// In all of the algorithms of interest to us, the block length
|
||||
// is twice the size of the hash length.
|
||||
int hashLength = hash.getDigestLength();
|
||||
int blockLength = hashLength * 2;
|
||||
byte[] block = new byte [blockLength];
|
||||
int index;
|
||||
try {
|
||||
if (keyLength <= blockLength) {
|
||||
System.arraycopy(key, keyOffset, block, 0, keyLength);
|
||||
Arrays.fill(block, keyLength, blockLength, (byte)0);
|
||||
} else {
|
||||
hash.reset();
|
||||
hash.update(key, keyOffset, keyLength);
|
||||
hash.digest(block, 0, hashLength);
|
||||
Arrays.fill(block, hashLength, blockLength, (byte)0);
|
||||
}
|
||||
for (index = 0; index < blockLength; ++index)
|
||||
block[index] ^= (byte)0x36;
|
||||
hash.reset();
|
||||
hash.update(block, 0, blockLength);
|
||||
hash.update(data, dataOffset, dataLength);
|
||||
hash.digest(output, outputOffset, hashLength);
|
||||
for (index = 0; index < blockLength; ++index)
|
||||
block[index] ^= (byte)(0x36 ^ 0x5C);
|
||||
hash.reset();
|
||||
hash.update(block, 0, blockLength);
|
||||
hash.update(output, outputOffset, hashLength);
|
||||
hash.digest(output, outputOffset, outputLength);
|
||||
} catch (DigestException e) {
|
||||
Arrays.fill(output, outputOffset, outputLength, (byte)0);
|
||||
} finally {
|
||||
Noise.destroy(block);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a HKDF value.
|
||||
*
|
||||
* @param key The buffer that contains the key.
|
||||
* @param keyOffset The offset of the key in the key buffer.
|
||||
* @param keyLength The length of the key in bytes.
|
||||
* @param data The buffer that contains the data.
|
||||
* @param dataOffset The offset of the data in the data buffer.
|
||||
* @param dataLength The length of the data in bytes.
|
||||
* @param output1 The first output buffer.
|
||||
* @param output1Offset Offset into the first output buffer.
|
||||
* @param output1Length Length of the first output which can be
|
||||
* less than the hash length.
|
||||
* @param output2 The second output buffer.
|
||||
* @param output2Offset Offset into the second output buffer.
|
||||
* @param output2Length Length of the second output which can be
|
||||
* less than the hash length.
|
||||
*/
|
||||
private void hkdf(byte[] key, int keyOffset, int keyLength,
|
||||
byte[] data, int dataOffset, int dataLength,
|
||||
byte[] output1, int output1Offset, int output1Length,
|
||||
byte[] output2, int output2Offset, int output2Length)
|
||||
{
|
||||
int hashLength = hash.getDigestLength();
|
||||
byte[] tempKey = new byte [hashLength];
|
||||
byte[] tempHash = new byte [hashLength + 1];
|
||||
try {
|
||||
hmac(key, keyOffset, keyLength, data, dataOffset, dataLength, tempKey, 0, hashLength);
|
||||
tempHash[0] = (byte)0x01;
|
||||
hmac(tempKey, 0, hashLength, tempHash, 0, 1, tempHash, 0, hashLength);
|
||||
System.arraycopy(tempHash, 0, output1, output1Offset, output1Length);
|
||||
tempHash[hashLength] = (byte)0x02;
|
||||
hmac(tempKey, 0, hashLength, tempHash, 0, hashLength + 1, tempHash, 0, hashLength);
|
||||
System.arraycopy(tempHash, 0, output2, output2Offset, output2Length);
|
||||
} finally {
|
||||
Noise.destroy(tempKey);
|
||||
Noise.destroy(tempHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,565 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* 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.bitchat.android.noise.southernstorm.protocol
|
||||
|
||||
import android.util.Log
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.createCipher
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.createHash
|
||||
import com.bitchat.android.noise.southernstorm.protocol.Noise.destroy
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.security.DigestException
|
||||
import java.security.MessageDigest
|
||||
import javax.crypto.BadPaddingException
|
||||
import javax.crypto.ShortBufferException
|
||||
|
||||
/**
|
||||
* Symmetric state for helping manage a Noise handshake.
|
||||
*/
|
||||
internal class SymmetricState(protocolName: String, cipherName: String, hashName: String) :
|
||||
Destroyable {
|
||||
/**
|
||||
* Gets the name of the Noise protocol.
|
||||
*
|
||||
* @return The protocol name.
|
||||
*/
|
||||
val protocolName: String
|
||||
private var cipher: CipherState?
|
||||
private var hash: MessageDigest?
|
||||
private var ck: ByteArray?
|
||||
|
||||
/**
|
||||
* Gets the current value of the handshake hash.
|
||||
*
|
||||
* @return The handshake hash. This must not be modified by the caller.
|
||||
*
|
||||
* The handshake hash value is only of use to the application after
|
||||
* split() has been called.
|
||||
*/
|
||||
var handshakeHash: ByteArray?
|
||||
private set
|
||||
private var prevH: ByteArray?
|
||||
|
||||
/**
|
||||
* Constructs a new symmetric state object.
|
||||
*
|
||||
* @param protocolName The name of the Noise protocol, which is assumed to be valid.
|
||||
* @param cipherName The name of the cipher within protocolName.
|
||||
* @param hashName The name of the hash within protocolName.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The cipher or hash algorithm in the
|
||||
* protocol name is not supported.
|
||||
*/
|
||||
init {
|
||||
this.protocolName = protocolName
|
||||
cipher = createCipher(cipherName)
|
||||
hash = createHash(hashName)
|
||||
val hashLength = hash!!.digestLength
|
||||
ck = ByteArray(hashLength)
|
||||
val initialHash = ByteArray(hashLength)
|
||||
this.handshakeHash = initialHash
|
||||
prevH = ByteArray(hashLength)
|
||||
|
||||
val protocolNameBytes: ByteArray = try {
|
||||
protocolName.toByteArray(charset("UTF-8"))
|
||||
} catch (_: UnsupportedEncodingException) {
|
||||
// If UTF-8 is not supported, then we are definitely in trouble!
|
||||
throw UnsupportedOperationException("UTF-8 encoding is not supported")
|
||||
}
|
||||
|
||||
if (protocolNameBytes.size <= hashLength) {
|
||||
protocolNameBytes.copyInto(initialHash, 0, 0, protocolNameBytes.size)
|
||||
initialHash.fill(0, protocolNameBytes.size, initialHash.size)
|
||||
} else {
|
||||
hashOne(
|
||||
protocolNameBytes, 0, protocolNameBytes.size,
|
||||
initialHash, 0, initialHash.size
|
||||
)
|
||||
}
|
||||
|
||||
initialHash.copyInto(ck!!, 0, 0, hashLength)
|
||||
|
||||
|
||||
// LOGGING: Initial symmetric state after protocol name initialization (matching iOS)
|
||||
Log.d(TAG, "=== ANDROID SYMMETRIC STATE INITIALIZED ===")
|
||||
Log.d(TAG, "Protocol: $protocolName")
|
||||
Log.d(TAG, "Initial hash (h): ${bytesToHex(initialHash)}")
|
||||
Log.d(TAG, "Initial chaining key (ck): ${bytesToHex(ck!!)}")
|
||||
Log.d(TAG, "Hash length: ${initialHash.size}")
|
||||
Log.d(TAG, "=========================================")
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of MAC values in the current state, or zero if the cipher
|
||||
* has not yet been initialized with a key.
|
||||
*/
|
||||
val macLength: Int
|
||||
get() = cipher!!.macLength
|
||||
|
||||
/**
|
||||
* Mixes data into the chaining key.
|
||||
*
|
||||
* @param data The buffer containing the data to mix in.
|
||||
* @param offset The offset of the first data byte to mix in.
|
||||
* @param length The number of bytes to mix in.
|
||||
*/
|
||||
fun mixKey(data: ByteArray, offset: Int, length: Int) {
|
||||
// LOGGING: Before mixKey operation (matching iOS)
|
||||
val inputData = ByteArray(length)
|
||||
data.copyInto(inputData, 0, offset, offset + length)
|
||||
Log.d(TAG, "*** Android mixKey() BEFORE ***")
|
||||
Log.d(TAG, "Input data ($length bytes): ${bytesToHex(inputData)}")
|
||||
Log.d(TAG, "Current CK: ${bytesToHex(ck!!)}")
|
||||
Log.d(TAG, "Current Hash: ${bytesToHex(handshakeHash!!)}")
|
||||
|
||||
val keyLength = cipher!!.keyLength
|
||||
val tempKey = ByteArray(keyLength)
|
||||
try {
|
||||
hkdf(
|
||||
ck!!,
|
||||
0,
|
||||
ck!!.size,
|
||||
data,
|
||||
offset,
|
||||
length,
|
||||
ck!!,
|
||||
0,
|
||||
ck!!.size,
|
||||
tempKey,
|
||||
0,
|
||||
keyLength
|
||||
)
|
||||
cipher!!.initializeKey(tempKey, 0)
|
||||
} finally {
|
||||
destroy(tempKey)
|
||||
}
|
||||
|
||||
|
||||
// LOGGING: After mixKey operation (matching iOS)
|
||||
Log.d(TAG, "*** Android mixKey() AFTER ***")
|
||||
Log.d(TAG, "New CK: ${bytesToHex(ck!!)}")
|
||||
Log.d(TAG, "Hash unchanged: ${bytesToHex(handshakeHash!!)}")
|
||||
Log.d(TAG, "Cipher now has key: ${cipher!!.macLength > 0}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes data into the handshake hash.
|
||||
*
|
||||
* @param data The buffer containing the data to mix in.
|
||||
* @param offset The offset of the first data byte to mix in.
|
||||
* @param length The number of bytes to mix in.
|
||||
*/
|
||||
fun mixHash(data: ByteArray, offset: Int, length: Int) {
|
||||
// LOGGING: Before mixHash operation (matching iOS)
|
||||
val inputData = ByteArray(length)
|
||||
data.copyInto(inputData, 0, offset, offset + length)
|
||||
Log.d(TAG, "*** Android mixHash() BEFORE ***")
|
||||
Log.d(TAG, "Input data ($length bytes): ${bytesToHex(inputData)}")
|
||||
Log.d(TAG, "Current Hash: ${bytesToHex(handshakeHash!!)}")
|
||||
|
||||
val h = handshakeHash!!
|
||||
hashTwo(
|
||||
h, 0, h.size, data, offset, length,
|
||||
h, 0, h.size
|
||||
)
|
||||
|
||||
|
||||
// LOGGING: After mixHash operation (matching iOS)
|
||||
Log.d(TAG, "*** Android mixHash() AFTER ***")
|
||||
Log.d(TAG, "New Hash: ${bytesToHex(handshakeHash!!)}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes a pre-shared key into the chaining key and handshake hash.
|
||||
*
|
||||
* @param key The pre-shared key value.
|
||||
*/
|
||||
fun mixPreSharedKey(key: ByteArray) {
|
||||
val temp = ByteArray(hash!!.digestLength)
|
||||
try {
|
||||
hkdf(ck!!, 0, ck!!.size, key, 0, key.size, ck!!, 0, ck!!.size, temp, 0, temp.size)
|
||||
mixHash(temp, 0, temp.size)
|
||||
} finally {
|
||||
destroy(temp)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes a pre-supplied public key into the handshake hash.
|
||||
*
|
||||
* @param dh The object containing the public key.
|
||||
*/
|
||||
fun mixPublicKey(dh: DHState) {
|
||||
val temp = ByteArray(dh.publicKeyLength)
|
||||
try {
|
||||
dh.getPublicKey(temp, 0)
|
||||
mixHash(temp, 0, temp.size)
|
||||
} finally {
|
||||
destroy(temp)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes a pre-supplied public key into the chaining key.
|
||||
*
|
||||
* @param dh The object containing the public key.
|
||||
*/
|
||||
fun mixPublicKeyIntoCK(dh: DHState) {
|
||||
val temp = ByteArray(dh.publicKeyLength)
|
||||
try {
|
||||
dh.getPublicKey(temp, 0)
|
||||
mixKey(temp, 0, temp.size)
|
||||
} finally {
|
||||
destroy(temp)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a block of plaintext and mixes the ciphertext into the handshake hash.
|
||||
*
|
||||
* @param plaintext The buffer containing the plaintext to encrypt.
|
||||
* @param plaintextOffset The offset within the plaintext buffer of the
|
||||
* first byte or plaintext data.
|
||||
* @param ciphertext The buffer to place the ciphertext in. This can
|
||||
* be the same as the plaintext buffer.
|
||||
* @param ciphertextOffset The first offset within the ciphertext buffer
|
||||
* to place the ciphertext and the MAC tag.
|
||||
* @param length The length of the plaintext.
|
||||
* @return The length of the ciphertext plus the MAC tag.
|
||||
*
|
||||
* @throws ShortBufferException There is not enough space in the
|
||||
* ciphertext buffer for the encrypted data plus MAC value.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* encryption. In that case, plaintextOffset must be identical to
|
||||
* ciphertextOffset.
|
||||
*
|
||||
* There must be enough space in the ciphertext buffer to accomodate
|
||||
* length + getMACLength() bytes of data starting at ciphertextOffset.
|
||||
*/
|
||||
@Throws(ShortBufferException::class)
|
||||
fun encryptAndHash(
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
length: Int
|
||||
): Int {
|
||||
val ciphertextLength = cipher!!.encryptWithAd(
|
||||
this.handshakeHash,
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
length
|
||||
)
|
||||
mixHash(ciphertext, ciphertextOffset, ciphertextLength)
|
||||
return ciphertextLength
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a block of ciphertext and mixes it into the handshake hash.
|
||||
*
|
||||
* @param ciphertext The buffer containing the ciphertext to decrypt.
|
||||
* @param ciphertextOffset The offset within the ciphertext buffer of
|
||||
* the first byte of ciphertext data.
|
||||
* @param plaintext The buffer to place the plaintext in. This can be
|
||||
* the same as the ciphertext buffer.
|
||||
* @param plaintextOffset The first offset within the plaintext buffer
|
||||
* to place the plaintext.
|
||||
* @param length The length of the incoming ciphertext plus the MAC tag.
|
||||
* @return The length of the plaintext with the MAC tag stripped off.
|
||||
*
|
||||
* @throws ShortBufferException There is not enough space in the plaintext
|
||||
* buffer for the decrypted data.
|
||||
*
|
||||
* @throws BadPaddingException The MAC value failed to verify.
|
||||
*
|
||||
* The plaintext and ciphertext buffers can be the same for in-place
|
||||
* decryption. In that case, ciphertextOffset must be identical to
|
||||
* plaintextOffset.
|
||||
*/
|
||||
@Throws(ShortBufferException::class, BadPaddingException::class)
|
||||
fun decryptAndHash(
|
||||
ciphertext: ByteArray,
|
||||
ciphertextOffset: Int,
|
||||
plaintext: ByteArray,
|
||||
plaintextOffset: Int,
|
||||
length: Int
|
||||
): Int {
|
||||
val h = handshakeHash!!
|
||||
h.copyInto(prevH!!, 0, 0, h.size)
|
||||
mixHash(ciphertext, ciphertextOffset, length)
|
||||
return cipher!!.decryptWithAd(
|
||||
prevH,
|
||||
ciphertext,
|
||||
ciphertextOffset,
|
||||
plaintext,
|
||||
plaintextOffset,
|
||||
length
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the symmetric state into two ciphers for session encryption,
|
||||
* and optionally mixes in a secondary symmetric key.
|
||||
*
|
||||
* @param secondaryKey The buffer containing the secondary key.
|
||||
* @param offset The offset of the first secondary key byte.
|
||||
* @param length The length of the secondary key in bytes, which
|
||||
* must be either 0 or 32.
|
||||
* @return The pair of ciphers for sending and receiving.
|
||||
*
|
||||
* @throws IllegalArgumentException The length is not 0 or 32.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun split(
|
||||
secondaryKey: ByteArray? = ByteArray(0),
|
||||
offset: Int = 0,
|
||||
length: Int = 0
|
||||
): CipherStatePair {
|
||||
require(!(length != 0 && length != 32)) { "Secondary keys must be 0 or 32 bytes in length" }
|
||||
val keyLength = cipher!!.keyLength
|
||||
val k1 = ByteArray(keyLength)
|
||||
val k2 = ByteArray(keyLength)
|
||||
try {
|
||||
// When length == 0 the buffer is unused by HKDF; substitute an
|
||||
// empty array so the helper signature can stay non-null.
|
||||
val sk = secondaryKey ?: ByteArray(0)
|
||||
hkdf(ck!!, 0, ck!!.size, sk, offset, length, k1, 0, k1.size, k2, 0, k2.size)
|
||||
var c1: CipherState? = null
|
||||
var c2: CipherState? = null
|
||||
var pair: CipherStatePair? = null
|
||||
try {
|
||||
c1 = cipher!!.fork(k1, 0)
|
||||
c2 = cipher!!.fork(k2, 0)
|
||||
pair = CipherStatePair(c1, c2)
|
||||
} finally {
|
||||
if (c1 == null || c2 == null || pair == null) {
|
||||
// Could not create some of the objects. Clean up the others
|
||||
// to avoid accidental leakage of k1 or k2.
|
||||
c1?.destroy()
|
||||
c2?.destroy()
|
||||
pair = null
|
||||
}
|
||||
}
|
||||
return pair!!
|
||||
} finally {
|
||||
destroy(k1)
|
||||
destroy(k2)
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
if (cipher != null) {
|
||||
cipher!!.destroy()
|
||||
cipher = null
|
||||
}
|
||||
if (hash != null) {
|
||||
// The built-in fallback implementations are destroyable.
|
||||
// JCA/JCE implementations aren't, so try reset() instead.
|
||||
if (hash is Destroyable) (hash as Destroyable).destroy()
|
||||
else hash!!.reset()
|
||||
hash = null
|
||||
}
|
||||
if (ck != null) {
|
||||
Noise.destroy(ck!!)
|
||||
ck = null
|
||||
}
|
||||
if (this.handshakeHash != null) {
|
||||
Noise.destroy(this.handshakeHash!!)
|
||||
this.handshakeHash = null
|
||||
}
|
||||
if (prevH != null) {
|
||||
Noise.destroy(prevH!!)
|
||||
prevH = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes a single data buffer.
|
||||
*
|
||||
* @param data The buffer containing the data to hash.
|
||||
* @param offset Offset into the data buffer of the first byte to hash.
|
||||
* @param length Length of the data to be hashed.
|
||||
* @param output The buffer to receive the output hash value.
|
||||
* @param outputOffset Offset into the output buffer to place the hash value.
|
||||
* @param outputLength The length of the hash output.
|
||||
*
|
||||
* The output buffer can be the same as the input data buffer.
|
||||
*/
|
||||
private fun hashOne(
|
||||
data: ByteArray,
|
||||
offset: Int,
|
||||
length: Int,
|
||||
output: ByteArray,
|
||||
outputOffset: Int,
|
||||
outputLength: Int
|
||||
) {
|
||||
hash!!.reset()
|
||||
hash!!.update(data, offset, length)
|
||||
try {
|
||||
hash!!.digest(output, outputOffset, outputLength)
|
||||
} catch (_: DigestException) {
|
||||
output.fill(0, outputOffset, outputLength)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes two data buffers.
|
||||
*
|
||||
* @param data1 The buffer containing the first data to hash.
|
||||
* @param offset1 Offset into the first data buffer of the first byte to hash.
|
||||
* @param length1 Length of the first data to be hashed.
|
||||
* @param data2 The buffer containing the second data to hash.
|
||||
* @param offset2 Offset into the second data buffer of the first byte to hash.
|
||||
* @param length2 Length of the second data to be hashed.
|
||||
* @param output The buffer to receive the output hash value.
|
||||
* @param outputOffset Offset into the output buffer to place the hash value.
|
||||
* @param outputLength The length of the hash output.
|
||||
*
|
||||
* The output buffer can be same as either of the input buffers.
|
||||
*/
|
||||
private fun hashTwo(
|
||||
data1: ByteArray, offset1: Int, length1: Int,
|
||||
data2: ByteArray, offset2: Int, length2: Int,
|
||||
output: ByteArray, outputOffset: Int, outputLength: Int
|
||||
) {
|
||||
hash!!.reset()
|
||||
hash!!.update(data1, offset1, length1)
|
||||
hash!!.update(data2, offset2, length2)
|
||||
try {
|
||||
hash!!.digest(output, outputOffset, outputLength)
|
||||
} catch (_: DigestException) {
|
||||
output.fill(0, outputOffset, outputLength)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a HMAC value using key and data values.
|
||||
*
|
||||
* @param key The buffer that contains the key.
|
||||
* @param keyOffset The offset of the key in the key buffer.
|
||||
* @param keyLength The length of the key in bytes.
|
||||
* @param data The buffer that contains the data.
|
||||
* @param dataOffset The offset of the data in the data buffer.
|
||||
* @param dataLength The length of the data in bytes.
|
||||
* @param output The output buffer to place the HMAC value in.
|
||||
* @param outputOffset Offset into the output buffer for the HMAC value.
|
||||
* @param outputLength The length of the HMAC output.
|
||||
*/
|
||||
private fun hmac(
|
||||
key: ByteArray, keyOffset: Int, keyLength: Int,
|
||||
data: ByteArray, dataOffset: Int, dataLength: Int,
|
||||
output: ByteArray, outputOffset: Int, outputLength: Int
|
||||
) {
|
||||
// In all of the algorithms of interest to us, the block length
|
||||
// is twice the size of the hash length.
|
||||
val hashLength = hash!!.digestLength
|
||||
val blockLength = hashLength * 2
|
||||
val block = ByteArray(blockLength)
|
||||
try {
|
||||
if (keyLength <= blockLength) {
|
||||
System.arraycopy(key, keyOffset, block, 0, keyLength)
|
||||
block.fill(0, keyLength, blockLength)
|
||||
} else {
|
||||
hash!!.reset()
|
||||
hash!!.update(key, keyOffset, keyLength)
|
||||
hash!!.digest(block, 0, hashLength)
|
||||
block.fill(0, hashLength, blockLength)
|
||||
}
|
||||
for (i in 0 until blockLength) {
|
||||
block[i] = (block[i].toInt() xor 0x36).toByte()
|
||||
}
|
||||
hash!!.reset()
|
||||
hash!!.update(block, 0, blockLength)
|
||||
hash!!.update(data, dataOffset, dataLength)
|
||||
hash!!.digest(output, outputOffset, hashLength)
|
||||
for (i in 0 until blockLength) {
|
||||
block[i] = (block[i].toInt() xor (0x36 xor 0x5C)).toByte()
|
||||
}
|
||||
hash!!.reset()
|
||||
hash!!.update(block, 0, blockLength)
|
||||
hash!!.update(output, outputOffset, hashLength)
|
||||
hash!!.digest(output, outputOffset, outputLength)
|
||||
} catch (_: DigestException) {
|
||||
output.fill(0, outputOffset, outputLength)
|
||||
} finally {
|
||||
destroy(block)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a HKDF value.
|
||||
*
|
||||
* @param key The buffer that contains the key.
|
||||
* @param keyOffset The offset of the key in the key buffer.
|
||||
* @param keyLength The length of the key in bytes.
|
||||
* @param data The buffer that contains the data.
|
||||
* @param dataOffset The offset of the data in the data buffer.
|
||||
* @param dataLength The length of the data in bytes.
|
||||
* @param output1 The first output buffer.
|
||||
* @param output1Offset Offset into the first output buffer.
|
||||
* @param output1Length Length of the first output which can be
|
||||
* less than the hash length.
|
||||
* @param output2 The second output buffer.
|
||||
* @param output2Offset Offset into the second output buffer.
|
||||
* @param output2Length Length of the second output which can be
|
||||
* less than the hash length.
|
||||
*/
|
||||
private fun hkdf(
|
||||
key: ByteArray, keyOffset: Int, keyLength: Int,
|
||||
data: ByteArray, dataOffset: Int, dataLength: Int,
|
||||
output1: ByteArray, output1Offset: Int, output1Length: Int,
|
||||
output2: ByteArray, output2Offset: Int, output2Length: Int
|
||||
) {
|
||||
val hashLength = hash!!.digestLength
|
||||
val tempKey = ByteArray(hashLength)
|
||||
val tempHash = ByteArray(hashLength + 1)
|
||||
try {
|
||||
hmac(key, keyOffset, keyLength, data, dataOffset, dataLength, tempKey, 0, hashLength)
|
||||
tempHash[0] = 0x01.toByte()
|
||||
hmac(tempKey, 0, hashLength, tempHash, 0, 1, tempHash, 0, hashLength)
|
||||
System.arraycopy(tempHash, 0, output1, output1Offset, output1Length)
|
||||
tempHash[hashLength] = 0x02.toByte()
|
||||
hmac(tempKey, 0, hashLength, tempHash, 0, hashLength + 1, tempHash, 0, hashLength)
|
||||
System.arraycopy(tempHash, 0, output2, output2Offset, output2Length)
|
||||
} finally {
|
||||
destroy(tempKey)
|
||||
destroy(tempHash)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "AndroidSymmetric"
|
||||
|
||||
/**
|
||||
* Converts a byte array to hex string for logging (matching iOS hex format)
|
||||
*/
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
val sb = StringBuilder()
|
||||
for (b in bytes) {
|
||||
sb.append("%02x".format(b))
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
|
||||
/**
|
||||
* Provides classes for communicating via the Noise protocol.
|
||||
*
|
||||
* Reference: http://noiseprotocol.org
|
||||
*/
|
||||
package com.bitchat.android.noise.southernstorm.protocol;
|
||||
Loading…
x
Reference in New Issue
Block a user