Fixing a bug with memo deserialization

This commit is contained in:
Nelson R. Perez 2017-10-12 23:34:22 -05:00
parent 61dc72724e
commit b305faa662
5 changed files with 90 additions and 39 deletions

View file

@ -1,7 +1,22 @@
package cy.agorise.graphenej; package cy.agorise.graphenej;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import org.tukaani.xz.*; import com.google.common.primitives.UnsignedLong;
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;
import org.tukaani.xz.CorruptedInputException;
import org.tukaani.xz.FinishableOutputStream;
import org.tukaani.xz.LZMA2Options;
import org.tukaani.xz.LZMAInputStream;
import org.tukaani.xz.LZMAOutputStream;
import org.tukaani.xz.XZInputStream;
import org.tukaani.xz.XZOutputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -13,13 +28,6 @@ import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; 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 * Class used to encapsulate common utility methods
@ -210,6 +218,15 @@ public class Util {
return ByteBuffer.allocate(Long.SIZE / 8).putLong(Long.reverseBytes(input)).array(); return ByteBuffer.allocate(Long.SIZE / 8).putLong(Long.reverseBytes(input)).array();
} }
/**
* Same operation as in the revertInteger function, but with an UnsignedLong object as argument.
* @param input An UnsignedLong class instance
* @return The array of bytes that represent this value in the reverse format.
*/
public static byte[] revertUnsignedLong(UnsignedLong input){
return ByteBuffer.allocate(Long.SIZE / 8).putLong(Long.reverseBytes(input.longValue())).array();
}
public static byte[] revertBytes(byte[] array){ public static byte[] revertBytes(byte[] array){
byte[] reverted = new byte[array.length]; byte[] reverted = new byte[array.length];
for(int i = 0; i < reverted.length; i++){ for(int i = 0; i < reverted.length; i++){

View file

@ -1,20 +1,13 @@
package cy.agorise.graphenej.objects; package cy.agorise.graphenej.objects;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedLong;
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer; import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import cy.agorise.graphenej.Address;
import cy.agorise.graphenej.PublicKey;
import cy.agorise.graphenej.Util;
import cy.agorise.graphenej.errors.ChecksumException;
import cy.agorise.graphenej.errors.MalformedAddressException;
import cy.agorise.graphenej.interfaces.ByteSerializable;
import cy.agorise.graphenej.interfaces.JsonSerializable;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
import org.spongycastle.math.ec.ECPoint; import org.spongycastle.math.ec.ECPoint;
@ -23,8 +16,17 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
import cy.agorise.graphenej.Address;
import cy.agorise.graphenej.PublicKey;
import cy.agorise.graphenej.Util;
import cy.agorise.graphenej.errors.ChecksumException;
import cy.agorise.graphenej.errors.MalformedAddressException;
import cy.agorise.graphenej.interfaces.ByteSerializable;
import cy.agorise.graphenej.interfaces.JsonSerializable;
/** /**
* Created by nelson on 11/9/16. * Class used to represent a memo data structure
* {@url https://bitshares.org/doxygen/structgraphene_1_1chain_1_1memo__data.html}
*/ */
public class Memo implements ByteSerializable, JsonSerializable { public class Memo implements ByteSerializable, JsonSerializable {
public final static String TAG = "Memo"; public final static String TAG = "Memo";
@ -35,7 +37,7 @@ public class Memo implements ByteSerializable, JsonSerializable {
private Address from; private Address from;
private Address to; private Address to;
private long nonce; private UnsignedLong nonce;
private byte[] message; private byte[] message;
private String plaintextMessage; private String plaintextMessage;
@ -66,7 +68,7 @@ public class Memo implements ByteSerializable, JsonSerializable {
* @param nonce: Nonce used in the encryption. * @param nonce: Nonce used in the encryption.
* @param message: Message in ciphertext. * @param message: Message in ciphertext.
*/ */
public Memo(Address from, Address to, long nonce, byte[] message){ public Memo(Address from, Address to, UnsignedLong nonce, byte[] message){
this.from = from; this.from = from;
this.to = to; this.to = to;
this.nonce = nonce; this.nonce = nonce;
@ -89,7 +91,7 @@ public class Memo implements ByteSerializable, JsonSerializable {
return this.to; return this.to;
} }
public long getNonce(){ public UnsignedLong getNonce(){
return this.nonce; return this.nonce;
} }
@ -235,7 +237,7 @@ public class Memo implements ByteSerializable, JsonSerializable {
new byte[]{(byte) this.message.length}, new byte[]{(byte) this.message.length},
this.message); this.message);
} else { } else {
byte[] nonceBytes = Util.revertLong(nonce); byte[] nonceBytes = Util.revertUnsignedLong(nonce);
ECPoint senderPoint = ECKey.compressPoint(from.getPublicKey().getKey().getPubKeyPoint()); ECPoint senderPoint = ECKey.compressPoint(from.getPublicKey().getKey().getPubKeyPoint());
PublicKey senderPublicKey = new PublicKey(ECKey.fromPublicOnly(senderPoint)); PublicKey senderPublicKey = new PublicKey(ECKey.fromPublicOnly(senderPoint));
@ -287,7 +289,7 @@ public class Memo implements ByteSerializable, JsonSerializable {
JsonObject jsonObject = json.getAsJsonObject(); JsonObject jsonObject = json.getAsJsonObject();
String fromAddress = jsonObject.get(KEY_FROM).getAsString(); String fromAddress = jsonObject.get(KEY_FROM).getAsString();
String toAddress = jsonObject.get(KEY_TO).getAsString(); String toAddress = jsonObject.get(KEY_TO).getAsString();
long nonce = jsonObject.get(KEY_NONCE).getAsLong(); UnsignedLong nonce = UnsignedLong.valueOf(jsonObject.get(KEY_NONCE).getAsString());
String msg = jsonObject.get(KEY_MESSAGE).getAsString(); String msg = jsonObject.get(KEY_MESSAGE).getAsString();
Memo memo = null; Memo memo = null;
@ -295,6 +297,7 @@ public class Memo implements ByteSerializable, JsonSerializable {
Address from = new Address(fromAddress); Address from = new Address(fromAddress);
Address to = new Address(toAddress); Address to = new Address(toAddress);
byte[] message = Util.hexToBytes(msg); byte[] message = Util.hexToBytes(msg);
memo = new Memo(from, to, nonce, message); memo = new Memo(from, to, nonce, message);
}catch(MalformedAddressException e){ }catch(MalformedAddressException e){
System.out.println("MalformedAddressException. Msg: "+e.getMessage()); System.out.println("MalformedAddressException. Msg: "+e.getMessage());

View file

@ -4,24 +4,30 @@ import com.google.common.primitives.UnsignedLong;
import com.neovisionaries.ws.client.WebSocket; import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketException; import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory; import com.neovisionaries.ws.client.WebSocketFactory;
import org.bitcoinj.core.ECKey;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import cy.agorise.graphenej.api.GetLimitOrders; import cy.agorise.graphenej.api.GetLimitOrders;
import cy.agorise.graphenej.api.TransactionBroadcastSequence; import cy.agorise.graphenej.api.TransactionBroadcastSequence;
import cy.agorise.graphenej.interfaces.WitnessResponseListener; import cy.agorise.graphenej.interfaces.WitnessResponseListener;
import cy.agorise.graphenej.models.BaseResponse; import cy.agorise.graphenej.models.BaseResponse;
import cy.agorise.graphenej.models.WitnessResponse; import cy.agorise.graphenej.models.WitnessResponse;
import cy.agorise.graphenej.objects.Memo; import cy.agorise.graphenej.objects.Memo;
import cy.agorise.graphenej.operations.*; import cy.agorise.graphenej.operations.LimitOrderCancelOperation;
import cy.agorise.graphenej.operations.LimitOrderCreateOperation;
import cy.agorise.graphenej.operations.TransferOperation;
import cy.agorise.graphenej.operations.TransferOperationBuilder;
import cy.agorise.graphenej.test.NaiveSSLContext; import cy.agorise.graphenej.test.NaiveSSLContext;
import org.bitcoinj.core.ECKey;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
/** /**
* Created by nelson on 3/6/17. * Created by nelson on 3/6/17.
@ -138,7 +144,7 @@ public class TransactionTest {
// Creating memo // Creating memo
long nonce = 1; long nonce = 1;
byte[] encryptedMessage = Memo.encryptMessage(sourcePrivateKey, to1, nonce, "another message"); byte[] encryptedMessage = Memo.encryptMessage(sourcePrivateKey, to1, nonce, "another message");
Memo memo = new Memo(new Address(ECKey.fromPublicOnly(sourcePrivateKey.getPubKey())), new Address(to1.getKey()), nonce, encryptedMessage); Memo memo = new Memo(new Address(ECKey.fromPublicOnly(sourcePrivateKey.getPubKey())), new Address(to1.getKey()), UnsignedLong.valueOf(nonce), encryptedMessage);
// Creating operation 1 // Creating operation 1
TransferOperation transferOperation1 = new TransferOperationBuilder() TransferOperation transferOperation1 = new TransferOperationBuilder()

View file

@ -0,0 +1,21 @@
package cy.agorise.graphenej;
import com.google.common.primitives.UnsignedLong;
import junit.framework.Assert;
import org.junit.Test;
/**
* Class used to test Util methods
*/
public class UtilTest {
@Test
public void testRevertUnsignedLong(){
UnsignedLong unsignedLong = UnsignedLong.valueOf("12179241258665439971");
byte[] reversed = Util.revertUnsignedLong(unsignedLong);
Assert.assertEquals("e3f28878655b05a9", Util.bytesToHex(reversed));
}
}

View file

@ -1,14 +1,18 @@
package cy.agorise.graphenej.objects; package cy.agorise.graphenej.objects;
import com.google.common.primitives.UnsignedLong;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey;
import org.junit.Before;
import org.junit.Test;
import cy.agorise.graphenej.Address; import cy.agorise.graphenej.Address;
import cy.agorise.graphenej.PublicKey; import cy.agorise.graphenej.PublicKey;
import cy.agorise.graphenej.Util; import cy.agorise.graphenej.Util;
import cy.agorise.graphenej.errors.ChecksumException; import cy.agorise.graphenej.errors.ChecksumException;
import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey;
import org.junit.*;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -130,7 +134,7 @@ public class MemoTest {
@Test @Test
public void shouldBeJsonObjectSerializable(){ public void shouldBeJsonObjectSerializable(){
byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage); byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage);
Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted); Memo memo = new Memo(sourceAddress, destinationAddress, UnsignedLong.ONE, encrypted);
JsonElement jsonObject = memo.toJsonObject(); JsonElement jsonObject = memo.toJsonObject();
JsonObject reference = new JsonObject(); JsonObject reference = new JsonObject();
reference.addProperty("from", "BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); reference.addProperty("from", "BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
@ -144,7 +148,7 @@ public class MemoTest {
public void shouldBeByteSerializable(){ public void shouldBeByteSerializable(){
String byteReference = "0103d1fb8c7421db64d46fba7e36f428854ca06eff65698b293f37c7ffaa54e2c2b203aece7c31616c02fcc96b50d3397c0e8d33d6384655d477c300d9196c728a5ee20100000000000000104c81c2db6ebc61e3f9e0ead65c0559dd"; String byteReference = "0103d1fb8c7421db64d46fba7e36f428854ca06eff65698b293f37c7ffaa54e2c2b203aece7c31616c02fcc96b50d3397c0e8d33d6384655d477c300d9196c728a5ee20100000000000000104c81c2db6ebc61e3f9e0ead65c0559dd";
byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage); byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage);
Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted); Memo memo = new Memo(sourceAddress, destinationAddress, UnsignedLong.ONE, encrypted);
byte[] memoBytes = memo.toBytes(); byte[] memoBytes = memo.toBytes();
assertEquals("Memo instance should generate a valid byte array", byteReference, Util.bytesToHex(memoBytes)); assertEquals("Memo instance should generate a valid byte array", byteReference, Util.bytesToHex(memoBytes));
} }