diff --git a/build.gradle.kts b/build.gradle.kts
index a3d2dbdf97..f948651833 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -134,6 +134,9 @@ dependencies {
implementation(libs.trove4j)
implementation(libs.bundles.jackson)
+ //Audio crypto libraries
+ implementation(libs.tink)
+
//Sets the dependencies for the examples
configurations["examplesImplementation"].withDependencies {
addAll(configurations["api"].allDependencies)
@@ -222,6 +225,10 @@ val minimalJar by tasks.creating(ShadowJar::class) {
from(sourceSets["main"].output)
exclude("natives/**") // ~2 MB
exclude("com/sun/jna/**") // ~1 MB
+ exclude("com/google/crypto/tink/**") // ~2 MB
+ exclude("com/google/gson/**") // ~300 KB
+ exclude("com/google/protobuf/**") // ~2 MB
+ exclude("google/protobuf/**")
exclude("club/minnced/opus/util/*")
exclude("tomp2p/opuswrapper/*")
manifest.inheritFrom(jar.manifest)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 2edf0d86c4..0c1d1b018e 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -23,6 +23,7 @@ dependencyResolutionManagement {
library("mockito", "org.mockito", "mockito-core" ).version("5.11.0")
library("reflections", "org.reflections", "reflections" ).version("0.10.2")
library("slf4j", "org.slf4j", "slf4j-api" ).version("2.0.13")
+ library("tink", "com.google.crypto.tink", "tink" ).version("1.14.1")
}
}
}
diff --git a/src/main/java/com/iwebpp/crypto/TweetNaclFast.java b/src/main/java/com/iwebpp/crypto/TweetNaclFast.java
deleted file mode 100644
index 8276a86c00..0000000000
--- a/src/main/java/com/iwebpp/crypto/TweetNaclFast.java
+++ /dev/null
@@ -1,3408 +0,0 @@
-/*
- * This is taken from:
- * https://github.com/InstantWebP2P/tweetnacl-java
- * All credit goes to the original author.
- *
- * Copyright (c) 2014 Tom Zhou
- */
-package com.iwebpp.crypto;
-
-import java.io.UnsupportedEncodingException;
-import java.security.SecureRandom;
-import java.util.Base64;
-import java.util.concurrent.atomic.AtomicLong;
-
-/*
- * @description
- * TweetNacl.c Java porting
- * */
-public final class TweetNaclFast {
-
- private final static String TAG = "TweetNaclFast";
-
- /*
- * @description
- * Box algorithm, Public-key authenticated encryption
- * */
- public static final class Box {
-
- private final static String TAG = "Box";
-
- private AtomicLong nonce;
-
- private byte [] theirPublicKey;
- private byte [] mySecretKey;
- private byte [] sharedKey;
-
- public Box(byte [] theirPublicKey, byte [] mySecretKey) {
- this(theirPublicKey, mySecretKey, 68);
- }
-
- public Box(byte [] theirPublicKey, byte [] mySecretKey, long nonce) {
- this.theirPublicKey = theirPublicKey;
- this.mySecretKey = mySecretKey;
-
- this.nonce = new AtomicLong(nonce);
-
- // generate pre-computed shared key
- before();
- }
-
- public void setNonce(long nonce) {
- this.nonce.set(nonce);
- }
- public long getNonce() {
- return this.nonce.get();
- }
- public long incrNonce() {
- return this.nonce.incrementAndGet();
- }
- private byte[] generateNonce() {
- // generate nonce
- long nonce = this.nonce.get();
-
- byte [] n = new byte[nonceLength];
- for (int i = 0; i < nonceLength; i += 8) {
- n[i+0] = (byte) (nonce>>> 0);
- n[i+1] = (byte) (nonce>>> 8);
- n[i+2] = (byte) (nonce>>>16);
- n[i+3] = (byte) (nonce>>>24);
- n[i+4] = (byte) (nonce>>>32);
- n[i+5] = (byte) (nonce>>>40);
- n[i+6] = (byte) (nonce>>>48);
- n[i+7] = (byte) (nonce>>>56);
- }
-
- return n;
- }
-
- /*
- * @description
- * Encrypt and authenticates message using peer's public key,
- * our secret key, and the given nonce, which must be unique
- * for each distinct message for a key pair.
- *
- * Returns an encrypted and authenticated message,
- * which is nacl.box.overheadLength longer than the original message.
- * */
- public byte [] box(byte [] message) {
- if (message==null) return null;
- return box(message, 0, message.length);
- }
-
- public byte [] box(byte [] message, final int moff) {
- if (!(message!=null && message.length>moff)) return null;
- return box(message, moff, message.length-moff);
- }
-
- public byte [] box(byte [] message, final int moff, final int mlen) {
- if (!(message!=null && message.length>=(moff+mlen))) return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return after(message, moff, mlen);
- }
-
- /*
- * @description
- * Encrypt and authenticates message using peer's public key,
- * our secret key, and the given nonce, which must be unique
- * for each distinct message for a key pair.
- *
- * Explicitly pass the nonce
- *
- * Returns an encrypted and authenticated message,
- * which is nacl.box.overheadLength longer than the original message.
- * */
- public byte [] box(byte [] message, byte [] theNonce) {
- if (message==null) return null;
- return box(message, 0, message.length, theNonce);
- }
-
- public byte [] box(byte [] message, final int moff, byte [] theNonce) {
- if (!(message!=null && message.length>moff)) return null;
- return box(message, moff, message.length-moff, theNonce);
- }
-
- public byte [] box(byte [] message, final int moff, final int mlen, byte [] theNonce) {
- if (!(message!=null && message.length>=(moff+mlen) &&
- theNonce!=null && theNonce.length==nonceLength))
- return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return after(message, moff, mlen, theNonce);
- }
-
- /*
- * @description
- * Authenticates and decrypts the given box with peer's public key,
- * our secret key, and the given nonce.
- *
- * Returns the original message, or null if authentication fails.
- * */
- public byte [] open(byte [] box) {
- if (box==null) return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return open_after(box, 0, box.length);
- }
- public byte [] open(byte [] box, final int boxoff) {
- if (!(box!=null && box.length>boxoff)) return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return open_after(box, boxoff, box.length-boxoff);
- }
- public byte [] open(byte [] box, final int boxoff, final int boxlen) {
- if (!(box!=null && box.length>=(boxoff+boxlen))) return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return open_after(box, boxoff, boxlen);
- }
-
-
- /*
- * @description
- * Authenticates and decrypts the given box with peer's public key,
- * our secret key, and the given nonce.
- * Explicit passing of nonce
- * Returns the original message, or null if authentication fails.
- * */
- public byte [] open(byte [] box, byte [] theNonce) {
- if (!(box!=null &&
- theNonce!=null && theNonce.length==nonceLength))
- return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return open_after(box, 0, box.length, theNonce);
- }
- public byte [] open(byte [] box, final int boxoff, byte [] theNonce) {
- if (!(box!=null && box.length>boxoff &&
- theNonce!=null && theNonce.length==nonceLength))
- return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return open_after(box, boxoff, box.length-boxoff, theNonce);
- }
- public byte [] open(byte [] box, final int boxoff, final int boxlen, byte [] theNonce) {
- if (!(box!=null && box.length>=(boxoff+boxlen) &&
- theNonce!=null && theNonce.length==nonceLength))
- return null;
-
- // prepare shared key
- if (this.sharedKey == null) before();
-
- return open_after(box, boxoff, boxlen, theNonce);
- }
-
-
- /*
- * @description
- * Returns a precomputed shared key
- * which can be used in nacl.box.after and nacl.box.open.after.
- * */
- public byte [] before() {
- if (this.sharedKey == null) {
- this.sharedKey = new byte[sharedKeyLength];
- crypto_box_beforenm(this.sharedKey, this.theirPublicKey, this.mySecretKey);
- }
-
- return this.sharedKey;
- }
-
- /*
- * @description
- * Same as nacl.box, but uses a shared key precomputed with nacl.box.before.
- * */
- public byte [] after(byte [] message, final int moff, final int mlen) {
- return after(message, moff, mlen, generateNonce());
- }
-
- /*
- * @description
- * Same as nacl.box, but uses a shared key precomputed with nacl.box.before,
- * and passes a nonce explicitly.
- * */
- public byte [] after(byte [] message, final int moff, final int mlen, byte [] theNonce) {
- // check message
- if (!(message!=null && message.length>=(moff+mlen) &&
- theNonce!=null && theNonce.length==nonceLength))
- return null;
-
- // message buffer
- byte [] m = new byte[mlen + zerobytesLength];
-
- // cipher buffer
- byte [] c = new byte[m.length];
-
- for (int i = 0; i < mlen; i ++)
- m[i+zerobytesLength] = message[i+moff];
-
- if (0 != crypto_box_afternm(c, m, m.length, theNonce, sharedKey))
- return null;
-
- // wrap byte_buf_t on c offset@boxzerobytesLength
- ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength);
- byte [] ret = new byte[c.length-boxzerobytesLength];
-
- for (int i = 0; i < ret.length; i ++)
- ret[i] = c[i+boxzerobytesLength];
-
- return ret;
- }
-
- /*
- * @description
- * Same as nacl.box.open,
- * but uses a shared key pre-computed with nacl.box.before.
- * */
- public byte [] open_after(byte [] box, final int boxoff, final int boxlen) {
- return open_after(box, boxoff, boxlen, generateNonce());
- }
-
- public byte [] open_after(byte [] box, final int boxoff, final int boxlen, byte [] theNonce) {
- // check message
- if (!(box!=null && box.length>=(boxoff+boxlen) && boxlen>=boxzerobytesLength))
- return null;
-
- // cipher buffer
- byte [] c = new byte[boxlen + boxzerobytesLength];
-
- // message buffer
- byte [] m = new byte[c.length];
-
- for (int i = 0; i < boxlen; i++)
- c[i+boxzerobytesLength] = box[i+boxoff];
-
- if (crypto_box_open_afternm(m, c, c.length, theNonce, sharedKey) != 0)
- return null;
-
- // wrap byte_buf_t on m offset@zerobytesLength
- ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength);
- byte [] ret = new byte[m.length-zerobytesLength];
-
- for (int i = 0; i < ret.length; i ++)
- ret[i] = m[i+zerobytesLength];
-
- return ret;
- }
-
- /*
- * @description
- * Length of public key in bytes.
- * */
- public static final int publicKeyLength = 32;
-
- /*
- * @description
- * Length of secret key in bytes.
- * */
- public static final int secretKeyLength = 32;
-
- /*
- * @description
- * Length of precomputed shared key in bytes.
- * */
- public static final int sharedKeyLength = 32;
-
- /*
- * @description
- * Length of nonce in bytes.
- * */
- public static final int nonceLength = 24;
-
- /*
- * @description
- * zero bytes in case box
- * */
- public static final int zerobytesLength = 32;
- /*
- * @description
- * zero bytes in case open box
- * */
- public static final int boxzerobytesLength = 16;
-
- /*
- * @description
- * Length of overhead added to box compared to original message.
- * */
- public static final int overheadLength = 16;
-
- public static class KeyPair {
- private byte [] publicKey;
- private byte [] secretKey;
-
- public KeyPair() {
- publicKey = new byte[publicKeyLength];
- secretKey = new byte[secretKeyLength];
- }
-
- public byte [] getPublicKey() {
- return publicKey;
- }
-
- public byte [] getSecretKey() {
- return secretKey;
- }
- }
-
- /*
- * @description
- * Generates a new random key pair for box and
- * returns it as an object with publicKey and secretKey members:
- * */
- public static KeyPair keyPair() {
- KeyPair kp = new KeyPair();
-
- crypto_box_keypair(kp.getPublicKey(), kp.getSecretKey());
- return kp;
- }
-
- public static KeyPair keyPair_fromSecretKey(byte [] secretKey) {
- KeyPair kp = new KeyPair();
- byte [] sk = kp.getSecretKey();
- byte [] pk = kp.getPublicKey();
-
- // copy sk
- for (int i = 0; i < sk.length; i ++)
- sk[i] = secretKey[i];
-
- crypto_scalarmult_base(pk, sk);
- return kp;
- }
-
- }
-
- /*
- * @description
- * Secret Box algorithm, secret key
- * */
- public static final class SecretBox {
-
- private final static String TAG = "SecretBox";
-
- private AtomicLong nonce;
-
- private byte [] key;
-
- public SecretBox(byte [] key) {
- this(key, 68);
- }
-
- public SecretBox(byte [] key, long nonce) {
- this.key = key;
-
- this.nonce = new AtomicLong(nonce);
- }
-
- public void setNonce(long nonce) {
- this.nonce.set(nonce);
- }
- public long getNonce() {
- return this.nonce.get();
- }
- public long incrNonce() {
- return this.nonce.incrementAndGet();
- }
- private byte[] generateNonce() {
- // generate nonce
- long nonce = this.nonce.get();
-
- byte [] n = new byte[nonceLength];
- for (int i = 0; i < nonceLength; i += 8) {
- n[i+0] = (byte) (nonce>>> 0);
- n[i+1] = (byte) (nonce>>> 8);
- n[i+2] = (byte) (nonce>>>16);
- n[i+3] = (byte) (nonce>>>24);
- n[i+4] = (byte) (nonce>>>32);
- n[i+5] = (byte) (nonce>>>40);
- n[i+6] = (byte) (nonce>>>48);
- n[i+7] = (byte) (nonce>>>56);
- }
-
- return n;
- }
-
- /*
- * @description
- * Encrypt and authenticates message using the key and the nonce.
- * The nonce must be unique for each distinct message for this key.
- *
- * Returns an encrypted and authenticated message,
- * which is nacl.secretbox.overheadLength longer than the original message.
- * */
- public byte [] box(byte [] message) {
- if (message==null) return null;
- return box(message, 0, message.length);
- }
-
- public byte [] box(byte [] message, final int moff) {
- if (!(message!=null && message.length>moff)) return null;
- return box(message, moff, message.length-moff);
- }
-
- public byte [] box(byte [] message, final int moff, final int mlen) {
- // check message
- if (!(message!=null && message.length>=(moff+mlen)))
- return null;
- return box(message, moff, message.length-moff, generateNonce());
- }
-
- public byte [] box(byte [] message, byte [] theNonce) {
- if (message==null) return null;
- return box(message, 0, message.length, theNonce);
- }
-
- public byte [] box(byte [] message, final int moff, byte [] theNonce) {
- if (!(message!=null && message.length>moff)) return null;
- return box(message, moff, message.length-moff, theNonce);
- }
-
- public byte [] box(byte [] message, final int moff, final int mlen, byte [] theNonce) {
- // check message
- if (!(message!=null && message.length>=(moff+mlen) &&
- theNonce!=null && theNonce.length==nonceLength))
- return null;
-
- // message buffer
- byte [] m = new byte[mlen + zerobytesLength];
-
- // cipher buffer
- byte [] c = new byte[m.length];
-
- for (int i = 0; i < mlen; i ++)
- m[i+zerobytesLength] = message[i+moff];
-
- if (0 != crypto_secretbox(c, m, m.length, theNonce, key))
- return null;
-
- // TBD optimizing ...
- // wrap byte_buf_t on c offset@boxzerobytesLength
- ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength);
- byte [] ret = new byte[c.length-boxzerobytesLength];
-
- for (int i = 0; i < ret.length; i ++)
- ret[i] = c[i+boxzerobytesLength];
-
- return ret;
- }
-
- /*
- * @description
- * Authenticates and decrypts the given secret box
- * using the key and the nonce.
- *
- * Returns the original message, or null if authentication fails.
- * */
- public byte [] open(byte [] box) {
- if (box==null) return null;
- return open(box, 0, box.length);
- }
-
- public byte [] open(byte [] box, final int boxoff) {
- if (!(box!=null && box.length>boxoff)) return null;
- return open(box, boxoff, box.length-boxoff);
- }
-
- public byte [] open(byte [] box, final int boxoff, final int boxlen) {
- // check message
- if (!(box!=null && box.length>=(boxoff+boxlen) && boxlen>=boxzerobytesLength))
- return null;
- return open(box, boxoff, box.length-boxoff, generateNonce());
- }
-
- public byte [] open(byte [] box, byte [] theNonce) {
- if (box==null) return null;
- return open(box, 0, box.length, theNonce);
- }
-
- public byte [] open(byte [] box, final int boxoff, byte [] theNonce) {
- if (!(box!=null && box.length>boxoff)) return null;
- return open(box, boxoff, box.length-boxoff, theNonce);
- }
-
- public byte [] open(byte [] box, final int boxoff, final int boxlen, byte [] theNonce) {
- // check message
- if (!(box!=null && box.length>=(boxoff+boxlen) && boxlen>=boxzerobytesLength &&
- theNonce!=null && theNonce.length==nonceLength))
- return null;
-
- // cipher buffer
- byte [] c = new byte[boxlen + boxzerobytesLength];
-
- // message buffer
- byte [] m = new byte[c.length];
-
- for (int i = 0; i < boxlen; i++)
- c[i+boxzerobytesLength] = box[i+boxoff];
-
- if (0 != crypto_secretbox_open(m, c, c.length, theNonce, key))
- return null;
-
- // wrap byte_buf_t on m offset@zerobytesLength
- ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength);
- byte [] ret = new byte[m.length-zerobytesLength];
-
- for (int i = 0; i < ret.length; i ++)
- ret[i] = m[i+zerobytesLength];
-
- return ret;
- }
-
- /*
- * @description
- * Length of key in bytes.
- * */
- public static final int keyLength = 32;
-
- /*
- * @description
- * Length of nonce in bytes.
- * */
- public static final int nonceLength = 24;
-
- /*
- * @description
- * Length of overhead added to secret box compared to original message.
- * */
- public static final int overheadLength = 16;
-
- /*
- * @description
- * zero bytes in case box
- * */
- public static final int zerobytesLength = 32;
- /*
- * @description
- * zero bytes in case open box
- * */
- public static final int boxzerobytesLength = 16;
-
- }
-
- /*
- * @description
- * Scalar multiplication, Implements curve25519.
- * */
- public static final class ScalarMult {
-
- private final static String TAG = "ScalarMult";
-
- /*
- * @description
- * Multiplies an integer n by a group element p and
- * returns the resulting group element.
- * */
- public static byte [] scalseMult(byte [] n, byte [] p) {
- if (!(n.length==scalarLength && p.length==groupElementLength))
- return null;
-
- byte [] q = new byte [scalarLength];
-
- crypto_scalarmult(q, n, p);
-
- return q;
- }
-
- /*
- * @description
- * Multiplies an integer n by a standard group element and
- * returns the resulting group element.
- * */
- public static byte [] scalseMult_base(byte [] n) {
- if (!(n.length==scalarLength))
- return null;
-
- byte [] q = new byte [scalarLength];
-
- crypto_scalarmult_base(q, n);
-
- return q;
- }
-
- /*
- * @description
- * Length of scalar in bytes.
- * */
- public static final int scalarLength = 32;
-
- /*
- * @description
- * Length of group element in bytes.
- * */
- public static final int groupElementLength = 32;
-
- }
-
-
- /*
- * @description
- * Hash algorithm, Implements SHA-512.
- * */
- public static final class Hash {
-
- private final static String TAG = "Hash";
-
- /*
- * @description
- * Returns SHA-512 hash of the message.
- * */
- public static byte[] sha512(byte [] message) {
- if (!(message!=null && message.length>0))
- return null;
-
- byte [] out = new byte[hashLength];
-
- crypto_hash(out, message);
-
- return out;
- }
- public static byte[] sha512(String message) throws UnsupportedEncodingException {
- return sha512(message.getBytes("utf-8"));
- }
-
- /*
- * @description
- * Length of hash in bytes.
- * */
- public static final int hashLength = 64;
-
- }
-
-
- /*
- * @description
- * Signature algorithm, Implements ed25519.
- * */
- public static final class Signature {
-
- private final static String TAG = "Signature";
-
- private byte [] theirPublicKey;
- private byte [] mySecretKey;
-
- public Signature(byte [] theirPublicKey, byte [] mySecretKey) {
- this.theirPublicKey = theirPublicKey;
- this.mySecretKey = mySecretKey;
- }
-
- /*
- * @description
- * Signs the message using the secret key and returns a signed message.
- * */
- public byte [] sign(byte [] message) {
- if (message==null) return null;
-
- return sign(message, 0, message.length);
- }
- public byte [] sign(byte [] message, final int moff) {
- if (!(message!=null && message.length>moff)) return null;
-
- return sign(message, moff, message.length-moff);
- }
- public byte [] sign(byte [] message, final int moff, final int mlen) {
- // check message
- if (!(message!=null && message.length>=(moff+mlen)))
- return null;
-
- // signed message
- byte [] sm = new byte[mlen + signatureLength];
-
- crypto_sign(sm, -1, message, moff, mlen, mySecretKey);
-
- return sm;
- }
-
- /*
- * @description
- * Verifies the signed message and returns the message without signature.
- * Returns null if verification failed.
- * */
- public byte [] open(byte [] signedMessage) {
- if (signedMessage==null) return null;
-
- return open(signedMessage, 0, signedMessage.length);
- }
- public byte [] open(byte [] signedMessage, final int smoff) {
- if (!(signedMessage!=null && signedMessage.length>smoff)) return null;
-
- return open(signedMessage, smoff, signedMessage.length-smoff);
- }
- public byte [] open(byte [] signedMessage, final int smoff, final int smlen) {
- // check sm length
- if (!(signedMessage!=null && signedMessage.length>=(smoff+smlen) && smlen>=signatureLength))
- return null;
-
- // temp buffer
- byte [] tmp = new byte[smlen];
-
- if (0 != crypto_sign_open(tmp, -1, signedMessage, smoff, smlen, theirPublicKey))
- return null;
-
- // message
- byte [] msg = new byte[smlen-signatureLength];
- for (int i = 0; i < msg.length; i ++)
- msg[i] = signedMessage[smoff+ i+signatureLength];
-
- return msg;
- }
-
- /*
- * @description
- * Signs the message using the secret key and returns a signature.
- * */
- public byte [] detached(byte [] message) {
- byte[] signedMsg = this.sign(message);
- byte[] sig = new byte[signatureLength];
- for (int i = 0; i < sig.length; i++)
- sig[i] = signedMsg[i];
- return sig;
- }
-
- /*
- * @description
- * Verifies the signature for the message and
- * returns true if verification succeeded or false if it failed.
- * */
- public boolean detached_verify(byte [] message, byte [] signature) {
- if (signature.length != signatureLength)
- return false;
- if (theirPublicKey.length != publicKeyLength)
- return false;
- byte [] sm = new byte[signatureLength + message.length];
- byte [] m = new byte[signatureLength + message.length];
- for (int i = 0; i < signatureLength; i++)
- sm[i] = signature[i];
- for (int i = 0; i < message.length; i++)
- sm[i + signatureLength] = message[i];
- return (crypto_sign_open(m, -1, sm, 0, sm.length, theirPublicKey) >= 0);
- }
-
- /*
- * @description
- * Generates new random key pair for signing and
- * returns it as an object with publicKey and secretKey members
- * */
- public static class KeyPair {
- private byte [] publicKey;
- private byte [] secretKey;
-
- public KeyPair() {
- publicKey = new byte[publicKeyLength];
- secretKey = new byte[secretKeyLength];
- }
-
- public byte [] getPublicKey() {
- return publicKey;
- }
-
- public byte [] getSecretKey() {
- return secretKey;
- }
- }
-
- /*
- * @description
- * Signs the message using the secret key and returns a signed message.
- * */
- public static KeyPair keyPair() {
- KeyPair kp = new KeyPair();
-
- crypto_sign_keypair(kp.getPublicKey(), kp.getSecretKey(), false);
- return kp;
- }
- public static KeyPair keyPair_fromSecretKey(byte [] secretKey) {
- KeyPair kp = new KeyPair();
- byte [] pk = kp.getPublicKey();
- byte [] sk = kp.getSecretKey();
-
- // copy sk
- for (int i = 0; i < kp.getSecretKey().length; i ++)
- sk[i] = secretKey[i];
-
- // copy pk from sk
- for (int i = 0; i < kp.getPublicKey().length; i ++)
- pk[i] = secretKey[32+i]; // hard-copy
-
- return kp;
- }
-
- public static KeyPair keyPair_fromSeed(byte [] seed) {
- KeyPair kp = new KeyPair();
- byte [] pk = kp.getPublicKey();
- byte [] sk = kp.getSecretKey();
-
- // copy sk
- for (int i = 0; i < seedLength; i ++)
- sk[i] = seed[i];
-
- // generate pk from sk
- crypto_sign_keypair(pk, sk, true);
-
- return kp;
- }
-
- /*
- * @description
- * Length of signing public key in bytes.
- * */
- public static final int publicKeyLength = 32;
-
- /*
- * @description
- * Length of signing secret key in bytes.
- * */
- public static final int secretKeyLength = 64;
-
- /*
- * @description
- * Length of seed for nacl.sign.keyPair.fromSeed in bytes.
- * */
- public static final int seedLength = 32;
-
- /*
- * @description
- * Length of signature in bytes.
- * */
- public static final int signatureLength = 64;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////////
- /*
- * @description
- * Codes below are ported tweetnacl-fast.js from TweetNacl.c/TweetNacl.h
- * */
-
- private static final byte [] _0 = new byte[16];
- private static final byte [] _9 = new byte[32];
- static {
- ///for (int i = 0; i < _0.length; i ++) _0[i] = 0;
-
- ///for (int i = 0; i < _9.length; i ++) _9[i] = 0;
- _9[0] = 9;
- }
-
- private static final long [] gf0 = new long[16];
- private static final long [] gf1 = new long[16];
- private static final long [] _121665 = new long[16];
- static {
- ///for (int i = 0; i < gf0.length; i ++) gf0[i] = 0;
-
- ///for (int i = 0; i < gf1.length; i ++) gf1[i] = 0;
- gf1[0] = 1;
-
- ///for (int i = 0; i < _121665.length; i ++) _121665[i] = 0;
- _121665[0] = 0xDB41; _121665[1] = 1;
- }
-
- private static final long [] D = new long [] {
- 0x78a3, 0x1359, 0x4dca, 0x75eb,
- 0xd8ab, 0x4141, 0x0a4d, 0x0070,
- 0xe898, 0x7779, 0x4079, 0x8cc7,
- 0xfe73, 0x2b6f, 0x6cee, 0x5203
- };
- private static final long [] D2 = new long [] {
- 0xf159, 0x26b2, 0x9b94, 0xebd6,
- 0xb156, 0x8283, 0x149a, 0x00e0,
- 0xd130, 0xeef3, 0x80f2, 0x198e,
- 0xfce7, 0x56df, 0xd9dc, 0x2406
- };
- private static final long [] X = new long [] {
- 0xd51a, 0x8f25, 0x2d60, 0xc956,
- 0xa7b2, 0x9525, 0xc760, 0x692c,
- 0xdc5c, 0xfdd6, 0xe231, 0xc0a4,
- 0x53fe, 0xcd6e, 0x36d3, 0x2169
- };
- private static final long [] Y = new long [] {
- 0x6658, 0x6666, 0x6666, 0x6666,
- 0x6666, 0x6666, 0x6666, 0x6666,
- 0x6666, 0x6666, 0x6666, 0x6666,
- 0x6666, 0x6666, 0x6666, 0x6666
- };
- private static final long [] I = new long [] {
- 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee,
- 0xe478, 0xad2f, 0x1806, 0x2f43,
- 0xd7a7, 0x3dfb, 0x0099, 0x2b4d,
- 0xdf0b, 0x4fc1, 0x2480, 0x2b83
- };
-
- private static void ts64(byte [] x, final int xoff, long u)
- {
- ///int i;
- ///for (i = 7;i >= 0;--i) { x[i+xoff] = (byte)(u&0xff); u >>>= 8; }
-
- x[7+xoff] = (byte)(u&0xff); u >>>= 8;
- x[6+xoff] = (byte)(u&0xff); u >>>= 8;
- x[5+xoff] = (byte)(u&0xff); u >>>= 8;
- x[4+xoff] = (byte)(u&0xff); u >>>= 8;
- x[3+xoff] = (byte)(u&0xff); u >>>= 8;
- x[2+xoff] = (byte)(u&0xff); u >>>= 8;
- x[1+xoff] = (byte)(u&0xff); u >>>= 8;
- x[0+xoff] = (byte)(u&0xff); ///u >>>= 8;
- }
-
- private static int vn(
- byte [] x, final int xoff,
- byte [] y, final int yoff,
- int n)
- {
- int i,d = 0;
- for (i = 0; i < n; i ++) d |= (x[i+xoff]^y[i+yoff]) & 0xff;
- return (1 & ((d - 1) >>> 8)) - 1;
- }
-
- private static int crypto_verify_16(
- byte [] x, final int xoff,
- byte [] y, final int yoff)
- {
- return vn(x,xoff,y,yoff,16);
- }
- public static int crypto_verify_16(byte [] x, byte [] y)
- {
- return crypto_verify_16(x,0, y,0);
- }
-
- private static int crypto_verify_32(
- byte [] x, final int xoff,
- byte [] y, final int yoff)
- {
- return vn(x,xoff,y,yoff,32);
- }
- public static int crypto_verify_32(byte [] x, byte [] y)
- {
- return crypto_verify_32(x,0, y,0);
- }
-
- private static void core_salsa20(byte [] o, byte [] p, byte [] k, byte [] c) {
- int j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24,
- j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24,
- j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24,
- j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24,
- j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24,
- j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24,
- j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24,
- j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24,
- j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24,
- j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24,
- j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24,
- j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24,
- j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24,
- j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24,
- j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24,
- j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24;
-
- int x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,
- x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,
- x15 = j15, u;
-
- for (int i = 0; i < 20; i += 2) {
- u = x0 + x12 | 0;
- x4 ^= u<<7 | u>>>(32-7);
- u = x4 + x0 | 0;
- x8 ^= u<<9 | u>>>(32-9);
- u = x8 + x4 | 0;
- x12 ^= u<<13 | u>>>(32-13);
- u = x12 + x8 | 0;
- x0 ^= u<<18 | u>>>(32-18);
-
- u = x5 + x1 | 0;
- x9 ^= u<<7 | u>>>(32-7);
- u = x9 + x5 | 0;
- x13 ^= u<<9 | u>>>(32-9);
- u = x13 + x9 | 0;
- x1 ^= u<<13 | u>>>(32-13);
- u = x1 + x13 | 0;
- x5 ^= u<<18 | u>>>(32-18);
-
- u = x10 + x6 | 0;
- x14 ^= u<<7 | u>>>(32-7);
- u = x14 + x10 | 0;
- x2 ^= u<<9 | u>>>(32-9);
- u = x2 + x14 | 0;
- x6 ^= u<<13 | u>>>(32-13);
- u = x6 + x2 | 0;
- x10 ^= u<<18 | u>>>(32-18);
-
- u = x15 + x11 | 0;
- x3 ^= u<<7 | u>>>(32-7);
- u = x3 + x15 | 0;
- x7 ^= u<<9 | u>>>(32-9);
- u = x7 + x3 | 0;
- x11 ^= u<<13 | u>>>(32-13);
- u = x11 + x7 | 0;
- x15 ^= u<<18 | u>>>(32-18);
-
- u = x0 + x3 | 0;
- x1 ^= u<<7 | u>>>(32-7);
- u = x1 + x0 | 0;
- x2 ^= u<<9 | u>>>(32-9);
- u = x2 + x1 | 0;
- x3 ^= u<<13 | u>>>(32-13);
- u = x3 + x2 | 0;
- x0 ^= u<<18 | u>>>(32-18);
-
- u = x5 + x4 | 0;
- x6 ^= u<<7 | u>>>(32-7);
- u = x6 + x5 | 0;
- x7 ^= u<<9 | u>>>(32-9);
- u = x7 + x6 | 0;
- x4 ^= u<<13 | u>>>(32-13);
- u = x4 + x7 | 0;
- x5 ^= u<<18 | u>>>(32-18);
-
- u = x10 + x9 | 0;
- x11 ^= u<<7 | u>>>(32-7);
- u = x11 + x10 | 0;
- x8 ^= u<<9 | u>>>(32-9);
- u = x8 + x11 | 0;
- x9 ^= u<<13 | u>>>(32-13);
- u = x9 + x8 | 0;
- x10 ^= u<<18 | u>>>(32-18);
-
- u = x15 + x14 | 0;
- x12 ^= u<<7 | u>>>(32-7);
- u = x12 + x15 | 0;
- x13 ^= u<<9 | u>>>(32-9);
- u = x13 + x12 | 0;
- x14 ^= u<<13 | u>>>(32-13);
- u = x14 + x13 | 0;
- x15 ^= u<<18 | u>>>(32-18);
- }
- x0 = x0 + j0 | 0;
- x1 = x1 + j1 | 0;
- x2 = x2 + j2 | 0;
- x3 = x3 + j3 | 0;
- x4 = x4 + j4 | 0;
- x5 = x5 + j5 | 0;
- x6 = x6 + j6 | 0;
- x7 = x7 + j7 | 0;
- x8 = x8 + j8 | 0;
- x9 = x9 + j9 | 0;
- x10 = x10 + j10 | 0;
- x11 = x11 + j11 | 0;
- x12 = x12 + j12 | 0;
- x13 = x13 + j13 | 0;
- x14 = x14 + j14 | 0;
- x15 = x15 + j15 | 0;
-
- o[ 0] = (byte) (x0 >>> 0 & 0xff);
- o[ 1] = (byte) (x0 >>> 8 & 0xff);
- o[ 2] = (byte) (x0 >>> 16 & 0xff);
- o[ 3] = (byte) (x0 >>> 24 & 0xff);
-
- o[ 4] = (byte) (x1 >>> 0 & 0xff);
- o[ 5] = (byte) (x1 >>> 8 & 0xff);
- o[ 6] = (byte) (x1 >>> 16 & 0xff);
- o[ 7] = (byte) (x1 >>> 24 & 0xff);
-
- o[ 8] = (byte) (x2 >>> 0 & 0xff);
- o[ 9] = (byte) (x2 >>> 8 & 0xff);
- o[10] = (byte) (x2 >>> 16 & 0xff);
- o[11] = (byte) (x2 >>> 24 & 0xff);
-
- o[12] = (byte) (x3 >>> 0 & 0xff);
- o[13] = (byte) (x3 >>> 8 & 0xff);
- o[14] = (byte) (x3 >>> 16 & 0xff);
- o[15] = (byte) (x3 >>> 24 & 0xff);
-
- o[16] = (byte) (x4 >>> 0 & 0xff);
- o[17] = (byte) (x4 >>> 8 & 0xff);
- o[18] = (byte) (x4 >>> 16 & 0xff);
- o[19] = (byte) (x4 >>> 24 & 0xff);
-
- o[20] = (byte) (x5 >>> 0 & 0xff);
- o[21] = (byte) (x5 >>> 8 & 0xff);
- o[22] = (byte) (x5 >>> 16 & 0xff);
- o[23] = (byte) (x5 >>> 24 & 0xff);
-
- o[24] = (byte) (x6 >>> 0 & 0xff);
- o[25] = (byte) (x6 >>> 8 & 0xff);
- o[26] = (byte) (x6 >>> 16 & 0xff);
- o[27] = (byte) (x6 >>> 24 & 0xff);
-
- o[28] = (byte) (x7 >>> 0 & 0xff);
- o[29] = (byte) (x7 >>> 8 & 0xff);
- o[30] = (byte) (x7 >>> 16 & 0xff);
- o[31] = (byte) (x7 >>> 24 & 0xff);
-
- o[32] = (byte) (x8 >>> 0 & 0xff);
- o[33] = (byte) (x8 >>> 8 & 0xff);
- o[34] = (byte) (x8 >>> 16 & 0xff);
- o[35] = (byte) (x8 >>> 24 & 0xff);
-
- o[36] = (byte) (x9 >>> 0 & 0xff);
- o[37] = (byte) (x9 >>> 8 & 0xff);
- o[38] = (byte) (x9 >>> 16 & 0xff);
- o[39] = (byte) (x9 >>> 24 & 0xff);
-
- o[40] = (byte) (x10 >>> 0 & 0xff);
- o[41] = (byte) (x10 >>> 8 & 0xff);
- o[42] = (byte) (x10 >>> 16 & 0xff);
- o[43] = (byte) (x10 >>> 24 & 0xff);
-
- o[44] = (byte) (x11 >>> 0 & 0xff);
- o[45] = (byte) (x11 >>> 8 & 0xff);
- o[46] = (byte) (x11 >>> 16 & 0xff);
- o[47] = (byte) (x11 >>> 24 & 0xff);
-
- o[48] = (byte) (x12 >>> 0 & 0xff);
- o[49] = (byte) (x12 >>> 8 & 0xff);
- o[50] = (byte) (x12 >>> 16 & 0xff);
- o[51] = (byte) (x12 >>> 24 & 0xff);
-
- o[52] = (byte) (x13 >>> 0 & 0xff);
- o[53] = (byte) (x13 >>> 8 & 0xff);
- o[54] = (byte) (x13 >>> 16 & 0xff);
- o[55] = (byte) (x13 >>> 24 & 0xff);
-
- o[56] = (byte) (x14 >>> 0 & 0xff);
- o[57] = (byte) (x14 >>> 8 & 0xff);
- o[58] = (byte) (x14 >>> 16 & 0xff);
- o[59] = (byte) (x14 >>> 24 & 0xff);
-
- o[60] = (byte) (x15 >>> 0 & 0xff);
- o[61] = (byte) (x15 >>> 8 & 0xff);
- o[62] = (byte) (x15 >>> 16 & 0xff);
- o[63] = (byte) (x15 >>> 24 & 0xff);
-
- /*String dbgt = "";
- for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg];
- Log.d(TAG, "core_salsa20 -> "+dbgt);
-*/
- }
-
- private static void core_hsalsa20(byte [] o, byte [] p, byte [] k, byte [] c) {
- int j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24,
- j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24,
- j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24,
- j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24,
- j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24,
- j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24,
- j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24,
- j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24,
- j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24,
- j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24,
- j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24,
- j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24,
- j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24,
- j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24,
- j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24,
- j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24;
-
- int x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,
- x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,
- x15 = j15, u;
-
- for (int i = 0; i < 20; i += 2) {
- u = x0 + x12 | 0;
- x4 ^= u<<7 | u>>>(32-7);
- u = x4 + x0 | 0;
- x8 ^= u<<9 | u>>>(32-9);
- u = x8 + x4 | 0;
- x12 ^= u<<13 | u>>>(32-13);
- u = x12 + x8 | 0;
- x0 ^= u<<18 | u>>>(32-18);
-
- u = x5 + x1 | 0;
- x9 ^= u<<7 | u>>>(32-7);
- u = x9 + x5 | 0;
- x13 ^= u<<9 | u>>>(32-9);
- u = x13 + x9 | 0;
- x1 ^= u<<13 | u>>>(32-13);
- u = x1 + x13 | 0;
- x5 ^= u<<18 | u>>>(32-18);
-
- u = x10 + x6 | 0;
- x14 ^= u<<7 | u>>>(32-7);
- u = x14 + x10 | 0;
- x2 ^= u<<9 | u>>>(32-9);
- u = x2 + x14 | 0;
- x6 ^= u<<13 | u>>>(32-13);
- u = x6 + x2 | 0;
- x10 ^= u<<18 | u>>>(32-18);
-
- u = x15 + x11 | 0;
- x3 ^= u<<7 | u>>>(32-7);
- u = x3 + x15 | 0;
- x7 ^= u<<9 | u>>>(32-9);
- u = x7 + x3 | 0;
- x11 ^= u<<13 | u>>>(32-13);
- u = x11 + x7 | 0;
- x15 ^= u<<18 | u>>>(32-18);
-
- u = x0 + x3 | 0;
- x1 ^= u<<7 | u>>>(32-7);
- u = x1 + x0 | 0;
- x2 ^= u<<9 | u>>>(32-9);
- u = x2 + x1 | 0;
- x3 ^= u<<13 | u>>>(32-13);
- u = x3 + x2 | 0;
- x0 ^= u<<18 | u>>>(32-18);
-
- u = x5 + x4 | 0;
- x6 ^= u<<7 | u>>>(32-7);
- u = x6 + x5 | 0;
- x7 ^= u<<9 | u>>>(32-9);
- u = x7 + x6 | 0;
- x4 ^= u<<13 | u>>>(32-13);
- u = x4 + x7 | 0;
- x5 ^= u<<18 | u>>>(32-18);
-
- u = x10 + x9 | 0;
- x11 ^= u<<7 | u>>>(32-7);
- u = x11 + x10 | 0;
- x8 ^= u<<9 | u>>>(32-9);
- u = x8 + x11 | 0;
- x9 ^= u<<13 | u>>>(32-13);
- u = x9 + x8 | 0;
- x10 ^= u<<18 | u>>>(32-18);
-
- u = x15 + x14 | 0;
- x12 ^= u<<7 | u>>>(32-7);
- u = x12 + x15 | 0;
- x13 ^= u<<9 | u>>>(32-9);
- u = x13 + x12 | 0;
- x14 ^= u<<13 | u>>>(32-13);
- u = x14 + x13 | 0;
- x15 ^= u<<18 | u>>>(32-18);
- }
-
- o[ 0] = (byte) (x0 >>> 0 & 0xff);
- o[ 1] = (byte) (x0 >>> 8 & 0xff);
- o[ 2] = (byte) (x0 >>> 16 & 0xff);
- o[ 3] = (byte) (x0 >>> 24 & 0xff);
-
- o[ 4] = (byte) (x5 >>> 0 & 0xff);
- o[ 5] = (byte) (x5 >>> 8 & 0xff);
- o[ 6] = (byte) (x5 >>> 16 & 0xff);
- o[ 7] = (byte) (x5 >>> 24 & 0xff);
-
- o[ 8] = (byte) (x10 >>> 0 & 0xff);
- o[ 9] = (byte) (x10 >>> 8 & 0xff);
- o[10] = (byte) (x10 >>> 16 & 0xff);
- o[11] = (byte) (x10 >>> 24 & 0xff);
-
- o[12] = (byte) (x15 >>> 0 & 0xff);
- o[13] = (byte) (x15 >>> 8 & 0xff);
- o[14] = (byte) (x15 >>> 16 & 0xff);
- o[15] = (byte) (x15 >>> 24 & 0xff);
-
- o[16] = (byte) (x6 >>> 0 & 0xff);
- o[17] = (byte) (x6 >>> 8 & 0xff);
- o[18] = (byte) (x6 >>> 16 & 0xff);
- o[19] = (byte) (x6 >>> 24 & 0xff);
-
- o[20] = (byte) (x7 >>> 0 & 0xff);
- o[21] = (byte) (x7 >>> 8 & 0xff);
- o[22] = (byte) (x7 >>> 16 & 0xff);
- o[23] = (byte) (x7 >>> 24 & 0xff);
-
- o[24] = (byte) (x8 >>> 0 & 0xff);
- o[25] = (byte) (x8 >>> 8 & 0xff);
- o[26] = (byte) (x8 >>> 16 & 0xff);
- o[27] = (byte) (x8 >>> 24 & 0xff);
-
- o[28] = (byte) (x9 >>> 0 & 0xff);
- o[29] = (byte) (x9 >>> 8 & 0xff);
- o[30] = (byte) (x9 >>> 16 & 0xff);
- o[31] = (byte) (x9 >>> 24 & 0xff);
-
-
- /*String dbgt = "";
- for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg];
- Log.d(TAG, "core_hsalsa20 -> "+dbgt);
-*/
- }
-
- public static int crypto_core_salsa20(byte [] out, byte [] in, byte [] k, byte [] c)
- {
- ///api(out,in,k,c,0);
- core_salsa20(out,in,k,c);
-
- ///String dbgt = "";
- ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg];
- ///L/og.d(TAG, "crypto_core_salsa20 -> "+dbgt);
-
- return 0;
- }
-
- public static int crypto_core_hsalsa20(byte [] out, byte [] in, byte [] k, byte [] c)
- {
- ///api(out,in,k,c,1);
- core_hsalsa20(out,in,k,c);
-
- ///String dbgt = "";
- ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg];
- ///L/og.d(TAG, "crypto_core_hsalsa20 -> "+dbgt);
-
- return 0;
- }
-
- // "expand 32-byte k"
- private static final byte[] sigma = {101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107};
-
- /*static {
- try {
- sigma = "expand 32-byte k".getBytes("utf-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }*/
-
- private static int crypto_stream_salsa20_xor(byte [] c,int cpos, byte [] m,int mpos, long b, byte [] n, byte [] k)
- {
- byte [] z = new byte[16], x = new byte[64];
- int u, i;
- for (i = 0; i < 16; i++) z[i] = 0;
- for (i = 0; i < 8; i++) z[i] = n[i];
- while (b >= 64) {
- crypto_core_salsa20(x,z,k,sigma);
- for (i = 0; i < 64; i++) c[cpos+i] = (byte) ((m[mpos+i] ^ x[i]) & 0xff);
- u = 1;
- for (i = 8; i < 16; i++) {
- u = u + (z[i] & 0xff) | 0;
- z[i] = (byte) (u & 0xff);
- u >>>= 8;
- }
- b -= 64;
- cpos += 64;
- mpos += 64;
- }
- if (b > 0) {
- crypto_core_salsa20(x,z,k,sigma);
- for (i = 0; i < b; i++) c[cpos+i] = (byte) ((m[mpos+i] ^ x[i]) & 0xff);
- }
-
- ///String dbgt = "";
- ///for (int dbg = 0; dbg < c.length-cpos; dbg ++) dbgt += " "+c[dbg +cpos];
- ///Log.d(TAG, "crypto_stream_salsa20_xor, c -> "+dbgt);
-
- return 0;
- }
-
- public static int crypto_stream_salsa20(byte [] c,int cpos, long b, byte [] n, byte [] k) {
- byte [] z = new byte[16], x = new byte[64];
- int u, i;
- for (i = 0; i < 16; i++) z[i] = 0;
- for (i = 0; i < 8; i++) z[i] = n[i];
- while (b >= 64) {
- crypto_core_salsa20(x,z,k,sigma);
- for (i = 0; i < 64; i++) c[cpos+i] = x[i];
- u = 1;
- for (i = 8; i < 16; i++) {
- u = u + (z[i] & 0xff) | 0;
- z[i] = (byte) (u & 0xff);
- u >>>= 8;
- }
- b -= 64;
- cpos += 64;
- }
- if (b > 0) {
- crypto_core_salsa20(x,z,k,sigma);
- for (i = 0; i < b; i++) c[cpos+i] = x[i];
- }
-
- ///String dbgt = "";
- ///for (int dbg = 0; dbg < c.length-cpos; dbg ++) dbgt += " "+c[dbg +cpos];
- ///Log.d(TAG, "crypto_stream_salsa20, c -> "+dbgt);
-
- return 0;
- }
-
- public static int crypto_stream(byte [] c,int cpos, long d, byte [] n, byte [] k) {
- byte [] s = new byte[32];
- crypto_core_hsalsa20(s,n,k,sigma);
- byte [] sn = new byte[8];
- for (int i = 0; i < 8; i++) sn[i] = n[i+16];
- return crypto_stream_salsa20(c,cpos,d,sn,s);
- }
-
- public static int crypto_stream_xor(byte [] c,int cpos, byte [] m,int mpos, long d, byte [] n, byte [] k) {
- byte [] s = new byte[32];
-
- /*String dbgt = "";
- for (int dbg = 0; dbg < n.length; dbg ++) dbgt += " "+n[dbg];
- Log.d(TAG, "crypto_stream_xor, nonce -> "+dbgt);
-
- dbgt = "";
- for (int dbg = 0; dbg < k.length; dbg ++) dbgt += " "+k[dbg];
- Log.d(TAG, "crypto_stream_xor, shk -> "+dbgt);
- */
-
- crypto_core_hsalsa20(s,n,k,sigma);
- byte [] sn = new byte[8];
- for (int i = 0; i < 8; i++) sn[i] = n[i+16];
- return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s);
- }
-
- /*
- * Port of Andrew Moon's Poly1305-donna-16. Public domain.
- * https://github.com/floodyberry/poly1305-donna
- */
- public static final class poly1305 {
-
- private byte[] buffer;
- private int[] r;
- private int[] h;
- private int[] pad;
- private int leftover;
- private int fin;
-
- public poly1305(byte [] key) {
- this.buffer = new byte[16];
- this.r = new int[10];
- this.h = new int[10];
- this.pad = new int[8];
- this.leftover = 0;
- this.fin = 0;
-
- int t0, t1, t2, t3, t4, t5, t6, t7;
-
- t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff;
- t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
- t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03;
- t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
- t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff;
- this.r[5] = ((t4 >>> 1)) & 0x1ffe;
- t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
- t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81;
- t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
- this.r[9] = ((t7 >>> 5)) & 0x007f;
-
- this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8;
- this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8;
- this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8;
- this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8;
- this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8;
- this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8;
- this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8;
- this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8;
- }
-
- public poly1305 blocks(byte [] m, int mpos, int bytes) {
- int hibit = this.fin!=0 ? 0 : (1 << 11);
- int t0, t1, t2, t3, t4, t5, t6, t7, c;
- int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9;
-
- int h0 = this.h[0],
- h1 = this.h[1],
- h2 = this.h[2],
- h3 = this.h[3],
- h4 = this.h[4],
- h5 = this.h[5],
- h6 = this.h[6],
- h7 = this.h[7],
- h8 = this.h[8],
- h9 = this.h[9];
-
- int r0 = this.r[0],
- r1 = this.r[1],
- r2 = this.r[2],
- r3 = this.r[3],
- r4 = this.r[4],
- r5 = this.r[5],
- r6 = this.r[6],
- r7 = this.r[7],
- r8 = this.r[8],
- r9 = this.r[9];
-
- while (bytes >= 16) {
- t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff;
- t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
- t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff;
- t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
- t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff;
- h5 += ((t4 >>> 1)) & 0x1fff;
- t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
- t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff;
- t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
- h9 += ((t7 >>> 5)) | hibit;
-
- c = 0;
-
- d0 = c;
- d0 += h0 * r0;
- d0 += h1 * (5 * r9);
- d0 += h2 * (5 * r8);
- d0 += h3 * (5 * r7);
- d0 += h4 * (5 * r6);
- c = (d0 >>> 13); d0 &= 0x1fff;
- d0 += h5 * (5 * r5);
- d0 += h6 * (5 * r4);
- d0 += h7 * (5 * r3);
- d0 += h8 * (5 * r2);
- d0 += h9 * (5 * r1);
- c += (d0 >>> 13); d0 &= 0x1fff;
-
- d1 = c;
- d1 += h0 * r1;
- d1 += h1 * r0;
- d1 += h2 * (5 * r9);
- d1 += h3 * (5 * r8);
- d1 += h4 * (5 * r7);
- c = (d1 >>> 13); d1 &= 0x1fff;
- d1 += h5 * (5 * r6);
- d1 += h6 * (5 * r5);
- d1 += h7 * (5 * r4);
- d1 += h8 * (5 * r3);
- d1 += h9 * (5 * r2);
- c += (d1 >>> 13); d1 &= 0x1fff;
-
- d2 = c;
- d2 += h0 * r2;
- d2 += h1 * r1;
- d2 += h2 * r0;
- d2 += h3 * (5 * r9);
- d2 += h4 * (5 * r8);
- c = (d2 >>> 13); d2 &= 0x1fff;
- d2 += h5 * (5 * r7);
- d2 += h6 * (5 * r6);
- d2 += h7 * (5 * r5);
- d2 += h8 * (5 * r4);
- d2 += h9 * (5 * r3);
- c += (d2 >>> 13); d2 &= 0x1fff;
-
- d3 = c;
- d3 += h0 * r3;
- d3 += h1 * r2;
- d3 += h2 * r1;
- d3 += h3 * r0;
- d3 += h4 * (5 * r9);
- c = (d3 >>> 13); d3 &= 0x1fff;
- d3 += h5 * (5 * r8);
- d3 += h6 * (5 * r7);
- d3 += h7 * (5 * r6);
- d3 += h8 * (5 * r5);
- d3 += h9 * (5 * r4);
- c += (d3 >>> 13); d3 &= 0x1fff;
-
- d4 = c;
- d4 += h0 * r4;
- d4 += h1 * r3;
- d4 += h2 * r2;
- d4 += h3 * r1;
- d4 += h4 * r0;
- c = (d4 >>> 13); d4 &= 0x1fff;
- d4 += h5 * (5 * r9);
- d4 += h6 * (5 * r8);
- d4 += h7 * (5 * r7);
- d4 += h8 * (5 * r6);
- d4 += h9 * (5 * r5);
- c += (d4 >>> 13); d4 &= 0x1fff;
-
- d5 = c;
- d5 += h0 * r5;
- d5 += h1 * r4;
- d5 += h2 * r3;
- d5 += h3 * r2;
- d5 += h4 * r1;
- c = (d5 >>> 13); d5 &= 0x1fff;
- d5 += h5 * r0;
- d5 += h6 * (5 * r9);
- d5 += h7 * (5 * r8);
- d5 += h8 * (5 * r7);
- d5 += h9 * (5 * r6);
- c += (d5 >>> 13); d5 &= 0x1fff;
-
- d6 = c;
- d6 += h0 * r6;
- d6 += h1 * r5;
- d6 += h2 * r4;
- d6 += h3 * r3;
- d6 += h4 * r2;
- c = (d6 >>> 13); d6 &= 0x1fff;
- d6 += h5 * r1;
- d6 += h6 * r0;
- d6 += h7 * (5 * r9);
- d6 += h8 * (5 * r8);
- d6 += h9 * (5 * r7);
- c += (d6 >>> 13); d6 &= 0x1fff;
-
- d7 = c;
- d7 += h0 * r7;
- d7 += h1 * r6;
- d7 += h2 * r5;
- d7 += h3 * r4;
- d7 += h4 * r3;
- c = (d7 >>> 13); d7 &= 0x1fff;
- d7 += h5 * r2;
- d7 += h6 * r1;
- d7 += h7 * r0;
- d7 += h8 * (5 * r9);
- d7 += h9 * (5 * r8);
- c += (d7 >>> 13); d7 &= 0x1fff;
-
- d8 = c;
- d8 += h0 * r8;
- d8 += h1 * r7;
- d8 += h2 * r6;
- d8 += h3 * r5;
- d8 += h4 * r4;
- c = (d8 >>> 13); d8 &= 0x1fff;
- d8 += h5 * r3;
- d8 += h6 * r2;
- d8 += h7 * r1;
- d8 += h8 * r0;
- d8 += h9 * (5 * r9);
- c += (d8 >>> 13); d8 &= 0x1fff;
-
- d9 = c;
- d9 += h0 * r9;
- d9 += h1 * r8;
- d9 += h2 * r7;
- d9 += h3 * r6;
- d9 += h4 * r5;
- c = (d9 >>> 13); d9 &= 0x1fff;
- d9 += h5 * r4;
- d9 += h6 * r3;
- d9 += h7 * r2;
- d9 += h8 * r1;
- d9 += h9 * r0;
- c += (d9 >>> 13); d9 &= 0x1fff;
-
- c = (((c << 2) + c)) | 0;
- c = (c + d0) | 0;
- d0 = c & 0x1fff;
- c = (c >>> 13);
- d1 += c;
-
- h0 = d0;
- h1 = d1;
- h2 = d2;
- h3 = d3;
- h4 = d4;
- h5 = d5;
- h6 = d6;
- h7 = d7;
- h8 = d8;
- h9 = d9;
-
- mpos += 16;
- bytes -= 16;
- }
- this.h[0] = h0;
- this.h[1] = h1;
- this.h[2] = h2;
- this.h[3] = h3;
- this.h[4] = h4;
- this.h[5] = h5;
- this.h[6] = h6;
- this.h[7] = h7;
- this.h[8] = h8;
- this.h[9] = h9;
-
- return this;
- }
-
- public poly1305 finish(byte [] mac, int macpos) {
- int [] g = new int[10];
- int c, mask, f, i;
-
- if (this.leftover != 0) {
- i = this.leftover;
- this.buffer[i++] = 1;
- for (; i < 16; i++) this.buffer[i] = 0;
- this.fin = 1;
- this.blocks(this.buffer, 0, 16);
- }
-
- c = this.h[1] >>> 13;
- this.h[1] &= 0x1fff;
- for (i = 2; i < 10; i++) {
- this.h[i] += c;
- c = this.h[i] >>> 13;
- this.h[i] &= 0x1fff;
- }
- this.h[0] += (c * 5);
- c = this.h[0] >>> 13;
- this.h[0] &= 0x1fff;
- this.h[1] += c;
- c = this.h[1] >>> 13;
- this.h[1] &= 0x1fff;
- this.h[2] += c;
-
- g[0] = this.h[0] + 5;
- c = g[0] >>> 13;
- g[0] &= 0x1fff;
- for (i = 1; i < 10; i++) {
- g[i] = this.h[i] + c;
- c = g[i] >>> 13;
- g[i] &= 0x1fff;
- }
- g[9] -= (1 << 13); g[9] &= 0xffff;
-
- mask = (g[9] >>> ((2 * 8) - 1)) - 1; mask &= 0xffff;
- for (i = 0; i < 10; i++) g[i] &= mask;
- mask = ~mask;
- for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i];
-
- this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff;
- this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff;
- this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff;
- this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff;
- this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff;
- this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff;
- this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff;
- this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff;
-
- f = this.h[0] + this.pad[0];
- this.h[0] = f & 0xffff;
- for (i = 1; i < 8; i++) {
- f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0;
- this.h[i] = f & 0xffff;
- }
-
- mac[macpos+ 0] = (byte) ((this.h[0] >>> 0) & 0xff);
- mac[macpos+ 1] = (byte) ((this.h[0] >>> 8) & 0xff);
- mac[macpos+ 2] = (byte) ((this.h[1] >>> 0) & 0xff);
- mac[macpos+ 3] = (byte) ((this.h[1] >>> 8) & 0xff);
- mac[macpos+ 4] = (byte) ((this.h[2] >>> 0) & 0xff);
- mac[macpos+ 5] = (byte) ((this.h[2] >>> 8) & 0xff);
- mac[macpos+ 6] = (byte) ((this.h[3] >>> 0) & 0xff);
- mac[macpos+ 7] = (byte) ((this.h[3] >>> 8) & 0xff);
- mac[macpos+ 8] = (byte) ((this.h[4] >>> 0) & 0xff);
- mac[macpos+ 9] = (byte) ((this.h[4] >>> 8) & 0xff);
- mac[macpos+10] = (byte) ((this.h[5] >>> 0) & 0xff);
- mac[macpos+11] = (byte) ((this.h[5] >>> 8) & 0xff);
- mac[macpos+12] = (byte) ((this.h[6] >>> 0) & 0xff);
- mac[macpos+13] = (byte) ((this.h[6] >>> 8) & 0xff);
- mac[macpos+14] = (byte) ((this.h[7] >>> 0) & 0xff);
- mac[macpos+15] = (byte) ((this.h[7] >>> 8) & 0xff);
-
- return this;
- }
-
- public poly1305 update(byte [] m, int mpos, int bytes) {
- int i, want;
-
- if (this.leftover != 0) {
- want = (16 - this.leftover);
- if (want > bytes)
- want = bytes;
- for (i = 0; i < want; i++)
- this.buffer[this.leftover + i] = m[mpos+i];
- bytes -= want;
- mpos += want;
- this.leftover += want;
- if (this.leftover < 16)
- return this;
- this.blocks(buffer, 0, 16);
- this.leftover = 0;
- }
-
- if (bytes >= 16) {
- want = bytes - (bytes % 16);
- this.blocks(m, mpos, want);
- mpos += want;
- bytes -= want;
- }
-
- if (bytes != 0) {
- for (i = 0; i < bytes; i++)
- this.buffer[this.leftover + i] = m[mpos+i];
- this.leftover += bytes;
- }
-
- return this;
- }
-
- }
-
- private static int crypto_onetimeauth(
- byte[] out,final int outpos,
- byte[] m,final int mpos,
- int n,
- byte [] k)
- {
- poly1305 s = new poly1305(k);
- s.update(m, mpos, n);
- s.finish(out, outpos);
-
- /*String dbgt = "";
- for (int dbg = 0; dbg < out.length-outpos; dbg ++) dbgt += " "+out[dbg+outpos];
- Log.d(TAG, "crypto_onetimeauth -> "+dbgt);
- */
-
- return 0;
- }
- public static int crypto_onetimeauth(byte [] out, byte [] m, int /*long*/ n , byte [] k) {
- return crypto_onetimeauth(out,0, m,0, n, k);
- }
-
- private static int crypto_onetimeauth_verify(
- byte[] h,final int hoff,
- byte[] m,final int moff,
- int /*long*/ n,
- byte [] k)
- {
- byte [] x = new byte[16];
- crypto_onetimeauth(x,0,m,moff,n,k);
- return crypto_verify_16(h,hoff,x,0);
- }
- public static int crypto_onetimeauth_verify(byte [] h, byte [] m, int /*long*/ n, byte [] k) {
- return crypto_onetimeauth_verify(h,0, m,0, n, k);
- }
- public static int crypto_onetimeauth_verify(byte [] h, byte [] m, byte [] k) {
- return crypto_onetimeauth_verify(h, m, m!=null? m.length:0, k);
- }
-
- public static int crypto_secretbox(byte [] c, byte [] m, int /*long*/ d, byte [] n, byte [] k)
- {
- int i;
- if (d < 32) return -1;
- crypto_stream_xor(c,0,m,0,d,n,k);
- crypto_onetimeauth(c,16, c,32, d-32, c);
- ///for (i = 0; i < 16; i++) c[i] = 0;
- return 0;
- }
-
- public static int crypto_secretbox_open(byte []m,byte []c,int /*long*/ d,byte []n,byte []k)
- {
- int i;
- byte[] x = new byte[32];
- if (d < 32) return -1;
- crypto_stream(x,0,32,n,k);
- if (crypto_onetimeauth_verify(c,16, c,32, d-32, x) != 0) return -1;
- crypto_stream_xor(m,0,c,0,d,n,k);
- ///for (i = 0; i < 32; i++) m[i] = 0;
- return 0;
- }
-
- private static void set25519(long [] r, long [] a)
- {
- int i;
- for (i = 0; i < 16; i ++) r[i]=a[i];
- }
-
- private static void car25519(long [] o)
- {
- int i;
- long v, c = 1;
- for (i = 0; i < 16; i++) {
- v = o[i] + c + 65535;
- c = v>>16;
- o[i] = v - c * 65536;
- }
- o[0] += c-1 + 37 * (c-1);
- }
-
- private static void sel25519(
- long[] p,
- long[] q,
- int b)
- {
- sel25519(p,0, q,0, b);
- }
- private static void sel25519(
- long[] p,final int poff,
- long[] q,final int qoff,
- int b)
- {
- long t, c = ~(b-1);
- for (int i = 0; i < 16; i++) {
- t = c & (p[i+poff] ^ q[i+qoff]);
- p[i+poff] ^= t;
- q[i+qoff] ^= t;
- }
- }
-
- private static void pack25519(byte [] o, long [] n,final int noff)
- {
- int i, j, b;
- long [] m = new long[16], t = new long[16];
- for (i = 0; i < 16; i++) t[i] = n[i+noff];
- car25519(t);
- car25519(t);
- car25519(t);
- for (j = 0; j < 2; j++) {
- m[0] = t[0] - 0xffed;
- for (i = 1; i < 15; i++) {
- m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1);
- m[i-1] &= 0xffff;
- }
- m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1);
- b = (int) ((m[15]>>16) & 1);
- m[14] &= 0xffff;
- sel25519(t,0, m,0, 1-b);
- }
- for (i = 0; i < 16; i++) {
- o[2*i] = (byte) (t[i] & 0xff);
- o[2*i+1] = (byte) (t[i]>>8);
- }
- }
-
- private static int neq25519(long [] a, long [] b) {
- return neq25519(a,0, b,0);
- }
- private static int neq25519(long [] a,final int aoff, long [] b,final int boff)
- {
- byte [] c = new byte[32], d = new byte[32];
- pack25519(c, a,aoff);
- pack25519(d, b,boff);
- return crypto_verify_32(c, 0, d, 0);
- }
-
- private static byte par25519(long [] a)
- {
- return par25519(a,0);
- }
- private static byte par25519(long [] a,final int aoff)
- {
- byte [] d = new byte[32];
- pack25519(d, a,aoff);
- return (byte) (d[0] & 1);
- }
-
- private static void unpack25519(long [] o, byte [] n)
- {
- int i;
- for (i = 0; i < 16; i ++) o[i]=(n[2*i]&0xff)+((long)((n[2*i+1]<<8)&0xffff));
- o[15] &= 0x7fff;
- }
-
- private static void A(
- long [] o,
- long [] a,
- long [] b)
- {
- A(o,0, a,0, b,0);
- }
- private static void A(
- long [] o,final int ooff,
- long [] a,final int aoff,
- long [] b,final int boff)
- {
- int i;
- for (i = 0; i < 16; i ++) o[i+ooff] = a[i+aoff] + b[i+boff];
- }
-
- private static void Z(
- long [] o,
- long [] a,
- long [] b)
- {
- Z(o,0, a,0, b,0);
- }
- private static void Z(
- long [] o,final int ooff,
- long [] a,final int aoff,
- long [] b,final int boff)
- {
- int i;
- for (i = 0; i < 16; i ++) o[i+ooff] = a[i+aoff] - b[i+boff];
- }
-
- private static void M(
- long [] o,
- long [] a,
- long [] b)
- {
- M(o,0, a,0, b,0);
- }
- private static void M(
- long [] o,final int ooff,
- long [] a,final int aoff,
- long [] b,final int boff)
- {
- long v, c,
- t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,
- t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0,
- t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0,
- t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0,
- b0 = b[0 +boff],
- b1 = b[1 +boff],
- b2 = b[2 +boff],
- b3 = b[3 +boff],
- b4 = b[4 +boff],
- b5 = b[5 +boff],
- b6 = b[6 +boff],
- b7 = b[7 +boff],
- b8 = b[8 +boff],
- b9 = b[9 +boff],
- b10 = b[10 +boff],
- b11 = b[11 +boff],
- b12 = b[12 +boff],
- b13 = b[13 +boff],
- b14 = b[14 +boff],
- b15 = b[15 +boff];
-
- v = a[0 +aoff];
- t0 += v * b0;
- t1 += v * b1;
- t2 += v * b2;
- t3 += v * b3;
- t4 += v * b4;
- t5 += v * b5;
- t6 += v * b6;
- t7 += v * b7;
- t8 += v * b8;
- t9 += v * b9;
- t10 += v * b10;
- t11 += v * b11;
- t12 += v * b12;
- t13 += v * b13;
- t14 += v * b14;
- t15 += v * b15;
- v = a[1 +aoff];
- t1 += v * b0;
- t2 += v * b1;
- t3 += v * b2;
- t4 += v * b3;
- t5 += v * b4;
- t6 += v * b5;
- t7 += v * b6;
- t8 += v * b7;
- t9 += v * b8;
- t10 += v * b9;
- t11 += v * b10;
- t12 += v * b11;
- t13 += v * b12;
- t14 += v * b13;
- t15 += v * b14;
- t16 += v * b15;
- v = a[2 +aoff];
- t2 += v * b0;
- t3 += v * b1;
- t4 += v * b2;
- t5 += v * b3;
- t6 += v * b4;
- t7 += v * b5;
- t8 += v * b6;
- t9 += v * b7;
- t10 += v * b8;
- t11 += v * b9;
- t12 += v * b10;
- t13 += v * b11;
- t14 += v * b12;
- t15 += v * b13;
- t16 += v * b14;
- t17 += v * b15;
- v = a[3 +aoff];
- t3 += v * b0;
- t4 += v * b1;
- t5 += v * b2;
- t6 += v * b3;
- t7 += v * b4;
- t8 += v * b5;
- t9 += v * b6;
- t10 += v * b7;
- t11 += v * b8;
- t12 += v * b9;
- t13 += v * b10;
- t14 += v * b11;
- t15 += v * b12;
- t16 += v * b13;
- t17 += v * b14;
- t18 += v * b15;
- v = a[4 +aoff];
- t4 += v * b0;
- t5 += v * b1;
- t6 += v * b2;
- t7 += v * b3;
- t8 += v * b4;
- t9 += v * b5;
- t10 += v * b6;
- t11 += v * b7;
- t12 += v * b8;
- t13 += v * b9;
- t14 += v * b10;
- t15 += v * b11;
- t16 += v * b12;
- t17 += v * b13;
- t18 += v * b14;
- t19 += v * b15;
- v = a[5 +aoff];
- t5 += v * b0;
- t6 += v * b1;
- t7 += v * b2;
- t8 += v * b3;
- t9 += v * b4;
- t10 += v * b5;
- t11 += v * b6;
- t12 += v * b7;
- t13 += v * b8;
- t14 += v * b9;
- t15 += v * b10;
- t16 += v * b11;
- t17 += v * b12;
- t18 += v * b13;
- t19 += v * b14;
- t20 += v * b15;
- v = a[6 +aoff];
- t6 += v * b0;
- t7 += v * b1;
- t8 += v * b2;
- t9 += v * b3;
- t10 += v * b4;
- t11 += v * b5;
- t12 += v * b6;
- t13 += v * b7;
- t14 += v * b8;
- t15 += v * b9;
- t16 += v * b10;
- t17 += v * b11;
- t18 += v * b12;
- t19 += v * b13;
- t20 += v * b14;
- t21 += v * b15;
- v = a[7 +aoff];
- t7 += v * b0;
- t8 += v * b1;
- t9 += v * b2;
- t10 += v * b3;
- t11 += v * b4;
- t12 += v * b5;
- t13 += v * b6;
- t14 += v * b7;
- t15 += v * b8;
- t16 += v * b9;
- t17 += v * b10;
- t18 += v * b11;
- t19 += v * b12;
- t20 += v * b13;
- t21 += v * b14;
- t22 += v * b15;
- v = a[8 +aoff];
- t8 += v * b0;
- t9 += v * b1;
- t10 += v * b2;
- t11 += v * b3;
- t12 += v * b4;
- t13 += v * b5;
- t14 += v * b6;
- t15 += v * b7;
- t16 += v * b8;
- t17 += v * b9;
- t18 += v * b10;
- t19 += v * b11;
- t20 += v * b12;
- t21 += v * b13;
- t22 += v * b14;
- t23 += v * b15;
- v = a[9 +aoff];
- t9 += v * b0;
- t10 += v * b1;
- t11 += v * b2;
- t12 += v * b3;
- t13 += v * b4;
- t14 += v * b5;
- t15 += v * b6;
- t16 += v * b7;
- t17 += v * b8;
- t18 += v * b9;
- t19 += v * b10;
- t20 += v * b11;
- t21 += v * b12;
- t22 += v * b13;
- t23 += v * b14;
- t24 += v * b15;
- v = a[10 +aoff];
- t10 += v * b0;
- t11 += v * b1;
- t12 += v * b2;
- t13 += v * b3;
- t14 += v * b4;
- t15 += v * b5;
- t16 += v * b6;
- t17 += v * b7;
- t18 += v * b8;
- t19 += v * b9;
- t20 += v * b10;
- t21 += v * b11;
- t22 += v * b12;
- t23 += v * b13;
- t24 += v * b14;
- t25 += v * b15;
- v = a[11 +aoff];
- t11 += v * b0;
- t12 += v * b1;
- t13 += v * b2;
- t14 += v * b3;
- t15 += v * b4;
- t16 += v * b5;
- t17 += v * b6;
- t18 += v * b7;
- t19 += v * b8;
- t20 += v * b9;
- t21 += v * b10;
- t22 += v * b11;
- t23 += v * b12;
- t24 += v * b13;
- t25 += v * b14;
- t26 += v * b15;
- v = a[12 +aoff];
- t12 += v * b0;
- t13 += v * b1;
- t14 += v * b2;
- t15 += v * b3;
- t16 += v * b4;
- t17 += v * b5;
- t18 += v * b6;
- t19 += v * b7;
- t20 += v * b8;
- t21 += v * b9;
- t22 += v * b10;
- t23 += v * b11;
- t24 += v * b12;
- t25 += v * b13;
- t26 += v * b14;
- t27 += v * b15;
- v = a[13 +aoff];
- t13 += v * b0;
- t14 += v * b1;
- t15 += v * b2;
- t16 += v * b3;
- t17 += v * b4;
- t18 += v * b5;
- t19 += v * b6;
- t20 += v * b7;
- t21 += v * b8;
- t22 += v * b9;
- t23 += v * b10;
- t24 += v * b11;
- t25 += v * b12;
- t26 += v * b13;
- t27 += v * b14;
- t28 += v * b15;
- v = a[14 +aoff];
- t14 += v * b0;
- t15 += v * b1;
- t16 += v * b2;
- t17 += v * b3;
- t18 += v * b4;
- t19 += v * b5;
- t20 += v * b6;
- t21 += v * b7;
- t22 += v * b8;
- t23 += v * b9;
- t24 += v * b10;
- t25 += v * b11;
- t26 += v * b12;
- t27 += v * b13;
- t28 += v * b14;
- t29 += v * b15;
- v = a[15 +aoff];
- t15 += v * b0;
- t16 += v * b1;
- t17 += v * b2;
- t18 += v * b3;
- t19 += v * b4;
- t20 += v * b5;
- t21 += v * b6;
- t22 += v * b7;
- t23 += v * b8;
- t24 += v * b9;
- t25 += v * b10;
- t26 += v * b11;
- t27 += v * b12;
- t28 += v * b13;
- t29 += v * b14;
- t30 += v * b15;
-
- t0 += 38 * t16;
- t1 += 38 * t17;
- t2 += 38 * t18;
- t3 += 38 * t19;
- t4 += 38 * t20;
- t5 += 38 * t21;
- t6 += 38 * t22;
- t7 += 38 * t23;
- t8 += 38 * t24;
- t9 += 38 * t25;
- t10 += 38 * t26;
- t11 += 38 * t27;
- t12 += 38 * t28;
- t13 += 38 * t29;
- t14 += 38 * t30;
- // t15 left as is
-
- // first car
- c = 1;
- v = t0 + c + 65535; c = v >> 16; t0 = v - c * 65536;
- v = t1 + c + 65535; c = v >> 16; t1 = v - c * 65536;
- v = t2 + c + 65535; c = v >> 16; t2 = v - c * 65536;
- v = t3 + c + 65535; c = v >> 16; t3 = v - c * 65536;
- v = t4 + c + 65535; c = v >> 16; t4 = v - c * 65536;
- v = t5 + c + 65535; c = v >> 16; t5 = v - c * 65536;
- v = t6 + c + 65535; c = v >> 16; t6 = v - c * 65536;
- v = t7 + c + 65535; c = v >> 16; t7 = v - c * 65536;
- v = t8 + c + 65535; c = v >> 16; t8 = v - c * 65536;
- v = t9 + c + 65535; c = v >> 16; t9 = v - c * 65536;
- v = t10 + c + 65535; c = v >> 16; t10 = v - c * 65536;
- v = t11 + c + 65535; c = v >> 16; t11 = v - c * 65536;
- v = t12 + c + 65535; c = v >> 16; t12 = v - c * 65536;
- v = t13 + c + 65535; c = v >> 16; t13 = v - c * 65536;
- v = t14 + c + 65535; c = v >> 16; t14 = v - c * 65536;
- v = t15 + c + 65535; c = v >> 16; t15 = v - c * 65536;
- t0 += c-1 + 37 * (c-1);
-
- // second car
- c = 1;
- v = t0 + c + 65535; c = v >> 16; t0 = v - c * 65536;
- v = t1 + c + 65535; c = v >> 16; t1 = v - c * 65536;
- v = t2 + c + 65535; c = v >> 16; t2 = v - c * 65536;
- v = t3 + c + 65535; c = v >> 16; t3 = v - c * 65536;
- v = t4 + c + 65535; c = v >> 16; t4 = v - c * 65536;
- v = t5 + c + 65535; c = v >> 16; t5 = v - c * 65536;
- v = t6 + c + 65535; c = v >> 16; t6 = v - c * 65536;
- v = t7 + c + 65535; c = v >> 16; t7 = v - c * 65536;
- v = t8 + c + 65535; c = v >> 16; t8 = v - c * 65536;
- v = t9 + c + 65535; c = v >> 16; t9 = v - c * 65536;
- v = t10 + c + 65535; c = v >> 16; t10 = v - c * 65536;
- v = t11 + c + 65535; c = v >> 16; t11 = v - c * 65536;
- v = t12 + c + 65535; c = v >> 16; t12 = v - c * 65536;
- v = t13 + c + 65535; c = v >> 16; t13 = v - c * 65536;
- v = t14 + c + 65535; c = v >> 16; t14 = v - c * 65536;
- v = t15 + c + 65535; c = v >> 16; t15 = v - c * 65536;
- t0 += c-1 + 37 * (c-1);
-
- o[ 0 +ooff] = t0;
- o[ 1 +ooff] = t1;
- o[ 2 +ooff] = t2;
- o[ 3 +ooff] = t3;
- o[ 4 +ooff] = t4;
- o[ 5 +ooff] = t5;
- o[ 6 +ooff] = t6;
- o[ 7 +ooff] = t7;
- o[ 8 +ooff] = t8;
- o[ 9 +ooff] = t9;
- o[10 +ooff] = t10;
- o[11 +ooff] = t11;
- o[12 +ooff] = t12;
- o[13 +ooff] = t13;
- o[14 +ooff] = t14;
- o[15 +ooff] = t15;
- }
-
- private static void S(
- long [] o,
- long [] a)
- {
- S(o,0, a,0);
- }
- private static void S(
- long [] o,final int ooff,
- long [] a,final int aoff)
- {
- M(o,ooff, a,aoff, a,aoff);
- }
-
- private static void inv25519(
- long [] o,final int ooff,
- long [] i,final int ioff)
- {
- long [] c = new long[16];
- int a;
- for (a = 0; a < 16; a++) c[a] = i[a+ioff];
- for (a = 253; a >= 0; a--) {
- S(c,0, c,0);
- if(a != 2 && a != 4) M(c,0, c,0, i,ioff);
- }
- for (a = 0; a < 16; a++) o[a+ooff] = c[a];
- }
-
- private static void pow2523(long [] o,long [] i)
- {
- long [] c = new long[16];
- int a;
-
- for (a = 0; a < 16; a ++) c[a]=i[a];
-
- for(a=250;a>=0;a--) {
- S(c,0, c,0);
- if(a!=1) M(c,0, c,0, i,0);
- }
-
- for (a = 0; a < 16; a ++) o[a]=c[a];
- }
-
- public static int crypto_scalarmult(byte []q,byte []n,byte []p)
- {
- byte [] z = new byte[32];
- long [] x = new long[80];
- int r, i;
- long [] a = new long[16], b = new long[16], c = new long[16],
- d = new long[16], e = new long[16], f = new long[16];
- for (i = 0; i < 31; i++) z[i] = n[i];
- z[31]=(byte) (((n[31]&127)|64) & 0xff);
- z[0]&=248;
- unpack25519(x,p);
- for (i = 0; i < 16; i++) {
- b[i]=x[i];
- d[i]=a[i]=c[i]=0;
- }
- a[0]=d[0]=1;
- for (i=254;i>=0;--i) {
- r=(z[i>>>3]>>>(i&7))&1;
- sel25519(a,b,r);
- sel25519(c,d,r);
- A(e,a,c);
- Z(a,a,c);
- A(c,b,d);
- Z(b,b,d);
- S(d,e);
- S(f,a);
- M(a,c,a);
- M(c,b,e);
- A(e,a,c);
- Z(a,a,c);
- S(b,a);
- Z(c,d,f);
- M(a,c,_121665);
- A(a,a,d);
- M(c,c,a);
- M(a,d,f);
- M(d,b,x);
- S(b,e);
- sel25519(a,b,r);
- sel25519(c,d,r);
- }
- for (i = 0; i < 16; i++) {
- x[i+16]=a[i];
- x[i+32]=c[i];
- x[i+48]=b[i];
- x[i+64]=d[i];
- }
- inv25519(x,32, x,32);
- M(x,16, x,16, x,32);
- pack25519(q, x,16);
-
- return 0;
- }
-
- public static int crypto_scalarmult_base(byte []q,byte []n)
- {
- return crypto_scalarmult(q,n,_9);
- }
-
- public static int crypto_box_keypair(byte [] y, byte [] x)
- {
- randombytes(x,32);
- return crypto_scalarmult_base(y,x);
- }
-
- public static int crypto_box_beforenm(byte []k,byte []y,byte []x)
- {
- byte[] s = new byte[32];
- crypto_scalarmult(s,x,y);
-
- /*String dbgt = "";
- for (int dbg = 0; dbg < s.length; dbg ++) dbgt += " "+s[dbg];
- Log.d(TAG, "crypto_box_beforenm -> "+dbgt);
-
- dbgt = "";
- for (int dbg = 0; dbg < x.length; dbg ++) dbgt += " "+x[dbg];
- Log.d(TAG, "crypto_box_beforenm, x -> "+dbgt);
- dbgt = "";
- for (int dbg = 0; dbg < y.length; dbg ++) dbgt += " "+y[dbg];
- Log.d(TAG, "crypto_box_beforenm, y -> "+dbgt);
- */
-
- return crypto_core_hsalsa20(k, _0, s, sigma);
- }
-
- public static int crypto_box_afternm(byte []c,byte []m,int /*long*/ d,byte []n,byte []k)
- {
- return crypto_secretbox(c,m,d,n,k);
- }
-
- public static int crypto_box_open_afternm(byte []m,byte []c,int /*long*/ d,byte []n,byte []k)
- {
- return crypto_secretbox_open(m,c,d,n,k);
- }
-
- public static int crypto_box(byte []c,byte []m,int /*long*/ d,byte []n,byte []y,byte []x)
- {
- byte[] k = new byte[32];
-
- ///L/og.d(TAG, "crypto_box start ...");
-
- crypto_box_beforenm(k,y,x);
- return crypto_box_afternm(c,m,d,n,k);
- }
-
- public static int crypto_box_open(byte []m,byte []c,int /*long*/ d,byte []n,byte []y,byte []x)
- {
- byte[] k = new byte[32];
- crypto_box_beforenm(k,y,x);
- return crypto_box_open_afternm(m,c,d,n,k);
- }
-
- 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 int crypto_hashblocks_hl(int [] hh,int [] hl, byte [] m,final int moff, int n) {
-
- ///String dbgt = "";
- ///for (int dbg = 0; dbg < n; dbg ++) dbgt += " "+m[dbg+moff];
- ///Log.d(TAG, "crypto_hashblocks_hl m/"+n + "-> "+dbgt);
-
- int [] wh = new int[16], wl = new int[16];
- int bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7,
- bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7,
- th, tl, h, l, i, j, a, b, c, d;
-
- int ah0 = hh[0],
- ah1 = hh[1],
- ah2 = hh[2],
- ah3 = hh[3],
- ah4 = hh[4],
- ah5 = hh[5],
- ah6 = hh[6],
- ah7 = hh[7],
-
- al0 = hl[0],
- al1 = hl[1],
- al2 = hl[2],
- al3 = hl[3],
- al4 = hl[4],
- al5 = hl[5],
- al6 = hl[6],
- al7 = hl[7];
-
- int pos = 0;
- while (n >= 128) {
- for (i = 0; i < 16; i++) {
- j = 8 * i + pos;
- wh[i] = ((m[j+0+moff]&0xff) << 24) | ((m[j+1+moff]&0xff) << 16) | ((m[j+2+moff]&0xff) << 8) | ((m[j+3+moff]&0xff) << 0);
- wl[i] = ((m[j+4+moff]&0xff) << 24) | ((m[j+5+moff]&0xff) << 16) | ((m[j+6+moff]&0xff) << 8) | ((m[j+7+moff]&0xff) << 0);
- }
- for (i = 0; i < 80; i++) {
- bh0 = ah0;
- bh1 = ah1;
- bh2 = ah2;
- bh3 = ah3;
- bh4 = ah4;
- bh5 = ah5;
- bh6 = ah6;
- bh7 = ah7;
-
- bl0 = al0;
- bl1 = al1;
- bl2 = al2;
- bl3 = al3;
- bl4 = al4;
- bl5 = al5;
- bl6 = al6;
- bl7 = al7;
-
- // add
- h = ah7;
- l = al7;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- // Sigma1
- h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32))));
- l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32))));
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- // Ch
- h = (ah4 & ah5) ^ (~ah4 & ah6);
- l = (al4 & al5) ^ (~al4 & al6);
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- // K
- ///h = K[i*2];
- ///l = K[i*2+1];
- h = (int) ((K[i]>>>32) & 0xffffffff);
- l = (int) ((K[i]>>> 0) & 0xffffffff);
-
- ///Log.d(TAG, "i"+i + ",h:0x"+Integer.toHexString(h) + ",l:0x"+Integer.toHexString(l));
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- // w
- h = wh[i%16];
- l = wl[i%16];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- th = c & 0xffff | d << 16;
- tl = a & 0xffff | b << 16;
-
- // add
- h = th;
- l = tl;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- // Sigma0
- h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32))));
- l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32))));
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- // Maj
- h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2);
- l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2);
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- bh7 = (c & 0xffff) | (d << 16);
- bl7 = (a & 0xffff) | (b << 16);
-
- // add
- h = bh3;
- l = bl3;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = th;
- l = tl;
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- bh3 = (c & 0xffff) | (d << 16);
- bl3 = (a & 0xffff) | (b << 16);
-
- ah1 = bh0;
- ah2 = bh1;
- ah3 = bh2;
- ah4 = bh3;
- ah5 = bh4;
- ah6 = bh5;
- ah7 = bh6;
- ah0 = bh7;
-
- al1 = bl0;
- al2 = bl1;
- al3 = bl2;
- al4 = bl3;
- al5 = bl4;
- al6 = bl5;
- al7 = bl6;
- al0 = bl7;
-
- if (i%16 == 15) {
- for (j = 0; j < 16; j++) {
- // add
- h = wh[j];
- l = wl[j];
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = wh[(j+9)%16];
- l = wl[(j+9)%16];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- // sigma0
- th = wh[(j+1)%16];
- tl = wl[(j+1)%16];
- h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7);
- l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7)));
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- // sigma1
- th = wh[(j+14)%16];
- tl = wl[(j+14)%16];
- h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6);
- l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6)));
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- wh[j] = (c & 0xffff) | (d << 16);
- wl[j] = (a & 0xffff) | (b << 16);
- }
- }
- }
-
- // add
- h = ah0;
- l = al0;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[0];
- l = hl[0];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[0] = ah0 = (c & 0xffff) | (d << 16);
- hl[0] = al0 = (a & 0xffff) | (b << 16);
-
- h = ah1;
- l = al1;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[1];
- l = hl[1];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[1] = ah1 = (c & 0xffff) | (d << 16);
- hl[1] = al1 = (a & 0xffff) | (b << 16);
-
- h = ah2;
- l = al2;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[2];
- l = hl[2];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[2] = ah2 = (c & 0xffff) | (d << 16);
- hl[2] = al2 = (a & 0xffff) | (b << 16);
-
- h = ah3;
- l = al3;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[3];
- l = hl[3];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[3] = ah3 = (c & 0xffff) | (d << 16);
- hl[3] = al3 = (a & 0xffff) | (b << 16);
-
- h = ah4;
- l = al4;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[4];
- l = hl[4];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[4] = ah4 = (c & 0xffff) | (d << 16);
- hl[4] = al4 = (a & 0xffff) | (b << 16);
-
- h = ah5;
- l = al5;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[5];
- l = hl[5];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[5] = ah5 = (c & 0xffff) | (d << 16);
- hl[5] = al5 = (a & 0xffff) | (b << 16);
-
- h = ah6;
- l = al6;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[6];
- l = hl[6];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[6] = ah6 = (c & 0xffff) | (d << 16);
- hl[6] = al6 = (a & 0xffff) | (b << 16);
-
- h = ah7;
- l = al7;
-
- a = l & 0xffff; b = l >>> 16;
- c = h & 0xffff; d = h >>> 16;
-
- h = hh[7];
- l = hl[7];
-
- a += l & 0xffff; b += l >>> 16;
- c += h & 0xffff; d += h >>> 16;
-
- b += a >>> 16;
- c += b >>> 16;
- d += c >>> 16;
-
- hh[7] = ah7 = (c & 0xffff) | (d << 16);
- hl[7] = al7 = (a & 0xffff) | (b << 16);
-
- pos += 128;
- n -= 128;
-
- /*dbgt = "";
- for (int dbg = 0; dbg < hh.length; dbg ++) dbgt += " "+hh[dbg];
- Log.d(TAG, "\ncrypto_hashblocks_hl hh -> "+dbgt);
-
- dbgt = "";
- for (int dbg = 0; dbg < hl.length; dbg ++) dbgt += " "+hl[dbg];
- Log.d(TAG, "\ncrypto_hashblocks_hl hl -> "+dbgt);*/
- }
-
- return n;
- }
-
- // TBD 64bits of n
- ///int crypto_hash(byte [] out, byte [] m, long n)
- public static int crypto_hash(byte [] out, byte [] m,final int moff, int n)
- {
- int [] hh = new int[8],
- hl = new int[8];
- byte [] x = new byte[256];
- int i, b = n;
- long u;
-
- hh[0] = 0x6a09e667;
- hh[1] = 0xbb67ae85;
- hh[2] = 0x3c6ef372;
- hh[3] = 0xa54ff53a;
- hh[4] = 0x510e527f;
- hh[5] = 0x9b05688c;
- hh[6] = 0x1f83d9ab;
- hh[7] = 0x5be0cd19;
-
- hl[0] = 0xf3bcc908;
- hl[1] = 0x84caa73b;
- hl[2] = 0xfe94f82b;
- hl[3] = 0x5f1d36f1;
- hl[4] = 0xade682d1;
- hl[5] = 0x2b3e6c1f;
- hl[6] = 0xfb41bd6b;
- hl[7] = 0x137e2179;
-
- if (n >= 128) {
- crypto_hashblocks_hl(hh, hl, m,moff, n);
- n %= 128;
- }
-
- for (i = 0; i < n; i++) x[i] = m[b-n+i +moff];
- x[n] = (byte) 128;
-
- n = 256-128*(n<112?1:0);
- x[n-9] = 0;
-
- ts64(x, n-8, b<<3/*(b / 0x20000000) | 0, b << 3*/);
-
- crypto_hashblocks_hl(hh, hl, x,0, n);
-
- for (i = 0; i < 8; i++) {
- u = hh[i]; u <<= 32; u |= hl[i]&0xffffffffL;
- ts64(out, 8*i, u);
- }
-
- return 0;
- }
- public static int crypto_hash(byte [] out, byte [] m) {
- return crypto_hash(out, m,0, m!=null? m.length : 0);
- }
-
- // gf: long[16]
- ///private static void add(gf p[4],gf q[4])
- private static void add(long [] p[], long [] q[])
- {
- long [] a = new long[16];
- long [] b = new long[16];
- long [] c = new long[16];
- long [] d = new long[16];
- long [] t = new long[16];
- long [] e = new long[16];
- long [] f = new long[16];
- long [] g = new long[16];
- long [] h = new long[16];
-
-
- long [] p0 = p[0];
- long [] p1 = p[1];
- long [] p2 = p[2];
- long [] p3 = p[3];
-
- long [] q0 = q[0];
- long [] q1 = q[1];
- long [] q2 = q[2];
- long [] q3 = q[3];
-
- Z(a,0, p1,0, p0,0);
- Z(t,0, q1,0, q0,0);
- M(a,0, a,0, t,0);
- A(b,0, p0,0, p1,0);
- A(t,0, q0,0, q1,0);
- M(b,0, b,0, t,0);
- M(c,0, p3,0, q3,0);
- M(c,0, c,0, D2,0);
- M(d,0, p2,0, q2,0);
-
- A(d,0, d,0, d,0);
- Z(e,0, b,0, a,0);
- Z(f,0, d,0, c,0);
- A(g,0, d,0, c,0);
- A(h,0, b,0, a,0);
-
- M(p0,0, e,0, f,0);
- M(p1,0, h,0, g,0);
- M(p2,0, g,0, f,0);
- M(p3,0, e,0, h,0);
- }
-
- private static void cswap(long [] p[], long [] q[], byte b)
- {
- int i;
-
- for (i = 0; i < 4; i ++)
- sel25519(p[i],0, q[i],0, b);
- }
-
- private static void pack(byte [] r, long [] p[])
- {
- long [] tx = new long[16];
- long [] ty = new long[16];
- long [] zi = new long[16];
-
- inv25519(zi,0, p[2],0);
-
- M(tx,0, p[0],0, zi,0);
- M(ty,0, p[1],0, zi,0);
-
- pack25519(r, ty,0);
-
- r[31] ^= par25519(tx,0) << 7;
- }
-
- private static void scalarmult(long [] p[], long [] q[], byte[] s,final int soff)
- {
- int i;
-
- set25519(p[0],gf0);
- set25519(p[1],gf1);
- set25519(p[2],gf1);
- set25519(p[3],gf0);
-
- for (i = 255;i >= 0;--i) {
- byte b = (byte) ((s[i/8+soff] >>> (i&7))&1);
-
- cswap(p,q,b);
- add(q,p);
- add(p,p);
- cswap(p,q,b);
- }
-
- ///String dbgt = "";
- ///for (int dbg = 0; dbg < p.length; dbg ++) for (int dd = 0; dd < p[dbg].length; dd ++) dbgt += " "+p[dbg][dd];
- ///L/og.d(TAG, "scalarmult -> "+dbgt);
- }
-
- private static void scalarbase(long [] p[], byte[] s,final int soff)
- {
- long [] [] q = new long [4] [];
-
- q[0] = new long [16];
- q[1] = new long [16];
- q[2] = new long [16];
- q[3] = new long [16];
-
- set25519(q[0],X);
- set25519(q[1],Y);
- set25519(q[2],gf1);
- M(q[3],0, X,0, Y,0);
- scalarmult(p,q, s,soff);
- }
-
- public static int crypto_sign_keypair(byte [] pk, byte [] sk, boolean seeded) {
- byte [] d = new byte[64];
- long [] [] p = new long [4] [];
-
- p[0] = new long [16];
- p[1] = new long [16];
- p[2] = new long [16];
- p[3] = new long [16];
-
- int i;
-
- if (!seeded) randombytes(sk, 32);
- crypto_hash(d, sk,0, 32);
- d[0] &= 248;
- d[31] &= 127;
- d[31] |= 64;
-
- scalarbase(p, d,0);
- pack(pk, p);
-
- for (i = 0; i < 32; i++) sk[i+32] = pk[i];
- return 0;
- }
-
- private static final long L[] = {
- 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
- 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0x10
- };
-
- private static void modL(byte[] r,final int roff, long x[])
- {
- long carry;
- int i, j;
-
- for (i = 63;i >= 32;--i) {
- carry = 0;
- for (j = i - 32;j < i - 12;++j) {
- x[j] += carry - 16 * x[i] * L[j - (i - 32)];
- carry = (x[j] + 128) >> 8;
- x[j] -= carry << 8;
- }
- x[j] += carry;
- x[i] = 0;
- }
- carry = 0;
-
- for (j = 0; j < 32; j ++) {
- x[j] += carry - (x[31] >> 4) * L[j];
- carry = x[j] >> 8;
- x[j] &= 255;
- }
-
- for (j = 0; j < 32; j ++) x[j] -= carry * L[j];
-
- for (i = 0; i < 32; i ++) {
- x[i+1] += x[i] >> 8;
- r[i+roff] = (byte) (x[i] & 255);
- }
- }
-
- private static void reduce(byte [] r)
- {
- long[] x = new long [64];
- int i;
-
- for (i = 0; i < 64; i ++) x[i] = (long) (r[i]&0xff);
-
- for (i = 0; i < 64; i ++) r[i] = 0;
-
- modL(r,0, x);
- }
-
- // TBD... 64bits of n
- ///int crypto_sign(byte [] sm, long * smlen, byte [] m, long n, byte [] sk)
- public static int crypto_sign(byte [] sm, long dummy /* *smlen not used*/, byte [] m,final int moff, int/*long*/ n, byte [] sk)
- {
- byte[] d = new byte[64], h = new byte[64], r = new byte[64];
-
- int i, j;
- long [] x = new long[64];
-
- long [] [] p = new long [4] [];
- p[0] = new long [16];
- p[1] = new long [16];
- p[2] = new long [16];
- p[3] = new long [16];
-
- crypto_hash(d, sk,0, 32);
- d[0] &= 248;
- d[31] &= 127;
- d[31] |= 64;
-
- ///*smlen = n+64;
-
- for (i = 0; i < n; i ++) sm[64 + i] = m[i+moff];
-
- for (i = 0; i < 32; i ++) sm[32 + i] = d[32 + i];
-
- crypto_hash(r, sm,32, n+32);
- reduce(r);
- scalarbase(p, r,0);
- pack(sm,p);
-
- for (i = 0; i < 32; i ++) sm[i+32] = sk[i+32];
- crypto_hash(h, sm,0, n + 64);
- reduce(h);
-
- for (i = 0; i < 64; i ++) x[i] = 0;
-
- for (i = 0; i < 32; i ++) x[i] = (long) (r[i]&0xff);
-
- for (i = 0; i < 32; i ++) for (j = 0; j < 32; j ++) x[i+j] += (h[i]&0xff) * (long) (d[j]&0xff);
-
- modL(sm,32, x);
-
- return 0;
- }
-
- private static int unpackneg(long [] r[], byte p[])
- {
- long [] t = new long [16];
- long [] chk = new long [16];
- long [] num = new long [16];
- long [] den = new long [16];
- long [] den2 = new long [16];
- long [] den4 = new long [16];
- long [] den6 = new long [16];
-
- set25519(r[2], gf1);
- unpack25519(r[1], p);
- S(num, r[1]);
- M(den, num, D);
- Z(num, num, r[2]);
- A(den, r[2], den);
-
- S(den2, den);
- S(den4, den2);
- M(den6, den4, den2);
- M(t, den6, num);
- M(t, t, den);
-
- pow2523(t, t);
- M(t, t, num);
- M(t, t, den);
- M(t, t, den);
- M(r[0], t, den);
-
- S(chk, r[0]);
- M(chk, chk, den);
- if (neq25519(chk, num)!=0) M(r[0], r[0], I);
-
- S(chk, r[0]);
- M(chk, chk, den);
- if (neq25519(chk, num)!=0) return -1;
-
- if (par25519(r[0]) == ((p[31]&0xFF)>>>7)) Z(r[0], gf0, r[0]);
-
- M(r[3], r[0], r[1]);
-
- return 0;
- }
-
- /// TBD 64bits of mlen
- ///int crypto_sign_open(byte []m,long *mlen,byte []sm,long n,byte []pk)
- public static int crypto_sign_open(byte [] m, long dummy /* *mlen not used*/, byte [] sm,final int smoff, int/*long*/ n, byte []pk)
- {
- int i;
- byte[] t = new byte[32], h = new byte[64];
-
- long [] [] p = new long [4] [];
- p[0] = new long [16];
- p[1] = new long [16];
- p[2] = new long [16];
- p[3] = new long [16];
-
- long [] [] q = new long [4] [];
- q[0] = new long [16];
- q[1] = new long [16];
- q[2] = new long [16];
- q[3] = new long [16];
-
- ///*mlen = -1;
-
- if (n < 64) return -1;
-
- if (unpackneg(q,pk)!=0) return -1;
-
- for (i = 0; i < n; i ++) m[i] = sm[i+smoff];
-
- for (i = 0; i < 32; i ++) m[i+32] = pk[i];
-
- crypto_hash(h, m,0, n);
-
- reduce(h);
- scalarmult(p,q, h,0);
-
- scalarbase(q, sm,32+smoff);
- add(p,q);
- pack(t,p);
-
- n -= 64;
- if (crypto_verify_32(sm,smoff, t,0)!=0) {
- // optimizing it
- ///for (i = 0; i < n; i ++) m[i] = 0;
- return -1;
- }
-
- // TBD optimizing ...
- ///for (i = 0; i < n; i ++) m[i] = sm[i + 64 + smoff];
- ///*mlen = n;
-
- return 0;
- }
-
- /*
- * @description
- * Java SecureRandom generator
- * */
- private static final SecureRandom jrandom = new SecureRandom();
-
- public static byte[] randombytes(byte [] x) {
- jrandom.nextBytes(x);
- return x;
- }
-
- public static byte[] randombytes(int len) {
- return randombytes(new byte[len]);
- }
-
- public static byte[] randombytes(byte [] x, int len) {
- byte [] b = randombytes(len);
- System.arraycopy(b, 0, x, 0, len);
- return x;
- }
-
-/*
- public static byte[] randombytes(byte [] x, int len) {
- int ret = len % 8;
- long rnd;
- for (int i = 0; i < len-ret; i += 8) {
- rnd = jrandom.nextLong();
- x[i+0] = (byte) (rnd >>> 0);
- x[i+1] = (byte) (rnd >>> 8);
- x[i+2] = (byte) (rnd >>> 16);
- x[i+3] = (byte) (rnd >>> 24);
- x[i+4] = (byte) (rnd >>> 32);
- x[i+5] = (byte) (rnd >>> 40);
- x[i+6] = (byte) (rnd >>> 48);
- x[i+7] = (byte) (rnd >>> 56);
- }
- if (ret > 0) {
- rnd = jrandom.nextLong();
- for (int i = len-ret; i < len; i ++)
- x[i] = (byte) (rnd >>> 8*i);
- }
- return x;
- }
-*/
-
- public static byte[] makeBoxNonce() {
- return randombytes(Box.nonceLength);
- }
-
- public static byte[] makeSecretBoxNonce() {
- return randombytes(SecretBox.nonceLength);
- }
-
- public static String base64EncodeToString(byte [] b) {
- return Base64.getUrlEncoder().withoutPadding().encodeToString(b);
- }
- // byte[] Base64.getUrlEncoder().withoutPadding().encode(b);
-
- public static byte[] base64Decode(String s) {
- return Base64.getUrlDecoder().decode(s);
- }
- // byte[] Base64.getUrlDecoder().decode(byte[] b)
-
- public static String hexEncodeToString( byte [] raw ) {
- String HEXES = "0123456789ABCDEF";
- final StringBuilder hex = new StringBuilder( 2 * raw.length );
- for ( final byte b : raw ) {
- hex.append(HEXES.charAt((b & 0xF0) >> 4))
- .append(HEXES.charAt((b & 0x0F)));
- }
- return hex.toString();
- }
-
- public static byte[] hexDecode(String s) {
- byte[] b = new byte[s.length() / 2];
- for (int i = 0; i < s.length(); i += 2) {
- b[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
- + Character.digit(s.charAt(i+1), 16));
- }
- return b;
- }
-
- // public static boolean java.util.Arrays.equals(array1, array2);
-}
diff --git a/src/main/java/net/dv8tion/jda/api/JDAInfo.java b/src/main/java/net/dv8tion/jda/api/JDAInfo.java
index 9900d317a6..913e53161c 100644
--- a/src/main/java/net/dv8tion/jda/api/JDAInfo.java
+++ b/src/main/java/net/dv8tion/jda/api/JDAInfo.java
@@ -22,7 +22,7 @@ public class JDAInfo
{
public static final int DISCORD_GATEWAY_VERSION = 10;
public static final int DISCORD_REST_VERSION = 10;
- public static final int AUDIO_GATEWAY_VERSION = 4;
+ public static final int AUDIO_GATEWAY_VERSION = 8;
public static final String GITHUB = "https://github.com/discord-jda/JDA";
public static final String VERSION_MAJOR = "@versionMajor@";
public static final String VERSION_MINOR = "@versionMinor@";
diff --git a/src/main/java/net/dv8tion/jda/internal/audio/AudioConnection.java b/src/main/java/net/dv8tion/jda/internal/audio/AudioConnection.java
index 2cacc2fdd5..2962691f9d 100644
--- a/src/main/java/net/dv8tion/jda/internal/audio/AudioConnection.java
+++ b/src/main/java/net/dv8tion/jda/internal/audio/AudioConnection.java
@@ -16,7 +16,6 @@
package net.dv8tion.jda.internal.audio;
-import com.iwebpp.crypto.TweetNaclFast;
import com.neovisionaries.ws.client.WebSocket;
import com.sun.jna.ptr.PointerByReference;
import gnu.trove.map.TIntLongMap;
@@ -36,7 +35,6 @@
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.managers.AudioManagerImpl;
-import net.dv8tion.jda.internal.utils.IOUtil;
import net.dv8tion.jda.internal.utils.JDALogger;
import org.slf4j.Logger;
import tomp2p.opuswrapper.Opus;
@@ -48,7 +46,10 @@
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.*;
-import java.util.concurrent.*;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -306,7 +307,7 @@ private synchronized void setupSendSystem()
{
setSpeaking(speakingMode);
IAudioSendFactory factory = getJDA().getAudioSendFactory();
- sendSystem = factory.createSendSystem(new PacketProvider(new TweetNaclFast.SecretBox(webSocket.getSecretKey())));
+ sendSystem = factory.createSendSystem(new PacketProvider());
sendSystem.setContextMap(getJDA().getContextMap());
sendSystem.start();
}
@@ -377,7 +378,7 @@ private synchronized void setupReceiveThread()
if (canReceive && webSocket.getSecretKey() != null)
{
couldReceive = true;
- AudioPacket decryptedPacket = AudioPacket.decryptAudioPacket(webSocket.encryption, receivedPacket, webSocket.getSecretKey());
+ AudioPacket decryptedPacket = AudioPacket.decryptAudioPacket(webSocket.crypto, receivedPacket);
if (decryptedPacket == null)
continue;
@@ -615,19 +616,11 @@ protected void finalize()
private class PacketProvider implements IPacketProvider
{
- private final TweetNaclFast.SecretBox boxer;
- private final byte[] nonceBuffer = new byte[TweetNaclFast.SecretBox.nonceLength];
private char seq = 0; //Sequence of audio packets. Used to determine the order of the packets.
private int timestamp = 0; //Used to sync up our packets within the same timeframe of other people talking.
- private long nonce = 0;
private ByteBuffer buffer = ByteBuffer.allocate(512);
private ByteBuffer encryptionBuffer = ByteBuffer.allocate(512);
- public PacketProvider(TweetNaclFast.SecretBox boxer)
- {
- this.boxer = boxer;
- }
-
@Nonnull
@Override
public String getIdentifier()
@@ -741,27 +734,7 @@ private ByteBuffer getPacketData(ByteBuffer rawAudio)
{
ensureEncryptionBuffer(rawAudio);
AudioPacket packet = new AudioPacket(encryptionBuffer, seq, timestamp, webSocket.getSSRC(), rawAudio);
- int nlen;
- switch (webSocket.encryption)
- {
- case XSALSA20_POLY1305:
- nlen = 0;
- break;
- case XSALSA20_POLY1305_LITE:
- if (nonce >= MAX_UINT_32)
- loadNextNonce(nonce = 0);
- else
- loadNextNonce(++nonce);
- nlen = 4;
- break;
- case XSALSA20_POLY1305_SUFFIX:
- ThreadLocalRandom.current().nextBytes(nonceBuffer);
- nlen = TweetNaclFast.SecretBox.nonceLength;
- break;
- default:
- throw new IllegalStateException("Encryption mode [" + webSocket.encryption + "] is not supported!");
- }
- return buffer = packet.asEncryptedPacket(boxer, buffer, nonceBuffer, nlen);
+ return buffer = packet.asEncryptedPacket(webSocket.crypto, buffer);
}
private void ensureEncryptionBuffer(ByteBuffer data)
@@ -773,11 +746,6 @@ private void ensureEncryptionBuffer(ByteBuffer data)
encryptionBuffer = ByteBuffer.allocate(requiredCapacity);
}
- private void loadNextNonce(long nonce)
- {
- IOUtil.setIntBigEndian(nonceBuffer, 0, (int) nonce);
- }
-
@Override
public void onConnectionError(@Nonnull ConnectionStatus status)
{
diff --git a/src/main/java/net/dv8tion/jda/internal/audio/AudioEncryption.java b/src/main/java/net/dv8tion/jda/internal/audio/AudioEncryption.java
index 9487199ff6..c7d0773c70 100644
--- a/src/main/java/net/dv8tion/jda/internal/audio/AudioEncryption.java
+++ b/src/main/java/net/dv8tion/jda/internal/audio/AudioEncryption.java
@@ -18,13 +18,16 @@
import net.dv8tion.jda.api.utils.data.DataArray;
+import java.util.EnumSet;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
public enum AudioEncryption
{
- // these are ordered by priority, lite > suffix > normal
- // we prefer lite because it uses only 4 bytes for its nonce while the others use 24 bytes
- XSALSA20_POLY1305_LITE,
- XSALSA20_POLY1305_SUFFIX,
- XSALSA20_POLY1305;
+ // ordered by priority descending
+ AEAD_AES256_GCM_RTPSIZE,
+ AEAD_XCHACHA20_POLY1305_RTPSIZE;
private final String key;
@@ -54,4 +57,26 @@ public static AudioEncryption getPreferredMode(DataArray array)
}
return encryption;
}
+
+ public static EnumSet fromArray(DataArray modes)
+ {
+ return modes.stream(DataArray::getString)
+ .map(mode -> mode.toLowerCase(Locale.ROOT))
+ .map(AudioEncryption::forMode)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toCollection(() -> EnumSet.noneOf(AudioEncryption.class)));
+ }
+
+ public static AudioEncryption forMode(String mode)
+ {
+ switch (mode)
+ {
+ case "aead_aes256_gcm_rtpsize":
+ return AEAD_AES256_GCM_RTPSIZE;
+ case "aead_xchacha20_poly1305_rtpsize":
+ return AEAD_XCHACHA20_POLY1305_RTPSIZE;
+ default:
+ return null;
+ }
+ }
}
diff --git a/src/main/java/net/dv8tion/jda/internal/audio/AudioPacket.java b/src/main/java/net/dv8tion/jda/internal/audio/AudioPacket.java
index 38d9c7c628..df9d79b51c 100644
--- a/src/main/java/net/dv8tion/jda/internal/audio/AudioPacket.java
+++ b/src/main/java/net/dv8tion/jda/internal/audio/AudioPacket.java
@@ -16,9 +16,6 @@
package net.dv8tion.jda.internal.audio;
-import com.iwebpp.crypto.TweetNaclFast;
-import net.dv8tion.jda.internal.utils.IOUtil;
-
import java.net.DatagramPacket;
import java.nio.Buffer;
import java.nio.ByteBuffer;
@@ -48,20 +45,14 @@ public class AudioPacket
*/
public static final byte RTP_PAYLOAD_TYPE = (byte) 0x78; //Binary: 0100 1000
- /**
- * This defines the extension type used by discord for presumably video?
- */
- public static final short RTP_DISCORD_EXTENSION = (short) 0xBEDE;
-
- public static final int PT_INDEX = 1;
- public static final int SEQ_INDEX = 2;
- public static final int TIMESTAMP_INDEX = 4;
- public static final int SSRC_INDEX = 8;
-
private final byte type;
private final char seq;
private final int timestamp;
private final int ssrc;
+ private final int extension;
+ private final boolean hasExtension;
+ private final int[] csrc;
+ private final int headerLength;
private final byte[] rawPacket;
private final ByteBuffer encodedAudio;
@@ -75,26 +66,28 @@ public AudioPacket(byte[] rawPacket)
this.rawPacket = rawPacket;
ByteBuffer buffer = ByteBuffer.wrap(rawPacket);
- this.seq = buffer.getChar(SEQ_INDEX);
- this.timestamp = buffer.getInt(TIMESTAMP_INDEX);
- this.ssrc = buffer.getInt(SSRC_INDEX);
- this.type = buffer.get(PT_INDEX);
- final byte profile = buffer.get(0);
- final byte[] data = buffer.array();
- final boolean hasExtension = (profile & 0x10) != 0; // extension bit is at 000X
- final byte cc = (byte) (profile & 0x0f); // CSRC count - we ignore this for now
- final int csrcLength = cc * 4; // defines count of 4-byte words
- // it seems as if extensions only exist without a csrc list being present
- final short extension = hasExtension ? IOUtil.getShortBigEndian(data, RTP_HEADER_BYTE_LENGTH + csrcLength) : 0;
+ // Parsing header as described by https://datatracker.ietf.org/doc/html/rfc3550#section-5.1
- int offset = RTP_HEADER_BYTE_LENGTH + csrcLength;
- if (hasExtension && extension == RTP_DISCORD_EXTENSION)
- offset = getPayloadOffset(data, csrcLength);
+ byte first = buffer.get();
+ // extension, 1 if extension is present
+ this.hasExtension = (first & 0b0001_0000) != 0;
+ // CSRC count, 0 to 15
+ int cc = first & 0x0f;
- this.encodedAudio = ByteBuffer.allocate(data.length - offset);
- this.encodedAudio.put(data, offset, encodedAudio.capacity());
- ((Buffer) this.encodedAudio).flip();
+ this.type = buffer.get();
+ this.seq = buffer.getChar();
+ this.timestamp = buffer.getInt();
+ this.ssrc = buffer.getInt();
+
+ this.csrc = new int[cc];
+ for (int i = 0; i < cc; i++)
+ this.csrc[i] = buffer.getInt();
+
+ this.extension = this.hasExtension ? buffer.getInt() : 0;
+
+ this.headerLength = buffer.position();
+ this.encodedAudio = buffer;
}
public AudioPacket(ByteBuffer buffer, char seq, int timestamp, int ssrc, ByteBuffer encodedAudio)
@@ -102,44 +95,18 @@ public AudioPacket(ByteBuffer buffer, char seq, int timestamp, int ssrc, ByteBuf
this.seq = seq;
this.ssrc = ssrc;
this.timestamp = timestamp;
- this.encodedAudio = encodedAudio;
+ this.csrc = new int[0];
+ this.extension = 0;
+ this.hasExtension = false;
+ this.headerLength = RTP_HEADER_BYTE_LENGTH;
this.type = RTP_PAYLOAD_TYPE;
this.rawPacket = generateRawPacket(buffer, seq, timestamp, ssrc, encodedAudio);
+ this.encodedAudio = encodedAudio;
}
- private int getPayloadOffset(byte[] data, int csrcLength)
- {
- // headerLength defines number of 4-byte words in the extension
- final short headerLength = IOUtil.getShortBigEndian(data, RTP_HEADER_BYTE_LENGTH + 2 + csrcLength);
- int i = RTP_HEADER_BYTE_LENGTH // RTP header = 12 bytes
- + 4 // header which defines a profile and length each 2-bytes = 4 bytes
- + csrcLength // length of CSRC list (this seems to be always 0 when an extension exists)
- + headerLength * 4; // number of 4-byte words in extension = len * 4 bytes
-
- // strip excess 0 bytes
- while (data[i] == 0)
- i++;
- return i;
- }
-
- @SuppressWarnings("unused")
public byte[] getHeader()
{
- //The first 12 bytes of the rawPacket are the RTP Discord Nonce.
- return Arrays.copyOf(rawPacket, RTP_HEADER_BYTE_LENGTH);
- }
-
- public byte[] getNoncePadded()
- {
- byte[] nonce = new byte[TweetNaclFast.SecretBox.nonceLength];
- //The first 12 bytes are the rawPacket are the RTP Discord Nonce.
- System.arraycopy(rawPacket, 0, nonce, 0, RTP_HEADER_BYTE_LENGTH);
- return nonce;
- }
-
- public byte[] getRawPacket()
- {
- return rawPacket;
+ return Arrays.copyOf(rawPacket, headerLength);
}
public ByteBuffer getEncodedAudio()
@@ -162,93 +129,29 @@ public int getTimestamp()
return timestamp;
}
- protected ByteBuffer asEncryptedPacket(TweetNaclFast.SecretBox boxer, ByteBuffer buffer, byte[] nonce, int nlen)
+ public ByteBuffer asEncryptedPacket(CryptoAdapter crypto, ByteBuffer buffer)
{
- //Xsalsa20's Nonce is 24 bytes long, however RTP (and consequently Discord)'s nonce is a different length
- // so we need to create a 24 byte array, and copy the nonce into it.
- // we will leave the extra bytes as nulls. (Java sets non-populated bytes as 0).
- byte[] extendedNonce = nonce;
- if (nlen == 0) // this means the header is the nonce!
- extendedNonce = getNoncePadded();
-
- //Create our SecretBox encoder with the secretKey provided by Discord.
- byte[] array = encodedAudio.array();
- int offset = encodedAudio.arrayOffset() + encodedAudio.position();
- int length = encodedAudio.remaining();
- byte[] encryptedAudio = boxer.box(array, offset, length, extendedNonce);
-
((Buffer) buffer).clear();
- int capacity = RTP_HEADER_BYTE_LENGTH + encryptedAudio.length + nlen;
- if (capacity > buffer.remaining())
- buffer = ByteBuffer.allocate(capacity);
- populateBuffer(seq, timestamp, ssrc, ByteBuffer.wrap(encryptedAudio), buffer);
- if (nlen > 0) // this means we append the nonce to the payload
- buffer.put(nonce, 0, nlen);
-
+ writeHeader(seq, timestamp, ssrc, buffer);
+ buffer = crypto.encrypt(buffer, encodedAudio);
((Buffer) buffer).flip();
return buffer;
}
- protected static AudioPacket decryptAudioPacket(AudioEncryption encryption, DatagramPacket packet, byte[] secretKey)
+ public static AudioPacket decryptAudioPacket(CryptoAdapter crypto, DatagramPacket packet)
{
- TweetNaclFast.SecretBox boxer = new TweetNaclFast.SecretBox(secretKey);
AudioPacket encryptedPacket = new AudioPacket(packet);
if (encryptedPacket.type != RTP_PAYLOAD_TYPE)
return null;
- byte[] extendedNonce;
- byte[] rawPacket = encryptedPacket.getRawPacket();
- switch (encryption)
- {
- case XSALSA20_POLY1305:
- extendedNonce = encryptedPacket.getNoncePadded();
- break;
- case XSALSA20_POLY1305_SUFFIX:
- extendedNonce = new byte[TweetNaclFast.SecretBox.nonceLength];
- System.arraycopy(rawPacket, rawPacket.length - extendedNonce.length, extendedNonce, 0, extendedNonce.length);
- break;
- case XSALSA20_POLY1305_LITE:
- extendedNonce = new byte[TweetNaclFast.SecretBox.nonceLength];
- System.arraycopy(rawPacket, rawPacket.length - 4, extendedNonce, 0, 4);
- break;
- default:
- AudioConnection.LOG.debug("Failed to decrypt audio packet, unsupported encryption mode!");
- return null;
- }
-
- ByteBuffer encodedAudio = encryptedPacket.encodedAudio;
- int length = encodedAudio.remaining();
- int offset = encodedAudio.arrayOffset() + encodedAudio.position();
- switch (encryption)
- {
- case XSALSA20_POLY1305:
-// length = encodedAudio.remaining();
- break;
- case XSALSA20_POLY1305_LITE:
- length -= 4;
- break;
- case XSALSA20_POLY1305_SUFFIX:
- length -= TweetNaclFast.SecretBox.nonceLength;
- break;
- default:
- AudioConnection.LOG.debug("Failed to decrypt audio packet, unsupported encryption mode!");
- return null;
- }
-
- final byte[] decryptedAudio = boxer.open(encodedAudio.array(), offset, length, extendedNonce);
- if (decryptedAudio == null)
- {
- AudioConnection.LOG.trace("Failed to decrypt audio packet");
- return null;
- }
- final byte[] decryptedRawPacket = new byte[RTP_HEADER_BYTE_LENGTH + decryptedAudio.length];
-
- //first 12 bytes of rawPacket are the RTP header
- //the rest is the audio data we just decrypted
- System.arraycopy(encryptedPacket.rawPacket, 0, decryptedRawPacket, 0, RTP_HEADER_BYTE_LENGTH);
- System.arraycopy(decryptedAudio, 0, decryptedRawPacket, RTP_HEADER_BYTE_LENGTH, decryptedAudio.length);
-
- return new AudioPacket(decryptedRawPacket);
+ byte[] decryptedPayload = crypto.decrypt(encryptedPacket.encodedAudio);
+ return new AudioPacket(
+ null,
+ encryptedPacket.seq,
+ encryptedPacket.timestamp,
+ encryptedPacket.ssrc,
+ ByteBuffer.wrap(decryptedPayload)
+ );
}
private static byte[] generateRawPacket(ByteBuffer buffer, char seq, int timestamp, int ssrc, ByteBuffer data)
@@ -259,13 +162,18 @@ private static byte[] generateRawPacket(ByteBuffer buffer, char seq, int timesta
return buffer.array();
}
- private static void populateBuffer(char seq, int timestamp, int ssrc, ByteBuffer data, ByteBuffer buffer)
+ private static void writeHeader(char seq, int timestamp, int ssrc, ByteBuffer buffer)
{
buffer.put(RTP_VERSION_PAD_EXTEND);
buffer.put(RTP_PAYLOAD_TYPE);
buffer.putChar(seq);
buffer.putInt(timestamp);
buffer.putInt(ssrc);
+ }
+
+ private static void populateBuffer(char seq, int timestamp, int ssrc, ByteBuffer data, ByteBuffer buffer)
+ {
+ writeHeader(seq, timestamp, ssrc, buffer);
buffer.put(data);
((Buffer) data).flip();
}
diff --git a/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java b/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java
index 888f257668..2af4545220 100644
--- a/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java
+++ b/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java
@@ -55,6 +55,7 @@ class AudioWebSocket extends WebSocketAdapter
private static final byte[] UDP_KEEP_ALIVE= { (byte) 0xC9, 0, 0, 0, 0, 0, 0, 0, 0 };
protected volatile AudioEncryption encryption;
+ protected volatile CryptoAdapter crypto;
protected WebSocket socket;
private final AudioConnection audioConnection;
@@ -73,6 +74,7 @@ class AudioWebSocket extends WebSocketAdapter
private byte[] secretKey;
private Future> keepAliveHandle;
private InetSocketAddress address;
+ private long sequence;
private volatile boolean shutdown = false;
@@ -392,6 +394,7 @@ public void onConnectError(WebSocket webSocket, WebSocketException e)
private void handleEvent(DataObject contentAll)
{
int opCode = contentAll.getInt("op");
+ sequence = contentAll.getLong("seq", sequence);
switch(opCode)
{
@@ -412,7 +415,7 @@ private void handleEvent(DataObject contentAll)
int port = content.getInt("port");
String ip = content.getString("ip");
DataArray modes = content.getArray("modes");
- encryption = AudioEncryption.getPreferredMode(modes);
+ encryption = CryptoAdapter.negotiate(AudioEncryption.fromArray(modes));
if (encryption == null)
{
close(ConnectionStatus.ERROR_UNSUPPORTED_ENCRYPTION_MODES);
@@ -474,6 +477,8 @@ private void handleEvent(DataObject contentAll)
for (int i = 0; i < keyArray.length(); i++)
secretKey[i] = (byte) keyArray.getInt(i);
+ crypto = CryptoAdapter.getAdapter(encryption, secretKey);
+
LOG.debug("Audio connection has finished connecting!");
ready = true;
MiscUtil.locked(audioConnection.readyLock, audioConnection.readyCondvar::signalAll);
@@ -489,7 +494,7 @@ private void handleEvent(DataObject contentAll)
case VoiceCode.HEARTBEAT_ACK:
{
LOG.trace("-> HEARTBEAT_ACK {}", contentAll);
- final long ping = System.currentTimeMillis() - contentAll.getLong("d");
+ final long ping = System.currentTimeMillis() - contentAll.getObject("d").getLong("t");
listener.onPing(ping);
break;
}
@@ -540,6 +545,7 @@ private void handleEvent(DataObject contentAll)
private void identify()
{
+ sequence = 0;
DataObject connectObj = DataObject.empty()
.put("server_id", guild.getId())
.put("user_id", getJDA().getSelfUser().getId())
@@ -554,7 +560,8 @@ private void resume()
DataObject resumeObj = DataObject.empty()
.put("server_id", guild.getId())
.put("session_id", sessionId)
- .put("token", token);
+ .put("token", token)
+ .put("seq_ack", sequence);
send(VoiceCode.RESUME, resumeObj);
}
@@ -675,7 +682,12 @@ private void setupKeepAlive(final int keepAliveInterval)
{
getJDA().setContext();
if (socket != null && socket.isOpen()) //TCP keep-alive
- send(VoiceCode.HEARTBEAT, System.currentTimeMillis());
+ {
+ DataObject packet = DataObject.empty().put("t", System.currentTimeMillis());
+ if (sequence > 0)
+ packet.put("seq_ack", sequence);
+ send(VoiceCode.HEARTBEAT, packet);
+ }
if (audioConnection.udpSocket != null && !audioConnection.udpSocket.isClosed()) //UDP keep-alive
{
try
diff --git a/src/main/java/net/dv8tion/jda/internal/audio/CryptoAdapter.java b/src/main/java/net/dv8tion/jda/internal/audio/CryptoAdapter.java
new file mode 100644
index 0000000000..34f18a51cb
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/internal/audio/CryptoAdapter.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dv8tion.jda.internal.audio;
+
+import com.google.crypto.tink.aead.internal.InsecureNonceAesGcmJce;
+import com.google.crypto.tink.aead.internal.InsecureNonceXChaCha20Poly1305;
+import net.dv8tion.jda.internal.utils.IOUtil;
+
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.EnumSet;
+
+public interface CryptoAdapter
+{
+ String AES_GCM_NO_PADDING = "AES_256/GCM/NOPADDING";
+
+ AudioEncryption getMode();
+
+ ByteBuffer encrypt(ByteBuffer output, ByteBuffer audio);
+
+ byte[] decrypt(ByteBuffer packet);
+
+ static AudioEncryption negotiate(EnumSet supportedModes)
+ {
+ for (AudioEncryption mode : AudioEncryption.values())
+ {
+ if (supportedModes.contains(mode) && isModeSupported(mode))
+ return mode;
+ }
+
+ return null;
+ }
+
+ static boolean isModeSupported(AudioEncryption mode)
+ {
+ switch (mode)
+ {
+ case AEAD_AES256_GCM_RTPSIZE:
+ return Security.getAlgorithms("Cipher").contains(AES_GCM_NO_PADDING);
+ case AEAD_XCHACHA20_POLY1305_RTPSIZE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static CryptoAdapter getAdapter(AudioEncryption mode, byte[] secretKey)
+ {
+ switch (mode)
+ {
+ case AEAD_AES256_GCM_RTPSIZE:
+ return new CryptoAdapter.AES_GCM_Adapter(secretKey);
+ case AEAD_XCHACHA20_POLY1305_RTPSIZE:
+ return new XChaCha20Poly1305Adapter(secretKey);
+ default:
+ throw new IllegalStateException("Unsupported encryption mode: " + mode);
+ }
+ }
+
+ abstract class AbstractAaedAdapter implements CryptoAdapter
+ {
+ protected static final int nonceBytes = 4;
+ protected static final SecureRandom random = new SecureRandom();
+
+ protected final byte[] secretKey;
+ protected final byte[] nonceBuffer;
+ protected final int tagBytes;
+ protected final int paddedNonceBytes;
+ protected int encryptCounter;
+
+ protected AbstractAaedAdapter(byte[] secretKey, int tagBytes, int paddedNonceBytes)
+ {
+ this.secretKey = secretKey;
+ this.tagBytes = tagBytes;
+ this.paddedNonceBytes = paddedNonceBytes;
+ this.nonceBuffer = new byte[paddedNonceBytes];
+ this.encryptCounter = Math.abs(random.nextInt()) % 513 + 1;
+ }
+
+ @Override
+ public ByteBuffer encrypt(ByteBuffer output, ByteBuffer audio)
+ {
+ int minimumOutputSize = audio.remaining() + this.tagBytes + nonceBytes;
+
+ if (output.remaining() < minimumOutputSize)
+ {
+ ByteBuffer newBuffer = ByteBuffer.allocate(output.capacity() + minimumOutputSize);
+ output.flip();
+ newBuffer.put(output);
+ output = newBuffer;
+ }
+
+ IOUtil.setIntBigEndian(nonceBuffer, 0, encryptCounter);
+
+ try
+ {
+ encryptInternally(output, audio, nonceBuffer);
+ output.putInt(encryptCounter++);
+ return output;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public byte[] decrypt(ByteBuffer packet)
+ {
+ try
+ {
+ int headerLength = packet.position();
+ packet.position(0);
+ byte[] associatedData = new byte[headerLength];
+ packet.get(associatedData);
+ byte[] cipherText = new byte[packet.remaining() - nonceBytes];
+ packet.get(cipherText);
+ byte[] nonce = new byte[paddedNonceBytes];
+ packet.get(nonce, 0, nonceBytes);
+ return decryptInternally(cipherText, associatedData, nonce);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected abstract void encryptInternally(ByteBuffer output, ByteBuffer audio, byte[] nonce) throws Exception;
+ protected abstract byte[] decryptInternally(byte[] cipherText, byte[] associatedData, byte[] nonce) throws Exception;
+
+ protected byte[] getAssociatedData(ByteBuffer output)
+ {
+ return Arrays.copyOfRange(output.array(), output.arrayOffset(), output.arrayOffset() + output.position());
+ }
+
+ protected byte[] getPlaintextCopy(ByteBuffer audio)
+ {
+ return Arrays.copyOfRange(audio.array(), audio.arrayOffset() + audio.position(), audio.arrayOffset() + audio.limit());
+ }
+ }
+
+ class AES_GCM_Adapter extends AbstractAaedAdapter implements CryptoAdapter
+ {
+ public AES_GCM_Adapter(byte[] secretKey)
+ {
+ super(secretKey, 16, 12);
+ }
+
+ @Override
+ public AudioEncryption getMode()
+ {
+ return AudioEncryption.AEAD_AES256_GCM_RTPSIZE;
+ }
+
+ @Override
+ protected void encryptInternally(ByteBuffer output, ByteBuffer audio, byte[] nonce) throws Exception
+ {
+ InsecureNonceAesGcmJce cipher = getCipher();
+ byte[] input = getPlaintextCopy(audio);
+ byte[] associatedData = getAssociatedData(output);
+ output.put(cipher.encrypt(nonce, input, associatedData));
+ }
+
+ @Override
+ public byte[] decryptInternally(byte[] cipherText, byte[] associatedData, byte[] nonce) throws Exception
+ {
+ InsecureNonceAesGcmJce cipher = getCipher();
+ return cipher.decrypt(nonce, cipherText, associatedData);
+ }
+
+ private InsecureNonceAesGcmJce getCipher() throws GeneralSecurityException
+ {
+ return new InsecureNonceAesGcmJce(secretKey);
+ }
+ }
+
+ class XChaCha20Poly1305Adapter extends AbstractAaedAdapter implements CryptoAdapter
+ {
+ public XChaCha20Poly1305Adapter(byte[] secretKey)
+ {
+ super(secretKey, 16, 24);
+ }
+
+ @Override
+ public AudioEncryption getMode()
+ {
+ return AudioEncryption.AEAD_XCHACHA20_POLY1305_RTPSIZE;
+ }
+
+ @Override
+ public void encryptInternally(ByteBuffer output, ByteBuffer audio, byte[] nonce) throws Exception
+ {
+ InsecureNonceXChaCha20Poly1305 cipher = getCipher();
+ byte[] input = getPlaintextCopy(audio);
+ byte[] associatedData = getAssociatedData(output);
+ output.put(cipher.encrypt(nonce, input, associatedData));
+ }
+
+ @Override
+ public byte[] decryptInternally(byte[] cipherText, byte[] associatedData, byte[] nonce) throws Exception
+ {
+ InsecureNonceXChaCha20Poly1305 cipher = getCipher();
+ return cipher.decrypt(nonce, cipherText, associatedData);
+ }
+
+ private InsecureNonceXChaCha20Poly1305 getCipher() throws GeneralSecurityException
+ {
+ return new InsecureNonceXChaCha20Poly1305(secretKey);
+ }
+ }
+}
diff --git a/src/test/java/net/dv8tion/jda/test/audio/CryptoAdapterTest.java b/src/test/java/net/dv8tion/jda/test/audio/CryptoAdapterTest.java
new file mode 100644
index 0000000000..b342ecebe0
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/audio/CryptoAdapterTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dv8tion.jda.test.audio;
+
+import net.dv8tion.jda.internal.audio.AudioEncryption;
+import net.dv8tion.jda.internal.audio.AudioPacket;
+import net.dv8tion.jda.internal.audio.CryptoAdapter;
+import org.junit.jupiter.api.Test;
+
+import java.net.DatagramPacket;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CryptoAdapterTest
+{
+ private static final String TEST_PAYLOAD = "text";
+ private static final char TEST_SEQ = 'a';
+ private static final int TEST_TIMESTAMP = 1234;
+ private static final int TEST_SSRC = 5678;
+ private static final int TEST_EXTENSION = 0xBEDE;
+
+ @Test
+ void minimalAES()
+ {
+ AudioPacket original = getMinimalPacket();
+ byte[] key = getKey();
+
+ CryptoAdapter adapter = CryptoAdapter.getAdapter(AudioEncryption.AEAD_AES256_GCM_RTPSIZE, key);
+ doRoundTripAndAssertPayload(adapter, original);
+ }
+
+ @Test
+ void minimalXChaCha20()
+ {
+ AudioPacket original = getMinimalPacket();
+ byte[] key = getKey();
+
+ CryptoAdapter adapter = CryptoAdapter.getAdapter(AudioEncryption.AEAD_XCHACHA20_POLY1305_RTPSIZE, key);
+ doRoundTripAndAssertPayload(adapter, original);
+ }
+
+ @Test
+ void extendedAES()
+ {
+ AudioPacket original = getPacketWithExtension();
+ byte[] key = getKey();
+
+ CryptoAdapter adapter = CryptoAdapter.getAdapter(AudioEncryption.AEAD_AES256_GCM_RTPSIZE, key);
+ doRoundTripAndAssertPayload(adapter, original);
+ }
+
+ @Test
+ void extendedXChaCha20()
+ {
+ AudioPacket original = getPacketWithExtension();
+ byte[] key = getKey();
+
+ CryptoAdapter adapter = CryptoAdapter.getAdapter(AudioEncryption.AEAD_XCHACHA20_POLY1305_RTPSIZE, key);
+ doRoundTripAndAssertPayload(adapter, original);
+ }
+
+ private void doRoundTripAndAssertPayload(CryptoAdapter adapter, AudioPacket original)
+ {
+ ByteBuffer buffer = ByteBuffer.allocate(512);
+ buffer = original.asEncryptedPacket(adapter, buffer);
+
+ AudioPacket decrypted = AudioPacket.decryptAudioPacket(adapter, new DatagramPacket(buffer.array(), buffer.position(), buffer.limit()));
+
+ byte[] payload = new byte[4];
+ decrypted.getEncodedAudio().get(payload);
+
+ assertThat(new String(payload, StandardCharsets.UTF_8))
+ .isEqualTo(TEST_PAYLOAD);
+
+ assertThat(decrypted.getSequence()).isEqualTo(TEST_SEQ);
+ assertThat(decrypted.getTimestamp()).isEqualTo(TEST_TIMESTAMP);
+ assertThat(decrypted.getSSRC()).isEqualTo(TEST_SSRC);
+ }
+
+ private static AudioPacket getMinimalPacket()
+ {
+ ByteBuffer rawPacket = ByteBuffer.allocate(12 + 4);
+
+ rawPacket.put(AudioPacket.RTP_VERSION_PAD_EXTEND);
+ rawPacket.put(AudioPacket.RTP_PAYLOAD_TYPE);
+ rawPacket.putChar(TEST_SEQ);
+ rawPacket.putInt(TEST_TIMESTAMP);
+ rawPacket.putInt(TEST_SSRC);
+ rawPacket.put(TEST_PAYLOAD.getBytes(StandardCharsets.UTF_8));
+
+ return new AudioPacket(rawPacket.array());
+ }
+
+ private static AudioPacket getPacketWithExtension()
+ {
+ ByteBuffer rawPacket = ByteBuffer.allocate(16 + 4);
+
+ rawPacket.put((byte) (AudioPacket.RTP_VERSION_PAD_EXTEND | 0x10));
+ rawPacket.put(AudioPacket.RTP_PAYLOAD_TYPE);
+ rawPacket.putChar(TEST_SEQ);
+ rawPacket.putInt(TEST_TIMESTAMP);
+ rawPacket.putInt(TEST_SSRC);
+ rawPacket.putInt(TEST_EXTENSION);
+ rawPacket.put(TEST_PAYLOAD.getBytes(StandardCharsets.UTF_8));
+
+ return new AudioPacket(rawPacket.array());
+ }
+
+ private static byte[] getKey()
+ {
+ SecureRandom random = new SecureRandom();
+ byte[] key = new byte[32];
+ random.nextBytes(key);
+ return key;
+ }
+}