/******************************************************************************
* 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;
public final class EncryptedData {
public static final EncryptedData EMPTY_DATA = new EncryptedData(new byte[0], new byte[0]);
public static EncryptedData encrypt(byte[] plaintext, String secretPhrase, byte[] theirPublicKey) {
if (plaintext.length == 0) {
return EMPTY_DATA;
}
byte[] nonce = new byte[32];
Crypto.getSecureRandom().nextBytes(nonce);
byte[] sharedKey = Crypto.getSharedKey(Crypto.getPrivateKey(secretPhrase), theirPublicKey, nonce);
byte[] data = Crypto.aesEncrypt(plaintext, sharedKey);
return new EncryptedData(data, nonce);
}
public static EncryptedData readEncryptedData(ByteBuffer buffer, int length, int maxLength)
throws NxtException.NotValidException {
if (length == 0) {
return EMPTY_DATA;
}
if (length > maxLength) {
throw new NxtException.NotValidException("Max encrypted data length exceeded: " + length);
}
byte[] data = new byte[length];
buffer.get(data);
byte[] nonce = new byte[32];
buffer.get(nonce);
return new EncryptedData(data, nonce);
}
public static EncryptedData readEncryptedData(byte[] bytes) {
if (bytes.length == 0) {
return EMPTY_DATA;
}
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
}
}
public static int getEncryptedDataLength(byte[] plaintext) {
if (plaintext.length == 0) {
return 0;
}
return Crypto.aesEncrypt(plaintext, new byte[32]).length;
}
public static int getEncryptedSize(byte[] plaintext) {
if (plaintext.length == 0) {
return 0;
}
return getEncryptedDataLength(plaintext) + 32;
}
private final byte[] data;
private final byte[] nonce;
public EncryptedData(byte[] data, byte[] nonce) {
this.data = data;
this.nonce = nonce;
}
public byte[] decrypt(String secretPhrase, byte[] theirPublicKey) {
if (data.length == 0) {
return data;
}
byte[] sharedKey = Crypto.getSharedKey(Crypto.getPrivateKey(secretPhrase), theirPublicKey, nonce);
return Crypto.aesDecrypt(data, sharedKey);
}
public byte[] getData() {
return data;
}
public byte[] getNonce() {
return nonce;
}
public int getSize() {
return data.length + nonce.length;
}
public byte[] getBytes() {
ByteBuffer buffer = ByteBuffer.allocate(nonce.length + data.length);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put(data);
buffer.put(nonce);
return buffer.array();
}
@Override
public String toString() {
return "data: " + Convert.toHexString(data) + " nonce: " + Convert.toHexString(nonce);
}
}