First class memo implementation
This commit is contained in:
parent
e235e096c9
commit
dc0c591a3d
3 changed files with 189 additions and 88 deletions
|
@ -49,14 +49,13 @@ public abstract class FileBin {
|
|||
byte[] finalKey = randomECKey.getPubKeyPoint().multiply(ECKey.fromPrivate(md.digest(password.getBytes("UTF-8"))).getPrivKey()).normalize().getXCoord().getEncoded();
|
||||
MessageDigest md1 = MessageDigest.getInstance("SHA-512");
|
||||
finalKey = md1.digest(finalKey);
|
||||
byte[] rawData = decryptAES(rawDataEncripted, byteToString(finalKey).getBytes());
|
||||
byte[] rawData = Util.decryptAES(rawDataEncripted, Util.byteToString(finalKey).getBytes());
|
||||
|
||||
byte[] checksum = new byte[4];
|
||||
System.arraycopy(rawData, 0, checksum, 0, 4);
|
||||
byte[] compressedData = new byte[rawData.length - 4];
|
||||
System.arraycopy(rawData, 4, compressedData, 0, compressedData.length);
|
||||
|
||||
System.out.println("Despues:"+byteToString(compressedData));
|
||||
byte[] wallet_object_bytes = Util.decompress(compressedData, Util.XZ);
|
||||
String wallet_string = new String(wallet_object_bytes, "UTF-8");
|
||||
JsonObject wallet = new JsonParser().parse(wallet_string).getAsJsonObject();
|
||||
|
@ -69,7 +68,7 @@ public abstract class FileBin {
|
|||
byte[] encKey_enc = new BigInteger(wallet.get("encryption_key").getAsString(), 16).toByteArray();
|
||||
byte[] temp = new byte[encKey_enc.length - (encKey_enc[0] == 0 ? 1 : 0)];
|
||||
System.arraycopy(encKey_enc, (encKey_enc[0] == 0 ? 1 : 0), temp, 0, temp.length);
|
||||
byte[] encKey = decryptAES(temp, password.getBytes("UTF-8"));
|
||||
byte[] encKey = Util.decryptAES(temp, password.getBytes("UTF-8"));
|
||||
temp = new byte[encKey.length];
|
||||
System.arraycopy(encKey, 0, temp, 0, temp.length);
|
||||
|
||||
|
@ -79,7 +78,7 @@ public abstract class FileBin {
|
|||
System.arraycopy(encBrain, 1, temp2, 0, temp2.length);
|
||||
encBrain = temp2;
|
||||
}
|
||||
String BrainKey = new String((decryptAES(encBrain, temp)), "UTF-8");
|
||||
String BrainKey = new String((Util.decryptAES(encBrain, temp)), "UTF-8");
|
||||
|
||||
return BrainKey;
|
||||
|
||||
|
@ -105,15 +104,15 @@ public abstract class FileBin {
|
|||
//randomStrengthener.addEntropySource(new AndroidRandomSource());
|
||||
SecureRandom secureRandom = randomStrengthener.generateAndSeedRandomNumberGenerator();
|
||||
secureRandom.nextBytes(encKey);
|
||||
byte[] encKey_enc = encryptAES(encKey, password.getBytes("UTF-8"));
|
||||
byte[] encBrain = encryptAES(BrainKey.getBytes("ASCII"), encKey);
|
||||
byte[] encKey_enc = Util.encryptAES(encKey, password.getBytes("UTF-8"));
|
||||
byte[] encBrain = Util.encryptAES(BrainKey.getBytes("ASCII"), encKey);
|
||||
|
||||
/**
|
||||
* Data to Store
|
||||
*/
|
||||
JsonObject wallet = new JsonObject();
|
||||
wallet.add("encryption_key", new JsonParser().parse(byteToString(encKey_enc)));
|
||||
wallet.add("encrypted_brainkey", new JsonParser().parse(byteToString(encBrain)));
|
||||
wallet.add("encryption_key", new JsonParser().parse(Util.byteToString(encKey_enc)));
|
||||
wallet.add("encrypted_brainkey", new JsonParser().parse(Util.byteToString(encBrain)));
|
||||
JsonObject wallet_object = new JsonObject();
|
||||
wallet_object.add("wallet", wallet);
|
||||
JsonArray accountNames = new JsonArray();
|
||||
|
@ -122,7 +121,6 @@ public abstract class FileBin {
|
|||
accountNames.add(jsonAccountName);
|
||||
wallet_object.add("linked_accounts", accountNames);
|
||||
byte[] compressedData = Util.compress(wallet_object.toString().getBytes("UTF-8"), Util.XZ);
|
||||
System.out.println("Antes:"+byteToString(compressedData));
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
byte[] checksum = md.digest(compressedData);
|
||||
byte[] rawData = new byte[compressedData.length + 4];
|
||||
|
@ -135,7 +133,7 @@ public abstract class FileBin {
|
|||
byte[] finalKey = randomECKey.getPubKeyPoint().multiply(ECKey.fromPrivate(md.digest(password.getBytes("UTF-8"))).getPrivKey()).normalize().getXCoord().getEncoded();
|
||||
MessageDigest md1 = MessageDigest.getInstance("SHA-512");
|
||||
finalKey = md1.digest(finalKey);
|
||||
rawData = encryptAES(rawData, byteToString(finalKey).getBytes());
|
||||
rawData = Util.encryptAES(rawData, Util.byteToString(finalKey).getBytes());
|
||||
|
||||
byte[] result = new byte[rawData.length + randPubKey.length];
|
||||
System.arraycopy(randPubKey, 0, result, 0, randPubKey.length);
|
||||
|
@ -149,80 +147,5 @@ public abstract class FileBin {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static byte[] encryptAES(byte[] input, byte[] key) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
byte[] result = md.digest(key);
|
||||
byte[] ivBytes = new byte[16];
|
||||
System.arraycopy(result, 32, ivBytes, 0, 16);
|
||||
byte[] sksBytes = new byte[32];
|
||||
System.arraycopy(result, 0, sksBytes, 0, 32);
|
||||
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
|
||||
cipher.init(true, new ParametersWithIV(new KeyParameter(sksBytes), ivBytes));
|
||||
byte[] temp = new byte[input.length + (16 - (input.length % 16))];
|
||||
System.arraycopy(input, 0, temp, 0, input.length);
|
||||
Arrays.fill(temp, input.length, temp.length, (byte) (16 - (input.length % 16)));
|
||||
byte[] out = new byte[cipher.getOutputSize(temp.length)];
|
||||
int proc = cipher.processBytes(temp, 0, temp.length, out, 0);
|
||||
cipher.doFinal(out, proc);
|
||||
temp = new byte[out.length - 16];
|
||||
System.arraycopy(out, 0, temp, 0, temp.length);
|
||||
return temp;
|
||||
} catch (NoSuchAlgorithmException | DataLengthException | IllegalStateException | InvalidCipherTextException ex) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] decryptAES(byte[] input, byte[] key) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
byte[] result = md.digest(key);
|
||||
byte[] ivBytes = new byte[16];
|
||||
System.arraycopy(result, 32, ivBytes, 0, 16);
|
||||
byte[] sksBytes = new byte[32];
|
||||
System.arraycopy(result, 0, sksBytes, 0, 32);
|
||||
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
|
||||
cipher.init(false, new ParametersWithIV(new KeyParameter(sksBytes), ivBytes));
|
||||
|
||||
byte[] pre_out = new byte[cipher.getOutputSize(input.length)];
|
||||
int proc = cipher.processBytes(input, 0, input.length, pre_out, 0);
|
||||
int proc2 = cipher.doFinal(pre_out, proc);
|
||||
byte[] out = new byte[proc+proc2];
|
||||
System.arraycopy(pre_out, 0, out, 0, proc+proc2);
|
||||
|
||||
//Unpadding
|
||||
byte countByte = (byte)((byte)out[out.length-1] % 16);
|
||||
int count = countByte & 0xFF;
|
||||
|
||||
if ((count > 15) || (count <= 0)){
|
||||
return out;
|
||||
}
|
||||
|
||||
byte[] temp = new byte[count];
|
||||
System.arraycopy(out, out.length - count, temp, 0, temp.length);
|
||||
byte[] temp2 = new byte[count];
|
||||
Arrays.fill(temp2, (byte) count);
|
||||
if (Arrays.equals(temp, temp2)) {
|
||||
temp = new byte[out.length - count];
|
||||
System.arraycopy(out, 0, temp, 0, out.length - count);
|
||||
return temp;
|
||||
} else {
|
||||
return out;
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | DataLengthException | IllegalStateException | InvalidCipherTextException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String byteToString(byte[] input) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (byte in : input) {
|
||||
if ((in & 0xff) < 0x10) {
|
||||
result.append("0");
|
||||
}
|
||||
result.append(Integer.toHexString(in & 0xff));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,89 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.luminiasoft.bitshares.crypto.SecureRandomStrengthener;
|
||||
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/9/16.
|
||||
*/
|
||||
public class Memo implements ByteSerializable {
|
||||
//TODO: Give this class a proper implementation
|
||||
|
||||
private byte[] from;
|
||||
private byte[] to;
|
||||
private byte[] nonce = new byte[8];
|
||||
private byte[] message;
|
||||
|
||||
@Override
|
||||
public byte[] toBytes() {
|
||||
return new byte[1];
|
||||
if ((this.from == null) || (this.to == null) || (this.nonce == null) ||(this.message == null)){
|
||||
return new byte[1];
|
||||
}
|
||||
|
||||
byte[] result = new byte[this.from.length+this.to.length+this.nonce.length+this.message.length];
|
||||
System.arraycopy(this.from, 0, result, 0, this.from.length);
|
||||
System.arraycopy(this.to, 0, result, this.from.length, this.to.length);
|
||||
System.arraycopy(this.nonce, 0, result, this.from.length+this.to.length, this.nonce.length);
|
||||
System.arraycopy(this.message, 0, result, this.from.length+this.to.length+this.nonce.length, this.message.length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Memo(){
|
||||
this.from = null;
|
||||
this.nonce = null;
|
||||
this.to = null;
|
||||
this.message = null;
|
||||
}
|
||||
|
||||
public Memo(byte[] private_key, byte[] public_key, byte[] msg){
|
||||
this(private_key,public_key,msg,0);
|
||||
}
|
||||
|
||||
public Memo(byte[] private_key, byte[] public_key, byte[] msg, long custom_nonce){
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
ECKey privateECKey = ECKey.fromPrivate(md.digest(private_key));
|
||||
|
||||
this.from = privateECKey.getPubKey();
|
||||
this.to = public_key;
|
||||
|
||||
if (custom_nonce == 0){
|
||||
SecureRandomStrengthener randomStrengthener = SecureRandomStrengthener.getInstance();
|
||||
//randomStrengthener.addEntropySource(new AndroidRandomSource());
|
||||
SecureRandom secureRandom = randomStrengthener.generateAndSeedRandomNumberGenerator();
|
||||
secureRandom.nextBytes(nonce);
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
for (int i = 7;i >=1; i--){
|
||||
this.nonce[i] = (byte)(time&0xff);
|
||||
time = time/0x100;
|
||||
}
|
||||
} else {
|
||||
for (int i = 7;i >=0; i--){
|
||||
this.nonce[i] = (byte)(custom_nonce&0xff);
|
||||
custom_nonce = custom_nonce/0x100;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte[] secret = privateECKey.getPubKeyPoint().multiply(ECKey.fromPublicOnly(md.digest(public_key)).getPrivKey()).normalize().getXCoord().getEncoded();
|
||||
byte[] finalKey = new byte[secret.length + this.nonce.length];
|
||||
|
||||
byte[] sha256Msg = md.digest(msg);
|
||||
byte[] serialChecksum = new byte[4];
|
||||
System.arraycopy(sha256Msg, 0, serialChecksum, 0, 4);
|
||||
byte[] msgFinal = new byte[serialChecksum.length + msg.length];
|
||||
System.arraycopy(serialChecksum, 0, msgFinal, 0, serialChecksum.length);
|
||||
System.arraycopy(msg, 0, msgFinal, serialChecksum.length, msg.length);
|
||||
|
||||
this.message = Util.encryptAES(msgFinal, finalKey);
|
||||
} catch (NoSuchAlgorithmException ex){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,18 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.spongycastle.crypto.DataLengthException;
|
||||
import org.spongycastle.crypto.InvalidCipherTextException;
|
||||
import org.spongycastle.crypto.engines.AESFastEngine;
|
||||
import org.spongycastle.crypto.modes.CBCBlockCipher;
|
||||
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
|
||||
import org.spongycastle.crypto.params.KeyParameter;
|
||||
import org.spongycastle.crypto.params.ParametersWithIV;
|
||||
|
||||
/**
|
||||
* Class used to encapsulate common utility methods
|
||||
|
@ -114,4 +124,98 @@ public class Util {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to encrypt a message with AES
|
||||
* @param input data to encrypt
|
||||
* @param key key for encryption
|
||||
* @return AES Encription of input
|
||||
*/
|
||||
public static byte[] encryptAES(byte[] input, byte[] key) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
byte[] result = md.digest(key);
|
||||
byte[] ivBytes = new byte[16];
|
||||
System.arraycopy(result, 32, ivBytes, 0, 16);
|
||||
byte[] sksBytes = new byte[32];
|
||||
System.arraycopy(result, 0, sksBytes, 0, 32);
|
||||
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
|
||||
cipher.init(true, new ParametersWithIV(new KeyParameter(sksBytes), ivBytes));
|
||||
byte[] temp = new byte[input.length + (16 - (input.length % 16))];
|
||||
System.arraycopy(input, 0, temp, 0, input.length);
|
||||
Arrays.fill(temp, input.length, temp.length, (byte) (16 - (input.length % 16)));
|
||||
byte[] out = new byte[cipher.getOutputSize(temp.length)];
|
||||
int proc = cipher.processBytes(temp, 0, temp.length, out, 0);
|
||||
cipher.doFinal(out, proc);
|
||||
temp = new byte[out.length - 16];
|
||||
System.arraycopy(out, 0, temp, 0, temp.length);
|
||||
return temp;
|
||||
} catch (NoSuchAlgorithmException | DataLengthException | IllegalStateException | InvalidCipherTextException ex) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to decrypt a message with AES encryption
|
||||
* @param input data to decrypt
|
||||
* @param key key for decryption
|
||||
* @return input decrypted with AES. Null if the decrypt failed (Bad Key)
|
||||
*/
|
||||
public static byte[] decryptAES(byte[] input, byte[] key) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
byte[] result = md.digest(key);
|
||||
byte[] ivBytes = new byte[16];
|
||||
System.arraycopy(result, 32, ivBytes, 0, 16);
|
||||
byte[] sksBytes = new byte[32];
|
||||
System.arraycopy(result, 0, sksBytes, 0, 32);
|
||||
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
|
||||
cipher.init(false, new ParametersWithIV(new KeyParameter(sksBytes), ivBytes));
|
||||
|
||||
byte[] pre_out = new byte[cipher.getOutputSize(input.length)];
|
||||
int proc = cipher.processBytes(input, 0, input.length, pre_out, 0);
|
||||
int proc2 = cipher.doFinal(pre_out, proc);
|
||||
byte[] out = new byte[proc+proc2];
|
||||
System.arraycopy(pre_out, 0, out, 0, proc+proc2);
|
||||
|
||||
//Unpadding
|
||||
byte countByte = (byte)((byte)out[out.length-1] % 16);
|
||||
int count = countByte & 0xFF;
|
||||
|
||||
if ((count > 15) || (count <= 0)){
|
||||
return out;
|
||||
}
|
||||
|
||||
byte[] temp = new byte[count];
|
||||
System.arraycopy(out, out.length - count, temp, 0, temp.length);
|
||||
byte[] temp2 = new byte[count];
|
||||
Arrays.fill(temp2, (byte) count);
|
||||
if (Arrays.equals(temp, temp2)) {
|
||||
temp = new byte[out.length - count];
|
||||
System.arraycopy(out, 0, temp, 0, out.length - count);
|
||||
return temp;
|
||||
} else {
|
||||
return out;
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | DataLengthException | IllegalStateException | InvalidCipherTextException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an array of bytes to an hex String representation
|
||||
* @param input array of bytes to transform as a string
|
||||
* @return Input as a String
|
||||
*/
|
||||
public static String byteToString(byte[] input) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (byte in : input) {
|
||||
if ((in & 0xff) < 0x10) {
|
||||
result.append("0");
|
||||
}
|
||||
result.append(Integer.toHexString(in & 0xff));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue