├── LICENSE ├── README.md └── src └── com └── haccercat └── client ├── DataStream └── ByteStream.java ├── Main.java ├── Messaging ├── LogicLaserMessageFactory.java └── Messages │ ├── Client │ ├── Authentication │ │ └── ClientHelloMessage.java │ └── Login │ │ └── LoginMessage.java │ ├── PiranhaMessage.java │ └── Server │ └── Security │ └── ServerHelloMessage.java ├── Pepper └── PepperCrypto.java ├── TcpSocket └── Connection.java └── libraries ├── Blake2b.java └── TweetNacl.java /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 HaccerCat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BrawlStars-JavaClient 2 | implementation of [brawl stars client](https://github.com/HaccerCat/BrawlStars-Client) in java 3 | 4 | ## BrawlStars-Client 5 | client for brawl stars v46 prod server 6 | 7 | # NOTE 8 | This content is not affiliated with, endorsed,sponsored, or specifically approved by supercell and supercell is not responsible for it. 9 | 10 | In addition, you are the only person responsible for your actions when using it. 11 | 12 | ## usage 13 | install java, then: 14 | ``` 15 | cd src 16 | ``` 17 | and compile the code using: 18 | ``` 19 | javac com/haccercat/client/Main.java -d out 20 | ``` 21 | then run it with: 22 | ``` 23 | cd out && java com/haccercat/client/Main game.brawlstarsgame.com 9339 24 | ``` 25 | if you want to save decrypted server packets, run the program with: 26 | ``` 27 | cd out && java com/haccercat/client/Main game.brawlstarsgame.com 9339 dump 28 | ``` 29 | 30 | # credits 31 | this project was made by [S.B#0056](https://github.com/HaccerCat) and [risporce#6552](https://github.com/risporce) 32 | 33 | ## give a 🌟 because why not :p 34 | 35 | # [join my discord server](https://discord.gg/b2ejYcJjqA) 36 | -------------------------------------------------------------------------------- /src/com/haccercat/client/DataStream/ByteStream.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.DataStream; 2 | 3 | import java.util.Arrays; 4 | 5 | public class ByteStream { 6 | 7 | public byte[] payload; 8 | public int offset = 0; 9 | 10 | public ByteStream(int size) { 11 | this.payload = new byte[size]; 12 | } 13 | 14 | public ByteStream(byte[] bytes) { 15 | this.payload = bytes; 16 | } 17 | 18 | public void write(int a1) { 19 | byte v1 = (byte) a1; 20 | this.payload[offset] = v1; 21 | offset += 1; 22 | } 23 | public int read() { 24 | int result = (this.payload[offset] & 0xFF); 25 | offset += 1; 26 | return result; 27 | } 28 | public void writeUInt(int a1) { 29 | this.write(a1 & 0xFF); 30 | } 31 | public void writeByte(int a1) { 32 | this.write(a1); 33 | } 34 | public void writeBoolean(Boolean a1) { 35 | this.write(a1 ? 1 : 0); 36 | } 37 | public void writeInt(int a1) { 38 | this.write((a1 >> 24) & 0xFF); 39 | this.write((a1 >> 16) & 0xFF); 40 | this.write((a1 >> 8) & 0xFF); 41 | this.write(a1 & 0xFF); 42 | } 43 | public void writeString(String a1) { 44 | byte[] b = a1.getBytes(); 45 | this.writeInt(b.length); 46 | for (int strOffset = 0; strOffset < b.length; strOffset++) { 47 | this.write(b[strOffset]); 48 | } 49 | } 50 | public void writeString() { 51 | this.writeInt(-1); 52 | } 53 | 54 | public void writeVInt(int a1) { 55 | int v1, v2, v3; 56 | v1 = (((a1 >> 25) & 0x40) | (a1 & 0x3F)); 57 | v2 = ((a1 ^ (a1 >> 31)) >> 6); 58 | a1 >>= 6; 59 | if (v2 == 0) { 60 | this.writeByte(v1); 61 | } else { 62 | this.writeByte(v1 | 0x80); 63 | while (v2 != 0) { 64 | v2 >>= 7; 65 | v3 = 0; 66 | if (v2 > 0) { 67 | v3 = 0x80; 68 | } 69 | this.writeByte((a1 & 0x7F) | v3); 70 | a1 >>= 7; 71 | } 72 | } 73 | } 74 | 75 | public void writeDataReference(int a1) { 76 | writeVInt(a1); 77 | } 78 | 79 | public void writeDataReference(int a1, int a2) { 80 | this.writeVInt(a1); 81 | this.writeVInt(a2); 82 | } 83 | public int readInt() { 84 | return (this.read() << 24 | this.read() << 16 | this.read() << 8 | this.read()); 85 | } 86 | public byte readByte() { 87 | return (byte) this.read(); 88 | } 89 | public byte[] readBytes(int size) { 90 | byte[] result = new byte[size]; 91 | for (var index = 0; index < size; index++) { 92 | result[index] = this.readByte(); 93 | } 94 | return result; 95 | } 96 | public Boolean readBoolean() { 97 | Boolean result = false; 98 | if (this.read() >= 1) { 99 | result = true; 100 | } 101 | return result; 102 | } 103 | public String readString() { 104 | String result = ""; 105 | int len = this.readInt(); 106 | if (len <= 0) { 107 | return ""; 108 | } 109 | result = new String(this.readBytes(len)); 110 | return result; 111 | } 112 | public int readVInt() { 113 | // this method is discovered by nameless#1347 114 | int result = 0, shift = 0, b, seventh, msb, n; 115 | while (true) { 116 | b = this.read(); 117 | if (shift == 0) { 118 | seventh = (b & 0x40) >> 6; 119 | msb = (b & 0x80) >> 7; 120 | n = b << 1; 121 | n = n & ~0x181; 122 | b = n | (msb << 7) | seventh; 123 | } 124 | result |= (b & 0x7f) << shift; 125 | shift += 7; 126 | if ((b & 0x80) <= 0) { 127 | break; 128 | } 129 | } 130 | return (result >> 1) ^ (-(result & 1)); 131 | } 132 | public byte[] getBytes() { 133 | return Arrays.copyOfRange(this.payload, 0, this.offset); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/com/haccercat/client/Main.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client; 2 | 3 | import com.haccercat.client.TcpSocket.Connection; 4 | 5 | public class Main { 6 | public static void main(String[] args) { 7 | if (args.length < 2) { 8 | System.out.println("2 required args are missing: "); 9 | System.exit(0); 10 | } 11 | int port = 0; 12 | try { 13 | port = Integer.parseInt(args[1]); 14 | } catch(NumberFormatException e) { 15 | System.out.printf("failed to parse port: %s\n", e.getMessage()); 16 | System.exit(0); 17 | } 18 | Boolean shouldDump = false; 19 | if (args.length > 2) { 20 | shouldDump = args[2].equals("dump"); 21 | } 22 | Connection connection = new Connection(args[0], port, shouldDump); 23 | connection.start(); 24 | try { 25 | Thread.currentThread().join(); // run forever. 26 | } catch(InterruptedException e) { 27 | System.out.printf("[fatal-error] failed to make main thread run forever: %s\n", e.getMessage()); 28 | System.exit(0); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/com/haccercat/client/Messaging/LogicLaserMessageFactory.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.Messaging; 2 | 3 | import com.haccercat.client.Messaging.Messages.PiranhaMessage; 4 | 5 | import com.haccercat.client.Messaging.Messages.Server.Security.ServerHelloMessage; 6 | 7 | import com.haccercat.client.Messaging.Messages.Client.Login.LoginMessage; 8 | 9 | public class LogicLaserMessageFactory { 10 | public static PiranhaMessage createMessageByType(int type) { 11 | PiranhaMessage message = null; 12 | if (type == 20100) { 13 | message = new ServerHelloMessage(); 14 | } else if (type == 10101) { 15 | message = new LoginMessage(); 16 | message.setCapacity(250); 17 | } 18 | return message; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/haccercat/client/Messaging/Messages/Client/Authentication/ClientHelloMessage.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.Messaging.Messages.Client.Authentication; 2 | 3 | import com.haccercat.client.Messaging.Messages.PiranhaMessage; 4 | import com.haccercat.client.DataStream.ByteStream; 5 | 6 | public class ClientHelloMessage extends PiranhaMessage { 7 | public ClientHelloMessage() { 8 | super(); 9 | } 10 | public void encode() { 11 | ByteStream bytestream = getByteStream(); 12 | bytestream.writeInt(2); // protocol version 13 | bytestream.writeInt(48); // crypto version 14 | bytestream.writeInt(59); // major version 15 | bytestream.writeInt(1); // build version 16 | bytestream.writeInt(212); // minor version 17 | bytestream.writeString("86460ad83cb5e3a4ff8474eddb936d23008dfc1f"); // master hash 18 | bytestream.writeInt(2); 19 | bytestream.writeInt(2); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/haccercat/client/Messaging/Messages/Client/Login/LoginMessage.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.Messaging.Messages.Client.Login; 2 | 3 | import com.haccercat.client.Messaging.Messages.PiranhaMessage; 4 | import com.haccercat.client.DataStream.ByteStream; 5 | 6 | public class LoginMessage extends PiranhaMessage { 7 | public LoginMessage() { 8 | super(); 9 | } 10 | public void encode() { 11 | ByteStream bytestream = getByteStream(); 12 | bytestream.writeInt(0); // high 13 | bytestream.writeInt(0); // low 14 | bytestream.writeString(); // token 15 | 16 | bytestream.writeInt(59); 17 | bytestream.writeInt(1); 18 | bytestream.writeInt(212); 19 | bytestream.writeString("86460ad83cb5e3a4ff8474eddb936d23008dfc1f"); 20 | 21 | bytestream.writeString(); 22 | bytestream.writeDataReference(1, 0); 23 | bytestream.writeString("en-US"); 24 | bytestream.writeString(); 25 | bytestream.writeBoolean(false); 26 | bytestream.writeString(); 27 | bytestream.writeString(); 28 | bytestream.writeBoolean(true); 29 | bytestream.writeString(); 30 | bytestream.writeInt(1448); 31 | bytestream.writeVInt(0); 32 | bytestream.writeString(); 33 | 34 | bytestream.writeString(); 35 | bytestream.writeString(); 36 | bytestream.writeVInt(0); 37 | 38 | bytestream.writeString(); 39 | bytestream.writeString(); 40 | bytestream.writeString(); 41 | 42 | bytestream.writeString(); 43 | 44 | bytestream.writeBoolean(false); 45 | bytestream.writeString(); 46 | bytestream.writeString(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/com/haccercat/client/Messaging/Messages/PiranhaMessage.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.Messaging.Messages; 2 | 3 | import com.haccercat.client.DataStream.ByteStream; 4 | 5 | public class PiranhaMessage { 6 | public ByteStream bytesream; 7 | 8 | public PiranhaMessage() {} 9 | 10 | public void setBuffer(byte[] buf) { 11 | bytesream = new ByteStream(buf); 12 | } 13 | 14 | public void setCapacity(int bufsize) { 15 | bytesream = new ByteStream(bufsize); 16 | } 17 | 18 | public byte[] getBuffer() { 19 | return bytesream.getBytes(); 20 | } 21 | 22 | public ByteStream getByteStream() { 23 | return bytesream; 24 | } 25 | 26 | public int getEncodingLength() { 27 | return bytesream.offset; 28 | } 29 | 30 | public void encode() {} 31 | public void decode() {} 32 | public int[] process() { 33 | return null; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/com/haccercat/client/Messaging/Messages/Server/Security/ServerHelloMessage.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.Messaging.Messages.Server.Security; 2 | 3 | import com.haccercat.client.Messaging.Messages.PiranhaMessage; 4 | import com.haccercat.client.DataStream.ByteStream; 5 | 6 | public class ServerHelloMessage extends PiranhaMessage { 7 | public ServerHelloMessage() { 8 | super(); 9 | } 10 | public void decode() { 11 | } 12 | public int[] process() { 13 | int[] r = new int[1]; 14 | r[0] = 10101; 15 | return r; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/haccercat/client/Pepper/PepperCrypto.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.Pepper; 2 | 3 | import com.haccercat.client.libraries.Blake2b; 4 | import com.haccercat.client.libraries.TweetNacl; 5 | 6 | import java.util.Arrays; 7 | import java.math.BigInteger; 8 | 9 | class Nonce { 10 | private byte[] nonce; 11 | public Nonce(byte[] cpk, byte[] spk) { 12 | Blake2b b2b = new Blake2b(192); 13 | b2b.update(cpk, 0, 32); 14 | b2b.update(spk, 0, 32); 15 | nonce = new byte[24]; 16 | b2b.doFinal(nonce, 0); 17 | } 18 | public Nonce(byte[] nonce, byte[] cpk, byte[] spk) { 19 | Blake2b b2b = new Blake2b(192); 20 | b2b.update(nonce, 0, 24); 21 | b2b.update(cpk, 0, 32); 22 | b2b.update(spk, 0, 32); 23 | this.nonce = new byte[24]; 24 | b2b.doFinal(this.nonce, 0); 25 | } 26 | public Nonce() { 27 | nonce = new byte[24]; 28 | TweetNacl.randombytes(nonce, 24); 29 | } 30 | public Nonce(byte[] nonce) { 31 | this.nonce = nonce; 32 | } 33 | public byte[] bytes() { 34 | return nonce; 35 | } 36 | public void increment() { 37 | int c = 1; 38 | for (int idx = 0; idx < 47; idx++) { 39 | if (idx == 24) c = 1; 40 | c += (int)nonce[idx % 24] & 0xFF; 41 | nonce[idx % 24] = (byte)c; 42 | c >>= 8; 43 | } 44 | } 45 | } 46 | 47 | public class PepperCrypto { 48 | public byte[] key; 49 | 50 | public Nonce server_nonce; 51 | public Nonce client_nonce; 52 | 53 | public byte[] client_secret_key; 54 | public byte[] client_public_key; 55 | public byte[] server_public_key; 56 | 57 | private TweetNacl.Box box; 58 | 59 | private byte[] session_key; 60 | 61 | public PepperCrypto() { 62 | server_public_key = hexStringToByteArray("5C344B84451436796B735CB62EE38DF813A31798D21294F8C05E0F2B4CA4C047"); 63 | client_nonce = new Nonce(); 64 | client_secret_key = new byte[32]; 65 | TweetNacl.randombytes(client_secret_key, 32); 66 | client_public_key = new byte[32]; 67 | TweetNacl.crypto_scalarmult_base(client_public_key, client_secret_key); 68 | key = new byte[32]; 69 | TweetNacl.crypto_box_beforenm(key, server_public_key, client_secret_key); 70 | } 71 | 72 | public byte[] encrypt(int type, byte[] payload) { 73 | if (type == 10100) { 74 | return payload; 75 | } else if (type == 10101) { 76 | Nonce nonce = new Nonce(client_public_key, server_public_key); 77 | byte[] encrypted = new TweetNacl.Box(server_public_key, client_secret_key).after(concat(session_key, client_nonce.bytes(), payload), nonce.bytes()); 78 | return concat(client_public_key, encrypted); 79 | } else { 80 | client_nonce.increment(); 81 | return box.after(payload, client_nonce.bytes()); 82 | } 83 | } 84 | 85 | public byte[] decrypt(int type, byte[] payload) { 86 | if (type == 20100) { 87 | session_key = Arrays.copyOfRange(payload, 4, payload.length); 88 | return payload; 89 | } else if (type == 20104 || type == 20103) { 90 | if (type == 20103 && server_nonce == null) return payload; 91 | Nonce nonce = new Nonce(client_nonce.bytes(), client_public_key, server_public_key); 92 | byte[] decrypted = new TweetNacl.Box(server_public_key, client_secret_key).open(payload, nonce.bytes()); 93 | server_nonce = new Nonce(Arrays.copyOfRange(decrypted, 0, 24)); 94 | box = new TweetNacl.Box(server_public_key, client_public_key); // temp. 95 | box.sharedKey = Arrays.copyOfRange(decrypted, 24, 56); 96 | return Arrays.copyOfRange(decrypted, 56, decrypted.length); 97 | } else { 98 | server_nonce.increment(); 99 | return box.open_after(payload, server_nonce.bytes()); 100 | } 101 | } 102 | 103 | public static byte[] concat(byte[]...arrays) { 104 | int totalLength = 0; 105 | for (int i = 0; i < arrays.length; i++) { 106 | totalLength += arrays[i].length; 107 | } 108 | byte[] result = new byte[totalLength]; 109 | int currentIndex = 0; 110 | for (int i = 0; i < arrays.length; i++) { 111 | System.arraycopy(arrays[i], 0, result, currentIndex, arrays[i].length); 112 | currentIndex += arrays[i].length; 113 | } 114 | return result; 115 | } 116 | public static byte[] hexStringToByteArray(String s) { 117 | byte[] b = new byte[s.length() / 2]; 118 | for (int i = 0; i < b.length; i++) { 119 | int index = i * 2; 120 | int v = Integer.parseInt(s.substring(index, index + 2), 16); 121 | b[i] = (byte) v; 122 | } 123 | return b; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/com/haccercat/client/TcpSocket/Connection.java: -------------------------------------------------------------------------------- 1 | package com.haccercat.client.TcpSocket; 2 | 3 | import java.io.IOException; 4 | import java.io.File; 5 | import java.net.InetSocketAddress; 6 | import java.nio.ByteBuffer; 7 | import java.nio.channels.AsynchronousSocketChannel; 8 | import java.nio.channels.CompletionHandler; 9 | import java.io.FileOutputStream; 10 | import java.util.HashMap; 11 | 12 | import com.haccercat.client.Messaging.Messages.PiranhaMessage; 13 | import com.haccercat.client.Messaging.LogicLaserMessageFactory; 14 | import com.haccercat.client.Pepper.PepperCrypto; 15 | import com.haccercat.client.Messaging.Messages.Client.Authentication.ClientHelloMessage; 16 | 17 | class Dumper { 18 | public static HashMap map = new HashMap(); 19 | public static void prepare() { 20 | File dir = new File("PacketsDumps"); 21 | if (!dir.exists()) { 22 | dir.mkdir(); 23 | } 24 | } 25 | public static void write(int type, byte[] data) { 26 | if (map.containsKey(type)) { 27 | map.put(type, map.get(type)+1); 28 | } else { 29 | map.put(type, 0); 30 | } 31 | try { 32 | FileOutputStream fos = new FileOutputStream("PacketsDumps/"+String.valueOf(type)+"-"+map.get(type).toString()+".bin"); 33 | fos.write(data); 34 | fos.close(); 35 | } catch (IOException e) { 36 | System.out.println(e.getMessage()); 37 | } 38 | } 39 | } 40 | 41 | public class Connection { 42 | 43 | private AsynchronousSocketChannel Channel; 44 | private String Domain; 45 | private int Port; 46 | public Boolean dump; 47 | public PepperCrypto Crypto; 48 | 49 | public Connection(String domain, int port, Boolean dump) { 50 | if (dump) { 51 | Dumper.prepare(); 52 | } 53 | this.dump = dump; 54 | try { 55 | Channel = AsynchronousSocketChannel.open(); 56 | } catch(IOException e) { 57 | System.out.printf("[fatal-error] failed to create async socket channel: %s\n", e.getMessage()); 58 | System.exit(0); 59 | } 60 | Domain = domain; 61 | Port = port; 62 | Crypto = new PepperCrypto(); 63 | } 64 | 65 | public void start() { 66 | Channel.connect(new InetSocketAddress(Domain, Port), Channel, new CompletionHandler < Void, AsynchronousSocketChannel > () { 67 | @Override 68 | public void completed(Void result, AsynchronousSocketChannel channel) { 69 | System.out.printf("succesfully connected to %s:%d\n", Domain, Port); 70 | nextHeader(); 71 | sendPepperAuthentication(); 72 | } 73 | @Override 74 | public void failed(Throwable err, AsynchronousSocketChannel channel) { 75 | System.out.printf("[fatal-error] failed to connect to %s:%d\n", Domain, Port); 76 | System.exit(0); 77 | } 78 | }); 79 | } 80 | 81 | public void nextMessage(byte[] header) { 82 | int type = (((header[0] & 0xFF) << 8) | (header[1] & 0xFF)); 83 | int length = (((header[2] & 0xFF) << 16) | ((header[3] & 0xFF) << 8) | (header[4] & 0xFF)); 84 | int version = (((header[5] & 0xFF) << 8) | (header[6] & 0xFF)); 85 | ByteBuffer buffer = ByteBuffer.allocate(length); 86 | Channel.read(buffer, Channel, new CompletionHandler < Integer, AsynchronousSocketChannel > () { 87 | @Override 88 | public void completed(Integer result, AsynchronousSocketChannel channel) { 89 | if (result == -1) { 90 | close(); 91 | System.out.println("[recv] server closed connection"); 92 | } else { 93 | onMessage(type, length, version, buffer.array()); 94 | nextHeader(); 95 | } 96 | } 97 | @Override 98 | public void failed(Throwable err, AsynchronousSocketChannel channel) { 99 | System.out.println("failed to receive data from server"); 100 | close(); 101 | } 102 | }); 103 | } 104 | 105 | public void nextHeader() { 106 | ByteBuffer buffer = ByteBuffer.allocate(7); 107 | Channel.read(buffer, 108 | Channel, 109 | new CompletionHandler < Integer, 110 | AsynchronousSocketChannel > () { 111 | @Override 112 | public void completed(Integer result, AsynchronousSocketChannel channel) { 113 | if (result == -1) { 114 | close(); 115 | System.out.println("[recv] server closed connection"); 116 | } else { 117 | nextMessage(buffer.array()); 118 | } 119 | } 120 | @Override 121 | public void failed(Throwable err, AsynchronousSocketChannel channel) { 122 | System.out.println("failed to receive data from server"); 123 | close(); 124 | } 125 | }); 126 | } 127 | 128 | public void onMessage(int type, 129 | int length, 130 | int version, 131 | byte[] payload) { 132 | System.out.printf("received message, type: %d, length: %d, version: %d, expected length: %d\n", 133 | type, 134 | payload.length, 135 | version, 136 | length); 137 | byte[] decrypted = Crypto.decrypt(type, 138 | payload); 139 | if (dump) { 140 | Dumper.write(type, decrypted); 141 | } 142 | PiranhaMessage message = LogicLaserMessageFactory.createMessageByType(type); 143 | if (message == null) { 144 | System.out.printf("ignoring unsupported message (%d)\n", type); 145 | return; 146 | } 147 | message.setBuffer(decrypted); 148 | message.decode(); 149 | int[] messages = message.process(); 150 | if (messages != null) { 151 | for (int msg: messages) { 152 | message = LogicLaserMessageFactory.createMessageByType(msg); 153 | message.encode(); 154 | encryptAndSend(msg, 1, message.getBuffer()); 155 | } 156 | } 157 | } 158 | 159 | public void encryptAndSend(int type, int version, byte[] payload) { 160 | byte[] encrypted = Crypto.encrypt(type, payload); 161 | int length = encrypted.length; 162 | byte[] header = new byte[7]; 163 | header[0] = (byte)(type >> 8 & 0xFF); 164 | header[1] = (byte)(type & 0xFF); 165 | header[2] = (byte)(length >> 16 & 0xFF); 166 | header[3] = (byte)(length >> 8 & 0xFF); 167 | header[4] = (byte)(length & 0xFF); 168 | header[5] = (byte)(version >> 8 & 0xFF); 169 | header[6] = (byte)(version & 0xFF); 170 | ByteBuffer buf = ByteBuffer.allocate(7 + length); 171 | buf.put(header); 172 | buf.put(encrypted); 173 | buf.flip(); 174 | sendMessage(buf, 175 | type); 176 | } 177 | 178 | public void sendMessage(ByteBuffer buffer, 179 | int type) { 180 | Channel.write(buffer, 181 | Channel, 182 | new CompletionHandler < Integer, 183 | AsynchronousSocketChannel > () { 184 | @Override 185 | public void completed(Integer result, AsynchronousSocketChannel channel) { 186 | if (result == -1) { 187 | System.out.println("[send] server close connection"); 188 | } else { 189 | System.out.printf("message of type %d was sent\n", type); 190 | } 191 | } 192 | @Override 193 | public void failed(Throwable err, AsynchronousSocketChannel channel) { 194 | System.out.println("failed to send data to server"); 195 | close(); 196 | } 197 | }); 198 | } 199 | 200 | public void sendPepperAuthentication() { 201 | PiranhaMessage message = new ClientHelloMessage(); 202 | message.setCapacity(100); 203 | message.encode(); 204 | encryptAndSend(10100, 205 | 0, 206 | message.getBuffer()); 207 | } 208 | 209 | public void close() { 210 | try { 211 | Channel.close(); 212 | } catch(IOException e) { 213 | System.out.println(e.getMessage()); 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/com/haccercat/client/libraries/Blake2b.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000 - 2020 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | * subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included 11 | * in all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 15 | * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | /* 21 | * The MIT License 22 | * 23 | * Copyright (C) 2020 Shamil 24 | * 25 | * Permission is hereby granted, free of charge, to any person obtaining 26 | * a copy of this software and associated documentation files (the 27 | * "Software"), to deal in the Software without restriction, including 28 | * without limitation the rights to use, copy, modify, merge, publish, 29 | * distribute, sublicense, and/or sell copies of the Software, and to 30 | * permit persons to whom the Software is furnished to do so, subject to 31 | * the following conditions: 32 | * 33 | * The above copyright notice and this permission notice shall be 34 | * included in all copies or substantial portions of the Software. 35 | * 36 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 37 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 38 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 39 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 40 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 41 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 42 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 43 | */ 44 | package com.haccercat.client.libraries; 45 | 46 | /* The BLAKE2 cryptographic hash function was designed by Jean- 47 | Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian 48 | Winnerlein. 49 | 50 | Reference Implementation and Description can be found at: https://blake2.net/ 51 | Internet Draft: https://tools.ietf.org/html/draft-saarinen-blake2-02 52 | This implementation does not support the Tree Hashing Mode. 53 | 54 | For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based 55 | message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2. 56 | Algorithm | Target | Collision | Hash | Hash ASN.1 | 57 | Identifier | Arch | Security | nn | OID Suffix | 58 | ---------------+--------+-----------+------+------------+ 59 | id-blake2b160 | 64-bit | 2**80 | 20 | x.1.20 | 60 | id-blake2b256 | 64-bit | 2**128 | 32 | x.1.32 | 61 | id-blake2b384 | 64-bit | 2**192 | 48 | x.1.48 | 62 | id-blake2b512 | 64-bit | 2**256 | 64 | x.1.64 | 63 | ---------------+--------+-----------+------+------------+ 64 | */ 65 | 66 | import java.util.Arrays; 67 | 68 | /** 69 | * Implementation of the cryptographic hash function Blake2b. 70 | *

71 | * Blake2b offers a built-in keying mechanism to be used directly 72 | * for authentication ("Prefix-MAC") rather than a HMAC construction. 73 | *

74 | * Blake2b offers a built-in support for a salt for randomized hashing 75 | * and a personal string for defining a unique hash function for each application. 76 | *

77 | * BLAKE2b is optimized for 64-bit platforms and produces digests of any size 78 | * between 1 and 64 bytes. 79 | */ 80 | public final class Blake2b { 81 | // Blake2b Initialization Vector: 82 | private final static long[] blake2b_IV = { 83 | // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19. 84 | // The same as SHA-512 IV. 85 | 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL, 86 | 0xa54ff53a5f1d36f1L, 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL, 87 | 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L 88 | }; 89 | 90 | // Message word permutations: 91 | private final static byte[][] blake2b_sigma = { 92 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 93 | {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, 94 | {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, 95 | {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, 96 | {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, 97 | {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, 98 | {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, 99 | {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, 100 | {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, 101 | {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, 102 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 103 | {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3} 104 | }; 105 | private final static int BLOCK_LENGTH_BYTES = 128;// bytes 106 | private static final int ROUNDS = 12; // to use for Catenas H' 107 | // General parameters: 108 | private int digestLength = 64; // 1- 64 bytes 109 | private int keyLength = 0; // 0 - 64 bytes for keyed hashing for MAC 110 | private byte[] salt = null;// new byte[16]; 111 | private byte[] personalization = null;// new byte[16]; 112 | 113 | // the key 114 | private byte[] key = null; 115 | 116 | // Tree hashing parameters: 117 | // Because this class does not implement the Tree Hashing Mode, 118 | // these parameters can be treated as constants (see init() function) 119 | /* 120 | * private int fanout = 1; // 0-255 private int depth = 1; // 1 - 255 121 | * private int leafLength= 0; private long nodeOffset = 0L; private int 122 | * nodeDepth = 0; private int innerHashLength = 0; 123 | */ 124 | 125 | // whenever this buffer overflows, it will be processed 126 | // in the compress() function. 127 | // For performance issues, long messages will not use this buffer. 128 | private byte[] buffer = null;// new byte[BLOCK_LENGTH_BYTES]; 129 | // Position of last inserted byte: 130 | private int bufferPos = 0;// a value from 0 up to 128 131 | 132 | private long[] internalState = new long[16]; // In the Blake2b paper it is 133 | // called: v 134 | private long[] chainValue = null; // state vector, in the Blake2b paper it 135 | // is called: h 136 | 137 | private long t0 = 0L; // holds last significant bits, counter (counts bytes) 138 | private long t1 = 0L; // counter: Length up to 2^128 are supported 139 | private long f0 = 0L; // finalization flag, for last block: ~0L 140 | 141 | // For Tree Hashing Mode, not used here: 142 | // private long f1 = 0L; // finalization flag, for last node: ~0L 143 | 144 | public Blake2b() { 145 | this(512); 146 | } 147 | 148 | public Blake2b(Blake2b digest) { 149 | this.bufferPos = digest.bufferPos; 150 | this.buffer = clone(digest.buffer); 151 | this.keyLength = digest.keyLength; 152 | this.key = clone(digest.key); 153 | this.digestLength = digest.digestLength; 154 | this.chainValue = clone(digest.chainValue); 155 | this.personalization = clone(digest.personalization); 156 | this.salt = clone(digest.salt); 157 | this.t0 = digest.t0; 158 | this.t1 = digest.t1; 159 | this.f0 = digest.f0; 160 | } 161 | 162 | /** 163 | * Basic sized constructor - size in bits. 164 | * 165 | * @param digestSize size of the digest in bits 166 | */ 167 | public Blake2b(int digestSize) { 168 | if (digestSize < 8 || digestSize > 512 || digestSize % 8 != 0) { 169 | throw new IllegalArgumentException("BLAKE2b digest bit length must be a multiple of 8 and not greater than 512"); 170 | } 171 | buffer = new byte[BLOCK_LENGTH_BYTES]; 172 | keyLength = 0; 173 | this.digestLength = digestSize / 8; 174 | init(); 175 | } 176 | 177 | /** 178 | * Blake2b for authentication ("Prefix-MAC mode"). 179 | * After calling the doFinal() method, the key will 180 | * remain to be used for further computations of 181 | * this instance. 182 | * The key can be overwritten using the clearKey() method. 183 | * 184 | * @param key A key up to 64 bytes or null 185 | */ 186 | public Blake2b(byte[] key) { 187 | buffer = new byte[BLOCK_LENGTH_BYTES]; 188 | if (key != null) { 189 | this.key = new byte[key.length]; 190 | System.arraycopy(key, 0, this.key, 0, key.length); 191 | 192 | if (key.length > 64) { 193 | throw new IllegalArgumentException("Keys > 64 are not supported"); 194 | } 195 | keyLength = key.length; 196 | System.arraycopy(key, 0, buffer, 0, key.length); 197 | bufferPos = BLOCK_LENGTH_BYTES; // zero padding 198 | } 199 | digestLength = 64; 200 | init(); 201 | } 202 | 203 | /** 204 | * Blake2b with key, required digest length (in bytes), salt and personalization. 205 | * After calling the doFinal() method, the key, the salt and the personal string 206 | * will remain and might be used for further computations with this instance. 207 | * The key can be overwritten using the clearKey() method, the salt (pepper) 208 | * can be overwritten using the clearSalt() method. 209 | * 210 | * @param key A key up to 64 bytes or null 211 | * @param digestLength from 1 up to 64 bytes 212 | * @param salt 16 bytes or null 213 | * @param personalization 16 bytes or null 214 | */ 215 | public Blake2b(byte[] key, int digestLength, byte[] salt, byte[] personalization) { 216 | buffer = new byte[BLOCK_LENGTH_BYTES]; 217 | if (digestLength < 1 || digestLength > 64) { 218 | throw new IllegalArgumentException("Invalid digest length (required: 1 - 64)"); 219 | } 220 | this.digestLength = digestLength; 221 | if (salt != null) { 222 | if (salt.length != 16) { 223 | throw new IllegalArgumentException("salt length must be exactly 16 bytes"); 224 | } 225 | this.salt = new byte[16]; 226 | System.arraycopy(salt, 0, this.salt, 0, salt.length); 227 | } 228 | if (personalization != null) { 229 | if (personalization.length != 16) { 230 | throw new IllegalArgumentException("personalization length must be exactly 16 bytes"); 231 | } 232 | this.personalization = new byte[16]; 233 | System.arraycopy(personalization, 0, this.personalization, 0, personalization.length); 234 | } 235 | if (key != null) { 236 | this.key = new byte[key.length]; 237 | System.arraycopy(key, 0, this.key, 0, key.length); 238 | 239 | if (key.length > 64) { 240 | throw new IllegalArgumentException("Keys > 64 are not supported"); 241 | } 242 | keyLength = key.length; 243 | System.arraycopy(key, 0, buffer, 0, key.length); 244 | bufferPos = BLOCK_LENGTH_BYTES; // zero padding 245 | } 246 | init(); 247 | } 248 | 249 | // initialize chainValue 250 | private void init() { 251 | if (chainValue == null) { 252 | chainValue = new long[8]; 253 | 254 | chainValue[0] = blake2b_IV[0] 255 | ^ (digestLength | (keyLength << 8) | 0x1010000); 256 | // 0x1010000 = ((fanout << 16) | (depth << 24) | (leafLength << 32)); 257 | // with fanout = 1; depth = 0; leafLength = 0; 258 | chainValue[1] = blake2b_IV[1];// ^ nodeOffset; with nodeOffset = 0; 259 | chainValue[2] = blake2b_IV[2];// ^ ( nodeDepth | (innerHashLength << 8)); 260 | // with nodeDepth = 0; innerHashLength = 0; 261 | 262 | chainValue[3] = blake2b_IV[3]; 263 | 264 | chainValue[4] = blake2b_IV[4]; 265 | chainValue[5] = blake2b_IV[5]; 266 | if (salt != null) { 267 | chainValue[4] ^= littleEndianToLong(salt, 0); 268 | chainValue[5] ^= littleEndianToLong(salt, 8); 269 | } 270 | 271 | chainValue[6] = blake2b_IV[6]; 272 | chainValue[7] = blake2b_IV[7]; 273 | if (personalization != null) { 274 | chainValue[6] ^= littleEndianToLong(personalization, 0); 275 | chainValue[7] ^= littleEndianToLong(personalization, 8); 276 | } 277 | } 278 | } 279 | 280 | private void initializeInternalState() { 281 | // initialize v: 282 | System.arraycopy(chainValue, 0, internalState, 0, chainValue.length); 283 | System.arraycopy(blake2b_IV, 0, internalState, chainValue.length, 4); 284 | internalState[12] = t0 ^ blake2b_IV[4]; 285 | internalState[13] = t1 ^ blake2b_IV[5]; 286 | internalState[14] = f0 ^ blake2b_IV[6]; 287 | internalState[15] = blake2b_IV[7];// ^ f1 with f1 = 0 288 | } 289 | 290 | /** 291 | * update the message digest with a single byte. 292 | * 293 | * @param b the input byte to be entered. 294 | */ 295 | public void update(byte b) { 296 | int remainingLength = 0; // left bytes of buffer 297 | 298 | // process the buffer if full else add to buffer: 299 | remainingLength = BLOCK_LENGTH_BYTES - bufferPos; 300 | if (remainingLength == 0) { // full buffer 301 | t0 += BLOCK_LENGTH_BYTES; 302 | if (t0 == 0) { // if message > 2^64 303 | t1++; 304 | } 305 | compress(buffer, 0); 306 | Arrays.fill(buffer, (byte) 0);// clear buffer 307 | buffer[0] = b; 308 | bufferPos = 1; 309 | } else { 310 | buffer[bufferPos] = b; 311 | bufferPos++; 312 | return; 313 | } 314 | } 315 | 316 | /** 317 | * update the message digest with a block of bytes. 318 | * 319 | * @param message the byte array containing the data. 320 | * @param offset the offset into the byte array where the data starts. 321 | * @param len the length of the data. 322 | */ 323 | public void update(byte[] message, int offset, int len) { 324 | if (message == null || len == 0) { 325 | return; 326 | } 327 | int remainingLength = 0; // left bytes of buffer 328 | 329 | if (bufferPos != 0) { // commenced, incomplete buffer 330 | // complete the buffer: 331 | remainingLength = BLOCK_LENGTH_BYTES - bufferPos; 332 | if (remainingLength < len) { // full buffer + at least 1 byte 333 | System.arraycopy(message, offset, buffer, bufferPos, remainingLength); 334 | t0 += BLOCK_LENGTH_BYTES; 335 | if (t0 == 0) { // if message > 2^64 336 | t1++; 337 | } 338 | compress(buffer, 0); 339 | bufferPos = 0; 340 | Arrays.fill(buffer, (byte) 0);// clear buffer 341 | } else { 342 | System.arraycopy(message, offset, buffer, bufferPos, len); 343 | bufferPos += len; 344 | return; 345 | } 346 | } 347 | 348 | // process blocks except last block (also if last block is full) 349 | int messagePos; 350 | int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES; 351 | for (messagePos = offset + remainingLength; messagePos < blockWiseLastPos; messagePos += BLOCK_LENGTH_BYTES) { // block wise 128 bytes 352 | // without buffer: 353 | t0 += BLOCK_LENGTH_BYTES; 354 | if (t0 == 0) { 355 | t1++; 356 | } 357 | compress(message, messagePos); 358 | } 359 | 360 | // fill the buffer with left bytes, this might be a full block 361 | System.arraycopy(message, messagePos, buffer, 0, offset + len - messagePos); 362 | bufferPos += offset + len - messagePos; 363 | } 364 | 365 | /** 366 | * close the digest, producing the final digest value. The doFinal 367 | * call leaves the digest reset. 368 | * Key, salt and personal string remain. 369 | * 370 | * @param out the array the digest is to be copied into. 371 | * @param outOffset the offset into the out array the digest is to start at. 372 | */ 373 | public int doFinal(byte[] out, int outOffset) { 374 | f0 = 0xFFFFFFFFFFFFFFFFL; 375 | t0 += bufferPos; 376 | if (bufferPos > 0 && t0 == 0) { 377 | t1++; 378 | } 379 | compress(buffer, 0); 380 | Arrays.fill(buffer, (byte) 0);// Holds eventually the key if input is null 381 | Arrays.fill(internalState, 0L); 382 | 383 | for (int i = 0; i < chainValue.length && (i * 8 < digestLength); i++) { 384 | byte[] bytes = longToLittleEndian(chainValue[i]); 385 | if (i * 8 < digestLength - 8) { 386 | System.arraycopy(bytes, 0, out, outOffset + i * 8, 8); 387 | } else { 388 | System.arraycopy(bytes, 0, out, outOffset + i * 8, digestLength - (i * 8)); 389 | } 390 | } 391 | Arrays.fill(chainValue, 0L); 392 | reset(); 393 | return digestLength; 394 | } 395 | 396 | /** 397 | * Reset the digest back to it's initial state. 398 | * The key, the salt and the personal string will 399 | * remain for further computations. 400 | */ 401 | public void reset() { 402 | bufferPos = 0; 403 | f0 = 0L; 404 | t0 = 0L; 405 | t1 = 0L; 406 | chainValue = null; 407 | Arrays.fill(buffer, (byte) 0); 408 | if (key != null) { 409 | System.arraycopy(key, 0, buffer, 0, key.length); 410 | bufferPos = BLOCK_LENGTH_BYTES; // zero padding 411 | } 412 | init(); 413 | } 414 | 415 | private void compress(byte[] message, int messagePos) { 416 | 417 | initializeInternalState(); 418 | 419 | long[] m = new long[16]; 420 | for (int j = 0; j < 16; j++) { 421 | m[j] = littleEndianToLong(message, messagePos + j * 8); 422 | } 423 | 424 | for (int round = 0; round < ROUNDS; round++) { 425 | 426 | // G apply to columns of internalState:m[blake2b_sigma[round][2 * 427 | // blockPos]] /+1 428 | G(m[blake2b_sigma[round][0]], m[blake2b_sigma[round][1]], 0, 4, 8, 12); 429 | G(m[blake2b_sigma[round][2]], m[blake2b_sigma[round][3]], 1, 5, 9, 13); 430 | G(m[blake2b_sigma[round][4]], m[blake2b_sigma[round][5]], 2, 6, 10, 14); 431 | G(m[blake2b_sigma[round][6]], m[blake2b_sigma[round][7]], 3, 7, 11, 15); 432 | // G apply to diagonals of internalState: 433 | G(m[blake2b_sigma[round][8]], m[blake2b_sigma[round][9]], 0, 5, 10, 15); 434 | G(m[blake2b_sigma[round][10]], m[blake2b_sigma[round][11]], 1, 6, 11, 12); 435 | G(m[blake2b_sigma[round][12]], m[blake2b_sigma[round][13]], 2, 7, 8, 13); 436 | G(m[blake2b_sigma[round][14]], m[blake2b_sigma[round][15]], 3, 4, 9, 14); 437 | } 438 | 439 | // update chain values: 440 | for (int offset = 0; offset < chainValue.length; offset++) { 441 | chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8]; 442 | } 443 | } 444 | 445 | private void G(long m1, long m2, int posA, int posB, int posC, int posD) { 446 | internalState[posA] = internalState[posA] + internalState[posB] + m1; 447 | internalState[posD] = rotateRight(internalState[posD] ^ internalState[posA], 32); 448 | internalState[posC] = internalState[posC] + internalState[posD]; 449 | internalState[posB] = rotateRight(internalState[posB] ^ internalState[posC], 24); // replaces 25 of BLAKE 450 | internalState[posA] = internalState[posA] + internalState[posB] + m2; 451 | internalState[posD] = rotateRight(internalState[posD] ^ internalState[posA], 16); 452 | internalState[posC] = internalState[posC] + internalState[posD]; 453 | internalState[posB] = rotateRight(internalState[posB] ^ internalState[posC], 63); // replaces 11 of BLAKE 454 | } 455 | 456 | /** 457 | * return the algorithm name 458 | * 459 | * @return the algorithm name 460 | */ 461 | public String getAlgorithmName() { 462 | return "BLAKE2b"; 463 | } 464 | 465 | /** 466 | * return the size, in bytes, of the digest produced by this message digest. 467 | * 468 | * @return the size, in bytes, of the digest produced by this message digest. 469 | */ 470 | public int getDigestSize() { 471 | return digestLength; 472 | } 473 | 474 | /** 475 | * Return the size in bytes of the internal buffer the digest applies it's compression 476 | * function to. 477 | * 478 | * @return byte length of the digests internal buffer. 479 | */ 480 | public int getByteLength() { 481 | return BLOCK_LENGTH_BYTES; 482 | } 483 | 484 | /** 485 | * Overwrite the key 486 | * if it is no longer used (zeroization) 487 | */ 488 | public void clearKey() { 489 | if (key != null) { 490 | Arrays.fill(key, (byte) 0); 491 | Arrays.fill(buffer, (byte) 0); 492 | } 493 | } 494 | 495 | /** 496 | * Overwrite the salt (pepper) if it 497 | * is secret and no longer used (zeroization) 498 | */ 499 | public void clearSalt() { 500 | if (salt != null) { 501 | Arrays.fill(salt, (byte) 0); 502 | } 503 | } 504 | 505 | // factory methods 506 | 507 | public static Blake2b blake2b512() { 508 | return new Blake2b(); 509 | } 510 | 511 | public static Blake2b blake2b384() { 512 | return new Blake2b(384); 513 | } 514 | 515 | public static Blake2b blake2b256() { 516 | return new Blake2b(256); 517 | } 518 | 519 | public static Blake2b blake2b160() { 520 | return new Blake2b(160); 521 | } 522 | 523 | 524 | // utility methods 525 | 526 | private static byte[] clone(byte[] arr) { 527 | return (arr == null) ? null : arr.clone(); 528 | } 529 | 530 | private static long[] clone(long[] data) { 531 | return null == data ? null : data.clone(); 532 | } 533 | 534 | private static int littleEndianToInt(byte[] bs, int off) { 535 | int n = bs[off] & 0xff; 536 | n |= (bs[++off] & 0xff) << 8; 537 | n |= (bs[++off] & 0xff) << 16; 538 | n |= bs[++off] << 24; 539 | return n; 540 | } 541 | 542 | private static void intToLittleEndian(int n, byte[] bs, int off) { 543 | bs[off] = (byte) (n); 544 | bs[++off] = (byte) (n >>> 8); 545 | bs[++off] = (byte) (n >>> 16); 546 | bs[++off] = (byte) (n >>> 24); 547 | } 548 | 549 | private static long littleEndianToLong(byte[] bs, int off) { 550 | int lo = littleEndianToInt(bs, off); 551 | int hi = littleEndianToInt(bs, off + 4); 552 | return ((long) (hi & 0xffffffffL) << 32) | (long) (lo & 0xffffffffL); 553 | } 554 | 555 | private static byte[] longToLittleEndian(long n) { 556 | byte[] bs = new byte[8]; 557 | longToLittleEndian(n, bs, 0); 558 | return bs; 559 | } 560 | 561 | private static void longToLittleEndian(long n, byte[] bs, int off) { 562 | intToLittleEndian((int) (n & 0xffffffffL), bs, off); 563 | intToLittleEndian((int) (n >>> 32), bs, off + 4); 564 | } 565 | 566 | private static long rotateRight(long i, int distance) { 567 | return Long.rotateRight(i, distance); 568 | } 569 | } 570 | -------------------------------------------------------------------------------- /src/com/haccercat/client/libraries/TweetNacl.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Tom Zhou 2 | 3 | 4 | package com.haccercat.client.libraries; 5 | 6 | import java.io.UnsupportedEncodingException; 7 | import java.security.SecureRandom; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | 11 | /* 12 | * @description 13 | * TweetNacl.c Java porting 14 | * */ 15 | public final class TweetNacl { 16 | 17 | private final static String TAG = "TweetNacl"; 18 | 19 | /* 20 | * @description 21 | * Box algorithm, Public-key authenticated encryption 22 | * */ 23 | public static final class Box { 24 | 25 | private final static String TAG = "Box"; 26 | 27 | private AtomicLong nonce; 28 | 29 | private byte [] theirPublicKey; 30 | private byte [] mySecretKey; 31 | public byte [] sharedKey; 32 | 33 | public Box(byte [] theirPublicKey, byte [] mySecretKey) { 34 | this(theirPublicKey, mySecretKey, 68); 35 | } 36 | 37 | public Box(byte [] theirPublicKey, byte [] mySecretKey, long nonce) { 38 | this.theirPublicKey = theirPublicKey; 39 | this.mySecretKey = mySecretKey; 40 | 41 | this.nonce = new AtomicLong(nonce); 42 | 43 | // generate pre-computed shared key 44 | before(); 45 | } 46 | 47 | public void setNonce(long nonce) { 48 | this.nonce.set(nonce); 49 | } 50 | public long getNonce() { 51 | return this.nonce.get(); 52 | } 53 | public long incrNonce() { 54 | return this.nonce.incrementAndGet(); 55 | } 56 | private byte[] generateNonce() { 57 | // generate nonce 58 | long nonce = this.nonce.get(); 59 | 60 | byte [] n = new byte[nonceLength]; 61 | for (int i = 0; i < nonceLength; i += 8) { 62 | n[i+0] = (byte) (nonce>>> 0); 63 | n[i+1] = (byte) (nonce>>> 8); 64 | n[i+2] = (byte) (nonce>>>16); 65 | n[i+3] = (byte) (nonce>>>24); 66 | n[i+4] = (byte) (nonce>>>32); 67 | n[i+5] = (byte) (nonce>>>40); 68 | n[i+6] = (byte) (nonce>>>48); 69 | n[i+7] = (byte) (nonce>>>56); 70 | } 71 | 72 | return n; 73 | } 74 | 75 | /* 76 | * @description 77 | * Encrypt and authenticates message using peer's public key, 78 | * our secret key, and the given nonce, which must be unique 79 | * for each distinct message for a key pair. 80 | * 81 | * Returns an encrypted and authenticated message, 82 | * which is nacl.box.overheadLength longer than the original message. 83 | * */ 84 | ///public byte_buf_t box(byte [] message) { 85 | public byte [] box(byte [] message) { 86 | 87 | return box(message, generateNonce()); 88 | 89 | } 90 | 91 | /* 92 | * @description 93 | * Encrypt and authenticates message using peer's public key, 94 | * our secret key, and the explicitly provided nonce. 95 | * Caller is responsible for ensuring that nonce is unique 96 | * for each distinct message for a key pair. 97 | * 98 | * Returns an encrypted and authenticated message, 99 | * which is nacl.box.overheadLength longer than the original message. 100 | * */ 101 | ///public byte_buf_t box(byte [] message) { 102 | public byte [] box(byte [] message, byte [] theNonce) { 103 | 104 | // check message 105 | if (!(message!=null && message.length>0 && 106 | theNonce!=null && theNonce.length==nonceLength)) 107 | return null; 108 | 109 | // message buffer 110 | byte [] m = new byte[message.length + zerobytesLength]; 111 | 112 | // cipher buffer 113 | byte [] c = new byte[m.length]; 114 | 115 | for (int i = 0; i < message.length; i ++) 116 | m[i+zerobytesLength] = message[i]; 117 | 118 | if (0 != crypto_box(c, m, m.length, theNonce, theirPublicKey, mySecretKey)) 119 | return null; 120 | 121 | // wrap byte_buf_t on c offset@boxzerobytesLength 122 | ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength); 123 | byte [] ret = new byte[c.length-boxzerobytesLength]; 124 | 125 | for (int i = 0; i < ret.length; i ++) 126 | ret[i] = c[i+boxzerobytesLength]; 127 | 128 | return ret; 129 | } 130 | 131 | /* 132 | * @description 133 | * Authenticates and decrypts the given box with peer's public key, 134 | * our secret key, and the given nonce. 135 | * 136 | * Returns the original message, or null if authentication fails. 137 | * */ 138 | public byte [] open(byte [] box) { 139 | 140 | return open(box, generateNonce()); 141 | 142 | } 143 | 144 | /* 145 | * @description 146 | * Authenticates and decrypts the given box with peer's public key, 147 | * our secret key, and the explicitly provided nonce. 148 | * 149 | * Returns the original message, or null if authentication fails. 150 | * */ 151 | public byte [] open(byte [] box, byte [] theNonce) { 152 | // check message 153 | if (!(box!=null && box.length>boxzerobytesLength && 154 | theNonce!=null && theNonce.length==nonceLength)) 155 | return null; 156 | 157 | // cipher buffer 158 | byte [] c = new byte[box.length + boxzerobytesLength]; 159 | 160 | // message buffer 161 | byte [] m = new byte[c.length]; 162 | 163 | for (int i = 0; i < box.length; i++) 164 | c[i+boxzerobytesLength] = box[i]; 165 | 166 | if (0 != crypto_box_open(m, c, c.length, theNonce, theirPublicKey, mySecretKey)) 167 | return null; 168 | 169 | // wrap byte_buf_t on m offset@zerobytesLength 170 | ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength); 171 | byte [] ret = new byte[m.length-zerobytesLength]; 172 | 173 | for (int i = 0; i < ret.length; i ++) 174 | ret[i] = m[i+zerobytesLength]; 175 | 176 | return ret; 177 | } 178 | 179 | /* 180 | * @description 181 | * Returns a precomputed shared key 182 | * which can be used in nacl.box.after and nacl.box.open.after. 183 | * */ 184 | public byte [] before() { 185 | if (this.sharedKey == null) { 186 | this.sharedKey = new byte[sharedKeyLength]; 187 | crypto_box_beforenm(this.sharedKey, this.theirPublicKey, this.mySecretKey); 188 | } 189 | 190 | return this.sharedKey; 191 | } 192 | 193 | /* 194 | * @description 195 | * Same as nacl.box, but uses a shared key precomputed with nacl.box.before. 196 | * */ 197 | public byte [] after(byte [] message) { 198 | 199 | return after(message, generateNonce()); 200 | 201 | } 202 | 203 | /* 204 | * @description 205 | * Same as nacl.box, but uses a shared key precomputed with nacl.box.before 206 | * and explicitly provided nonce 207 | * */ 208 | public byte [] after(byte [] message, byte [] theNonce) { 209 | // check message 210 | if (!(message!=null && message.length>0 && 211 | theNonce!=null && theNonce.length==nonceLength)) 212 | return null; 213 | 214 | // message buffer 215 | byte [] m = new byte[message.length + zerobytesLength]; 216 | 217 | // cipher buffer 218 | byte [] c = new byte[m.length]; 219 | 220 | for (int i = 0; i < message.length; i ++) 221 | m[i+zerobytesLength] = message[i]; 222 | 223 | if (0 != crypto_box_afternm(c, m, m.length, theNonce, sharedKey)) 224 | return null; 225 | 226 | // wrap byte_buf_t on c offset@boxzerobytesLength 227 | ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength); 228 | byte [] ret = new byte[c.length-boxzerobytesLength]; 229 | 230 | for (int i = 0; i < ret.length; i ++) 231 | ret[i] = c[i+boxzerobytesLength]; 232 | 233 | return ret; 234 | } 235 | 236 | /* 237 | * @description 238 | * Same as nacl.box.open, 239 | * but uses a shared key pre-computed with nacl.box.before. 240 | * */ 241 | public byte [] open_after(byte [] box) { 242 | 243 | return open_after(box, generateNonce()); 244 | 245 | } 246 | 247 | /* 248 | * @description 249 | * Same as nacl.box.open, 250 | * but uses a shared key pre-computed with nacl.box.before, 251 | * and explicitly passed nonce 252 | * */ 253 | public byte [] open_after(byte [] box, byte [] theNonce) { 254 | // check message 255 | if (!(box!=null && box.length>boxzerobytesLength && 256 | theNonce!=null && theNonce.length==nonceLength)) 257 | return null; 258 | 259 | // cipher buffer 260 | byte [] c = new byte[box.length + boxzerobytesLength]; 261 | 262 | // message buffer 263 | byte [] m = new byte[c.length]; 264 | 265 | for (int i = 0; i < box.length; i++) 266 | c[i+boxzerobytesLength] = box[i]; 267 | 268 | if (crypto_box_open_afternm(m, c, c.length, theNonce, sharedKey) != 0) 269 | return null; 270 | 271 | // wrap byte_buf_t on m offset@zerobytesLength 272 | ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength); 273 | byte [] ret = new byte[m.length-zerobytesLength]; 274 | 275 | for (int i = 0; i < ret.length; i ++) 276 | ret[i] = m[i+zerobytesLength]; 277 | 278 | return ret; 279 | } 280 | 281 | /* 282 | * @description 283 | * Length of public key in bytes. 284 | * */ 285 | public static final int publicKeyLength = 32; 286 | 287 | /* 288 | * @description 289 | * Length of secret key in bytes. 290 | * */ 291 | public static final int secretKeyLength = 32; 292 | 293 | /* 294 | * @description 295 | * Length of precomputed shared key in bytes. 296 | * */ 297 | public static final int sharedKeyLength = 32; 298 | 299 | /* 300 | * @description 301 | * Length of nonce in bytes. 302 | * */ 303 | public static final int nonceLength = 24; 304 | 305 | /* 306 | * @description 307 | * zero bytes in case box 308 | * */ 309 | public static final int zerobytesLength = 32; 310 | /* 311 | * @description 312 | * zero bytes in case open box 313 | * */ 314 | public static final int boxzerobytesLength = 16; 315 | 316 | /* 317 | * @description 318 | * Length of overhead added to box compared to original message. 319 | * */ 320 | public static final int overheadLength = 16; 321 | 322 | public static class KeyPair { 323 | private byte [] publicKey; 324 | private byte [] secretKey; 325 | 326 | public KeyPair() { 327 | publicKey = new byte[publicKeyLength]; 328 | secretKey = new byte[secretKeyLength]; 329 | } 330 | 331 | public byte [] getPublicKey() { 332 | return publicKey; 333 | } 334 | 335 | public byte [] getSecretKey() { 336 | return secretKey; 337 | } 338 | } 339 | 340 | /* 341 | * @description 342 | * Generates a new random key pair for box and 343 | * returns it as an object with publicKey and secretKey members: 344 | * */ 345 | public static KeyPair keyPair() { 346 | KeyPair kp = new KeyPair(); 347 | 348 | crypto_box_keypair(kp.getPublicKey(), kp.getSecretKey()); 349 | return kp; 350 | } 351 | 352 | public static KeyPair keyPair_fromSecretKey(byte [] secretKey) { 353 | KeyPair kp = new KeyPair(); 354 | byte [] sk = kp.getSecretKey(); 355 | byte [] pk = kp.getPublicKey(); 356 | 357 | // copy sk 358 | for (int i = 0; i < sk.length; i ++) 359 | sk[i] = secretKey[i]; 360 | 361 | crypto_scalarmult_base(pk, sk); 362 | return kp; 363 | } 364 | 365 | } 366 | 367 | /* 368 | * @description 369 | * Secret Box algorithm, secret key 370 | * */ 371 | public static final class SecretBox { 372 | 373 | private final static String TAG = "SecretBox"; 374 | 375 | private AtomicLong nonce; 376 | 377 | private byte [] key; 378 | 379 | public SecretBox(byte [] key) { 380 | this(key, 68); 381 | } 382 | 383 | public SecretBox(byte [] key, long nonce) { 384 | this.key = key; 385 | 386 | this.nonce = new AtomicLong(nonce); 387 | } 388 | 389 | public void setNonce(long nonce) { 390 | this.nonce.set(nonce); 391 | } 392 | public long getNonce() { 393 | return this.nonce.get(); 394 | } 395 | public long incrNonce() { 396 | return this.nonce.incrementAndGet(); 397 | } 398 | private byte[] generateNonce() { 399 | // generate nonce 400 | long nonce = this.nonce.get(); 401 | 402 | byte [] n = new byte[nonceLength]; 403 | for (int i = 0; i < nonceLength; i += 8) { 404 | n[i+0] = (byte) (nonce>>> 0); 405 | n[i+1] = (byte) (nonce>>> 8); 406 | n[i+2] = (byte) (nonce>>>16); 407 | n[i+3] = (byte) (nonce>>>24); 408 | n[i+4] = (byte) (nonce>>>32); 409 | n[i+5] = (byte) (nonce>>>40); 410 | n[i+6] = (byte) (nonce>>>48); 411 | n[i+7] = (byte) (nonce>>>56); 412 | } 413 | 414 | return n; 415 | } 416 | 417 | /* 418 | * @description 419 | * Encrypt and authenticates message using the key and the nonce. 420 | * The nonce must be unique for each distinct message for this key. 421 | * 422 | * Returns an encrypted and authenticated message, 423 | * which is nacl.secretbox.overheadLength longer than the original message. 424 | * */ 425 | ///public byte_buf_t box(byte [] message) { 426 | public byte [] box(byte [] message) { 427 | 428 | return box(message, generateNonce()); 429 | 430 | } 431 | 432 | /* 433 | * @description 434 | * Encrypt and authenticates message using the key 435 | * and the explicitly passed nonce. 436 | * The nonce must be unique for each distinct message for this key. 437 | * 438 | * Returns an encrypted and authenticated message, 439 | * which is nacl.secretbox.overheadLength longer than the original message. 440 | * */ 441 | ///public byte_buf_t box(byte [] message) { 442 | public byte [] box(byte [] message, byte [] theNonce) { 443 | // check message 444 | if (!(message!=null && message.length>0 && 445 | theNonce!=null && theNonce.length==nonceLength)) 446 | return null; 447 | 448 | // message buffer 449 | byte [] m = new byte[message.length + zerobytesLength]; 450 | 451 | // cipher buffer 452 | byte [] c = new byte[m.length]; 453 | 454 | for (int i = 0; i < message.length; i ++) 455 | m[i+zerobytesLength] = message[i]; 456 | 457 | if (0 != crypto_secretbox(c, m, m.length, theNonce, key)) 458 | return null; 459 | 460 | // TBD optimizing ... 461 | // wrap byte_buf_t on c offset@boxzerobytesLength 462 | ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength); 463 | byte [] ret = new byte[c.length-boxzerobytesLength]; 464 | 465 | for (int i = 0; i < ret.length; i ++) 466 | ret[i] = c[i+boxzerobytesLength]; 467 | 468 | return ret; 469 | } 470 | 471 | /* 472 | * @description 473 | * Authenticates and decrypts the given secret box 474 | * using the key and the nonce. 475 | * 476 | * Returns the original message, or null if authentication fails. 477 | * */ 478 | public byte [] open(byte [] box) { 479 | 480 | return open(box, generateNonce()); 481 | 482 | } 483 | 484 | /* 485 | * @description 486 | * Authenticates and decrypts the given secret box 487 | * using the key and the explicitly passed nonce. 488 | * 489 | * Returns the original message, or null if authentication fails. 490 | * */ 491 | public byte [] open(byte [] box, byte [] theNonce) { 492 | // check message 493 | if (!(box!=null && box.length>boxzerobytesLength && 494 | theNonce!=null && theNonce.length==nonceLength)) 495 | return null; 496 | 497 | // cipher buffer 498 | byte [] c = new byte[box.length + boxzerobytesLength]; 499 | 500 | // message buffer 501 | byte [] m = new byte[c.length]; 502 | 503 | for (int i = 0; i < box.length; i++) 504 | c[i+boxzerobytesLength] = box[i]; 505 | 506 | if (0 != crypto_secretbox_open(m, c, c.length, theNonce, key)) 507 | return null; 508 | 509 | // wrap byte_buf_t on m offset@zerobytesLength 510 | ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength); 511 | byte [] ret = new byte[m.length-zerobytesLength]; 512 | 513 | for (int i = 0; i < ret.length; i ++) 514 | ret[i] = m[i+zerobytesLength]; 515 | 516 | return ret; 517 | } 518 | 519 | /* 520 | * @description 521 | * Length of key in bytes. 522 | * */ 523 | public static final int keyLength = 32; 524 | 525 | /* 526 | * @description 527 | * Length of nonce in bytes. 528 | * */ 529 | public static final int nonceLength = 24; 530 | 531 | /* 532 | * @description 533 | * Length of overhead added to secret box compared to original message. 534 | * */ 535 | public static final int overheadLength = 16; 536 | 537 | /* 538 | * @description 539 | * zero bytes in case box 540 | * */ 541 | public static final int zerobytesLength = 32; 542 | /* 543 | * @description 544 | * zero bytes in case open box 545 | * */ 546 | public static final int boxzerobytesLength = 16; 547 | 548 | } 549 | 550 | /* 551 | * @description 552 | * Scalar multiplication, Implements curve25519. 553 | * */ 554 | public static final class ScalarMult { 555 | 556 | private final static String TAG = "ScalarMult"; 557 | 558 | /* 559 | * @description 560 | * Multiplies an integer n by a group element p and 561 | * returns the resulting group element. 562 | * */ 563 | public static byte [] scalseMult(byte [] n, byte [] p) { 564 | if (!(n.length==scalarLength && p.length==groupElementLength)) 565 | return null; 566 | 567 | byte [] q = new byte [scalarLength]; 568 | 569 | crypto_scalarmult(q, n, p); 570 | 571 | return q; 572 | } 573 | 574 | /* 575 | * @description 576 | * Multiplies an integer n by a standard group element and 577 | * returns the resulting group element. 578 | * */ 579 | public static byte [] scalseMult_base(byte [] n) { 580 | if (!(n.length==scalarLength)) 581 | return null; 582 | 583 | byte [] q = new byte [scalarLength]; 584 | 585 | crypto_scalarmult_base(q, n); 586 | 587 | return q; 588 | } 589 | 590 | /* 591 | * @description 592 | * Length of scalar in bytes. 593 | * */ 594 | public static final int scalarLength = 32; 595 | 596 | /* 597 | * @description 598 | * Length of group element in bytes. 599 | * */ 600 | public static final int groupElementLength = 32; 601 | 602 | } 603 | 604 | 605 | /* 606 | * @description 607 | * Hash algorithm, Implements SHA-512. 608 | * */ 609 | public static final class Hash { 610 | 611 | private final static String TAG = "Hash"; 612 | 613 | /* 614 | * @description 615 | * Returns SHA-512 hash of the message. 616 | * */ 617 | public static byte[] sha512(byte [] message) { 618 | if (!(message!=null && message.length>0)) 619 | return null; 620 | 621 | byte [] out = new byte[hashLength]; 622 | 623 | crypto_hash(out, message); 624 | 625 | return out; 626 | } 627 | public static byte[] sha512(String message) throws UnsupportedEncodingException { 628 | return sha512(message.getBytes("utf-8")); 629 | } 630 | 631 | /* 632 | * @description 633 | * Length of hash in bytes. 634 | * */ 635 | public static final int hashLength = 64; 636 | 637 | } 638 | 639 | 640 | /* 641 | * @description 642 | * Signature algorithm, Implements ed25519. 643 | * */ 644 | public static final class Signature { 645 | 646 | private final static String TAG = "Signature"; 647 | 648 | private byte [] theirPublicKey; 649 | private byte [] mySecretKey; 650 | 651 | public Signature(byte [] theirPublicKey, byte [] mySecretKey) { 652 | this.theirPublicKey = theirPublicKey; 653 | this.mySecretKey = mySecretKey; 654 | } 655 | 656 | /* 657 | * @description 658 | * Signs the message using the secret key and returns a signed message. 659 | * */ 660 | public byte [] sign(byte [] message) { 661 | // signed message 662 | byte [] sm = new byte[message.length + signatureLength]; 663 | 664 | crypto_sign(sm, -1, message, message.length, mySecretKey); 665 | 666 | return sm; 667 | } 668 | 669 | /* 670 | * @description 671 | * Verifies the signed message and returns the message without signature. 672 | * Returns null if verification failed. 673 | * */ 674 | public byte [] open(byte [] signedMessage) { 675 | // check sm length 676 | if (!(signedMessage!=null && signedMessage.length>signatureLength)) 677 | return null; 678 | 679 | // temp buffer 680 | byte [] tmp = new byte[signedMessage.length]; 681 | 682 | if (0 != crypto_sign_open(tmp, -1, signedMessage, signedMessage.length, theirPublicKey)) 683 | return null; 684 | 685 | // message 686 | byte [] msg = new byte[signedMessage.length-signatureLength]; 687 | for (int i = 0; i < msg.length; i ++) 688 | msg[i] = signedMessage[i+signatureLength]; 689 | 690 | return msg; 691 | } 692 | 693 | /* 694 | * @description 695 | * Signs the message using the secret key and returns a signature. 696 | * */ 697 | public byte [] detached(byte [] message) { 698 | byte[] signedMsg = this.sign(message); 699 | byte[] sig = new byte[signatureLength]; 700 | for (int i = 0; i < sig.length; i++) 701 | sig[i] = signedMsg[i]; 702 | return sig; 703 | } 704 | 705 | /* 706 | * @description 707 | * Verifies the signature for the message and 708 | * returns true if verification succeeded or false if it failed. 709 | * */ 710 | public boolean detached_verify(byte [] message, byte [] signature) { 711 | if (signature.length != signatureLength) 712 | return false; 713 | if (theirPublicKey.length != publicKeyLength) 714 | return false; 715 | byte [] sm = new byte[signatureLength + message.length]; 716 | byte [] m = new byte[signatureLength + message.length]; 717 | for (int i = 0; i < signatureLength; i++) 718 | sm[i] = signature[i]; 719 | for (int i = 0; i < message.length; i++) 720 | sm[i + signatureLength] = message[i]; 721 | return (crypto_sign_open(m, -1, sm, sm.length, theirPublicKey) >= 0); 722 | } 723 | 724 | /* 725 | * @description 726 | * Generates new random key pair for signing and 727 | * returns it as an object with publicKey and secretKey members 728 | * */ 729 | public static class KeyPair { 730 | private byte [] publicKey; 731 | private byte [] secretKey; 732 | 733 | public KeyPair() { 734 | publicKey = new byte[publicKeyLength]; 735 | secretKey = new byte[secretKeyLength]; 736 | } 737 | 738 | public byte [] getPublicKey() { 739 | return publicKey; 740 | } 741 | 742 | public byte [] getSecretKey() { 743 | return secretKey; 744 | } 745 | } 746 | 747 | /* 748 | * @description 749 | * Signs the message using the secret key and returns a signed message. 750 | * */ 751 | public static KeyPair keyPair() { 752 | KeyPair kp = new KeyPair(); 753 | 754 | crypto_sign_keypair(kp.getPublicKey(), kp.getSecretKey(), false); 755 | return kp; 756 | } 757 | 758 | public static KeyPair keyPair_fromSecretKey(byte [] secretKey) { 759 | KeyPair kp = new KeyPair(); 760 | byte [] pk = kp.getPublicKey(); 761 | byte [] sk = kp.getSecretKey(); 762 | 763 | // copy sk 764 | for (int i = 0; i < kp.getSecretKey().length; i ++) 765 | sk[i] = secretKey[i]; 766 | 767 | // copy pk from sk 768 | for (int i = 0; i < kp.getPublicKey().length; i ++) 769 | pk[i] = secretKey[32+i]; // hard-copy 770 | 771 | return kp; 772 | } 773 | 774 | public static KeyPair keyPair_fromSeed(byte [] seed) { 775 | KeyPair kp = new KeyPair(); 776 | byte [] pk = kp.getPublicKey(); 777 | byte [] sk = kp.getSecretKey(); 778 | 779 | // copy sk 780 | for (int i = 0; i < seedLength; i ++) 781 | sk[i] = seed[i]; 782 | 783 | // generate pk from sk 784 | crypto_sign_keypair(pk, sk, true); 785 | 786 | return kp; 787 | } 788 | 789 | /* 790 | * @description 791 | * Length of signing public key in bytes. 792 | * */ 793 | public static final int publicKeyLength = 32; 794 | 795 | /* 796 | * @description 797 | * Length of signing secret key in bytes. 798 | * */ 799 | public static final int secretKeyLength = 64; 800 | 801 | /* 802 | * @description 803 | * Length of seed for nacl.sign.keyPair.fromSeed in bytes. 804 | * */ 805 | public static final int seedLength = 32; 806 | 807 | /* 808 | * @description 809 | * Length of signature in bytes. 810 | * */ 811 | public static final int signatureLength = 64; 812 | } 813 | 814 | 815 | //////////////////////////////////////////////////////////////////////////////////// 816 | /* 817 | * @description 818 | * Codes below are ported from TweetNacl.c/TweetNacl.h 819 | * */ 820 | 821 | private static final byte [] _0 = new byte[16]; 822 | private static final byte [] _9 = new byte[32]; 823 | static { 824 | for (int i = 0; i < _0.length; i ++) _0[i] = 0; 825 | 826 | for (int i = 0; i < _9.length; i ++) _9[i] = 0; _9[0] = 9; 827 | } 828 | 829 | private static final long [] gf0 = new long[16]; 830 | private static final long [] gf1 = new long[16]; 831 | private static final long [] _121665 = new long[16]; 832 | static { 833 | for (int i = 0; i < gf0.length; i ++) gf0[i] = 0; 834 | 835 | for (int i = 0; i < gf1.length; i ++) gf1[i] = 0; gf1[0] = 1; 836 | 837 | for (int i = 0; i < _121665.length; i ++) _121665[i] = 0; _121665[0] = 0xDB41; _121665[1] = 1; 838 | } 839 | 840 | private static final long [] D = new long [] { 841 | 0x78a3, 0x1359, 0x4dca, 0x75eb, 842 | 0xd8ab, 0x4141, 0x0a4d, 0x0070, 843 | 0xe898, 0x7779, 0x4079, 0x8cc7, 844 | 0xfe73, 0x2b6f, 0x6cee, 0x5203 845 | }; 846 | private static final long [] D2 = new long [] { 847 | 0xf159, 0x26b2, 0x9b94, 0xebd6, 848 | 0xb156, 0x8283, 0x149a, 0x00e0, 849 | 0xd130, 0xeef3, 0x80f2, 0x198e, 850 | 0xfce7, 0x56df, 0xd9dc, 0x2406 851 | }; 852 | private static final long [] X = new long [] { 853 | 0xd51a, 0x8f25, 0x2d60, 0xc956, 854 | 0xa7b2, 0x9525, 0xc760, 0x692c, 855 | 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 856 | 0x53fe, 0xcd6e, 0x36d3, 0x2169 857 | }; 858 | private static final long [] Y = new long [] { 859 | 0x6658, 0x6666, 0x6666, 0x6666, 860 | 0x6666, 0x6666, 0x6666, 0x6666, 861 | 0x6666, 0x6666, 0x6666, 0x6666, 862 | 0x6666, 0x6666, 0x6666, 0x6666 863 | }; 864 | private static final long [] I = new long [] { 865 | 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 866 | 0xe478, 0xad2f, 0x1806, 0x2f43, 867 | 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 868 | 0xdf0b, 0x4fc1, 0x2480, 0x2b83 869 | }; 870 | 871 | private static int L32(int x, int c) 872 | { 873 | return (x << c) | ((x&0xffffffff) >>> (32 - c)); 874 | } 875 | 876 | private static int ld32(byte [] x, final int xoff, final int xlen) 877 | { 878 | int u = (x[3+xoff]&0xff); 879 | u = (u<<8)|(x[2+xoff]&0xff); 880 | u = (u<<8)|(x[1+xoff]&0xff); 881 | return (u<<8)|(x[0+xoff]&0xff); 882 | } 883 | 884 | private static long dl64(byte [] x, final int xoff, final int xlen) { 885 | int i; 886 | long u=0; 887 | for (i = 0; i < 8; i ++) u=(u<<8)|(x[i+xoff]&0xff); 888 | return u; 889 | } 890 | 891 | private static void st32(byte [] x, final int xoff, final int xlen, int u) 892 | { 893 | int i; 894 | for (i = 0; i < 4; i ++) { x[i+xoff] = (byte)(u&0xff); u >>>= 8; } 895 | } 896 | 897 | private static void ts64(byte [] x, final int xoff, final int xlen, long u) 898 | { 899 | int i; 900 | for (i = 7;i >= 0;--i) { x[i+xoff] = (byte)(u&0xff); u >>>= 8; } 901 | } 902 | 903 | private static int vn( 904 | byte [] x, final int xoff, final int xlen, 905 | byte [] y, final int yoff, final int ylen, 906 | int n) 907 | { 908 | int i,d = 0; 909 | for (i = 0; i < n; i ++) d |= (x[i+xoff]^y[i+yoff]) & 0xff; 910 | return (1 & ((d - 1) >>> 8)) - 1; 911 | } 912 | 913 | private static int crypto_verify_16( 914 | byte [] x, final int xoff, final int xlen, 915 | byte [] y, final int yoff, final int ylen) 916 | { 917 | return vn(x,xoff,xlen,y,yoff,ylen,16); 918 | } 919 | public static int crypto_verify_16(byte [] x, byte [] y) 920 | { 921 | return crypto_verify_16(x, 0, x.length, y, 0, y.length); 922 | } 923 | 924 | private static int crypto_verify_32( 925 | byte [] x, final int xoff, final int xlen, 926 | byte [] y, final int yoff, final int ylen) 927 | { 928 | return vn(x,xoff,xlen,y,yoff,ylen,32); 929 | } 930 | public static int crypto_verify_32(byte [] x, byte [] y) 931 | { 932 | return crypto_verify_32(x, 0, x.length, y, 0, y.length); 933 | } 934 | 935 | private static void core(byte [] out, byte [] in, byte [] k, byte [] c, int h) 936 | { 937 | int [] w = new int[16], x = new int[16], y = new int[16], t = new int[4]; 938 | int i,j,m; 939 | 940 | for (i = 0; i < 4; i ++) { 941 | x[5*i] = ld32(c, 4*i, 4); 942 | x[1+i] = ld32(k, 4*i, 4); 943 | x[6+i] = ld32(in, 4*i, 4); 944 | x[11+i] = ld32(k, 16+4*i, 4); 945 | } 946 | 947 | for (i = 0; i < 16; i ++) y[i] = x[i]; 948 | 949 | for (i = 0; i < 19; i ++) { 950 | for (j = 0; j < 4; j ++) { 951 | for (m = 0; m < 4; m ++) t[m] = x[(5*j+4*m)%16]; 952 | t[1] ^= L32(t[0]+t[3], 7); 953 | t[2] ^= L32(t[1]+t[0], 9); 954 | t[3] ^= L32(t[2]+t[1],13); 955 | t[0] ^= L32(t[3]+t[2],18); 956 | for (m = 0; m < 4; m ++) w[4*j+(j+m)%4] = t[m]; 957 | } 958 | for (m = 0; m < 16; m ++) x[m] = w[m]; 959 | } 960 | 961 | if (h != 0) { 962 | for (i = 0; i < 16; i ++) x[i] += y[i]; 963 | for (i = 0; i < 4; i ++) { 964 | x[5*i] -= ld32(c, 4*i, 4); 965 | x[6+i] -= ld32(in, 4*i, 4); 966 | } 967 | for (i = 0; i < 4; i ++) { 968 | st32(out, 4*i, 4, x[5*i]); 969 | st32(out, 16+4*i, 4, x[6+i]); 970 | } 971 | } else 972 | for (i = 0; i < 16; i ++) st32(out, 4*i, 4, x[i] + y[i]); 973 | 974 | ///String dbgt = ""; 975 | ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg]; 976 | ///L/og.d(TAG, "core -> "+dbgt); 977 | } 978 | 979 | public static int crypto_core_salsa20(byte [] out, byte [] in, byte [] k, byte [] c) 980 | { 981 | core(out,in,k,c,0); 982 | 983 | ///String dbgt = ""; 984 | ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg]; 985 | ///L/og.d(TAG, "crypto_core_salsa20 -> "+dbgt); 986 | 987 | return 0; 988 | } 989 | 990 | public static int crypto_core_hsalsa20(byte [] out, byte [] in, byte [] k, byte [] c) 991 | { 992 | core(out,in,k,c,1); 993 | 994 | ///String dbgt = ""; 995 | ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg]; 996 | ///L/og.d(TAG, "crypto_core_hsalsa20 -> "+dbgt); 997 | 998 | return 0; 999 | } 1000 | 1001 | private static final byte[] sigma = { 101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107 }; 1002 | /*static { 1003 | try { 1004 | sigma = "expand 32-byte k".getBytes("utf-8"); 1005 | } catch (UnsupportedEncodingException e) { 1006 | e.printStackTrace(); 1007 | } 1008 | }*/ 1009 | 1010 | private static int crypto_stream_salsa20_xor(byte [] c, byte [] m, long b, byte [] n,final int noff,final int nlen, byte [] k) 1011 | { 1012 | byte[] z = new byte[16], x = new byte[64]; 1013 | int u,i; 1014 | if (0==b) return 0; 1015 | 1016 | for (i = 0; i < 16; i ++) z[i] = 0; 1017 | for (i = 0; i < 8; i ++) z[i] = n[i+noff]; 1018 | 1019 | int coffset = 0; 1020 | int moffset = 0; 1021 | while (b >= 64) { 1022 | crypto_core_salsa20(x,z,k,sigma); 1023 | for (i = 0; i < 64; i ++) c[i+coffset] = (byte) (((m!=null?m[i+moffset]:0) ^ x[i]) & 0xff); 1024 | u = 1; 1025 | for (i = 8;i < 16;++i) { 1026 | u += (int) (z[i]&0xff); 1027 | z[i] = (byte) (u&0xff); 1028 | u >>>= 8; 1029 | } 1030 | b -= 64; 1031 | coffset += 64; 1032 | if (m!=null) moffset += 64; 1033 | } 1034 | if (b!=0) { 1035 | crypto_core_salsa20(x,z,k,sigma); 1036 | for (i = 0; i < b; i ++) c[i+coffset] = (byte) (((m!=null?m[i+moffset]:0) ^ x[i]) & 0xff); 1037 | } 1038 | return 0; 1039 | } 1040 | public static int crypto_stream_salsa20_xor(byte [] c, byte [] m, long b, byte [] n, byte [] k) { 1041 | return crypto_stream_salsa20_xor(c, m, b, n,0,n.length, k); 1042 | } 1043 | 1044 | private static int crypto_stream_salsa20(byte [] c, long d, byte [] n,final int noff,final int nlen, byte [] k) 1045 | { 1046 | return crypto_stream_salsa20_xor(c,null,d, n,noff,nlen, k); 1047 | } 1048 | public static int crypto_stream_salsa20(byte [] c, long d, byte [] n, byte [] k) { 1049 | return crypto_stream_salsa20(c, d, n,0,n.length, k); 1050 | } 1051 | 1052 | public static int crypto_stream(byte [] c, long d, byte [] n, byte [] k) 1053 | { 1054 | byte[] s = new byte[32]; 1055 | crypto_core_hsalsa20(s,n,k,sigma); 1056 | return crypto_stream_salsa20(c,d, n,16,n.length-16, s); 1057 | } 1058 | 1059 | public static int crypto_stream_xor(byte []c,byte []m,long d,byte []n,byte []k) 1060 | { 1061 | byte[] s = new byte[32]; 1062 | crypto_core_hsalsa20(s,n,k,sigma); 1063 | return crypto_stream_salsa20_xor(c,m,d, n,16,n.length-16, s); 1064 | } 1065 | 1066 | /* !!! Use TweetNaclFast.java onetimeauth function 1067 | private static void add1305(int [] h,int [] c) 1068 | { 1069 | int j; 1070 | int u = 0; 1071 | for (j = 0; j < 17; j ++) { 1072 | u = (u + ((h[j] + c[j]) | 0)) | 0; 1073 | h[j] = u & 255; 1074 | u >>>= 8; 1075 | } 1076 | } 1077 | 1078 | private final static int minusp[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 }; 1079 | 1080 | private static int crypto_onetimeauth( 1081 | byte[] out,final int outoff,final int outlen, 1082 | byte[] m,final int moff,final int mlen, 1083 | long n, 1084 | byte [] k) 1085 | { 1086 | int i,j; 1087 | int s,u; 1088 | int [] x = new int[17], r = new int [17], 1089 | h = new int[17], c = new int [17], g = new int[17]; 1090 | 1091 | for (j = 0; j < 17; j ++) r[j] = h[j] = 0; 1092 | 1093 | for (j = 0; j < 16; j ++) r[j] = k[j] & 0xff; 1094 | 1095 | r[3]&=15; 1096 | r[4]&=252; 1097 | r[7]&=15; 1098 | r[8]&=252; 1099 | r[11]&=15; 1100 | r[12]&=252; 1101 | r[15]&=15; 1102 | 1103 | int moffset = moff; 1104 | while (n > 0) { 1105 | for (j = 0; j < 17; j ++) c[j] = 0; 1106 | for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j+moffset] & 0xff; 1107 | c[j] = 1; 1108 | 1109 | moffset += j; 1110 | 1111 | n -= j; 1112 | add1305(h,c); 1113 | for (i = 0; i < 17; i ++) { 1114 | x[i] = 0; 1115 | for (j = 0; j < 17; j ++) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]); 1116 | for (j = 0; j < 17; j++) x[i] = (x[i] + (h[j] * ((j <= i) ? r[i - j] : ((320 * r[i + 17 - j])|0))) | 0) | 0; 1117 | } 1118 | for (i = 0; i < 17; i ++) h[i] = x[i]; 1119 | u = 0; 1120 | for (j = 0; j < 16; j ++) { 1121 | u = (u + h[j]) | 0; 1122 | h[j] = u & 255; 1123 | u >>>= 8; 1124 | } 1125 | u = (u + h[16]) | 0; h[16] = u & 3; 1126 | u = (5 * (u >>> 2)) | 0; 1127 | for (j = 0; j < 16; j ++) { 1128 | u = (u + h[j]) | 0; 1129 | h[j] = u & 255; 1130 | u >>>= 8; 1131 | } 1132 | u = (u + h[16]) | 0; h[16] = u; 1133 | } 1134 | 1135 | for (j = 0; j < 17; j ++) g[j] = h[j]; 1136 | add1305(h,minusp); 1137 | s = (-(h[16] >>> 7) | 0); 1138 | for (j = 0; j < 17; j ++) h[j] ^= s & (g[j] ^ h[j]); 1139 | 1140 | for (j = 0; j < 16; j ++) c[j] = k[j + 16] & 0xff; 1141 | c[16] = 0; 1142 | add1305(h,c); 1143 | for (j = 0; j < 16; j ++) out[j+outoff] = (byte) (h[j]&0xff); 1144 | 1145 | return 0; 1146 | }*/ 1147 | 1148 | /* 1149 | * Port of Andrew Moon's Poly1305-donna-16. Public domain. 1150 | * https://github.com/floodyberry/poly1305-donna 1151 | */ 1152 | public static final class poly1305 { 1153 | 1154 | private byte[] buffer; 1155 | private int[] r; 1156 | private int[] h; 1157 | private int[] pad; 1158 | private int leftover; 1159 | private int fin; 1160 | 1161 | public poly1305(byte [] key) { 1162 | this.buffer = new byte[16]; 1163 | this.r = new int[10]; 1164 | this.h = new int[10]; 1165 | this.pad = new int[8]; 1166 | this.leftover = 0; 1167 | this.fin = 0; 1168 | 1169 | int t0, t1, t2, t3, t4, t5, t6, t7; 1170 | 1171 | t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; 1172 | t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; 1173 | t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; 1174 | t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; 1175 | t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; 1176 | this.r[5] = ((t4 >>> 1)) & 0x1ffe; 1177 | t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; 1178 | t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; 1179 | t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; 1180 | this.r[9] = ((t7 >>> 5)) & 0x007f; 1181 | 1182 | this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; 1183 | this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; 1184 | this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; 1185 | this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; 1186 | this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; 1187 | this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; 1188 | this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; 1189 | this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; 1190 | } 1191 | 1192 | public poly1305 blocks(byte [] m, int mpos, int bytes) { 1193 | int hibit = this.fin!=0 ? 0 : (1 << 11); 1194 | int t0, t1, t2, t3, t4, t5, t6, t7, c; 1195 | int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; 1196 | 1197 | int h0 = this.h[0], 1198 | h1 = this.h[1], 1199 | h2 = this.h[2], 1200 | h3 = this.h[3], 1201 | h4 = this.h[4], 1202 | h5 = this.h[5], 1203 | h6 = this.h[6], 1204 | h7 = this.h[7], 1205 | h8 = this.h[8], 1206 | h9 = this.h[9]; 1207 | 1208 | int r0 = this.r[0], 1209 | r1 = this.r[1], 1210 | r2 = this.r[2], 1211 | r3 = this.r[3], 1212 | r4 = this.r[4], 1213 | r5 = this.r[5], 1214 | r6 = this.r[6], 1215 | r7 = this.r[7], 1216 | r8 = this.r[8], 1217 | r9 = this.r[9]; 1218 | 1219 | while (bytes >= 16) { 1220 | t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; 1221 | t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; 1222 | t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; 1223 | t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; 1224 | t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; 1225 | h5 += ((t4 >>> 1)) & 0x1fff; 1226 | t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; 1227 | t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; 1228 | t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; 1229 | h9 += ((t7 >>> 5)) | hibit; 1230 | 1231 | c = 0; 1232 | 1233 | d0 = c; 1234 | d0 += h0 * r0; 1235 | d0 += h1 * (5 * r9); 1236 | d0 += h2 * (5 * r8); 1237 | d0 += h3 * (5 * r7); 1238 | d0 += h4 * (5 * r6); 1239 | c = (d0 >>> 13); d0 &= 0x1fff; 1240 | d0 += h5 * (5 * r5); 1241 | d0 += h6 * (5 * r4); 1242 | d0 += h7 * (5 * r3); 1243 | d0 += h8 * (5 * r2); 1244 | d0 += h9 * (5 * r1); 1245 | c += (d0 >>> 13); d0 &= 0x1fff; 1246 | 1247 | d1 = c; 1248 | d1 += h0 * r1; 1249 | d1 += h1 * r0; 1250 | d1 += h2 * (5 * r9); 1251 | d1 += h3 * (5 * r8); 1252 | d1 += h4 * (5 * r7); 1253 | c = (d1 >>> 13); d1 &= 0x1fff; 1254 | d1 += h5 * (5 * r6); 1255 | d1 += h6 * (5 * r5); 1256 | d1 += h7 * (5 * r4); 1257 | d1 += h8 * (5 * r3); 1258 | d1 += h9 * (5 * r2); 1259 | c += (d1 >>> 13); d1 &= 0x1fff; 1260 | 1261 | d2 = c; 1262 | d2 += h0 * r2; 1263 | d2 += h1 * r1; 1264 | d2 += h2 * r0; 1265 | d2 += h3 * (5 * r9); 1266 | d2 += h4 * (5 * r8); 1267 | c = (d2 >>> 13); d2 &= 0x1fff; 1268 | d2 += h5 * (5 * r7); 1269 | d2 += h6 * (5 * r6); 1270 | d2 += h7 * (5 * r5); 1271 | d2 += h8 * (5 * r4); 1272 | d2 += h9 * (5 * r3); 1273 | c += (d2 >>> 13); d2 &= 0x1fff; 1274 | 1275 | d3 = c; 1276 | d3 += h0 * r3; 1277 | d3 += h1 * r2; 1278 | d3 += h2 * r1; 1279 | d3 += h3 * r0; 1280 | d3 += h4 * (5 * r9); 1281 | c = (d3 >>> 13); d3 &= 0x1fff; 1282 | d3 += h5 * (5 * r8); 1283 | d3 += h6 * (5 * r7); 1284 | d3 += h7 * (5 * r6); 1285 | d3 += h8 * (5 * r5); 1286 | d3 += h9 * (5 * r4); 1287 | c += (d3 >>> 13); d3 &= 0x1fff; 1288 | 1289 | d4 = c; 1290 | d4 += h0 * r4; 1291 | d4 += h1 * r3; 1292 | d4 += h2 * r2; 1293 | d4 += h3 * r1; 1294 | d4 += h4 * r0; 1295 | c = (d4 >>> 13); d4 &= 0x1fff; 1296 | d4 += h5 * (5 * r9); 1297 | d4 += h6 * (5 * r8); 1298 | d4 += h7 * (5 * r7); 1299 | d4 += h8 * (5 * r6); 1300 | d4 += h9 * (5 * r5); 1301 | c += (d4 >>> 13); d4 &= 0x1fff; 1302 | 1303 | d5 = c; 1304 | d5 += h0 * r5; 1305 | d5 += h1 * r4; 1306 | d5 += h2 * r3; 1307 | d5 += h3 * r2; 1308 | d5 += h4 * r1; 1309 | c = (d5 >>> 13); d5 &= 0x1fff; 1310 | d5 += h5 * r0; 1311 | d5 += h6 * (5 * r9); 1312 | d5 += h7 * (5 * r8); 1313 | d5 += h8 * (5 * r7); 1314 | d5 += h9 * (5 * r6); 1315 | c += (d5 >>> 13); d5 &= 0x1fff; 1316 | 1317 | d6 = c; 1318 | d6 += h0 * r6; 1319 | d6 += h1 * r5; 1320 | d6 += h2 * r4; 1321 | d6 += h3 * r3; 1322 | d6 += h4 * r2; 1323 | c = (d6 >>> 13); d6 &= 0x1fff; 1324 | d6 += h5 * r1; 1325 | d6 += h6 * r0; 1326 | d6 += h7 * (5 * r9); 1327 | d6 += h8 * (5 * r8); 1328 | d6 += h9 * (5 * r7); 1329 | c += (d6 >>> 13); d6 &= 0x1fff; 1330 | 1331 | d7 = c; 1332 | d7 += h0 * r7; 1333 | d7 += h1 * r6; 1334 | d7 += h2 * r5; 1335 | d7 += h3 * r4; 1336 | d7 += h4 * r3; 1337 | c = (d7 >>> 13); d7 &= 0x1fff; 1338 | d7 += h5 * r2; 1339 | d7 += h6 * r1; 1340 | d7 += h7 * r0; 1341 | d7 += h8 * (5 * r9); 1342 | d7 += h9 * (5 * r8); 1343 | c += (d7 >>> 13); d7 &= 0x1fff; 1344 | 1345 | d8 = c; 1346 | d8 += h0 * r8; 1347 | d8 += h1 * r7; 1348 | d8 += h2 * r6; 1349 | d8 += h3 * r5; 1350 | d8 += h4 * r4; 1351 | c = (d8 >>> 13); d8 &= 0x1fff; 1352 | d8 += h5 * r3; 1353 | d8 += h6 * r2; 1354 | d8 += h7 * r1; 1355 | d8 += h8 * r0; 1356 | d8 += h9 * (5 * r9); 1357 | c += (d8 >>> 13); d8 &= 0x1fff; 1358 | 1359 | d9 = c; 1360 | d9 += h0 * r9; 1361 | d9 += h1 * r8; 1362 | d9 += h2 * r7; 1363 | d9 += h3 * r6; 1364 | d9 += h4 * r5; 1365 | c = (d9 >>> 13); d9 &= 0x1fff; 1366 | d9 += h5 * r4; 1367 | d9 += h6 * r3; 1368 | d9 += h7 * r2; 1369 | d9 += h8 * r1; 1370 | d9 += h9 * r0; 1371 | c += (d9 >>> 13); d9 &= 0x1fff; 1372 | 1373 | c = (((c << 2) + c)) | 0; 1374 | c = (c + d0) | 0; 1375 | d0 = c & 0x1fff; 1376 | c = (c >>> 13); 1377 | d1 += c; 1378 | 1379 | h0 = d0; 1380 | h1 = d1; 1381 | h2 = d2; 1382 | h3 = d3; 1383 | h4 = d4; 1384 | h5 = d5; 1385 | h6 = d6; 1386 | h7 = d7; 1387 | h8 = d8; 1388 | h9 = d9; 1389 | 1390 | mpos += 16; 1391 | bytes -= 16; 1392 | } 1393 | this.h[0] = h0; 1394 | this.h[1] = h1; 1395 | this.h[2] = h2; 1396 | this.h[3] = h3; 1397 | this.h[4] = h4; 1398 | this.h[5] = h5; 1399 | this.h[6] = h6; 1400 | this.h[7] = h7; 1401 | this.h[8] = h8; 1402 | this.h[9] = h9; 1403 | 1404 | return this; 1405 | } 1406 | 1407 | public poly1305 finish(byte [] mac, int macpos) { 1408 | int [] g = new int[10]; 1409 | int c, mask, f, i; 1410 | 1411 | if (this.leftover != 0) { 1412 | i = this.leftover; 1413 | this.buffer[i++] = 1; 1414 | for (; i < 16; i++) this.buffer[i] = 0; 1415 | this.fin = 1; 1416 | this.blocks(this.buffer, 0, 16); 1417 | } 1418 | 1419 | c = this.h[1] >>> 13; 1420 | this.h[1] &= 0x1fff; 1421 | for (i = 2; i < 10; i++) { 1422 | this.h[i] += c; 1423 | c = this.h[i] >>> 13; 1424 | this.h[i] &= 0x1fff; 1425 | } 1426 | this.h[0] += (c * 5); 1427 | c = this.h[0] >>> 13; 1428 | this.h[0] &= 0x1fff; 1429 | this.h[1] += c; 1430 | c = this.h[1] >>> 13; 1431 | this.h[1] &= 0x1fff; 1432 | this.h[2] += c; 1433 | 1434 | g[0] = this.h[0] + 5; 1435 | c = g[0] >>> 13; 1436 | g[0] &= 0x1fff; 1437 | for (i = 1; i < 10; i++) { 1438 | g[i] = this.h[i] + c; 1439 | c = g[i] >>> 13; 1440 | g[i] &= 0x1fff; 1441 | } 1442 | g[9] -= (1 << 13); g[9] &= 0xffff; 1443 | 1444 | mask = (g[9] >>> ((2 * 8) - 1)) - 1; mask &= 0xffff; 1445 | for (i = 0; i < 10; i++) g[i] &= mask; 1446 | mask = ~mask; 1447 | for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; 1448 | 1449 | this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; 1450 | this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; 1451 | this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; 1452 | this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; 1453 | this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; 1454 | this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; 1455 | this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; 1456 | this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; 1457 | 1458 | f = this.h[0] + this.pad[0]; 1459 | this.h[0] = f & 0xffff; 1460 | for (i = 1; i < 8; i++) { 1461 | f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; 1462 | this.h[i] = f & 0xffff; 1463 | } 1464 | 1465 | mac[macpos+ 0] = (byte) ((this.h[0] >>> 0) & 0xff); 1466 | mac[macpos+ 1] = (byte) ((this.h[0] >>> 8) & 0xff); 1467 | mac[macpos+ 2] = (byte) ((this.h[1] >>> 0) & 0xff); 1468 | mac[macpos+ 3] = (byte) ((this.h[1] >>> 8) & 0xff); 1469 | mac[macpos+ 4] = (byte) ((this.h[2] >>> 0) & 0xff); 1470 | mac[macpos+ 5] = (byte) ((this.h[2] >>> 8) & 0xff); 1471 | mac[macpos+ 6] = (byte) ((this.h[3] >>> 0) & 0xff); 1472 | mac[macpos+ 7] = (byte) ((this.h[3] >>> 8) & 0xff); 1473 | mac[macpos+ 8] = (byte) ((this.h[4] >>> 0) & 0xff); 1474 | mac[macpos+ 9] = (byte) ((this.h[4] >>> 8) & 0xff); 1475 | mac[macpos+10] = (byte) ((this.h[5] >>> 0) & 0xff); 1476 | mac[macpos+11] = (byte) ((this.h[5] >>> 8) & 0xff); 1477 | mac[macpos+12] = (byte) ((this.h[6] >>> 0) & 0xff); 1478 | mac[macpos+13] = (byte) ((this.h[6] >>> 8) & 0xff); 1479 | mac[macpos+14] = (byte) ((this.h[7] >>> 0) & 0xff); 1480 | mac[macpos+15] = (byte) ((this.h[7] >>> 8) & 0xff); 1481 | 1482 | return this; 1483 | } 1484 | 1485 | public poly1305 update(byte [] m, int mpos, int bytes) { 1486 | int i, want; 1487 | 1488 | if (this.leftover != 0) { 1489 | want = (16 - this.leftover); 1490 | if (want > bytes) 1491 | want = bytes; 1492 | for (i = 0; i < want; i++) 1493 | this.buffer[this.leftover + i] = m[mpos+i]; 1494 | bytes -= want; 1495 | mpos += want; 1496 | this.leftover += want; 1497 | if (this.leftover < 16) 1498 | return this; 1499 | this.blocks(buffer, 0, 16); 1500 | this.leftover = 0; 1501 | } 1502 | 1503 | if (bytes >= 16) { 1504 | want = bytes - (bytes % 16); 1505 | this.blocks(m, mpos, want); 1506 | mpos += want; 1507 | bytes -= want; 1508 | } 1509 | 1510 | if (bytes != 0) { 1511 | for (i = 0; i < bytes; i++) 1512 | this.buffer[this.leftover + i] = m[mpos+i]; 1513 | this.leftover += bytes; 1514 | } 1515 | 1516 | return this; 1517 | } 1518 | 1519 | } 1520 | 1521 | private static int crypto_onetimeauth( 1522 | byte[] out,final int outpos,final int outlen, 1523 | byte[] m,final int mpos,final int mlen, 1524 | int n, 1525 | byte [] k) 1526 | { 1527 | poly1305 s = new poly1305(k); 1528 | s.update(m, mpos, n); 1529 | s.finish(out, outpos); 1530 | 1531 | /*String dbgt = ""; 1532 | for (int dbg = 0; dbg < out.length-outpos; dbg ++) dbgt += " "+out[dbg+outpos]; 1533 | Log.d(TAG, "crypto_onetimeauth -> "+dbgt); 1534 | */ 1535 | 1536 | return 0; 1537 | } 1538 | 1539 | public static int crypto_onetimeauth(byte [] out, byte [] m, int n , byte [] k) { 1540 | return crypto_onetimeauth(out,0,out.length, m,0,m.length, n, k); 1541 | } 1542 | 1543 | private static int crypto_onetimeauth_verify( 1544 | byte[] h,final int hoff,final int hlen, 1545 | byte[] m,final int moff,final int mlen, 1546 | int n, 1547 | byte [] k) 1548 | { 1549 | byte[] x = new byte[16]; 1550 | crypto_onetimeauth(x,0,x.length, m,moff,mlen, n,k); 1551 | return crypto_verify_16(h,hoff,hlen, x,0,x.length); 1552 | } 1553 | public static int crypto_onetimeauth_verify(byte [] h, byte [] m, int n, byte [] k) { 1554 | return crypto_onetimeauth_verify(h,0,h.length, m,0,m.length, n, k); 1555 | } 1556 | public static int crypto_onetimeauth_verify(byte [] h, byte [] m, byte [] k) { 1557 | return crypto_onetimeauth_verify(h, m, m!=null? m.length:0, k); 1558 | } 1559 | 1560 | public static int crypto_secretbox(byte [] c, byte [] m, int d, byte [] n, byte [] k) 1561 | { 1562 | int i; 1563 | 1564 | if (d < 32) return -1; 1565 | 1566 | crypto_stream_xor(c,m,d,n,k); 1567 | crypto_onetimeauth(c,16,c.length-16, c,32,c.length-32, d - 32, c); 1568 | 1569 | //for (i = 0; i < 16; i ++) c[i] = 0; 1570 | 1571 | return 0; 1572 | } 1573 | 1574 | public static int crypto_secretbox_open(byte []m,byte []c,int d,byte []n,byte []k) 1575 | { 1576 | int i; 1577 | byte[] x = new byte[32]; 1578 | 1579 | if (d < 32) return -1; 1580 | 1581 | crypto_stream(x,32,n,k); 1582 | if (crypto_onetimeauth_verify(c,16,16, c,32,c.length-32, d-32, x) != 0) return -1; 1583 | crypto_stream_xor(m,c,d,n,k); 1584 | 1585 | ///for (i = 0; i < 32; i ++) m[i] = 0; 1586 | 1587 | return 0; 1588 | } 1589 | 1590 | private static void set25519(long [] r, long [] a) 1591 | { 1592 | int i; 1593 | for (i = 0; i < 16; i ++) r[i]=a[i]; 1594 | } 1595 | 1596 | private static void car25519(long [] o,final int ooff,final int olen) 1597 | { 1598 | int i; 1599 | long c; 1600 | 1601 | ///String dbgt = ""; 1602 | ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg); 1603 | ///L/og.d(TAG, "car25519 pre -> "+dbgt); 1604 | 1605 | for (i = 0; i < 16; i ++) { 1606 | o[i+ooff] += (1L<<16); 1607 | 1608 | c = o[i+ooff]>>16; 1609 | 1610 | o[(i+1)*((i<15) ? 1 : 0)+ooff] += c-1+37*(c-1)*((i==15) ? 1 : 0); 1611 | 1612 | o[i+ooff] -= (c<<16); 1613 | } 1614 | 1615 | ///dbgt = ""; 1616 | ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg); 1617 | ///L/og.d(TAG, "car25519 -> "+dbgt); 1618 | 1619 | } 1620 | 1621 | private static void sel25519( 1622 | long[] p,final int poff,final int plen, 1623 | long[] q,final int qoff,final int qlen, 1624 | int b) 1625 | { 1626 | int i; 1627 | long t,c=~(b-1); 1628 | 1629 | for (i = 0; i < 16; i ++) { 1630 | t = c & (p[i+poff] ^ q[i+qoff]); 1631 | p[i+poff] ^= t; 1632 | q[i+qoff] ^= t; 1633 | } 1634 | 1635 | ///String dbgt = ""; 1636 | ///for (int dbg = 0; dbg < p.length; dbg ++) dbgt += " "+p.get(dbg); 1637 | ///L/og.d(TAG, "sel25519 -> "+dbgt); 1638 | 1639 | } 1640 | 1641 | private static void pack25519(byte [] o, long [] n,final int noff,final int nlen) 1642 | { 1643 | int i,j,b; 1644 | long [] m = new long[16], t = new long[16]; 1645 | 1646 | for (i = 0; i < 16; i ++) t[i] = n[i+noff]; 1647 | 1648 | car25519(t,0,t.length); 1649 | car25519(t,0,t.length); 1650 | car25519(t,0,t.length); 1651 | 1652 | for (j = 0; j < 2; j ++) { 1653 | m[0]=t[0]-0xffed; 1654 | 1655 | for(i=1;i<15;i++) { 1656 | m[i]=t[i]-0xffff-((m[i-1] >> 16)&1); 1657 | m[i-1]&=0xffff; 1658 | } 1659 | 1660 | m[15]=t[15]-0x7fff-((m[14] >> 16)&1); 1661 | b=(int) ((m[15] >> 16)&1); 1662 | m[14]&=0xffff; 1663 | 1664 | sel25519(t,0,t.length, m,0,m.length, 1-b); 1665 | } 1666 | 1667 | for (i = 0; i < 16; i ++) { 1668 | o[2*i]=(byte) (t[i]&0xff); 1669 | o[2*i+1]=(byte) (t[i] >> 8); 1670 | } 1671 | 1672 | ///String dbgt = ""; 1673 | ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg]; 1674 | ///L/og.d(TAG, "pack25519 -> "+dbgt); 1675 | } 1676 | 1677 | private static int neq25519(long [] a, long [] b) 1678 | { 1679 | byte[] c = new byte[32], d = new byte[32]; 1680 | 1681 | pack25519(c, a,0,a.length); 1682 | pack25519(d, b,0,b.length); 1683 | 1684 | return crypto_verify_32(c,0,c.length, d,0,d.length); 1685 | } 1686 | 1687 | private static byte par25519(long [] a) 1688 | { 1689 | byte[] d = new byte[32]; 1690 | 1691 | pack25519(d, a,0,a.length); 1692 | 1693 | return (byte) (d[0]&1); 1694 | } 1695 | 1696 | private static void unpack25519(long [] o, byte [] n) 1697 | { 1698 | int i; 1699 | 1700 | for (i = 0; i < 16; i ++) o[i]=(n[2*i]&0xff)+((long)((n[2*i+1]<<8)&0xffff)); 1701 | 1702 | o[15]&=0x7fff; 1703 | 1704 | ///String dbgt = ""; 1705 | ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg]; 1706 | ///L/og.d(TAG, "unpack25519 -> "+dbgt); 1707 | } 1708 | 1709 | private static void A( 1710 | long [] o,final int ooff,final int olen, 1711 | long [] a,final int aoff,final int alen, 1712 | long [] b,final int boff,final int blen) 1713 | { 1714 | int i; 1715 | for (i = 0; i < 16; i ++) o[i+ooff] = a[i+aoff] + b[i+boff]; 1716 | } 1717 | 1718 | private static void Z( 1719 | long [] o,final int ooff,final int olen, 1720 | long [] a,final int aoff,final int alen, 1721 | long [] b,final int boff,final int blen) 1722 | { 1723 | int i; 1724 | for (i = 0; i < 16; i ++) o[i+ooff] = a[i+aoff] - b[i+boff]; 1725 | } 1726 | 1727 | private static void M( 1728 | long [] o,final int ooff,final int olen, 1729 | long [] a,final int aoff,final int alen, 1730 | long [] b,final int boff,final int blen) 1731 | { 1732 | int i,j; 1733 | long [] t = new long[31]; 1734 | 1735 | for (i = 0; i < 31; i ++) t[i]=0; 1736 | 1737 | for (i = 0; i < 16; i ++) for (j = 0; j < 16; j ++) t[i+j]+=a[i+aoff]*b[j+boff]; 1738 | 1739 | for (i = 0; i < 15; i ++) t[i]+=38*t[i+16]; 1740 | 1741 | for (i = 0; i < 16; i ++) o[i+ooff]=t[i]; 1742 | 1743 | car25519(o,ooff,olen); 1744 | car25519(o,ooff,olen); 1745 | 1746 | ///String dbgt = ""; 1747 | ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg); 1748 | ///L/og.d(TAG, "M -> "+dbgt); 1749 | } 1750 | 1751 | private static void S( 1752 | long [] o,final int ooff,final int olen, 1753 | long [] a,final int aoff,final int alen) 1754 | { 1755 | M(o,ooff,olen, a,aoff,alen, a,aoff,alen); 1756 | } 1757 | 1758 | private static void inv25519( 1759 | long [] o,final int ooff,final int olen, 1760 | long [] i,final int ioff,final int ilen) 1761 | { 1762 | long [] c = new long[16]; 1763 | int a; 1764 | 1765 | for (a = 0; a < 16; a ++) c[a]=i[a+ioff]; 1766 | 1767 | for(a=253;a>=0;a--) { 1768 | S(c,0,c.length, c,0,c.length); 1769 | if(a!=2&&a!=4) M(c,0,c.length, c,0,c.length, i,ioff,ilen); 1770 | } 1771 | 1772 | for (a = 0; a < 16; a ++) o[a+ooff] = c[a]; 1773 | 1774 | ///String dbgt = ""; 1775 | ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg); 1776 | ///L/og.d(TAG, "inv25519 -> "+dbgt); 1777 | } 1778 | 1779 | private static void pow2523(long [] o,long [] i) 1780 | { 1781 | long [] c = new long[16]; 1782 | int a; 1783 | 1784 | for (a = 0; a < 16; a ++) c[a]=i[a]; 1785 | 1786 | for(a=250;a>=0;a--) { 1787 | S(c,0,c.length, c,0,c.length); 1788 | if(a!=1) M(c,0,c.length, c,0,c.length, i,0,i.length); 1789 | } 1790 | 1791 | for (a = 0; a < 16; a ++) o[a]=c[a]; 1792 | } 1793 | 1794 | public static int crypto_scalarmult(byte []q,byte []n,byte []p) 1795 | { 1796 | byte[] z = new byte[32]; 1797 | long[] x = new long[80]; 1798 | int r,i; 1799 | 1800 | long [] a = new long[16], b = new long[16], c = new long[16], 1801 | d = new long[16], e = new long[16], f = new long[16]; 1802 | 1803 | for (i = 0; i < 31; i ++) z[i]=n[i]; 1804 | 1805 | z[31]=(byte) (((n[31]&127)|64) & 0xff); 1806 | z[0]&=248; 1807 | 1808 | unpack25519(x,p); 1809 | 1810 | for (i = 0; i < 16; i ++) { 1811 | b[i]=x[i]; 1812 | d[i]=a[i]=c[i]=0; 1813 | } 1814 | a[0]=d[0]=1; 1815 | 1816 | for(i=254;i>=0;--i) { 1817 | r=(z[i>>>3]>>>(i&7))&1; 1818 | sel25519(a,0,a.length, b,0,b.length, r); 1819 | sel25519(c,0,c.length, d,0,d.length, r); 1820 | A(e,0,e.length, a,0,a.length, c,0,c.length); 1821 | Z(a,0,a.length, a,0,a.length, c,0,c.length); 1822 | A(c,0,c.length, b,0,b.length, d,0,d.length); 1823 | Z(b,0,b.length, b,0,b.length, d,0,d.length); 1824 | S(d,0,d.length, e,0,e.length); 1825 | S(f,0,f.length, a,0,a.length); 1826 | M(a,0,a.length, c,0,c.length, a,0,a.length); 1827 | M(c,0,c.length, b,0,b.length, e,0,e.length); 1828 | A(e,0,e.length, a,0,a.length, c,0,c.length); 1829 | Z(a,0,a.length, a,0,a.length, c,0,c.length); 1830 | S(b,0,b.length, a,0,a.length); 1831 | Z(c,0,c.length, d,0,d.length, f,0,f.length); 1832 | M(a,0,a.length, c,0,c.length, _121665,0,_121665.length); 1833 | A(a,0,a.length, a,0,a.length, d,0,d.length); 1834 | M(c,0,c.length, c,0,c.length, a,0,a.length); 1835 | M(a,0,a.length, d,0,d.length, f,0,f.length); 1836 | M(d,0,d.length, b,0,b.length, x,0,x.length); 1837 | S(b,0,b.length, e,0,e.length); 1838 | sel25519(a,0,a.length, b,0,b.length, r); 1839 | sel25519(c,0,c.length, d,0,d.length, r); 1840 | } 1841 | 1842 | for (i = 0; i < 16; i ++) { 1843 | x[i+16]=a[i]; 1844 | x[i+32]=c[i]; 1845 | x[i+48]=b[i]; 1846 | x[i+64]=d[i]; 1847 | } 1848 | 1849 | inv25519(x, 32, x.length-32, x, 32, x.length-32); 1850 | 1851 | M(x,16,x.length-16, x,16,x.length-16, x,32,x.length-32); 1852 | 1853 | pack25519(q, x,16,x.length-16); 1854 | 1855 | ///String dbgt = ""; 1856 | ///for (int dbg = 0; dbg < q.length; dbg ++) dbgt += " "+q[dbg]; 1857 | ///L/og.d(TAG, "crypto_scalarmult -> "+dbgt); 1858 | 1859 | return 0; 1860 | } 1861 | 1862 | public static int crypto_scalarmult_base(byte []q,byte []n) 1863 | { 1864 | return crypto_scalarmult(q,n,_9); 1865 | } 1866 | 1867 | public static int crypto_box_keypair(byte [] y, byte [] x) 1868 | { 1869 | randombytes(x,32); 1870 | return crypto_scalarmult_base(y,x); 1871 | } 1872 | 1873 | public static int crypto_box_beforenm(byte []k,byte []y,byte []x) 1874 | { 1875 | byte[] s = new byte[32]; 1876 | crypto_scalarmult(s,x,y); 1877 | 1878 | ///String dbgt = ""; 1879 | ///for (int dbg = 0; dbg < s.length; dbg ++) dbgt += " "+s[dbg]; 1880 | ///L/og.d(TAG, "crypto_box_beforenm -> "+dbgt); 1881 | 1882 | return crypto_core_hsalsa20(k,_0,s,sigma); 1883 | } 1884 | 1885 | public static int crypto_box_afternm(byte []c,byte []m,int d,byte []n,byte []k) 1886 | { 1887 | return crypto_secretbox(c,m,d,n,k); 1888 | } 1889 | 1890 | public static int crypto_box_open_afternm(byte []m,byte []c,int d,byte []n,byte []k) 1891 | { 1892 | return crypto_secretbox_open(m,c,d,n,k); 1893 | } 1894 | 1895 | public static int crypto_box(byte []c,byte []m,int d,byte []n,byte []y,byte []x) 1896 | { 1897 | byte[] k = new byte[32]; 1898 | 1899 | ///L/og.d(TAG, "crypto_box start ..."); 1900 | 1901 | crypto_box_beforenm(k,y,x); 1902 | return crypto_box_afternm(c,m,d,n,k); 1903 | } 1904 | 1905 | public static int crypto_box_open(byte []m,byte []c,int d,byte []n,byte []y,byte []x) 1906 | { 1907 | byte[] k = new byte[32]; 1908 | crypto_box_beforenm(k,y,x); 1909 | return crypto_box_open_afternm(m,c,d,n,k); 1910 | } 1911 | 1912 | private static long R(long x,int c) { return (x >>> c) | (x << (64 - c)); } 1913 | 1914 | private static long Ch( long x,long y,long z) { return (x & y) ^ (~x & z); } 1915 | private static long Maj(long x,long y,long z) { return (x & y) ^ (x & z) ^ (y & z); } 1916 | 1917 | private static long Sigma0(long x) { return R(x,28) ^ R(x,34) ^ R(x,39); } 1918 | private static long Sigma1(long x) { return R(x,14) ^ R(x,18) ^ R(x,41); } 1919 | private static long sigma0(long x) { return R(x, 1) ^ R(x, 8) ^ (x >>> 7); } 1920 | private static long sigma1(long x) { return R(x,19) ^ R(x,61) ^ (x >>> 6); } 1921 | 1922 | private static final long K[] = { 1923 | 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL, 1924 | 0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, 1925 | 0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L, 1926 | 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L, 1927 | 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, 1928 | 0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L, 1929 | 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L, 1930 | 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L, 1931 | 0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL, 1932 | 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL, 1933 | 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L, 1934 | 0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L, 1935 | 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L, 1936 | 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, 1937 | 0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL, 1938 | 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL, 1939 | 0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, 1940 | 0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL, 1941 | 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL, 1942 | 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L 1943 | }; 1944 | 1945 | // TBD... long length n 1946 | ///int crypto_hashblocks(byte [] x, byte [] m, long n) 1947 | private static int crypto_hashblocks(byte [] x, byte [] m,final int moff,final int mlen, int n) 1948 | { 1949 | long [] z = new long [8], b = new long [8], a = new long [8], w = new long [16]; 1950 | long t; 1951 | int i,j; 1952 | 1953 | for (i = 0; i < 8; i ++) z[i] = a[i] = dl64(x, 8*i, x.length-8*i); 1954 | 1955 | int moffset = moff; 1956 | 1957 | while (n >= 128) { 1958 | for (i = 0; i < 16; i ++) w[i] = dl64(m, 8*i+moffset, mlen-8*i); 1959 | 1960 | for (i = 0; i < 80; i ++) { 1961 | for (j = 0; j < 8; j ++) b[j] = a[j]; 1962 | 1963 | t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16]; 1964 | b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]); 1965 | b[3] += t; 1966 | 1967 | for (j = 0; j < 8; j ++) a[(j+1)%8] = b[j]; 1968 | 1969 | if (i%16 == 15) 1970 | for (j = 0; j < 16; j ++) 1971 | w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]); 1972 | } 1973 | 1974 | for (i = 0; i < 8; i ++) { a[i] += z[i]; z[i] = a[i]; } 1975 | 1976 | moffset += 128; 1977 | n -= 128; 1978 | } 1979 | 1980 | for (i = 0; i < 8; i ++) ts64(x,8*i,x.length-8*i, z[i]); 1981 | 1982 | return n; 1983 | } 1984 | public static int crypto_hashblocks(byte [] x, byte [] m, int n) { 1985 | return crypto_hashblocks(x, m,0,m.length, n); 1986 | } 1987 | 1988 | private final static byte iv[] = { 1989 | 0x6a,0x09,(byte) 0xe6,0x67,(byte) 0xf3,(byte) 0xbc,(byte) 0xc9,0x08, 1990 | (byte) 0xbb,0x67,(byte) 0xae,(byte) 0x85,(byte) 0x84,(byte) 0xca,(byte) 0xa7,0x3b, 1991 | 0x3c,0x6e,(byte) 0xf3,0x72,(byte) 0xfe,(byte) 0x94,(byte) 0xf8,0x2b, 1992 | (byte) 0xa5,0x4f,(byte) 0xf5,0x3a,0x5f,0x1d,0x36,(byte) 0xf1, 1993 | 0x51,0x0e,0x52,0x7f,(byte) 0xad,(byte) 0xe6,(byte) 0x82,(byte) 0xd1, 1994 | (byte) 0x9b,0x05,0x68,(byte) 0x8c,0x2b,0x3e,0x6c,0x1f, 1995 | 0x1f,(byte) 0x83,(byte) 0xd9,(byte) 0xab,(byte) 0xfb,0x41,(byte) 0xbd,0x6b, 1996 | 0x5b,(byte) 0xe0,(byte) 0xcd,0x19,0x13,0x7e,0x21,0x79 1997 | } ; 1998 | 1999 | // TBD 64bits of n 2000 | ///int crypto_hash(byte [] out, byte [] m, long n) 2001 | private static int crypto_hash(byte [] out, byte [] m,final int moff,final int mlen, int n) 2002 | { 2003 | byte[] h = new byte[64], x = new byte [256]; 2004 | long b = n; 2005 | int i; 2006 | 2007 | for (i = 0; i < 64; i ++) h[i] = iv[i]; 2008 | 2009 | crypto_hashblocks(h, m,moff,mlen, n); 2010 | ///m += n; 2011 | n &= 127; 2012 | ///m -= n; 2013 | 2014 | for (i = 0; i < 256; i ++) x[i] = 0; 2015 | 2016 | for (i = 0; i < n; i ++) x[i] = m[i+moff]; 2017 | x[n] = (byte) 128; 2018 | 2019 | n = 256-128*(n<112?1:0); 2020 | x[n-9] = (byte) (b >>> 61); 2021 | ts64(x,n-8,x.length-(n-8), b<<3); 2022 | crypto_hashblocks(h, x,0,x.length, n); 2023 | 2024 | for (i = 0; i < 64; i ++) out[i] = h[i]; 2025 | 2026 | return 0; 2027 | } 2028 | public static int crypto_hash(byte [] out, byte [] m, int n) { 2029 | return crypto_hash(out, m,0,m.length, n); 2030 | } 2031 | public static int crypto_hash(byte [] out, byte [] m) { 2032 | return crypto_hash(out, m, m!=null? m.length : 0); 2033 | } 2034 | 2035 | // gf: long[16] 2036 | ///private static void add(gf p[4],gf q[4]) 2037 | private static void add(long [] p[], long [] q[]) 2038 | { 2039 | long [] a = new long[16]; 2040 | long [] b = new long[16]; 2041 | long [] c = new long[16]; 2042 | long [] d = new long[16]; 2043 | long [] t = new long[16]; 2044 | long [] e = new long[16]; 2045 | long [] f = new long[16]; 2046 | long [] g = new long[16]; 2047 | long [] h = new long[16]; 2048 | 2049 | 2050 | long [] p0 = p[0]; 2051 | long [] p1 = p[1]; 2052 | long [] p2 = p[2]; 2053 | long [] p3 = p[3]; 2054 | 2055 | long [] q0 = q[0]; 2056 | long [] q1 = q[1]; 2057 | long [] q2 = q[2]; 2058 | long [] q3 = q[3]; 2059 | 2060 | Z(a,0,a.length, p1,0,p1.length, p0,0,p0.length); 2061 | Z(t,0,t.length, q1,0,q1.length, q0,0,q0.length); 2062 | M(a,0,a.length, a,0,a.length, t,0,t.length); 2063 | A(b,0,b.length, p0,0,p0.length, p1,0,p1.length); 2064 | A(t,0,t.length, q0,0,q0.length, q1,0,q1.length); 2065 | M(b,0,b.length, b,0,b.length, t,0,t.length); 2066 | M(c,0,c.length, p3,0,p3.length, q3,0,q3.length); 2067 | M(c,0,c.length, c,0,c.length, D2,0,D2.length); 2068 | M(d,0,d.length, p2,0,p2.length, q2,0,q2.length); 2069 | 2070 | A(d,0,d.length, d,0,d.length, d,0,d.length); 2071 | Z(e,0,e.length, b,0,b.length, a,0,a.length); 2072 | Z(f,0,f.length, d,0,d.length, c,0,c.length); 2073 | A(g,0,g.length, d,0,d.length, c,0,c.length); 2074 | A(h,0,h.length, b,0,b.length, a,0,a.length); 2075 | 2076 | M(p0,0,p0.length, e,0,e.length, f,0,f.length); 2077 | M(p1,0,p1.length, h,0,h.length, g,0,g.length); 2078 | M(p2,0,p2.length, g,0,g.length, f,0,f.length); 2079 | M(p3,0,p3.length, e,0,e.length, h,0,h.length); 2080 | } 2081 | 2082 | private static void cswap(long [] p[], long [] q[], byte b) 2083 | { 2084 | int i; 2085 | 2086 | for (i = 0; i < 4; i ++) 2087 | sel25519(p[i],0,p[i].length, q[i],0,q[i].length, b); 2088 | } 2089 | 2090 | private static void pack(byte [] r, long [] p[]) 2091 | { 2092 | long [] tx = new long[16]; 2093 | long [] ty = new long[16]; 2094 | long [] zi = new long[16]; 2095 | 2096 | inv25519(zi,0,zi.length, p[2],0,p[2].length); 2097 | 2098 | M(tx,0,tx.length, p[0],0,p[0].length, zi,0,zi.length); 2099 | M(ty,0,ty.length, p[1],0,p[1].length, zi,0,zi.length); 2100 | 2101 | pack25519(r, ty,0,ty.length); 2102 | 2103 | r[31] ^= par25519(tx) << 7; 2104 | } 2105 | 2106 | private static void scalarmult(long [] p[], long [] q[], byte[] s,final int soff,final int slen) 2107 | { 2108 | int i; 2109 | 2110 | set25519(p[0],gf0); 2111 | set25519(p[1],gf1); 2112 | set25519(p[2],gf1); 2113 | set25519(p[3],gf0); 2114 | 2115 | for (i = 255;i >= 0;--i) { 2116 | byte b = (byte) ((s[i/8+soff] >> (i&7))&1); 2117 | 2118 | cswap(p,q,b); 2119 | add(q,p); 2120 | add(p,p); 2121 | cswap(p,q,b); 2122 | } 2123 | 2124 | ///String dbgt = ""; 2125 | ///for (int dbg = 0; dbg < p.length; dbg ++) for (int dd = 0; dd < p[dbg].length; dd ++) dbgt += " "+p[dbg][dd]; 2126 | ///L/og.d(TAG, "scalarmult -> "+dbgt); 2127 | } 2128 | 2129 | private static void scalarbase(long [] p[], byte[] s,final int soff,final int slen) 2130 | { 2131 | long [] [] q = new long [4] []; 2132 | 2133 | q[0] = new long [16]; 2134 | q[1] = new long [16]; 2135 | q[2] = new long [16]; 2136 | q[3] = new long [16]; 2137 | 2138 | set25519(q[0],X); 2139 | set25519(q[1],Y); 2140 | set25519(q[2],gf1); 2141 | M(q[3],0,q[3].length, X,0,X.length, Y,0,Y.length); 2142 | scalarmult(p,q, s,soff,slen); 2143 | } 2144 | 2145 | public static int crypto_sign_keypair(byte [] pk, byte [] sk, boolean seeded) { 2146 | byte [] d = new byte[64]; 2147 | long [] [] p = new long [4] []; 2148 | 2149 | p[0] = new long [16]; 2150 | p[1] = new long [16]; 2151 | p[2] = new long [16]; 2152 | p[3] = new long [16]; 2153 | 2154 | int i; 2155 | 2156 | if (!seeded) randombytes(sk, 32); 2157 | crypto_hash(d, sk,0,sk.length, 32); 2158 | d[0] &= 248; 2159 | d[31] &= 127; 2160 | d[31] |= 64; 2161 | 2162 | scalarbase(p, d,0,d.length); 2163 | pack(pk, p); 2164 | 2165 | for (i = 0; i < 32; i++) sk[i+32] = pk[i]; 2166 | return 0; 2167 | } 2168 | 2169 | private static final long L[] = { 2170 | 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 2171 | 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 2172 | 0, 0, 0, 0, 0, 0, 0, 0, 2173 | 0, 0, 0, 0, 0, 0, 0, 0x10 2174 | }; 2175 | 2176 | private static void modL(byte[] r,final int roff,final int rlen, long x[]) 2177 | { 2178 | long carry; 2179 | int i, j; 2180 | 2181 | for (i = 63;i >= 32;--i) { 2182 | carry = 0; 2183 | for (j = i - 32;j < i - 12;++j) { 2184 | x[j] += carry - 16 * x[i] * L[j - (i - 32)]; 2185 | carry = (x[j] + 128) >> 8; 2186 | x[j] -= carry << 8; 2187 | } 2188 | x[j] += carry; 2189 | x[i] = 0; 2190 | } 2191 | carry = 0; 2192 | 2193 | for (j = 0; j < 32; j ++) { 2194 | x[j] += carry - (x[31] >> 4) * L[j]; 2195 | carry = x[j] >> 8; 2196 | x[j] &= 255; 2197 | } 2198 | 2199 | for (j = 0; j < 32; j ++) x[j] -= carry * L[j]; 2200 | 2201 | for (i = 0; i < 32; i ++) { 2202 | x[i+1] += x[i] >> 8; 2203 | r[i+roff] = (byte) (x[i] & 255); 2204 | } 2205 | } 2206 | 2207 | private static void reduce(byte [] r) 2208 | { 2209 | long[] x = new long [64]; 2210 | int i; 2211 | 2212 | for (i = 0; i < 64; i ++) x[i] = (long) (r[i]&0xff); 2213 | 2214 | for (i = 0; i < 64; i ++) r[i] = 0; 2215 | 2216 | modL(r,0,r.length, x); 2217 | } 2218 | 2219 | // TBD... 64bits of n 2220 | ///int crypto_sign(byte [] sm, long * smlen, byte [] m, long n, byte [] sk) 2221 | public static int crypto_sign(byte [] sm, long dummy /* *smlen not used*/, byte [] m, int/*long*/ n, byte [] sk) 2222 | { 2223 | byte[] d = new byte[64], h = new byte[64], r = new byte[64]; 2224 | 2225 | int i, j; 2226 | long [] x = new long[64]; 2227 | 2228 | long [] [] p = new long [4] []; 2229 | p[0] = new long [16]; 2230 | p[1] = new long [16]; 2231 | p[2] = new long [16]; 2232 | p[3] = new long [16]; 2233 | 2234 | crypto_hash(d, sk,0,sk.length, 32); 2235 | d[0] &= 248; 2236 | d[31] &= 127; 2237 | d[31] |= 64; 2238 | 2239 | ///*smlen = n+64; 2240 | 2241 | for (i = 0; i < n; i ++) sm[64 + i] = m[i]; 2242 | 2243 | for (i = 0; i < 32; i ++) sm[32 + i] = d[32 + i]; 2244 | 2245 | crypto_hash(r, sm,32,sm.length-32, n+32); 2246 | reduce(r); 2247 | scalarbase(p, r,0,r.length); 2248 | pack(sm,p); 2249 | 2250 | for (i = 0; i < 32; i ++) sm[i+32] = sk[i+32]; 2251 | crypto_hash(h, sm,0,sm.length, n + 64); 2252 | reduce(h); 2253 | 2254 | for (i = 0; i < 64; i ++) x[i] = 0; 2255 | 2256 | for (i = 0; i < 32; i ++) x[i] = (long) (r[i]&0xff); 2257 | 2258 | for (i = 0; i < 32; i ++) for (j = 0; j < 32; j ++) x[i+j] += (h[i]&0xff) * (long) (d[j]&0xff); 2259 | 2260 | modL(sm,32,sm.length-32, x); 2261 | 2262 | return 0; 2263 | } 2264 | 2265 | private static int unpackneg(long [] r[], byte p[]) 2266 | { 2267 | long [] t = new long [16]; 2268 | long [] chk = new long [16]; 2269 | long [] num = new long [16]; 2270 | long [] den = new long [16]; 2271 | long [] den2 = new long [16]; 2272 | long [] den4 = new long [16]; 2273 | long [] den6 = new long [16]; 2274 | 2275 | set25519(r[2],gf1); 2276 | unpack25519(r[1], p); 2277 | S(num,0,num.length, r[1],0,r[1].length); 2278 | M(den,0,den.length, num,0,num.length, D,0,D.length); 2279 | Z(num,0,num.length, num,0,num.length, r[2],0,r[2].length); 2280 | A(den,0,den.length, r[2],0,r[2].length, den,0,den.length); 2281 | 2282 | S(den2,0,den2.length, den,0,den.length); 2283 | S(den4,0,den4.length, den2,0,den2.length); 2284 | M(den6,0,den6.length, den4,0,den4.length, den2,0,den2.length); 2285 | M(t,0,t.length, den6,0,den6.length, num,0,num.length); 2286 | M(t,0,t.length, t,0,t.length, den,0,den.length); 2287 | 2288 | pow2523(t, t); 2289 | M(t,0,t.length, t,0,t.length, num,0,num.length); 2290 | M(t,0,t.length, t,0,t.length, den,0,den.length); 2291 | M(t,0,t.length, t,0,t.length, den,0,den.length); 2292 | M(r[0],0,r[0].length, t,0,t.length, den,0,den.length); 2293 | 2294 | S(chk,0,chk.length, r[0],0,r[0].length); 2295 | M(chk,0,chk.length, chk,0,chk.length, den,0,den.length); 2296 | if (neq25519(chk, num)!=0) M(r[0],0,r[0].length, r[0],0,r[0].length, I,0,I.length); 2297 | 2298 | S(chk,0,chk.length, r[0],0,r[0].length); 2299 | M(chk,0,chk.length, chk,0,chk.length, den,0,den.length); 2300 | if (neq25519(chk, num)!=0) return -1; 2301 | 2302 | if (par25519(r[0]) == ((p[31]&0xFF)>>7)) Z(r[0],0,r[0].length, gf0,0,gf0.length, r[0],0,r[0].length); 2303 | 2304 | M(r[3],0,r[3].length, r[0],0,r[0].length, r[1],0,r[1].length); 2305 | return 0; 2306 | } 2307 | 2308 | /// TBD 64bits of mlen 2309 | ///int crypto_sign_open(byte []m,long *mlen,byte []sm,long n,byte []pk) 2310 | public static int crypto_sign_open(byte [] m, long dummy /* *mlen not used*/, byte [] sm, int/*long*/ n, byte []pk) 2311 | { 2312 | int i; 2313 | byte[] t = new byte[32], h = new byte[64]; 2314 | 2315 | long [] [] p = new long [4] []; 2316 | p[0] = new long [16]; 2317 | p[1] = new long [16]; 2318 | p[2] = new long [16]; 2319 | p[3] = new long [16]; 2320 | 2321 | long [] [] q = new long [4] []; 2322 | q[0] = new long [16]; 2323 | q[1] = new long [16]; 2324 | q[2] = new long [16]; 2325 | q[3] = new long [16]; 2326 | 2327 | ///*mlen = -1; 2328 | 2329 | if (n < 64) return -1; 2330 | 2331 | if (unpackneg(q,pk)!=0) return -1; 2332 | 2333 | for (i = 0; i < n; i ++) m[i] = sm[i]; 2334 | 2335 | for (i = 0; i < 32; i ++) m[i+32] = pk[i]; 2336 | 2337 | crypto_hash(h, m,0,m.length, n); 2338 | 2339 | reduce(h); 2340 | scalarmult(p,q, h,0,h.length); 2341 | 2342 | scalarbase(q, sm,32,sm.length-32); 2343 | add(p,q); 2344 | pack(t,p); 2345 | 2346 | n -= 64; 2347 | if (crypto_verify_32(sm,0,sm.length, t,0,t.length)!=0) { 2348 | // optimizing it 2349 | ///for (i = 0; i < n; i ++) m[i] = 0; 2350 | return -1; 2351 | } 2352 | 2353 | // TBD optimizing ... 2354 | ///for (i = 0; i < n; i ++) m[i] = sm[i + 64]; 2355 | ///*mlen = n; 2356 | 2357 | return 0; 2358 | } 2359 | 2360 | /* 2361 | * @description 2362 | * Java SecureRandom generator 2363 | * */ 2364 | private static final SecureRandom jrandom = new SecureRandom(); 2365 | 2366 | public static void randombytes(byte [] x, int len) { 2367 | int ret = len % 8; 2368 | long rnd; 2369 | 2370 | for (int i = 0; i < len-ret; i += 8) { 2371 | rnd = jrandom.nextLong(); 2372 | 2373 | x[i+0] = (byte) (rnd >>> 0); 2374 | x[i+1] = (byte) (rnd >>> 8); 2375 | x[i+2] = (byte) (rnd >>> 16); 2376 | x[i+3] = (byte) (rnd >>> 24); 2377 | x[i+4] = (byte) (rnd >>> 32); 2378 | x[i+5] = (byte) (rnd >>> 40); 2379 | x[i+6] = (byte) (rnd >>> 48); 2380 | x[i+7] = (byte) (rnd >>> 56); 2381 | } 2382 | 2383 | if (ret > 0) { 2384 | rnd = jrandom.nextLong(); 2385 | for (int i = len-ret; i < len; i ++) 2386 | x[i] = (byte) (rnd >>> 8*i); 2387 | } 2388 | } 2389 | 2390 | } 2391 | --------------------------------------------------------------------------------