/******************************************************************************
* Copyright © 2013-2016 The Nxt Core Developers. *
* *
* See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* Nxt software, including this file, may be copied, modified, propagated, *
* or distributed except according to the terms contained in the LICENSE.txt *
* file. *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
package nxt.peer;
import nxt.Account;
import nxt.Constants;
import nxt.crypto.Crypto;
import nxt.util.Convert;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.ThreadLocalRandom;
public final class Hallmark {
public static int parseDate(String dateValue) {
return Integer.parseInt(dateValue.substring(0, 4)) * 10000
+ Integer.parseInt(dateValue.substring(5, 7)) * 100
+ Integer.parseInt(dateValue.substring(8, 10));
}
public static String formatDate(int date) {
int year = date / 10000;
int month = (date % 10000) / 100;
int day = date % 100;
return (year < 10 ? "000" : (year < 100 ? "00" : (year < 1000 ? "0" : ""))) + year + "-" + (month < 10 ? "0" : "") + month + "-" + (day < 10 ? "0" : "") + day;
}
public static String generateHallmark(String secretPhrase, String host, int weight, int date) {
if (host.length() == 0 || host.length() > 100) {
throw new IllegalArgumentException("Hostname length should be between 1 and 100");
}
if (weight <= 0 || weight > Constants.MAX_BALANCE_NXT) {
throw new IllegalArgumentException("Weight should be between 1 and " + Constants.MAX_BALANCE_NXT);
}
byte[] publicKey = Crypto.getPublicKey(secretPhrase);
byte[] hostBytes = Convert.toBytes(host);
ByteBuffer buffer = ByteBuffer.allocate(32 + 2 + hostBytes.length + 4 + 4 + 1);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put(publicKey);
buffer.putShort((short)hostBytes.length);
buffer.put(hostBytes);
buffer.putInt(weight);
buffer.putInt(date);
byte[] data = buffer.array();
data[data.length - 1] = (byte) ThreadLocalRandom.current().nextInt();
byte[] signature = Crypto.sign(data, secretPhrase);
return Convert.toHexString(data) + Convert.toHexString(signature);
}
public static Hallmark parseHallmark(String hallmarkString) {
byte[] hallmarkBytes = Convert.parseHexString(hallmarkString);
ByteBuffer buffer = ByteBuffer.wrap(hallmarkBytes);
buffer.order(ByteOrder.LITTLE_ENDIAN);
byte[] publicKey = new byte[32];
buffer.get(publicKey);
int hostLength = buffer.getShort();
if (hostLength > 300) {
throw new IllegalArgumentException("Invalid host length");
}
byte[] hostBytes = new byte[hostLength];
buffer.get(hostBytes);
String host = Convert.toString(hostBytes);
int weight = buffer.getInt();
int date = buffer.getInt();
buffer.get();
byte[] signature = new byte[64];
buffer.get(signature);
byte[] data = new byte[hallmarkBytes.length - 64];
System.arraycopy(hallmarkBytes, 0, data, 0, data.length);
boolean isValid = host.length() < 100 && weight > 0 && weight <= Constants.MAX_BALANCE_NXT
&& Crypto.verify(signature, data, publicKey, true);
try {
return new Hallmark(hallmarkString, publicKey, signature, host, weight, date, isValid);
} catch (URISyntaxException e) {
throw new RuntimeException(e.toString(), e);
}
}
private final String hallmarkString;
private final String host;
private final int port;
private final int weight;
private final int date;
private final byte[] publicKey;
private final long accountId;
private final byte[] signature;
private final boolean isValid;
private Hallmark(String hallmarkString, byte[] publicKey, byte[] signature, String host, int weight, int date, boolean isValid)
throws URISyntaxException {
this.hallmarkString = hallmarkString;
URI uri = new URI("http://" + host);
this.host = uri.getHost();
this.port = uri.getPort() == -1 ? Peers.getDefaultPeerPort() : uri.getPort();
this.publicKey = publicKey;
this.accountId = Account.getId(publicKey);
this.signature = signature;
this.weight = weight;
this.date = date;
this.isValid = isValid;
}
public String getHallmarkString() {
return hallmarkString;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public int getWeight() {
return weight;
}
public int getDate() {
return date;
}
public byte[] getSignature() {
return signature;
}
public byte[] getPublicKey() {
return publicKey;
}
public long getAccountId() {
return accountId;
}
public boolean isValid() {
return isValid;
}
}