/******************************************************************************
* 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.crypto;
import nxt.NxtException;
import nxt.util.Convert;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
public final class AnonymouslyEncryptedData {
public static AnonymouslyEncryptedData encrypt(byte[] plaintext, String secretPhrase, byte[] theirPublicKey, byte[] nonce) {
byte[] keySeed = Crypto.getKeySeed(secretPhrase, theirPublicKey, nonce);
byte[] myPrivateKey = Crypto.getPrivateKey(keySeed);
byte[] myPublicKey = Crypto.getPublicKey(keySeed);
byte[] sharedKey = Crypto.getSharedKey(myPrivateKey, theirPublicKey);
byte[] data = Crypto.aesGCMEncrypt(plaintext, sharedKey);
return new AnonymouslyEncryptedData(data, myPublicKey);
}
public static AnonymouslyEncryptedData readEncryptedData(ByteBuffer buffer, int length, int maxLength)
throws NxtException.NotValidException {
if (length > maxLength) {
throw new NxtException.NotValidException("Max encrypted data length exceeded: " + length);
}
byte[] data = new byte[length];
buffer.get(data);
byte[] publicKey = new byte[32];
buffer.get(publicKey);
return new AnonymouslyEncryptedData(data, publicKey);
}
public static AnonymouslyEncryptedData readEncryptedData(byte[] bytes) {
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.order(ByteOrder.LITTLE_ENDIAN);
try {
return readEncryptedData(buffer, bytes.length - 32, Integer.MAX_VALUE);
} catch (NxtException.NotValidException e) {
throw new RuntimeException(e.toString(), e); // never
}
}
private final byte[] data;
private final byte[] publicKey;
public AnonymouslyEncryptedData(byte[] data, byte[] publicKey) {
this.data = data;
this.publicKey = publicKey;
}
public byte[] decrypt(String secretPhrase) {
byte[] sharedKey = Crypto.getSharedKey(Crypto.getPrivateKey(secretPhrase), publicKey);
return Crypto.aesGCMDecrypt(data, sharedKey);
}
public byte[] decrypt(byte[] keySeed, byte[] theirPublicKey) {
if (!Arrays.equals(Crypto.getPublicKey(keySeed), publicKey)) {
throw new RuntimeException("Data was not encrypted using this keySeed");
}
byte[] sharedKey = Crypto.getSharedKey(Crypto.getPrivateKey(keySeed), theirPublicKey);
return Crypto.aesGCMDecrypt(data, sharedKey);
}
public byte[] getData() {
return data;
}
public byte[] getPublicKey() {
return publicKey;
}
public int getSize() {
return data.length + 32;
}
public byte[] getBytes() {
ByteBuffer buffer = ByteBuffer.allocate(data.length + 32);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put(data);
buffer.put(publicKey);
return buffer.array();
}
@Override
public String toString() {
return "data: " + Convert.toHexString(data) + " publicKey: " + Convert.toHexString(publicKey);
}
}