package com.dgex.offspring.ui.messaging;
import java.io.UnsupportedEncodingException;
import nxt.crypto.MyCurve25519;
import nxt.crypto.XoredData;
import org.apache.log4j.Logger;
import com.dgex.offspring.config.Config;
public class MessageCrypto {
static Logger logger = Logger.getLogger(MessageCrypto.class);
/* Encrypted messages start with this number */
public static byte[] MAGIC_ENCRYPTED_MESSAGE_NUMBER = new byte[] { 0x42,
0x45, 0x4c, 0x4c, 0x41, 0x4c, 0x55, 0x56 };
/* Non encrypted messages start with this number */
public static byte[] MAGIC_UNENCRYPTED_MESSAGE_NUMBER = new byte[] { 0x4d,
0x41, 0x52, 0x45, 0x4c, 0x55, 0x56 };
// public static boolean test(String secretPhrase, byte[] theirPublicKey)
// throws UnsupportedEncodingException {
//
// String secretMessage = "Hello world";
// logger.info("secretPhrase=" + secretPhrase);
// logger.info("secretMessage=" + secretMessage);
// logger.info("theirPublicKey=" + theirPublicKey);
//
// byte[] ciphertext;
// try {
// ciphertext = encrypt(secretMessage, secretPhrase, theirPublicKey);
// logger.info("ciphertext=" + ciphertext);
// }
// catch (UnsupportedEncodingException e) {
// e.printStackTrace();
// return false;
// }
//
// if (!startsWithMagicByte(ciphertext)) {
// logger.info("Does not start with magic byte");
// return false;
// }
//
// String clearText;
// try {
// clearText = decrypt(ciphertext, secretPhrase, theirPublicKey);
// logger.info("clearText=" + clearText);
// }
// catch (UnsupportedEncodingException e) {
// e.printStackTrace();
// return false;
// }
//
// boolean match = clearText.equals(secretMessage);
// logger.info("match=" + match);
// return match;
// }
/**
* Encrypt a clear text string for use in a message.
*
* @param plaintext
* @param secretPhrase
* String
* @param theirPublicKey
* @return
* @throws UnsupportedEncodingException
*/
public static byte[] encrypt(String plaintext, String secretPhrase,
byte[] theirPublicKey) throws UnsupportedEncodingException {
byte[] bytes = plaintext.getBytes("UTF-8");
byte[] myPrivateKey = MyCurve25519.getPrivateKey(secretPhrase);
XoredData xored = XoredData.encrypt(bytes, myPrivateKey, theirPublicKey);
byte[] magic = Config.MAGIC_ENCRYPTED_MESSAGE_NUMBER;
byte[] nonce = xored.getNonce();
byte[] data = xored.getData();
byte[] message = new byte[magic.length + nonce.length + data.length];
System.arraycopy(magic, 0, message, 0, magic.length);
System.arraycopy(nonce, 0, message, magic.length, nonce.length);
System
.arraycopy(data, 0, message, nonce.length + magic.length, data.length);
return message;
}
/**
* Decrypts an encrypted string
*
* @param bytes
* @param secretPhrase
* @param theirPublicKey
* @return
* @throws UnsupportedEncodingException
*/
public static String decrypt(byte[] bytes, String secretPhrase,
byte[] theirPublicKey) throws UnsupportedEncodingException {
byte[] mykey = MyCurve25519.getPrivateKey(secretPhrase);
byte[] magic = new byte[Config.MAGIC_ENCRYPTED_MESSAGE_NUMBER.length];
byte[] nonce = new byte[32];
byte[] data = new byte[bytes.length - magic.length - nonce.length];
if (!startsWith(bytes, Config.MAGIC_ENCRYPTED_MESSAGE_NUMBER))
throw new RuntimeException("Ciphertext does not start with magic number");
getBytes(bytes, 0, magic.length, magic, 0);
getBytes(bytes, magic.length, magic.length + nonce.length, nonce, 0);
getBytes(bytes, magic.length + nonce.length, magic.length + nonce.length
+ data.length, data, 0);
XoredData xored = new XoredData(data, nonce);
byte[] plainText = xored.decrypt(mykey, theirPublicKey);
return new String(plainText, "UTF-8");
}
public static boolean startsWithMagicEncryptedByte(byte[] bytes) {
return startsWith(bytes, Config.MAGIC_ENCRYPTED_MESSAGE_NUMBER);
}
public static boolean startsWithMagicUnEncryptedByte(byte[] bytes) {
return startsWith(bytes, Config.MAGIC_UNENCRYPTED_MESSAGE_NUMBER);
}
private static boolean startsWith(byte[] source, byte[] match) {
return startsWith(source, 0, match);
}
private static boolean startsWith(byte[] source, int offset, byte[] match) {
if (match.length > (source.length - offset)) {
return false;
}
for (int i = 0; i < match.length; i++) {
if (source[offset + i] != match[i]) {
return false;
}
}
return true;
}
/**
* Copies bytes from the source byte array to the destination array
*
* @param source
* The source array
* @param srcBegin
* Index of the first source byte to copy
* @param srcEnd
* Index after the last source byte to copy
* @param destination
* The destination array
* @param dstBegin
* The starting offset in the destination array
*/
private static void getBytes(byte[] source, int srcBegin, int srcEnd,
byte[] destination, int dstBegin) {
System
.arraycopy(source, srcBegin, destination, dstBegin, srcEnd - srcBegin);
}
}