All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.iwebpp.crypto.TweetNaclFast Maven / Gradle / Ivy

Go to download

Java wrapper for the popular chat & VOIP service: Discord https://discord.com

There is a newer version: 5.1.0
Show newest version
/*
 * This is taken from:
 * https://github.com/InstantWebP2P/tweetnacl-java
* All credit goes to the original author. * * Copyright (c) 2014 Tom Zhou */ package com.iwebpp.crypto; import java.io.UnsupportedEncodingException; import java.security.SecureRandom; import java.util.Base64; import java.util.concurrent.atomic.AtomicLong; /* * @description * TweetNacl.c Java porting * */ public final class TweetNaclFast { private final static String TAG = "TweetNaclFast"; /* * @description * Box algorithm, Public-key authenticated encryption * */ public static final class Box { private final static String TAG = "Box"; private AtomicLong nonce; private byte [] theirPublicKey; private byte [] mySecretKey; private byte [] sharedKey; public Box(byte [] theirPublicKey, byte [] mySecretKey) { this(theirPublicKey, mySecretKey, 68); } public Box(byte [] theirPublicKey, byte [] mySecretKey, long nonce) { this.theirPublicKey = theirPublicKey; this.mySecretKey = mySecretKey; this.nonce = new AtomicLong(nonce); // generate pre-computed shared key before(); } public void setNonce(long nonce) { this.nonce.set(nonce); } public long getNonce() { return this.nonce.get(); } public long incrNonce() { return this.nonce.incrementAndGet(); } private byte[] generateNonce() { // generate nonce long nonce = this.nonce.get(); byte [] n = new byte[nonceLength]; for (int i = 0; i < nonceLength; i += 8) { n[i+0] = (byte) (nonce>>> 0); n[i+1] = (byte) (nonce>>> 8); n[i+2] = (byte) (nonce>>>16); n[i+3] = (byte) (nonce>>>24); n[i+4] = (byte) (nonce>>>32); n[i+5] = (byte) (nonce>>>40); n[i+6] = (byte) (nonce>>>48); n[i+7] = (byte) (nonce>>>56); } return n; } /* * @description * Encrypt and authenticates message using peer's public key, * our secret key, and the given nonce, which must be unique * for each distinct message for a key pair. * * Returns an encrypted and authenticated message, * which is nacl.box.overheadLength longer than the original message. * */ public byte [] box(byte [] message) { if (message==null) return null; return box(message, 0, message.length); } public byte [] box(byte [] message, final int moff) { if (!(message!=null && message.length>moff)) return null; return box(message, moff, message.length-moff); } public byte [] box(byte [] message, final int moff, final int mlen) { if (!(message!=null && message.length>=(moff+mlen))) return null; // prepare shared key if (this.sharedKey == null) before(); return after(message, moff, mlen); } /* * @description * Encrypt and authenticates message using peer's public key, * our secret key, and the given nonce, which must be unique * for each distinct message for a key pair. * * Explicitly pass the nonce * * Returns an encrypted and authenticated message, * which is nacl.box.overheadLength longer than the original message. * */ public byte [] box(byte [] message, byte [] theNonce) { if (message==null) return null; return box(message, 0, message.length, theNonce); } public byte [] box(byte [] message, final int moff, byte [] theNonce) { if (!(message!=null && message.length>moff)) return null; return box(message, moff, message.length-moff, theNonce); } public byte [] box(byte [] message, final int moff, final int mlen, byte [] theNonce) { if (!(message!=null && message.length>=(moff+mlen) && theNonce!=null && theNonce.length==nonceLength)) return null; // prepare shared key if (this.sharedKey == null) before(); return after(message, moff, mlen, theNonce); } /* * @description * Authenticates and decrypts the given box with peer's public key, * our secret key, and the given nonce. * * Returns the original message, or null if authentication fails. * */ public byte [] open(byte [] box) { if (box==null) return null; // prepare shared key if (this.sharedKey == null) before(); return open_after(box, 0, box.length); } public byte [] open(byte [] box, final int boxoff) { if (!(box!=null && box.length>boxoff)) return null; // prepare shared key if (this.sharedKey == null) before(); return open_after(box, boxoff, box.length-boxoff); } public byte [] open(byte [] box, final int boxoff, final int boxlen) { if (!(box!=null && box.length>=(boxoff+boxlen))) return null; // prepare shared key if (this.sharedKey == null) before(); return open_after(box, boxoff, boxlen); } /* * @description * Authenticates and decrypts the given box with peer's public key, * our secret key, and the given nonce. * Explicit passing of nonce * Returns the original message, or null if authentication fails. * */ public byte [] open(byte [] box, byte [] theNonce) { if (!(box!=null && theNonce!=null && theNonce.length==nonceLength)) return null; // prepare shared key if (this.sharedKey == null) before(); return open_after(box, 0, box.length, theNonce); } public byte [] open(byte [] box, final int boxoff, byte [] theNonce) { if (!(box!=null && box.length>boxoff && theNonce!=null && theNonce.length==nonceLength)) return null; // prepare shared key if (this.sharedKey == null) before(); return open_after(box, boxoff, box.length-boxoff, theNonce); } public byte [] open(byte [] box, final int boxoff, final int boxlen, byte [] theNonce) { if (!(box!=null && box.length>=(boxoff+boxlen) && theNonce!=null && theNonce.length==nonceLength)) return null; // prepare shared key if (this.sharedKey == null) before(); return open_after(box, boxoff, boxlen, theNonce); } /* * @description * Returns a precomputed shared key * which can be used in nacl.box.after and nacl.box.open.after. * */ public byte [] before() { if (this.sharedKey == null) { this.sharedKey = new byte[sharedKeyLength]; crypto_box_beforenm(this.sharedKey, this.theirPublicKey, this.mySecretKey); } return this.sharedKey; } /* * @description * Same as nacl.box, but uses a shared key precomputed with nacl.box.before. * */ public byte [] after(byte [] message, final int moff, final int mlen) { return after(message, moff, mlen, generateNonce()); } /* * @description * Same as nacl.box, but uses a shared key precomputed with nacl.box.before, * and passes a nonce explicitly. * */ public byte [] after(byte [] message, final int moff, final int mlen, byte [] theNonce) { // check message if (!(message!=null && message.length>=(moff+mlen) && theNonce!=null && theNonce.length==nonceLength)) return null; // message buffer byte [] m = new byte[mlen + zerobytesLength]; // cipher buffer byte [] c = new byte[m.length]; for (int i = 0; i < mlen; i ++) m[i+zerobytesLength] = message[i+moff]; if (0 != crypto_box_afternm(c, m, m.length, theNonce, sharedKey)) return null; // wrap byte_buf_t on c offset@boxzerobytesLength ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength); byte [] ret = new byte[c.length-boxzerobytesLength]; for (int i = 0; i < ret.length; i ++) ret[i] = c[i+boxzerobytesLength]; return ret; } /* * @description * Same as nacl.box.open, * but uses a shared key pre-computed with nacl.box.before. * */ public byte [] open_after(byte [] box, final int boxoff, final int boxlen) { return open_after(box, boxoff, boxlen, generateNonce()); } public byte [] open_after(byte [] box, final int boxoff, final int boxlen, byte [] theNonce) { // check message if (!(box!=null && box.length>=(boxoff+boxlen) && boxlen>=boxzerobytesLength)) return null; // cipher buffer byte [] c = new byte[boxlen + boxzerobytesLength]; // message buffer byte [] m = new byte[c.length]; for (int i = 0; i < boxlen; i++) c[i+boxzerobytesLength] = box[i+boxoff]; if (crypto_box_open_afternm(m, c, c.length, theNonce, sharedKey) != 0) return null; // wrap byte_buf_t on m offset@zerobytesLength ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength); byte [] ret = new byte[m.length-zerobytesLength]; for (int i = 0; i < ret.length; i ++) ret[i] = m[i+zerobytesLength]; return ret; } /* * @description * Length of public key in bytes. * */ public static final int publicKeyLength = 32; /* * @description * Length of secret key in bytes. * */ public static final int secretKeyLength = 32; /* * @description * Length of precomputed shared key in bytes. * */ public static final int sharedKeyLength = 32; /* * @description * Length of nonce in bytes. * */ public static final int nonceLength = 24; /* * @description * zero bytes in case box * */ public static final int zerobytesLength = 32; /* * @description * zero bytes in case open box * */ public static final int boxzerobytesLength = 16; /* * @description * Length of overhead added to box compared to original message. * */ public static final int overheadLength = 16; public static class KeyPair { private byte [] publicKey; private byte [] secretKey; public KeyPair() { publicKey = new byte[publicKeyLength]; secretKey = new byte[secretKeyLength]; } public byte [] getPublicKey() { return publicKey; } public byte [] getSecretKey() { return secretKey; } } /* * @description * Generates a new random key pair for box and * returns it as an object with publicKey and secretKey members: * */ public static KeyPair keyPair() { KeyPair kp = new KeyPair(); crypto_box_keypair(kp.getPublicKey(), kp.getSecretKey()); return kp; } public static KeyPair keyPair_fromSecretKey(byte [] secretKey) { KeyPair kp = new KeyPair(); byte [] sk = kp.getSecretKey(); byte [] pk = kp.getPublicKey(); // copy sk for (int i = 0; i < sk.length; i ++) sk[i] = secretKey[i]; crypto_scalarmult_base(pk, sk); return kp; } } /* * @description * Secret Box algorithm, secret key * */ public static final class SecretBox { private final static String TAG = "SecretBox"; private AtomicLong nonce; private byte [] key; public SecretBox(byte [] key) { this(key, 68); } public SecretBox(byte [] key, long nonce) { this.key = key; this.nonce = new AtomicLong(nonce); } public void setNonce(long nonce) { this.nonce.set(nonce); } public long getNonce() { return this.nonce.get(); } public long incrNonce() { return this.nonce.incrementAndGet(); } private byte[] generateNonce() { // generate nonce long nonce = this.nonce.get(); byte [] n = new byte[nonceLength]; for (int i = 0; i < nonceLength; i += 8) { n[i+0] = (byte) (nonce>>> 0); n[i+1] = (byte) (nonce>>> 8); n[i+2] = (byte) (nonce>>>16); n[i+3] = (byte) (nonce>>>24); n[i+4] = (byte) (nonce>>>32); n[i+5] = (byte) (nonce>>>40); n[i+6] = (byte) (nonce>>>48); n[i+7] = (byte) (nonce>>>56); } return n; } /* * @description * Encrypt and authenticates message using the key and the nonce. * The nonce must be unique for each distinct message for this key. * * Returns an encrypted and authenticated message, * which is nacl.secretbox.overheadLength longer than the original message. * */ public byte [] box(byte [] message) { if (message==null) return null; return box(message, 0, message.length); } public byte [] box(byte [] message, final int moff) { if (!(message!=null && message.length>moff)) return null; return box(message, moff, message.length-moff); } public byte [] box(byte [] message, final int moff, final int mlen) { // check message if (!(message!=null && message.length>=(moff+mlen))) return null; return box(message, moff, message.length-moff, generateNonce()); } public byte [] box(byte [] message, byte [] theNonce) { if (message==null) return null; return box(message, 0, message.length, theNonce); } public byte [] box(byte [] message, final int moff, byte [] theNonce) { if (!(message!=null && message.length>moff)) return null; return box(message, moff, message.length-moff, theNonce); } public byte [] box(byte [] message, final int moff, final int mlen, byte [] theNonce) { // check message if (!(message!=null && message.length>=(moff+mlen) && theNonce!=null && theNonce.length==nonceLength)) return null; // message buffer byte [] m = new byte[mlen + zerobytesLength]; // cipher buffer byte [] c = new byte[m.length]; for (int i = 0; i < mlen; i ++) m[i+zerobytesLength] = message[i+moff]; if (0 != crypto_secretbox(c, m, m.length, theNonce, key)) return null; // TBD optimizing ... // wrap byte_buf_t on c offset@boxzerobytesLength ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength); byte [] ret = new byte[c.length-boxzerobytesLength]; for (int i = 0; i < ret.length; i ++) ret[i] = c[i+boxzerobytesLength]; return ret; } /* * @description * Authenticates and decrypts the given secret box * using the key and the nonce. * * Returns the original message, or null if authentication fails. * */ public byte [] open(byte [] box) { if (box==null) return null; return open(box, 0, box.length); } public byte [] open(byte [] box, final int boxoff) { if (!(box!=null && box.length>boxoff)) return null; return open(box, boxoff, box.length-boxoff); } public byte [] open(byte [] box, final int boxoff, final int boxlen) { // check message if (!(box!=null && box.length>=(boxoff+boxlen) && boxlen>=boxzerobytesLength)) return null; return open(box, boxoff, box.length-boxoff, generateNonce()); } public byte [] open(byte [] box, byte [] theNonce) { if (box==null) return null; return open(box, 0, box.length, theNonce); } public byte [] open(byte [] box, final int boxoff, byte [] theNonce) { if (!(box!=null && box.length>boxoff)) return null; return open(box, boxoff, box.length-boxoff, theNonce); } public byte [] open(byte [] box, final int boxoff, final int boxlen, byte [] theNonce) { // check message if (!(box!=null && box.length>=(boxoff+boxlen) && boxlen>=boxzerobytesLength && theNonce!=null && theNonce.length==nonceLength)) return null; // cipher buffer byte [] c = new byte[boxlen + boxzerobytesLength]; // message buffer byte [] m = new byte[c.length]; for (int i = 0; i < boxlen; i++) c[i+boxzerobytesLength] = box[i+boxoff]; if (0 != crypto_secretbox_open(m, c, c.length, theNonce, key)) return null; // wrap byte_buf_t on m offset@zerobytesLength ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength); byte [] ret = new byte[m.length-zerobytesLength]; for (int i = 0; i < ret.length; i ++) ret[i] = m[i+zerobytesLength]; return ret; } /* * @description * Length of key in bytes. * */ public static final int keyLength = 32; /* * @description * Length of nonce in bytes. * */ public static final int nonceLength = 24; /* * @description * Length of overhead added to secret box compared to original message. * */ public static final int overheadLength = 16; /* * @description * zero bytes in case box * */ public static final int zerobytesLength = 32; /* * @description * zero bytes in case open box * */ public static final int boxzerobytesLength = 16; } /* * @description * Scalar multiplication, Implements curve25519. * */ public static final class ScalarMult { private final static String TAG = "ScalarMult"; /* * @description * Multiplies an integer n by a group element p and * returns the resulting group element. * */ public static byte [] scalseMult(byte [] n, byte [] p) { if (!(n.length==scalarLength && p.length==groupElementLength)) return null; byte [] q = new byte [scalarLength]; crypto_scalarmult(q, n, p); return q; } /* * @description * Multiplies an integer n by a standard group element and * returns the resulting group element. * */ public static byte [] scalseMult_base(byte [] n) { if (!(n.length==scalarLength)) return null; byte [] q = new byte [scalarLength]; crypto_scalarmult_base(q, n); return q; } /* * @description * Length of scalar in bytes. * */ public static final int scalarLength = 32; /* * @description * Length of group element in bytes. * */ public static final int groupElementLength = 32; } /* * @description * Hash algorithm, Implements SHA-512. * */ public static final class Hash { private final static String TAG = "Hash"; /* * @description * Returns SHA-512 hash of the message. * */ public static byte[] sha512(byte [] message) { if (!(message!=null && message.length>0)) return null; byte [] out = new byte[hashLength]; crypto_hash(out, message); return out; } public static byte[] sha512(String message) throws UnsupportedEncodingException { return sha512(message.getBytes("utf-8")); } /* * @description * Length of hash in bytes. * */ public static final int hashLength = 64; } /* * @description * Signature algorithm, Implements ed25519. * */ public static final class Signature { private final static String TAG = "Signature"; private byte [] theirPublicKey; private byte [] mySecretKey; public Signature(byte [] theirPublicKey, byte [] mySecretKey) { this.theirPublicKey = theirPublicKey; this.mySecretKey = mySecretKey; } /* * @description * Signs the message using the secret key and returns a signed message. * */ public byte [] sign(byte [] message) { if (message==null) return null; return sign(message, 0, message.length); } public byte [] sign(byte [] message, final int moff) { if (!(message!=null && message.length>moff)) return null; return sign(message, moff, message.length-moff); } public byte [] sign(byte [] message, final int moff, final int mlen) { // check message if (!(message!=null && message.length>=(moff+mlen))) return null; // signed message byte [] sm = new byte[mlen + signatureLength]; crypto_sign(sm, -1, message, moff, mlen, mySecretKey); return sm; } /* * @description * Verifies the signed message and returns the message without signature. * Returns null if verification failed. * */ public byte [] open(byte [] signedMessage) { if (signedMessage==null) return null; return open(signedMessage, 0, signedMessage.length); } public byte [] open(byte [] signedMessage, final int smoff) { if (!(signedMessage!=null && signedMessage.length>smoff)) return null; return open(signedMessage, smoff, signedMessage.length-smoff); } public byte [] open(byte [] signedMessage, final int smoff, final int smlen) { // check sm length if (!(signedMessage!=null && signedMessage.length>=(smoff+smlen) && smlen>=signatureLength)) return null; // temp buffer byte [] tmp = new byte[smlen]; if (0 != crypto_sign_open(tmp, -1, signedMessage, smoff, smlen, theirPublicKey)) return null; // message byte [] msg = new byte[smlen-signatureLength]; for (int i = 0; i < msg.length; i ++) msg[i] = signedMessage[smoff+ i+signatureLength]; return msg; } /* * @description * Signs the message using the secret key and returns a signature. * */ public byte [] detached(byte [] message) { byte[] signedMsg = this.sign(message); byte[] sig = new byte[signatureLength]; for (int i = 0; i < sig.length; i++) sig[i] = signedMsg[i]; return sig; } /* * @description * Verifies the signature for the message and * returns true if verification succeeded or false if it failed. * */ public boolean detached_verify(byte [] message, byte [] signature) { if (signature.length != signatureLength) return false; if (theirPublicKey.length != publicKeyLength) return false; byte [] sm = new byte[signatureLength + message.length]; byte [] m = new byte[signatureLength + message.length]; for (int i = 0; i < signatureLength; i++) sm[i] = signature[i]; for (int i = 0; i < message.length; i++) sm[i + signatureLength] = message[i]; return (crypto_sign_open(m, -1, sm, 0, sm.length, theirPublicKey) >= 0); } /* * @description * Generates new random key pair for signing and * returns it as an object with publicKey and secretKey members * */ public static class KeyPair { private byte [] publicKey; private byte [] secretKey; public KeyPair() { publicKey = new byte[publicKeyLength]; secretKey = new byte[secretKeyLength]; } public byte [] getPublicKey() { return publicKey; } public byte [] getSecretKey() { return secretKey; } } /* * @description * Signs the message using the secret key and returns a signed message. * */ public static KeyPair keyPair() { KeyPair kp = new KeyPair(); crypto_sign_keypair(kp.getPublicKey(), kp.getSecretKey(), false); return kp; } public static KeyPair keyPair_fromSecretKey(byte [] secretKey) { KeyPair kp = new KeyPair(); byte [] pk = kp.getPublicKey(); byte [] sk = kp.getSecretKey(); // copy sk for (int i = 0; i < kp.getSecretKey().length; i ++) sk[i] = secretKey[i]; // copy pk from sk for (int i = 0; i < kp.getPublicKey().length; i ++) pk[i] = secretKey[32+i]; // hard-copy return kp; } public static KeyPair keyPair_fromSeed(byte [] seed) { KeyPair kp = new KeyPair(); byte [] pk = kp.getPublicKey(); byte [] sk = kp.getSecretKey(); // copy sk for (int i = 0; i < seedLength; i ++) sk[i] = seed[i]; // generate pk from sk crypto_sign_keypair(pk, sk, true); return kp; } /* * @description * Length of signing public key in bytes. * */ public static final int publicKeyLength = 32; /* * @description * Length of signing secret key in bytes. * */ public static final int secretKeyLength = 64; /* * @description * Length of seed for nacl.sign.keyPair.fromSeed in bytes. * */ public static final int seedLength = 32; /* * @description * Length of signature in bytes. * */ public static final int signatureLength = 64; } //////////////////////////////////////////////////////////////////////////////////// /* * @description * Codes below are ported tweetnacl-fast.js from TweetNacl.c/TweetNacl.h * */ private static final byte [] _0 = new byte[16]; private static final byte [] _9 = new byte[32]; static { ///for (int i = 0; i < _0.length; i ++) _0[i] = 0; ///for (int i = 0; i < _9.length; i ++) _9[i] = 0; _9[0] = 9; } private static final long [] gf0 = new long[16]; private static final long [] gf1 = new long[16]; private static final long [] _121665 = new long[16]; static { ///for (int i = 0; i < gf0.length; i ++) gf0[i] = 0; ///for (int i = 0; i < gf1.length; i ++) gf1[i] = 0; gf1[0] = 1; ///for (int i = 0; i < _121665.length; i ++) _121665[i] = 0; _121665[0] = 0xDB41; _121665[1] = 1; } private static final long [] D = new long [] { 0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203 }; private static final long [] D2 = new long [] { 0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406 }; private static final long [] X = new long [] { 0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169 }; private static final long [] Y = new long [] { 0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666 }; private static final long [] I = new long [] { 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83 }; private static void ts64(byte [] x, final int xoff, long u) { ///int i; ///for (i = 7;i >= 0;--i) { x[i+xoff] = (byte)(u&0xff); u >>>= 8; } x[7+xoff] = (byte)(u&0xff); u >>>= 8; x[6+xoff] = (byte)(u&0xff); u >>>= 8; x[5+xoff] = (byte)(u&0xff); u >>>= 8; x[4+xoff] = (byte)(u&0xff); u >>>= 8; x[3+xoff] = (byte)(u&0xff); u >>>= 8; x[2+xoff] = (byte)(u&0xff); u >>>= 8; x[1+xoff] = (byte)(u&0xff); u >>>= 8; x[0+xoff] = (byte)(u&0xff); ///u >>>= 8; } private static int vn( byte [] x, final int xoff, byte [] y, final int yoff, int n) { int i,d = 0; for (i = 0; i < n; i ++) d |= (x[i+xoff]^y[i+yoff]) & 0xff; return (1 & ((d - 1) >>> 8)) - 1; } private static int crypto_verify_16( byte [] x, final int xoff, byte [] y, final int yoff) { return vn(x,xoff,y,yoff,16); } public static int crypto_verify_16(byte [] x, byte [] y) { return crypto_verify_16(x,0, y,0); } private static int crypto_verify_32( byte [] x, final int xoff, byte [] y, final int yoff) { return vn(x,xoff,y,yoff,32); } public static int crypto_verify_32(byte [] x, byte [] y) { return crypto_verify_32(x,0, y,0); } private static void core_salsa20(byte [] o, byte [] p, byte [] k, byte [] c) { int j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; int x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, x15 = j15, u; for (int i = 0; i < 20; i += 2) { u = x0 + x12 | 0; x4 ^= u<<7 | u>>>(32-7); u = x4 + x0 | 0; x8 ^= u<<9 | u>>>(32-9); u = x8 + x4 | 0; x12 ^= u<<13 | u>>>(32-13); u = x12 + x8 | 0; x0 ^= u<<18 | u>>>(32-18); u = x5 + x1 | 0; x9 ^= u<<7 | u>>>(32-7); u = x9 + x5 | 0; x13 ^= u<<9 | u>>>(32-9); u = x13 + x9 | 0; x1 ^= u<<13 | u>>>(32-13); u = x1 + x13 | 0; x5 ^= u<<18 | u>>>(32-18); u = x10 + x6 | 0; x14 ^= u<<7 | u>>>(32-7); u = x14 + x10 | 0; x2 ^= u<<9 | u>>>(32-9); u = x2 + x14 | 0; x6 ^= u<<13 | u>>>(32-13); u = x6 + x2 | 0; x10 ^= u<<18 | u>>>(32-18); u = x15 + x11 | 0; x3 ^= u<<7 | u>>>(32-7); u = x3 + x15 | 0; x7 ^= u<<9 | u>>>(32-9); u = x7 + x3 | 0; x11 ^= u<<13 | u>>>(32-13); u = x11 + x7 | 0; x15 ^= u<<18 | u>>>(32-18); u = x0 + x3 | 0; x1 ^= u<<7 | u>>>(32-7); u = x1 + x0 | 0; x2 ^= u<<9 | u>>>(32-9); u = x2 + x1 | 0; x3 ^= u<<13 | u>>>(32-13); u = x3 + x2 | 0; x0 ^= u<<18 | u>>>(32-18); u = x5 + x4 | 0; x6 ^= u<<7 | u>>>(32-7); u = x6 + x5 | 0; x7 ^= u<<9 | u>>>(32-9); u = x7 + x6 | 0; x4 ^= u<<13 | u>>>(32-13); u = x4 + x7 | 0; x5 ^= u<<18 | u>>>(32-18); u = x10 + x9 | 0; x11 ^= u<<7 | u>>>(32-7); u = x11 + x10 | 0; x8 ^= u<<9 | u>>>(32-9); u = x8 + x11 | 0; x9 ^= u<<13 | u>>>(32-13); u = x9 + x8 | 0; x10 ^= u<<18 | u>>>(32-18); u = x15 + x14 | 0; x12 ^= u<<7 | u>>>(32-7); u = x12 + x15 | 0; x13 ^= u<<9 | u>>>(32-9); u = x13 + x12 | 0; x14 ^= u<<13 | u>>>(32-13); u = x14 + x13 | 0; x15 ^= u<<18 | u>>>(32-18); } x0 = x0 + j0 | 0; x1 = x1 + j1 | 0; x2 = x2 + j2 | 0; x3 = x3 + j3 | 0; x4 = x4 + j4 | 0; x5 = x5 + j5 | 0; x6 = x6 + j6 | 0; x7 = x7 + j7 | 0; x8 = x8 + j8 | 0; x9 = x9 + j9 | 0; x10 = x10 + j10 | 0; x11 = x11 + j11 | 0; x12 = x12 + j12 | 0; x13 = x13 + j13 | 0; x14 = x14 + j14 | 0; x15 = x15 + j15 | 0; o[ 0] = (byte) (x0 >>> 0 & 0xff); o[ 1] = (byte) (x0 >>> 8 & 0xff); o[ 2] = (byte) (x0 >>> 16 & 0xff); o[ 3] = (byte) (x0 >>> 24 & 0xff); o[ 4] = (byte) (x1 >>> 0 & 0xff); o[ 5] = (byte) (x1 >>> 8 & 0xff); o[ 6] = (byte) (x1 >>> 16 & 0xff); o[ 7] = (byte) (x1 >>> 24 & 0xff); o[ 8] = (byte) (x2 >>> 0 & 0xff); o[ 9] = (byte) (x2 >>> 8 & 0xff); o[10] = (byte) (x2 >>> 16 & 0xff); o[11] = (byte) (x2 >>> 24 & 0xff); o[12] = (byte) (x3 >>> 0 & 0xff); o[13] = (byte) (x3 >>> 8 & 0xff); o[14] = (byte) (x3 >>> 16 & 0xff); o[15] = (byte) (x3 >>> 24 & 0xff); o[16] = (byte) (x4 >>> 0 & 0xff); o[17] = (byte) (x4 >>> 8 & 0xff); o[18] = (byte) (x4 >>> 16 & 0xff); o[19] = (byte) (x4 >>> 24 & 0xff); o[20] = (byte) (x5 >>> 0 & 0xff); o[21] = (byte) (x5 >>> 8 & 0xff); o[22] = (byte) (x5 >>> 16 & 0xff); o[23] = (byte) (x5 >>> 24 & 0xff); o[24] = (byte) (x6 >>> 0 & 0xff); o[25] = (byte) (x6 >>> 8 & 0xff); o[26] = (byte) (x6 >>> 16 & 0xff); o[27] = (byte) (x6 >>> 24 & 0xff); o[28] = (byte) (x7 >>> 0 & 0xff); o[29] = (byte) (x7 >>> 8 & 0xff); o[30] = (byte) (x7 >>> 16 & 0xff); o[31] = (byte) (x7 >>> 24 & 0xff); o[32] = (byte) (x8 >>> 0 & 0xff); o[33] = (byte) (x8 >>> 8 & 0xff); o[34] = (byte) (x8 >>> 16 & 0xff); o[35] = (byte) (x8 >>> 24 & 0xff); o[36] = (byte) (x9 >>> 0 & 0xff); o[37] = (byte) (x9 >>> 8 & 0xff); o[38] = (byte) (x9 >>> 16 & 0xff); o[39] = (byte) (x9 >>> 24 & 0xff); o[40] = (byte) (x10 >>> 0 & 0xff); o[41] = (byte) (x10 >>> 8 & 0xff); o[42] = (byte) (x10 >>> 16 & 0xff); o[43] = (byte) (x10 >>> 24 & 0xff); o[44] = (byte) (x11 >>> 0 & 0xff); o[45] = (byte) (x11 >>> 8 & 0xff); o[46] = (byte) (x11 >>> 16 & 0xff); o[47] = (byte) (x11 >>> 24 & 0xff); o[48] = (byte) (x12 >>> 0 & 0xff); o[49] = (byte) (x12 >>> 8 & 0xff); o[50] = (byte) (x12 >>> 16 & 0xff); o[51] = (byte) (x12 >>> 24 & 0xff); o[52] = (byte) (x13 >>> 0 & 0xff); o[53] = (byte) (x13 >>> 8 & 0xff); o[54] = (byte) (x13 >>> 16 & 0xff); o[55] = (byte) (x13 >>> 24 & 0xff); o[56] = (byte) (x14 >>> 0 & 0xff); o[57] = (byte) (x14 >>> 8 & 0xff); o[58] = (byte) (x14 >>> 16 & 0xff); o[59] = (byte) (x14 >>> 24 & 0xff); o[60] = (byte) (x15 >>> 0 & 0xff); o[61] = (byte) (x15 >>> 8 & 0xff); o[62] = (byte) (x15 >>> 16 & 0xff); o[63] = (byte) (x15 >>> 24 & 0xff); /*String dbgt = ""; for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg]; Log.d(TAG, "core_salsa20 -> "+dbgt); */ } private static void core_hsalsa20(byte [] o, byte [] p, byte [] k, byte [] c) { int j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; int x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, x15 = j15, u; for (int i = 0; i < 20; i += 2) { u = x0 + x12 | 0; x4 ^= u<<7 | u>>>(32-7); u = x4 + x0 | 0; x8 ^= u<<9 | u>>>(32-9); u = x8 + x4 | 0; x12 ^= u<<13 | u>>>(32-13); u = x12 + x8 | 0; x0 ^= u<<18 | u>>>(32-18); u = x5 + x1 | 0; x9 ^= u<<7 | u>>>(32-7); u = x9 + x5 | 0; x13 ^= u<<9 | u>>>(32-9); u = x13 + x9 | 0; x1 ^= u<<13 | u>>>(32-13); u = x1 + x13 | 0; x5 ^= u<<18 | u>>>(32-18); u = x10 + x6 | 0; x14 ^= u<<7 | u>>>(32-7); u = x14 + x10 | 0; x2 ^= u<<9 | u>>>(32-9); u = x2 + x14 | 0; x6 ^= u<<13 | u>>>(32-13); u = x6 + x2 | 0; x10 ^= u<<18 | u>>>(32-18); u = x15 + x11 | 0; x3 ^= u<<7 | u>>>(32-7); u = x3 + x15 | 0; x7 ^= u<<9 | u>>>(32-9); u = x7 + x3 | 0; x11 ^= u<<13 | u>>>(32-13); u = x11 + x7 | 0; x15 ^= u<<18 | u>>>(32-18); u = x0 + x3 | 0; x1 ^= u<<7 | u>>>(32-7); u = x1 + x0 | 0; x2 ^= u<<9 | u>>>(32-9); u = x2 + x1 | 0; x3 ^= u<<13 | u>>>(32-13); u = x3 + x2 | 0; x0 ^= u<<18 | u>>>(32-18); u = x5 + x4 | 0; x6 ^= u<<7 | u>>>(32-7); u = x6 + x5 | 0; x7 ^= u<<9 | u>>>(32-9); u = x7 + x6 | 0; x4 ^= u<<13 | u>>>(32-13); u = x4 + x7 | 0; x5 ^= u<<18 | u>>>(32-18); u = x10 + x9 | 0; x11 ^= u<<7 | u>>>(32-7); u = x11 + x10 | 0; x8 ^= u<<9 | u>>>(32-9); u = x8 + x11 | 0; x9 ^= u<<13 | u>>>(32-13); u = x9 + x8 | 0; x10 ^= u<<18 | u>>>(32-18); u = x15 + x14 | 0; x12 ^= u<<7 | u>>>(32-7); u = x12 + x15 | 0; x13 ^= u<<9 | u>>>(32-9); u = x13 + x12 | 0; x14 ^= u<<13 | u>>>(32-13); u = x14 + x13 | 0; x15 ^= u<<18 | u>>>(32-18); } o[ 0] = (byte) (x0 >>> 0 & 0xff); o[ 1] = (byte) (x0 >>> 8 & 0xff); o[ 2] = (byte) (x0 >>> 16 & 0xff); o[ 3] = (byte) (x0 >>> 24 & 0xff); o[ 4] = (byte) (x5 >>> 0 & 0xff); o[ 5] = (byte) (x5 >>> 8 & 0xff); o[ 6] = (byte) (x5 >>> 16 & 0xff); o[ 7] = (byte) (x5 >>> 24 & 0xff); o[ 8] = (byte) (x10 >>> 0 & 0xff); o[ 9] = (byte) (x10 >>> 8 & 0xff); o[10] = (byte) (x10 >>> 16 & 0xff); o[11] = (byte) (x10 >>> 24 & 0xff); o[12] = (byte) (x15 >>> 0 & 0xff); o[13] = (byte) (x15 >>> 8 & 0xff); o[14] = (byte) (x15 >>> 16 & 0xff); o[15] = (byte) (x15 >>> 24 & 0xff); o[16] = (byte) (x6 >>> 0 & 0xff); o[17] = (byte) (x6 >>> 8 & 0xff); o[18] = (byte) (x6 >>> 16 & 0xff); o[19] = (byte) (x6 >>> 24 & 0xff); o[20] = (byte) (x7 >>> 0 & 0xff); o[21] = (byte) (x7 >>> 8 & 0xff); o[22] = (byte) (x7 >>> 16 & 0xff); o[23] = (byte) (x7 >>> 24 & 0xff); o[24] = (byte) (x8 >>> 0 & 0xff); o[25] = (byte) (x8 >>> 8 & 0xff); o[26] = (byte) (x8 >>> 16 & 0xff); o[27] = (byte) (x8 >>> 24 & 0xff); o[28] = (byte) (x9 >>> 0 & 0xff); o[29] = (byte) (x9 >>> 8 & 0xff); o[30] = (byte) (x9 >>> 16 & 0xff); o[31] = (byte) (x9 >>> 24 & 0xff); /*String dbgt = ""; for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg]; Log.d(TAG, "core_hsalsa20 -> "+dbgt); */ } public static int crypto_core_salsa20(byte [] out, byte [] in, byte [] k, byte [] c) { ///api(out,in,k,c,0); core_salsa20(out,in,k,c); ///String dbgt = ""; ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg]; ///L/og.d(TAG, "crypto_core_salsa20 -> "+dbgt); return 0; } public static int crypto_core_hsalsa20(byte [] out, byte [] in, byte [] k, byte [] c) { ///api(out,in,k,c,1); core_hsalsa20(out,in,k,c); ///String dbgt = ""; ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg]; ///L/og.d(TAG, "crypto_core_hsalsa20 -> "+dbgt); return 0; } // "expand 32-byte k" private static final byte[] sigma = {101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107}; /*static { try { sigma = "expand 32-byte k".getBytes("utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }*/ private static int crypto_stream_salsa20_xor(byte [] c,int cpos, byte [] m,int mpos, long b, byte [] n, byte [] k) { byte [] z = new byte[16], x = new byte[64]; int u, i; for (i = 0; i < 16; i++) z[i] = 0; for (i = 0; i < 8; i++) z[i] = n[i]; while (b >= 64) { crypto_core_salsa20(x,z,k,sigma); for (i = 0; i < 64; i++) c[cpos+i] = (byte) ((m[mpos+i] ^ x[i]) & 0xff); u = 1; for (i = 8; i < 16; i++) { u = u + (z[i] & 0xff) | 0; z[i] = (byte) (u & 0xff); u >>>= 8; } b -= 64; cpos += 64; mpos += 64; } if (b > 0) { crypto_core_salsa20(x,z,k,sigma); for (i = 0; i < b; i++) c[cpos+i] = (byte) ((m[mpos+i] ^ x[i]) & 0xff); } ///String dbgt = ""; ///for (int dbg = 0; dbg < c.length-cpos; dbg ++) dbgt += " "+c[dbg +cpos]; ///Log.d(TAG, "crypto_stream_salsa20_xor, c -> "+dbgt); return 0; } public static int crypto_stream_salsa20(byte [] c,int cpos, long b, byte [] n, byte [] k) { byte [] z = new byte[16], x = new byte[64]; int u, i; for (i = 0; i < 16; i++) z[i] = 0; for (i = 0; i < 8; i++) z[i] = n[i]; while (b >= 64) { crypto_core_salsa20(x,z,k,sigma); for (i = 0; i < 64; i++) c[cpos+i] = x[i]; u = 1; for (i = 8; i < 16; i++) { u = u + (z[i] & 0xff) | 0; z[i] = (byte) (u & 0xff); u >>>= 8; } b -= 64; cpos += 64; } if (b > 0) { crypto_core_salsa20(x,z,k,sigma); for (i = 0; i < b; i++) c[cpos+i] = x[i]; } ///String dbgt = ""; ///for (int dbg = 0; dbg < c.length-cpos; dbg ++) dbgt += " "+c[dbg +cpos]; ///Log.d(TAG, "crypto_stream_salsa20, c -> "+dbgt); return 0; } public static int crypto_stream(byte [] c,int cpos, long d, byte [] n, byte [] k) { byte [] s = new byte[32]; crypto_core_hsalsa20(s,n,k,sigma); byte [] sn = new byte[8]; for (int i = 0; i < 8; i++) sn[i] = n[i+16]; return crypto_stream_salsa20(c,cpos,d,sn,s); } public static int crypto_stream_xor(byte [] c,int cpos, byte [] m,int mpos, long d, byte [] n, byte [] k) { byte [] s = new byte[32]; /*String dbgt = ""; for (int dbg = 0; dbg < n.length; dbg ++) dbgt += " "+n[dbg]; Log.d(TAG, "crypto_stream_xor, nonce -> "+dbgt); dbgt = ""; for (int dbg = 0; dbg < k.length; dbg ++) dbgt += " "+k[dbg]; Log.d(TAG, "crypto_stream_xor, shk -> "+dbgt); */ crypto_core_hsalsa20(s,n,k,sigma); byte [] sn = new byte[8]; for (int i = 0; i < 8; i++) sn[i] = n[i+16]; return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s); } /* * Port of Andrew Moon's Poly1305-donna-16. Public domain. * https://github.com/floodyberry/poly1305-donna */ public static final class poly1305 { private byte[] buffer; private int[] r; private int[] h; private int[] pad; private int leftover; private int fin; public poly1305(byte [] key) { this.buffer = new byte[16]; this.r = new int[10]; this.h = new int[10]; this.pad = new int[8]; this.leftover = 0; this.fin = 0; int t0, t1, t2, t3, t4, t5, t6, t7; t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; this.r[5] = ((t4 >>> 1)) & 0x1ffe; t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; this.r[9] = ((t7 >>> 5)) & 0x007f; this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; } public poly1305 blocks(byte [] m, int mpos, int bytes) { int hibit = this.fin!=0 ? 0 : (1 << 11); int t0, t1, t2, t3, t4, t5, t6, t7, c; int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; int h0 = this.h[0], h1 = this.h[1], h2 = this.h[2], h3 = this.h[3], h4 = this.h[4], h5 = this.h[5], h6 = this.h[6], h7 = this.h[7], h8 = this.h[8], h9 = this.h[9]; int r0 = this.r[0], r1 = this.r[1], r2 = this.r[2], r3 = this.r[3], r4 = this.r[4], r5 = this.r[5], r6 = this.r[6], r7 = this.r[7], r8 = this.r[8], r9 = this.r[9]; while (bytes >= 16) { t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; h5 += ((t4 >>> 1)) & 0x1fff; t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; h9 += ((t7 >>> 5)) | hibit; c = 0; d0 = c; d0 += h0 * r0; d0 += h1 * (5 * r9); d0 += h2 * (5 * r8); d0 += h3 * (5 * r7); d0 += h4 * (5 * r6); c = (d0 >>> 13); d0 &= 0x1fff; d0 += h5 * (5 * r5); d0 += h6 * (5 * r4); d0 += h7 * (5 * r3); d0 += h8 * (5 * r2); d0 += h9 * (5 * r1); c += (d0 >>> 13); d0 &= 0x1fff; d1 = c; d1 += h0 * r1; d1 += h1 * r0; d1 += h2 * (5 * r9); d1 += h3 * (5 * r8); d1 += h4 * (5 * r7); c = (d1 >>> 13); d1 &= 0x1fff; d1 += h5 * (5 * r6); d1 += h6 * (5 * r5); d1 += h7 * (5 * r4); d1 += h8 * (5 * r3); d1 += h9 * (5 * r2); c += (d1 >>> 13); d1 &= 0x1fff; d2 = c; d2 += h0 * r2; d2 += h1 * r1; d2 += h2 * r0; d2 += h3 * (5 * r9); d2 += h4 * (5 * r8); c = (d2 >>> 13); d2 &= 0x1fff; d2 += h5 * (5 * r7); d2 += h6 * (5 * r6); d2 += h7 * (5 * r5); d2 += h8 * (5 * r4); d2 += h9 * (5 * r3); c += (d2 >>> 13); d2 &= 0x1fff; d3 = c; d3 += h0 * r3; d3 += h1 * r2; d3 += h2 * r1; d3 += h3 * r0; d3 += h4 * (5 * r9); c = (d3 >>> 13); d3 &= 0x1fff; d3 += h5 * (5 * r8); d3 += h6 * (5 * r7); d3 += h7 * (5 * r6); d3 += h8 * (5 * r5); d3 += h9 * (5 * r4); c += (d3 >>> 13); d3 &= 0x1fff; d4 = c; d4 += h0 * r4; d4 += h1 * r3; d4 += h2 * r2; d4 += h3 * r1; d4 += h4 * r0; c = (d4 >>> 13); d4 &= 0x1fff; d4 += h5 * (5 * r9); d4 += h6 * (5 * r8); d4 += h7 * (5 * r7); d4 += h8 * (5 * r6); d4 += h9 * (5 * r5); c += (d4 >>> 13); d4 &= 0x1fff; d5 = c; d5 += h0 * r5; d5 += h1 * r4; d5 += h2 * r3; d5 += h3 * r2; d5 += h4 * r1; c = (d5 >>> 13); d5 &= 0x1fff; d5 += h5 * r0; d5 += h6 * (5 * r9); d5 += h7 * (5 * r8); d5 += h8 * (5 * r7); d5 += h9 * (5 * r6); c += (d5 >>> 13); d5 &= 0x1fff; d6 = c; d6 += h0 * r6; d6 += h1 * r5; d6 += h2 * r4; d6 += h3 * r3; d6 += h4 * r2; c = (d6 >>> 13); d6 &= 0x1fff; d6 += h5 * r1; d6 += h6 * r0; d6 += h7 * (5 * r9); d6 += h8 * (5 * r8); d6 += h9 * (5 * r7); c += (d6 >>> 13); d6 &= 0x1fff; d7 = c; d7 += h0 * r7; d7 += h1 * r6; d7 += h2 * r5; d7 += h3 * r4; d7 += h4 * r3; c = (d7 >>> 13); d7 &= 0x1fff; d7 += h5 * r2; d7 += h6 * r1; d7 += h7 * r0; d7 += h8 * (5 * r9); d7 += h9 * (5 * r8); c += (d7 >>> 13); d7 &= 0x1fff; d8 = c; d8 += h0 * r8; d8 += h1 * r7; d8 += h2 * r6; d8 += h3 * r5; d8 += h4 * r4; c = (d8 >>> 13); d8 &= 0x1fff; d8 += h5 * r3; d8 += h6 * r2; d8 += h7 * r1; d8 += h8 * r0; d8 += h9 * (5 * r9); c += (d8 >>> 13); d8 &= 0x1fff; d9 = c; d9 += h0 * r9; d9 += h1 * r8; d9 += h2 * r7; d9 += h3 * r6; d9 += h4 * r5; c = (d9 >>> 13); d9 &= 0x1fff; d9 += h5 * r4; d9 += h6 * r3; d9 += h7 * r2; d9 += h8 * r1; d9 += h9 * r0; c += (d9 >>> 13); d9 &= 0x1fff; c = (((c << 2) + c)) | 0; c = (c + d0) | 0; d0 = c & 0x1fff; c = (c >>> 13); d1 += c; h0 = d0; h1 = d1; h2 = d2; h3 = d3; h4 = d4; h5 = d5; h6 = d6; h7 = d7; h8 = d8; h9 = d9; mpos += 16; bytes -= 16; } this.h[0] = h0; this.h[1] = h1; this.h[2] = h2; this.h[3] = h3; this.h[4] = h4; this.h[5] = h5; this.h[6] = h6; this.h[7] = h7; this.h[8] = h8; this.h[9] = h9; return this; } public poly1305 finish(byte [] mac, int macpos) { int [] g = new int[10]; int c, mask, f, i; if (this.leftover != 0) { i = this.leftover; this.buffer[i++] = 1; for (; i < 16; i++) this.buffer[i] = 0; this.fin = 1; this.blocks(this.buffer, 0, 16); } c = this.h[1] >>> 13; this.h[1] &= 0x1fff; for (i = 2; i < 10; i++) { this.h[i] += c; c = this.h[i] >>> 13; this.h[i] &= 0x1fff; } this.h[0] += (c * 5); c = this.h[0] >>> 13; this.h[0] &= 0x1fff; this.h[1] += c; c = this.h[1] >>> 13; this.h[1] &= 0x1fff; this.h[2] += c; g[0] = this.h[0] + 5; c = g[0] >>> 13; g[0] &= 0x1fff; for (i = 1; i < 10; i++) { g[i] = this.h[i] + c; c = g[i] >>> 13; g[i] &= 0x1fff; } g[9] -= (1 << 13); g[9] &= 0xffff; mask = (g[9] >>> ((2 * 8) - 1)) - 1; mask &= 0xffff; for (i = 0; i < 10; i++) g[i] &= mask; mask = ~mask; for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; f = this.h[0] + this.pad[0]; this.h[0] = f & 0xffff; for (i = 1; i < 8; i++) { f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; this.h[i] = f & 0xffff; } mac[macpos+ 0] = (byte) ((this.h[0] >>> 0) & 0xff); mac[macpos+ 1] = (byte) ((this.h[0] >>> 8) & 0xff); mac[macpos+ 2] = (byte) ((this.h[1] >>> 0) & 0xff); mac[macpos+ 3] = (byte) ((this.h[1] >>> 8) & 0xff); mac[macpos+ 4] = (byte) ((this.h[2] >>> 0) & 0xff); mac[macpos+ 5] = (byte) ((this.h[2] >>> 8) & 0xff); mac[macpos+ 6] = (byte) ((this.h[3] >>> 0) & 0xff); mac[macpos+ 7] = (byte) ((this.h[3] >>> 8) & 0xff); mac[macpos+ 8] = (byte) ((this.h[4] >>> 0) & 0xff); mac[macpos+ 9] = (byte) ((this.h[4] >>> 8) & 0xff); mac[macpos+10] = (byte) ((this.h[5] >>> 0) & 0xff); mac[macpos+11] = (byte) ((this.h[5] >>> 8) & 0xff); mac[macpos+12] = (byte) ((this.h[6] >>> 0) & 0xff); mac[macpos+13] = (byte) ((this.h[6] >>> 8) & 0xff); mac[macpos+14] = (byte) ((this.h[7] >>> 0) & 0xff); mac[macpos+15] = (byte) ((this.h[7] >>> 8) & 0xff); return this; } public poly1305 update(byte [] m, int mpos, int bytes) { int i, want; if (this.leftover != 0) { want = (16 - this.leftover); if (want > bytes) want = bytes; for (i = 0; i < want; i++) this.buffer[this.leftover + i] = m[mpos+i]; bytes -= want; mpos += want; this.leftover += want; if (this.leftover < 16) return this; this.blocks(buffer, 0, 16); this.leftover = 0; } if (bytes >= 16) { want = bytes - (bytes % 16); this.blocks(m, mpos, want); mpos += want; bytes -= want; } if (bytes != 0) { for (i = 0; i < bytes; i++) this.buffer[this.leftover + i] = m[mpos+i]; this.leftover += bytes; } return this; } } private static int crypto_onetimeauth( byte[] out,final int outpos, byte[] m,final int mpos, int n, byte [] k) { poly1305 s = new poly1305(k); s.update(m, mpos, n); s.finish(out, outpos); /*String dbgt = ""; for (int dbg = 0; dbg < out.length-outpos; dbg ++) dbgt += " "+out[dbg+outpos]; Log.d(TAG, "crypto_onetimeauth -> "+dbgt); */ return 0; } public static int crypto_onetimeauth(byte [] out, byte [] m, int /*long*/ n , byte [] k) { return crypto_onetimeauth(out,0, m,0, n, k); } private static int crypto_onetimeauth_verify( byte[] h,final int hoff, byte[] m,final int moff, int /*long*/ n, byte [] k) { byte [] x = new byte[16]; crypto_onetimeauth(x,0,m,moff,n,k); return crypto_verify_16(h,hoff,x,0); } public static int crypto_onetimeauth_verify(byte [] h, byte [] m, int /*long*/ n, byte [] k) { return crypto_onetimeauth_verify(h,0, m,0, n, k); } public static int crypto_onetimeauth_verify(byte [] h, byte [] m, byte [] k) { return crypto_onetimeauth_verify(h, m, m!=null? m.length:0, k); } public static int crypto_secretbox(byte [] c, byte [] m, int /*long*/ d, byte [] n, byte [] k) { int i; if (d < 32) return -1; crypto_stream_xor(c,0,m,0,d,n,k); crypto_onetimeauth(c,16, c,32, d-32, c); ///for (i = 0; i < 16; i++) c[i] = 0; return 0; } public static int crypto_secretbox_open(byte []m,byte []c,int /*long*/ d,byte []n,byte []k) { int i; byte[] x = new byte[32]; if (d < 32) return -1; crypto_stream(x,0,32,n,k); if (crypto_onetimeauth_verify(c,16, c,32, d-32, x) != 0) return -1; crypto_stream_xor(m,0,c,0,d,n,k); ///for (i = 0; i < 32; i++) m[i] = 0; return 0; } private static void set25519(long [] r, long [] a) { int i; for (i = 0; i < 16; i ++) r[i]=a[i]; } private static void car25519(long [] o) { int i; long v, c = 1; for (i = 0; i < 16; i++) { v = o[i] + c + 65535; c = v>>16; o[i] = v - c * 65536; } o[0] += c-1 + 37 * (c-1); } private static void sel25519( long[] p, long[] q, int b) { sel25519(p,0, q,0, b); } private static void sel25519( long[] p,final int poff, long[] q,final int qoff, int b) { long t, c = ~(b-1); for (int i = 0; i < 16; i++) { t = c & (p[i+poff] ^ q[i+qoff]); p[i+poff] ^= t; q[i+qoff] ^= t; } } private static void pack25519(byte [] o, long [] n,final int noff) { int i, j, b; long [] m = new long[16], t = new long[16]; for (i = 0; i < 16; i++) t[i] = n[i+noff]; car25519(t); car25519(t); car25519(t); for (j = 0; j < 2; j++) { m[0] = t[0] - 0xffed; for (i = 1; i < 15; i++) { m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); m[i-1] &= 0xffff; } m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); b = (int) ((m[15]>>16) & 1); m[14] &= 0xffff; sel25519(t,0, m,0, 1-b); } for (i = 0; i < 16; i++) { o[2*i] = (byte) (t[i] & 0xff); o[2*i+1] = (byte) (t[i]>>8); } } private static int neq25519(long [] a, long [] b) { return neq25519(a,0, b,0); } private static int neq25519(long [] a,final int aoff, long [] b,final int boff) { byte [] c = new byte[32], d = new byte[32]; pack25519(c, a,aoff); pack25519(d, b,boff); return crypto_verify_32(c, 0, d, 0); } private static byte par25519(long [] a) { return par25519(a,0); } private static byte par25519(long [] a,final int aoff) { byte [] d = new byte[32]; pack25519(d, a,aoff); return (byte) (d[0] & 1); } private static void unpack25519(long [] o, byte [] n) { int i; for (i = 0; i < 16; i ++) o[i]=(n[2*i]&0xff)+((long)((n[2*i+1]<<8)&0xffff)); o[15] &= 0x7fff; } private static void A( long [] o, long [] a, long [] b) { A(o,0, a,0, b,0); } private static void A( long [] o,final int ooff, long [] a,final int aoff, long [] b,final int boff) { int i; for (i = 0; i < 16; i ++) o[i+ooff] = a[i+aoff] + b[i+boff]; } private static void Z( long [] o, long [] a, long [] b) { Z(o,0, a,0, b,0); } private static void Z( long [] o,final int ooff, long [] a,final int aoff, long [] b,final int boff) { int i; for (i = 0; i < 16; i ++) o[i+ooff] = a[i+aoff] - b[i+boff]; } private static void M( long [] o, long [] a, long [] b) { M(o,0, a,0, b,0); } private static void M( long [] o,final int ooff, long [] a,final int aoff, long [] b,final int boff) { long v, c, t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, b0 = b[0 +boff], b1 = b[1 +boff], b2 = b[2 +boff], b3 = b[3 +boff], b4 = b[4 +boff], b5 = b[5 +boff], b6 = b[6 +boff], b7 = b[7 +boff], b8 = b[8 +boff], b9 = b[9 +boff], b10 = b[10 +boff], b11 = b[11 +boff], b12 = b[12 +boff], b13 = b[13 +boff], b14 = b[14 +boff], b15 = b[15 +boff]; v = a[0 +aoff]; t0 += v * b0; t1 += v * b1; t2 += v * b2; t3 += v * b3; t4 += v * b4; t5 += v * b5; t6 += v * b6; t7 += v * b7; t8 += v * b8; t9 += v * b9; t10 += v * b10; t11 += v * b11; t12 += v * b12; t13 += v * b13; t14 += v * b14; t15 += v * b15; v = a[1 +aoff]; t1 += v * b0; t2 += v * b1; t3 += v * b2; t4 += v * b3; t5 += v * b4; t6 += v * b5; t7 += v * b6; t8 += v * b7; t9 += v * b8; t10 += v * b9; t11 += v * b10; t12 += v * b11; t13 += v * b12; t14 += v * b13; t15 += v * b14; t16 += v * b15; v = a[2 +aoff]; t2 += v * b0; t3 += v * b1; t4 += v * b2; t5 += v * b3; t6 += v * b4; t7 += v * b5; t8 += v * b6; t9 += v * b7; t10 += v * b8; t11 += v * b9; t12 += v * b10; t13 += v * b11; t14 += v * b12; t15 += v * b13; t16 += v * b14; t17 += v * b15; v = a[3 +aoff]; t3 += v * b0; t4 += v * b1; t5 += v * b2; t6 += v * b3; t7 += v * b4; t8 += v * b5; t9 += v * b6; t10 += v * b7; t11 += v * b8; t12 += v * b9; t13 += v * b10; t14 += v * b11; t15 += v * b12; t16 += v * b13; t17 += v * b14; t18 += v * b15; v = a[4 +aoff]; t4 += v * b0; t5 += v * b1; t6 += v * b2; t7 += v * b3; t8 += v * b4; t9 += v * b5; t10 += v * b6; t11 += v * b7; t12 += v * b8; t13 += v * b9; t14 += v * b10; t15 += v * b11; t16 += v * b12; t17 += v * b13; t18 += v * b14; t19 += v * b15; v = a[5 +aoff]; t5 += v * b0; t6 += v * b1; t7 += v * b2; t8 += v * b3; t9 += v * b4; t10 += v * b5; t11 += v * b6; t12 += v * b7; t13 += v * b8; t14 += v * b9; t15 += v * b10; t16 += v * b11; t17 += v * b12; t18 += v * b13; t19 += v * b14; t20 += v * b15; v = a[6 +aoff]; t6 += v * b0; t7 += v * b1; t8 += v * b2; t9 += v * b3; t10 += v * b4; t11 += v * b5; t12 += v * b6; t13 += v * b7; t14 += v * b8; t15 += v * b9; t16 += v * b10; t17 += v * b11; t18 += v * b12; t19 += v * b13; t20 += v * b14; t21 += v * b15; v = a[7 +aoff]; t7 += v * b0; t8 += v * b1; t9 += v * b2; t10 += v * b3; t11 += v * b4; t12 += v * b5; t13 += v * b6; t14 += v * b7; t15 += v * b8; t16 += v * b9; t17 += v * b10; t18 += v * b11; t19 += v * b12; t20 += v * b13; t21 += v * b14; t22 += v * b15; v = a[8 +aoff]; t8 += v * b0; t9 += v * b1; t10 += v * b2; t11 += v * b3; t12 += v * b4; t13 += v * b5; t14 += v * b6; t15 += v * b7; t16 += v * b8; t17 += v * b9; t18 += v * b10; t19 += v * b11; t20 += v * b12; t21 += v * b13; t22 += v * b14; t23 += v * b15; v = a[9 +aoff]; t9 += v * b0; t10 += v * b1; t11 += v * b2; t12 += v * b3; t13 += v * b4; t14 += v * b5; t15 += v * b6; t16 += v * b7; t17 += v * b8; t18 += v * b9; t19 += v * b10; t20 += v * b11; t21 += v * b12; t22 += v * b13; t23 += v * b14; t24 += v * b15; v = a[10 +aoff]; t10 += v * b0; t11 += v * b1; t12 += v * b2; t13 += v * b3; t14 += v * b4; t15 += v * b5; t16 += v * b6; t17 += v * b7; t18 += v * b8; t19 += v * b9; t20 += v * b10; t21 += v * b11; t22 += v * b12; t23 += v * b13; t24 += v * b14; t25 += v * b15; v = a[11 +aoff]; t11 += v * b0; t12 += v * b1; t13 += v * b2; t14 += v * b3; t15 += v * b4; t16 += v * b5; t17 += v * b6; t18 += v * b7; t19 += v * b8; t20 += v * b9; t21 += v * b10; t22 += v * b11; t23 += v * b12; t24 += v * b13; t25 += v * b14; t26 += v * b15; v = a[12 +aoff]; t12 += v * b0; t13 += v * b1; t14 += v * b2; t15 += v * b3; t16 += v * b4; t17 += v * b5; t18 += v * b6; t19 += v * b7; t20 += v * b8; t21 += v * b9; t22 += v * b10; t23 += v * b11; t24 += v * b12; t25 += v * b13; t26 += v * b14; t27 += v * b15; v = a[13 +aoff]; t13 += v * b0; t14 += v * b1; t15 += v * b2; t16 += v * b3; t17 += v * b4; t18 += v * b5; t19 += v * b6; t20 += v * b7; t21 += v * b8; t22 += v * b9; t23 += v * b10; t24 += v * b11; t25 += v * b12; t26 += v * b13; t27 += v * b14; t28 += v * b15; v = a[14 +aoff]; t14 += v * b0; t15 += v * b1; t16 += v * b2; t17 += v * b3; t18 += v * b4; t19 += v * b5; t20 += v * b6; t21 += v * b7; t22 += v * b8; t23 += v * b9; t24 += v * b10; t25 += v * b11; t26 += v * b12; t27 += v * b13; t28 += v * b14; t29 += v * b15; v = a[15 +aoff]; t15 += v * b0; t16 += v * b1; t17 += v * b2; t18 += v * b3; t19 += v * b4; t20 += v * b5; t21 += v * b6; t22 += v * b7; t23 += v * b8; t24 += v * b9; t25 += v * b10; t26 += v * b11; t27 += v * b12; t28 += v * b13; t29 += v * b14; t30 += v * b15; t0 += 38 * t16; t1 += 38 * t17; t2 += 38 * t18; t3 += 38 * t19; t4 += 38 * t20; t5 += 38 * t21; t6 += 38 * t22; t7 += 38 * t23; t8 += 38 * t24; t9 += 38 * t25; t10 += 38 * t26; t11 += 38 * t27; t12 += 38 * t28; t13 += 38 * t29; t14 += 38 * t30; // t15 left as is // first car c = 1; v = t0 + c + 65535; c = v >> 16; t0 = v - c * 65536; v = t1 + c + 65535; c = v >> 16; t1 = v - c * 65536; v = t2 + c + 65535; c = v >> 16; t2 = v - c * 65536; v = t3 + c + 65535; c = v >> 16; t3 = v - c * 65536; v = t4 + c + 65535; c = v >> 16; t4 = v - c * 65536; v = t5 + c + 65535; c = v >> 16; t5 = v - c * 65536; v = t6 + c + 65535; c = v >> 16; t6 = v - c * 65536; v = t7 + c + 65535; c = v >> 16; t7 = v - c * 65536; v = t8 + c + 65535; c = v >> 16; t8 = v - c * 65536; v = t9 + c + 65535; c = v >> 16; t9 = v - c * 65536; v = t10 + c + 65535; c = v >> 16; t10 = v - c * 65536; v = t11 + c + 65535; c = v >> 16; t11 = v - c * 65536; v = t12 + c + 65535; c = v >> 16; t12 = v - c * 65536; v = t13 + c + 65535; c = v >> 16; t13 = v - c * 65536; v = t14 + c + 65535; c = v >> 16; t14 = v - c * 65536; v = t15 + c + 65535; c = v >> 16; t15 = v - c * 65536; t0 += c-1 + 37 * (c-1); // second car c = 1; v = t0 + c + 65535; c = v >> 16; t0 = v - c * 65536; v = t1 + c + 65535; c = v >> 16; t1 = v - c * 65536; v = t2 + c + 65535; c = v >> 16; t2 = v - c * 65536; v = t3 + c + 65535; c = v >> 16; t3 = v - c * 65536; v = t4 + c + 65535; c = v >> 16; t4 = v - c * 65536; v = t5 + c + 65535; c = v >> 16; t5 = v - c * 65536; v = t6 + c + 65535; c = v >> 16; t6 = v - c * 65536; v = t7 + c + 65535; c = v >> 16; t7 = v - c * 65536; v = t8 + c + 65535; c = v >> 16; t8 = v - c * 65536; v = t9 + c + 65535; c = v >> 16; t9 = v - c * 65536; v = t10 + c + 65535; c = v >> 16; t10 = v - c * 65536; v = t11 + c + 65535; c = v >> 16; t11 = v - c * 65536; v = t12 + c + 65535; c = v >> 16; t12 = v - c * 65536; v = t13 + c + 65535; c = v >> 16; t13 = v - c * 65536; v = t14 + c + 65535; c = v >> 16; t14 = v - c * 65536; v = t15 + c + 65535; c = v >> 16; t15 = v - c * 65536; t0 += c-1 + 37 * (c-1); o[ 0 +ooff] = t0; o[ 1 +ooff] = t1; o[ 2 +ooff] = t2; o[ 3 +ooff] = t3; o[ 4 +ooff] = t4; o[ 5 +ooff] = t5; o[ 6 +ooff] = t6; o[ 7 +ooff] = t7; o[ 8 +ooff] = t8; o[ 9 +ooff] = t9; o[10 +ooff] = t10; o[11 +ooff] = t11; o[12 +ooff] = t12; o[13 +ooff] = t13; o[14 +ooff] = t14; o[15 +ooff] = t15; } private static void S( long [] o, long [] a) { S(o,0, a,0); } private static void S( long [] o,final int ooff, long [] a,final int aoff) { M(o,ooff, a,aoff, a,aoff); } private static void inv25519( long [] o,final int ooff, long [] i,final int ioff) { long [] c = new long[16]; int a; for (a = 0; a < 16; a++) c[a] = i[a+ioff]; for (a = 253; a >= 0; a--) { S(c,0, c,0); if(a != 2 && a != 4) M(c,0, c,0, i,ioff); } for (a = 0; a < 16; a++) o[a+ooff] = c[a]; } private static void pow2523(long [] o,long [] i) { long [] c = new long[16]; int a; for (a = 0; a < 16; a ++) c[a]=i[a]; for(a=250;a>=0;a--) { S(c,0, c,0); if(a!=1) M(c,0, c,0, i,0); } for (a = 0; a < 16; a ++) o[a]=c[a]; } public static int crypto_scalarmult(byte []q,byte []n,byte []p) { byte [] z = new byte[32]; long [] x = new long[80]; int r, i; long [] a = new long[16], b = new long[16], c = new long[16], d = new long[16], e = new long[16], f = new long[16]; for (i = 0; i < 31; i++) z[i] = n[i]; z[31]=(byte) (((n[31]&127)|64) & 0xff); z[0]&=248; unpack25519(x,p); for (i = 0; i < 16; i++) { b[i]=x[i]; d[i]=a[i]=c[i]=0; } a[0]=d[0]=1; for (i=254;i>=0;--i) { r=(z[i>>>3]>>>(i&7))&1; sel25519(a,b,r); sel25519(c,d,r); A(e,a,c); Z(a,a,c); A(c,b,d); Z(b,b,d); S(d,e); S(f,a); M(a,c,a); M(c,b,e); A(e,a,c); Z(a,a,c); S(b,a); Z(c,d,f); M(a,c,_121665); A(a,a,d); M(c,c,a); M(a,d,f); M(d,b,x); S(b,e); sel25519(a,b,r); sel25519(c,d,r); } for (i = 0; i < 16; i++) { x[i+16]=a[i]; x[i+32]=c[i]; x[i+48]=b[i]; x[i+64]=d[i]; } inv25519(x,32, x,32); M(x,16, x,16, x,32); pack25519(q, x,16); return 0; } public static int crypto_scalarmult_base(byte []q,byte []n) { return crypto_scalarmult(q,n,_9); } public static int crypto_box_keypair(byte [] y, byte [] x) { randombytes(x,32); return crypto_scalarmult_base(y,x); } public static int crypto_box_beforenm(byte []k,byte []y,byte []x) { byte[] s = new byte[32]; crypto_scalarmult(s,x,y); /*String dbgt = ""; for (int dbg = 0; dbg < s.length; dbg ++) dbgt += " "+s[dbg]; Log.d(TAG, "crypto_box_beforenm -> "+dbgt); dbgt = ""; for (int dbg = 0; dbg < x.length; dbg ++) dbgt += " "+x[dbg]; Log.d(TAG, "crypto_box_beforenm, x -> "+dbgt); dbgt = ""; for (int dbg = 0; dbg < y.length; dbg ++) dbgt += " "+y[dbg]; Log.d(TAG, "crypto_box_beforenm, y -> "+dbgt); */ return crypto_core_hsalsa20(k, _0, s, sigma); } public static int crypto_box_afternm(byte []c,byte []m,int /*long*/ d,byte []n,byte []k) { return crypto_secretbox(c,m,d,n,k); } public static int crypto_box_open_afternm(byte []m,byte []c,int /*long*/ d,byte []n,byte []k) { return crypto_secretbox_open(m,c,d,n,k); } public static int crypto_box(byte []c,byte []m,int /*long*/ d,byte []n,byte []y,byte []x) { byte[] k = new byte[32]; ///L/og.d(TAG, "crypto_box start ..."); crypto_box_beforenm(k,y,x); return crypto_box_afternm(c,m,d,n,k); } public static int crypto_box_open(byte []m,byte []c,int /*long*/ d,byte []n,byte []y,byte []x) { byte[] k = new byte[32]; crypto_box_beforenm(k,y,x); return crypto_box_open_afternm(m,c,d,n,k); } private static final long K[] = { 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL, 0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, 0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L, 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L, 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, 0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L, 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L, 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L, 0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL, 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL, 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L, 0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L, 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L, 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, 0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL, 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL, 0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, 0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL, 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL, 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L }; private static int crypto_hashblocks_hl(int [] hh,int [] hl, byte [] m,final int moff, int n) { ///String dbgt = ""; ///for (int dbg = 0; dbg < n; dbg ++) dbgt += " "+m[dbg+moff]; ///Log.d(TAG, "crypto_hashblocks_hl m/"+n + "-> "+dbgt); int [] wh = new int[16], wl = new int[16]; int bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7, bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7, th, tl, h, l, i, j, a, b, c, d; int ah0 = hh[0], ah1 = hh[1], ah2 = hh[2], ah3 = hh[3], ah4 = hh[4], ah5 = hh[5], ah6 = hh[6], ah7 = hh[7], al0 = hl[0], al1 = hl[1], al2 = hl[2], al3 = hl[3], al4 = hl[4], al5 = hl[5], al6 = hl[6], al7 = hl[7]; int pos = 0; while (n >= 128) { for (i = 0; i < 16; i++) { j = 8 * i + pos; wh[i] = ((m[j+0+moff]&0xff) << 24) | ((m[j+1+moff]&0xff) << 16) | ((m[j+2+moff]&0xff) << 8) | ((m[j+3+moff]&0xff) << 0); wl[i] = ((m[j+4+moff]&0xff) << 24) | ((m[j+5+moff]&0xff) << 16) | ((m[j+6+moff]&0xff) << 8) | ((m[j+7+moff]&0xff) << 0); } for (i = 0; i < 80; i++) { bh0 = ah0; bh1 = ah1; bh2 = ah2; bh3 = ah3; bh4 = ah4; bh5 = ah5; bh6 = ah6; bh7 = ah7; bl0 = al0; bl1 = al1; bl2 = al2; bl3 = al3; bl4 = al4; bl5 = al5; bl6 = al6; bl7 = al7; // add h = ah7; l = al7; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; // Sigma1 h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32)))); l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32)))); a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; // Ch h = (ah4 & ah5) ^ (~ah4 & ah6); l = (al4 & al5) ^ (~al4 & al6); a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; // K ///h = K[i*2]; ///l = K[i*2+1]; h = (int) ((K[i]>>>32) & 0xffffffff); l = (int) ((K[i]>>> 0) & 0xffffffff); ///Log.d(TAG, "i"+i + ",h:0x"+Integer.toHexString(h) + ",l:0x"+Integer.toHexString(l)); a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; // w h = wh[i%16]; l = wl[i%16]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; th = c & 0xffff | d << 16; tl = a & 0xffff | b << 16; // add h = th; l = tl; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; // Sigma0 h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32)))); l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32)))); a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; // Maj h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2); l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2); a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; bh7 = (c & 0xffff) | (d << 16); bl7 = (a & 0xffff) | (b << 16); // add h = bh3; l = bl3; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = th; l = tl; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; bh3 = (c & 0xffff) | (d << 16); bl3 = (a & 0xffff) | (b << 16); ah1 = bh0; ah2 = bh1; ah3 = bh2; ah4 = bh3; ah5 = bh4; ah6 = bh5; ah7 = bh6; ah0 = bh7; al1 = bl0; al2 = bl1; al3 = bl2; al4 = bl3; al5 = bl4; al6 = bl5; al7 = bl6; al0 = bl7; if (i%16 == 15) { for (j = 0; j < 16; j++) { // add h = wh[j]; l = wl[j]; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = wh[(j+9)%16]; l = wl[(j+9)%16]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; // sigma0 th = wh[(j+1)%16]; tl = wl[(j+1)%16]; h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7); l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7))); a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; // sigma1 th = wh[(j+14)%16]; tl = wl[(j+14)%16]; h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6); l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6))); a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; wh[j] = (c & 0xffff) | (d << 16); wl[j] = (a & 0xffff) | (b << 16); } } } // add h = ah0; l = al0; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[0]; l = hl[0]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[0] = ah0 = (c & 0xffff) | (d << 16); hl[0] = al0 = (a & 0xffff) | (b << 16); h = ah1; l = al1; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[1]; l = hl[1]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[1] = ah1 = (c & 0xffff) | (d << 16); hl[1] = al1 = (a & 0xffff) | (b << 16); h = ah2; l = al2; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[2]; l = hl[2]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[2] = ah2 = (c & 0xffff) | (d << 16); hl[2] = al2 = (a & 0xffff) | (b << 16); h = ah3; l = al3; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[3]; l = hl[3]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[3] = ah3 = (c & 0xffff) | (d << 16); hl[3] = al3 = (a & 0xffff) | (b << 16); h = ah4; l = al4; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[4]; l = hl[4]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[4] = ah4 = (c & 0xffff) | (d << 16); hl[4] = al4 = (a & 0xffff) | (b << 16); h = ah5; l = al5; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[5]; l = hl[5]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[5] = ah5 = (c & 0xffff) | (d << 16); hl[5] = al5 = (a & 0xffff) | (b << 16); h = ah6; l = al6; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[6]; l = hl[6]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[6] = ah6 = (c & 0xffff) | (d << 16); hl[6] = al6 = (a & 0xffff) | (b << 16); h = ah7; l = al7; a = l & 0xffff; b = l >>> 16; c = h & 0xffff; d = h >>> 16; h = hh[7]; l = hl[7]; a += l & 0xffff; b += l >>> 16; c += h & 0xffff; d += h >>> 16; b += a >>> 16; c += b >>> 16; d += c >>> 16; hh[7] = ah7 = (c & 0xffff) | (d << 16); hl[7] = al7 = (a & 0xffff) | (b << 16); pos += 128; n -= 128; /*dbgt = ""; for (int dbg = 0; dbg < hh.length; dbg ++) dbgt += " "+hh[dbg]; Log.d(TAG, "\ncrypto_hashblocks_hl hh -> "+dbgt); dbgt = ""; for (int dbg = 0; dbg < hl.length; dbg ++) dbgt += " "+hl[dbg]; Log.d(TAG, "\ncrypto_hashblocks_hl hl -> "+dbgt);*/ } return n; } // TBD 64bits of n ///int crypto_hash(byte [] out, byte [] m, long n) public static int crypto_hash(byte [] out, byte [] m,final int moff, int n) { int [] hh = new int[8], hl = new int[8]; byte [] x = new byte[256]; int i, b = n; long u; hh[0] = 0x6a09e667; hh[1] = 0xbb67ae85; hh[2] = 0x3c6ef372; hh[3] = 0xa54ff53a; hh[4] = 0x510e527f; hh[5] = 0x9b05688c; hh[6] = 0x1f83d9ab; hh[7] = 0x5be0cd19; hl[0] = 0xf3bcc908; hl[1] = 0x84caa73b; hl[2] = 0xfe94f82b; hl[3] = 0x5f1d36f1; hl[4] = 0xade682d1; hl[5] = 0x2b3e6c1f; hl[6] = 0xfb41bd6b; hl[7] = 0x137e2179; if (n >= 128) { crypto_hashblocks_hl(hh, hl, m,moff, n); n %= 128; } for (i = 0; i < n; i++) x[i] = m[b-n+i +moff]; x[n] = (byte) 128; n = 256-128*(n<112?1:0); x[n-9] = 0; ts64(x, n-8, b<<3/*(b / 0x20000000) | 0, b << 3*/); crypto_hashblocks_hl(hh, hl, x,0, n); for (i = 0; i < 8; i++) { u = hh[i]; u <<= 32; u |= hl[i]&0xffffffffL; ts64(out, 8*i, u); } return 0; } public static int crypto_hash(byte [] out, byte [] m) { return crypto_hash(out, m,0, m!=null? m.length : 0); } // gf: long[16] ///private static void add(gf p[4],gf q[4]) private static void add(long [] p[], long [] q[]) { long [] a = new long[16]; long [] b = new long[16]; long [] c = new long[16]; long [] d = new long[16]; long [] t = new long[16]; long [] e = new long[16]; long [] f = new long[16]; long [] g = new long[16]; long [] h = new long[16]; long [] p0 = p[0]; long [] p1 = p[1]; long [] p2 = p[2]; long [] p3 = p[3]; long [] q0 = q[0]; long [] q1 = q[1]; long [] q2 = q[2]; long [] q3 = q[3]; Z(a,0, p1,0, p0,0); Z(t,0, q1,0, q0,0); M(a,0, a,0, t,0); A(b,0, p0,0, p1,0); A(t,0, q0,0, q1,0); M(b,0, b,0, t,0); M(c,0, p3,0, q3,0); M(c,0, c,0, D2,0); M(d,0, p2,0, q2,0); A(d,0, d,0, d,0); Z(e,0, b,0, a,0); Z(f,0, d,0, c,0); A(g,0, d,0, c,0); A(h,0, b,0, a,0); M(p0,0, e,0, f,0); M(p1,0, h,0, g,0); M(p2,0, g,0, f,0); M(p3,0, e,0, h,0); } private static void cswap(long [] p[], long [] q[], byte b) { int i; for (i = 0; i < 4; i ++) sel25519(p[i],0, q[i],0, b); } private static void pack(byte [] r, long [] p[]) { long [] tx = new long[16]; long [] ty = new long[16]; long [] zi = new long[16]; inv25519(zi,0, p[2],0); M(tx,0, p[0],0, zi,0); M(ty,0, p[1],0, zi,0); pack25519(r, ty,0); r[31] ^= par25519(tx,0) << 7; } private static void scalarmult(long [] p[], long [] q[], byte[] s,final int soff) { int i; set25519(p[0],gf0); set25519(p[1],gf1); set25519(p[2],gf1); set25519(p[3],gf0); for (i = 255;i >= 0;--i) { byte b = (byte) ((s[i/8+soff] >>> (i&7))&1); cswap(p,q,b); add(q,p); add(p,p); cswap(p,q,b); } ///String dbgt = ""; ///for (int dbg = 0; dbg < p.length; dbg ++) for (int dd = 0; dd < p[dbg].length; dd ++) dbgt += " "+p[dbg][dd]; ///L/og.d(TAG, "scalarmult -> "+dbgt); } private static void scalarbase(long [] p[], byte[] s,final int soff) { long [] [] q = new long [4] []; q[0] = new long [16]; q[1] = new long [16]; q[2] = new long [16]; q[3] = new long [16]; set25519(q[0],X); set25519(q[1],Y); set25519(q[2],gf1); M(q[3],0, X,0, Y,0); scalarmult(p,q, s,soff); } public static int crypto_sign_keypair(byte [] pk, byte [] sk, boolean seeded) { byte [] d = new byte[64]; long [] [] p = new long [4] []; p[0] = new long [16]; p[1] = new long [16]; p[2] = new long [16]; p[3] = new long [16]; int i; if (!seeded) randombytes(sk, 32); crypto_hash(d, sk,0, 32); d[0] &= 248; d[31] &= 127; d[31] |= 64; scalarbase(p, d,0); pack(pk, p); for (i = 0; i < 32; i++) sk[i+32] = pk[i]; return 0; } private static final long L[] = { 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10 }; private static void modL(byte[] r,final int roff, long x[]) { long carry; int i, j; for (i = 63;i >= 32;--i) { carry = 0; for (j = i - 32;j < i - 12;++j) { x[j] += carry - 16 * x[i] * L[j - (i - 32)]; carry = (x[j] + 128) >> 8; x[j] -= carry << 8; } x[j] += carry; x[i] = 0; } carry = 0; for (j = 0; j < 32; j ++) { x[j] += carry - (x[31] >> 4) * L[j]; carry = x[j] >> 8; x[j] &= 255; } for (j = 0; j < 32; j ++) x[j] -= carry * L[j]; for (i = 0; i < 32; i ++) { x[i+1] += x[i] >> 8; r[i+roff] = (byte) (x[i] & 255); } } private static void reduce(byte [] r) { long[] x = new long [64]; int i; for (i = 0; i < 64; i ++) x[i] = (long) (r[i]&0xff); for (i = 0; i < 64; i ++) r[i] = 0; modL(r,0, x); } // TBD... 64bits of n ///int crypto_sign(byte [] sm, long * smlen, byte [] m, long n, byte [] sk) public static int crypto_sign(byte [] sm, long dummy /* *smlen not used*/, byte [] m,final int moff, int/*long*/ n, byte [] sk) { byte[] d = new byte[64], h = new byte[64], r = new byte[64]; int i, j; long [] x = new long[64]; long [] [] p = new long [4] []; p[0] = new long [16]; p[1] = new long [16]; p[2] = new long [16]; p[3] = new long [16]; crypto_hash(d, sk,0, 32); d[0] &= 248; d[31] &= 127; d[31] |= 64; ///*smlen = n+64; for (i = 0; i < n; i ++) sm[64 + i] = m[i+moff]; for (i = 0; i < 32; i ++) sm[32 + i] = d[32 + i]; crypto_hash(r, sm,32, n+32); reduce(r); scalarbase(p, r,0); pack(sm,p); for (i = 0; i < 32; i ++) sm[i+32] = sk[i+32]; crypto_hash(h, sm,0, n + 64); reduce(h); for (i = 0; i < 64; i ++) x[i] = 0; for (i = 0; i < 32; i ++) x[i] = (long) (r[i]&0xff); for (i = 0; i < 32; i ++) for (j = 0; j < 32; j ++) x[i+j] += (h[i]&0xff) * (long) (d[j]&0xff); modL(sm,32, x); return 0; } private static int unpackneg(long [] r[], byte p[]) { long [] t = new long [16]; long [] chk = new long [16]; long [] num = new long [16]; long [] den = new long [16]; long [] den2 = new long [16]; long [] den4 = new long [16]; long [] den6 = new long [16]; set25519(r[2], gf1); unpack25519(r[1], p); S(num, r[1]); M(den, num, D); Z(num, num, r[2]); A(den, r[2], den); S(den2, den); S(den4, den2); M(den6, den4, den2); M(t, den6, num); M(t, t, den); pow2523(t, t); M(t, t, num); M(t, t, den); M(t, t, den); M(r[0], t, den); S(chk, r[0]); M(chk, chk, den); if (neq25519(chk, num)!=0) M(r[0], r[0], I); S(chk, r[0]); M(chk, chk, den); if (neq25519(chk, num)!=0) return -1; if (par25519(r[0]) == ((p[31]&0xFF)>>>7)) Z(r[0], gf0, r[0]); M(r[3], r[0], r[1]); return 0; } /// TBD 64bits of mlen ///int crypto_sign_open(byte []m,long *mlen,byte []sm,long n,byte []pk) public static int crypto_sign_open(byte [] m, long dummy /* *mlen not used*/, byte [] sm,final int smoff, int/*long*/ n, byte []pk) { int i; byte[] t = new byte[32], h = new byte[64]; long [] [] p = new long [4] []; p[0] = new long [16]; p[1] = new long [16]; p[2] = new long [16]; p[3] = new long [16]; long [] [] q = new long [4] []; q[0] = new long [16]; q[1] = new long [16]; q[2] = new long [16]; q[3] = new long [16]; ///*mlen = -1; if (n < 64) return -1; if (unpackneg(q,pk)!=0) return -1; for (i = 0; i < n; i ++) m[i] = sm[i+smoff]; for (i = 0; i < 32; i ++) m[i+32] = pk[i]; crypto_hash(h, m,0, n); reduce(h); scalarmult(p,q, h,0); scalarbase(q, sm,32+smoff); add(p,q); pack(t,p); n -= 64; if (crypto_verify_32(sm,smoff, t,0)!=0) { // optimizing it ///for (i = 0; i < n; i ++) m[i] = 0; return -1; } // TBD optimizing ... ///for (i = 0; i < n; i ++) m[i] = sm[i + 64 + smoff]; ///*mlen = n; return 0; } /* * @description * Java SecureRandom generator * */ private static final SecureRandom jrandom = new SecureRandom(); public static byte[] randombytes(byte [] x) { jrandom.nextBytes(x); return x; } public static byte[] randombytes(int len) { return randombytes(new byte[len]); } public static byte[] randombytes(byte [] x, int len) { byte [] b = randombytes(len); System.arraycopy(b, 0, x, 0, len); return x; } /* public static byte[] randombytes(byte [] x, int len) { int ret = len % 8; long rnd; for (int i = 0; i < len-ret; i += 8) { rnd = jrandom.nextLong(); x[i+0] = (byte) (rnd >>> 0); x[i+1] = (byte) (rnd >>> 8); x[i+2] = (byte) (rnd >>> 16); x[i+3] = (byte) (rnd >>> 24); x[i+4] = (byte) (rnd >>> 32); x[i+5] = (byte) (rnd >>> 40); x[i+6] = (byte) (rnd >>> 48); x[i+7] = (byte) (rnd >>> 56); } if (ret > 0) { rnd = jrandom.nextLong(); for (int i = len-ret; i < len; i ++) x[i] = (byte) (rnd >>> 8*i); } return x; } */ public static byte[] makeBoxNonce() { return randombytes(Box.nonceLength); } public static byte[] makeSecretBoxNonce() { return randombytes(SecretBox.nonceLength); } public static String base64EncodeToString(byte [] b) { return Base64.getUrlEncoder().withoutPadding().encodeToString(b); } // byte[] Base64.getUrlEncoder().withoutPadding().encode(b); public static byte[] base64Decode(String s) { return Base64.getUrlDecoder().decode(s); } // byte[] Base64.getUrlDecoder().decode(byte[] b) public static String hexEncodeToString( byte [] raw ) { String HEXES = "0123456789ABCDEF"; final StringBuilder hex = new StringBuilder( 2 * raw.length ); for ( final byte b : raw ) { hex.append(HEXES.charAt((b & 0xF0) >> 4)) .append(HEXES.charAt((b & 0x0F))); } return hex.toString(); } public static byte[] hexDecode(String s) { byte[] b = new byte[s.length() / 2]; for (int i = 0; i < s.length(); i += 2) { b[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } return b; } // public static boolean java.util.Arrays.equals(array1, array2); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy