From 591e28ca6ee6085dcab953b2e6fd401e4549b7d9 Mon Sep 17 00:00:00 2001 From: carbotaniuman Date: Sat, 22 Aug 2020 03:23:18 +0000 Subject: [PATCH] No libsodium --- CHANGELOG.md | 11 +- Dockerfile | 2 +- build.gradle | 3 - .../java/mdnet/security/TweetNaclFast.java | 3425 +++++++++++++++++ src/main/kotlin/mdnet/base/Constants.kt | 2 +- .../kotlin/mdnet/base/server/ImageServer.kt | 26 +- .../base/server/{naclbox.kt => crypto.kt} | 21 - 7 files changed, 3451 insertions(+), 39 deletions(-) create mode 100644 src/main/java/mdnet/security/TweetNaclFast.java rename src/main/kotlin/mdnet/base/server/{naclbox.kt => crypto.kt} (60%) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa653bf..770f4e2 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Security +## [1.2.2] - 2020-08-21 +### Changed +- [2020-08-11] Moved to a Java implementation of NaCl [@carbotaniuman]. + +### Fixed +- [2020-08-11] Revert WebUI changes in 1.2.1 [@carbotaniuman]. + + ## [1.2.1] - 2020-08-11 ### Added - [2020-08-11] New CLI for specifying database location, cache folder, and settings [@carbotaniuman]. @@ -234,7 +242,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - [2020-06-11] Tweaked logging configuration to reduce log file sizes by [@carbotaniuman]. -[Unreleased]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.1...HEAD +[Unreleased]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.2...HEAD +[1.2.1]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.1...1.2.2 [1.2.1]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.0...1.2.1 [1.2.0]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.1.5...1.2.0 [1.1.5]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.1.4...1.1.5 diff --git a/Dockerfile b/Dockerfile index f357dc6..e0bd3e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM openjdk:15-alpine WORKDIR /mangahome COPY /build/libs/mangadex_at_home.jar . -RUN apk update && apk add --no-cache libsodium +RUN apk update VOLUME "/mangahome/cache" EXPOSE 443 8080 CMD java -Dfile-level=off -Dstdout-level=trace -jar mangadex_at_home.jar \ No newline at end of file diff --git a/build.gradle b/build.gradle index 999f6e9..4808a71 100644 --- a/build.gradle +++ b/build.gradle @@ -44,9 +44,6 @@ dependencies { implementation group: "org.xerial", name: "sqlite-jdbc", version: "3.30.1" - implementation "com.goterl.lazycode:lazysodium-java:4.3.0" - implementation "net.java.dev.jna:jna:5.5.0" - implementation "info.picocli:picocli:4.5.0" kapt "info.picocli:picocli-codegen:4.5.0" } diff --git a/src/main/java/mdnet/security/TweetNaclFast.java b/src/main/java/mdnet/security/TweetNaclFast.java new file mode 100644 index 0000000..ae09315 --- /dev/null +++ b/src/main/java/mdnet/security/TweetNaclFast.java @@ -0,0 +1,3425 @@ +// Copyright (c) 2014-present Tom Zhou + +package mdnet.security; + +import java.io.UnsupportedEncodingException; +import java.security.SecureRandom; +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) { + /// core(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) { + /// core(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; + + /* + * backport from tweetnacl-fast.js + * https://github.com/dchest/tweetnacl-js/releases/tag/v0.14.3 <<< "The issue + * was not properly detecting if st->h was >= 2^130 - 5, coupled with [testing + * mistake] not catching the failure. The chance of the bug affecting anything + * in the real world is essentially zero luckily, but it's good to have it + * fixed." >>> + */ + /// change mask = (g[9] >>> ((2 * 8) - 1)) - 1; to as + mask = (c ^ 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 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/kotlin/mdnet/base/Constants.kt b/src/main/kotlin/mdnet/base/Constants.kt index 4978e0e..d5ca3a0 100644 --- a/src/main/kotlin/mdnet/base/Constants.kt +++ b/src/main/kotlin/mdnet/base/Constants.kt @@ -21,7 +21,7 @@ package mdnet.base import java.time.Duration object Constants { - const val CLIENT_BUILD = 18 + const val CLIENT_BUILD = 19 @JvmField val MAX_AGE_CACHE: Duration = Duration.ofDays(14) diff --git a/src/main/kotlin/mdnet/base/server/ImageServer.kt b/src/main/kotlin/mdnet/base/server/ImageServer.kt index e3a455b..7ba01eb 100644 --- a/src/main/kotlin/mdnet/base/server/ImageServer.kt +++ b/src/main/kotlin/mdnet/base/server/ImageServer.kt @@ -25,9 +25,6 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava -import com.goterl.lazycode.lazysodium.exceptions.SodiumException import java.io.BufferedInputStream import java.io.BufferedOutputStream import java.io.File @@ -54,6 +51,7 @@ import mdnet.base.trace import mdnet.base.warn import mdnet.cache.CachingInputStream import mdnet.cache.DiskLruCache +import mdnet.security.TweetNaclFast import org.apache.http.client.config.CookieSpecs import org.apache.http.client.config.RequestConfig import org.apache.http.impl.client.HttpClients @@ -91,6 +89,7 @@ class ImageServer( private val executor = Executors.newCachedThreadPool() fun handler(dataSaver: Boolean, tokenized: Boolean = false): HttpHandler { + val box = TweetNaclFast.SecretBox(remoteSettings.tokenKey) return baseHandler().then { request -> val chapterHash = Path.of("chapterHash")(request) val fileName = Path.of("fileName")(request) @@ -114,19 +113,19 @@ class ImageServer( } val token = try { JACKSON.readValue( - try { - SODIUM.cryptoBoxOpenEasyAfterNm( - tokenArr.sliceArray(24 until tokenArr.size), tokenArr.sliceArray(0 until 24), remoteSettings.tokenKey - ) - } catch (_: SodiumException) { - LOGGER.info { "Request for $sanitizedUri rejected for invalid token" } - return@then Response(Status.FORBIDDEN) + box.open(tokenArr.sliceArray(24 until tokenArr.size), tokenArr.sliceArray(0 until 24)).apply { + if (this == null) { + LOGGER.info { "Request for $sanitizedUri rejected for invalid token" } + return@then Response(Status.FORBIDDEN) + } } ) } catch (e: JsonProcessingException) { - LOGGER.info { "Request for $sanitizedUri rejected for invalid token" } + println(e) + LOGGER.info(e) { "Request for $sanitizedUri rejected for invalid token" } return@then Response(Status.FORBIDDEN) } + println(token) if (OffsetDateTime.now().isAfter(token.expires)) { LOGGER.info { "Request for $sanitizedUri rejected for expired token" } @@ -164,6 +163,7 @@ class ImageServer( snapshot.close() LOGGER.warn { "Removing broken cache file for $sanitizedUri" } cache.removeUnsafe(imageId.toCacheId()) + cache.flush() } request.handleCacheMiss(sanitizedUri, getRc4(rc4Bytes), imageId, imageDatum) @@ -276,8 +276,11 @@ class ImageServer( if (editor.getLength(0) == contentLength.toLong()) { LOGGER.info { "Cache download for $sanitizedUri committed" } editor.commit() + println("A") + cache.flush() } else { LOGGER.warn { "Cache download for $sanitizedUri aborted" } + println("B") editor.abort() } } catch (e: Exception) { @@ -317,7 +320,6 @@ class ImageServer( .header("X-Cache", if (cached) "HIT" else "MISS") companion object { - private val SODIUM = LazySodiumJava(SodiumJava()) private val JACKSON: ObjectMapper = jacksonObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .registerModule(JavaTimeModule()) diff --git a/src/main/kotlin/mdnet/base/server/naclbox.kt b/src/main/kotlin/mdnet/base/server/crypto.kt similarity index 60% rename from src/main/kotlin/mdnet/base/server/naclbox.kt rename to src/main/kotlin/mdnet/base/server/crypto.kt index 991de4d..a9fdcfc 100644 --- a/src/main/kotlin/mdnet/base/server/naclbox.kt +++ b/src/main/kotlin/mdnet/base/server/crypto.kt @@ -19,31 +19,10 @@ along with this MangaDex@Home. If not, see . /* ktlint-disable no-wildcard-imports */ package mdnet.base.server -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.exceptions.SodiumException -import com.goterl.lazycode.lazysodium.interfaces.Box import java.security.MessageDigest import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec -@Throws(SodiumException::class) -fun LazySodiumJava.cryptoBoxOpenEasyAfterNm(cipherBytes: ByteArray, nonce: ByteArray, sharedKey: ByteArray): String { - if (!Box.Checker.checkNonce(nonce.size)) { - throw SodiumException("Incorrect nonce length.") - } - - if (!Box.Checker.checkBeforeNmBytes(sharedKey.size)) { - throw SodiumException("Incorrect shared secret key length.") - } - - val message = ByteArray(cipherBytes.size - Box.MACBYTES) - val res: Boolean = cryptoBoxOpenEasyAfterNm(message, cipherBytes, cipherBytes.size.toLong(), nonce, sharedKey) - if (!res) { - throw SodiumException("Could not fully complete shared secret key decryption.") - } - return str(message) -} - fun getRc4(key: ByteArray): Cipher { val rc4 = Cipher.getInstance("RC4") rc4.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "RC4"))