Coverage Summary for Class: PeerDiscoveryMessage (co.rsk.net.discovery.message)
Class |
Class, %
|
Method, %
|
Line, %
|
PeerDiscoveryMessage |
0%
(0/1)
|
0%
(0/16)
|
0%
(0/60)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package co.rsk.net.discovery.message;
20
21 import co.rsk.net.NodeID;
22 import org.apache.commons.lang3.builder.ToStringBuilder;
23 import org.bouncycastle.util.BigIntegers;
24 import org.ethereum.crypto.ECKey;
25 import org.ethereum.crypto.HashUtil;
26 import org.ethereum.crypto.signature.ECDSASignature;
27 import org.ethereum.crypto.signature.Secp256k1;
28 import org.ethereum.util.ByteUtil;
29 import org.ethereum.util.RLPElement;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import java.security.SignatureException;
34 import java.util.Optional;
35 import java.util.OptionalInt;
36
37 import static org.ethereum.crypto.HashUtil.keccak256;
38 import static org.ethereum.util.ByteUtil.merge;
39
40 public abstract class PeerDiscoveryMessage {
41 private static final Logger logger = LoggerFactory.getLogger(PeerDiscoveryMessage.class);
42
43 private byte[] wire;
44
45 private byte[] mdc;
46 private byte[] signature;
47 private byte[] type;
48 private byte[] data;
49 private OptionalInt networkId;
50
51 public PeerDiscoveryMessage() {}
52
53 public PeerDiscoveryMessage(byte[] wire, byte[] mdc, byte[] signature, byte[] type, byte[] data){
54 this.mdc = mdc;
55 this.signature = signature;
56 this.type = type;
57 this.data = data;
58 this.wire = wire;
59 }
60
61 public PeerDiscoveryMessage encode(byte[] type, byte[] data, ECKey privKey) {
62 /* [1] Calc sha3 - prepare for sig */
63 byte[] payload = new byte[type.length + data.length];
64 payload[0] = type[0];
65 System.arraycopy(data, 0, payload, 1, data.length);
66 byte[] forSig = HashUtil.keccak256(payload);
67
68 /* [2] Crate signature*/
69 ECDSASignature ecdsaSignature = ECDSASignature.fromSignature(privKey.sign(forSig));
70
71 ecdsaSignature.setV((byte)(ecdsaSignature.getV() - 27));
72
73 byte[] sigBytes =
74 merge(BigIntegers.asUnsignedByteArray(32, ecdsaSignature.getR()),
75 BigIntegers.asUnsignedByteArray(32, ecdsaSignature.getS()), new byte[]{ecdsaSignature.getV()});
76
77 // [3] calculate MDC
78 byte[] forSha = merge(sigBytes, type, data);
79
80 // wrap all the data in to the packet
81 this.mdc = HashUtil.keccak256(forSha);
82 this.signature = sigBytes;
83 this.type = type;
84 this.data = data;
85
86 this.wire = merge(this.mdc, this.signature, this.type, this.data);
87
88 return this;
89 }
90
91 public ECKey getKey() {
92
93 byte[] r = new byte[32];
94 byte[] s = new byte[32];
95 byte v = signature[64];
96
97 if (v == 1) {
98 v = 28;
99 }
100
101 if (v == 0) {
102 v = 27;
103 }
104
105 System.arraycopy(signature, 0, r, 0, 32);
106 System.arraycopy(signature, 32, s, 0, 32);
107
108 byte[] msgHash = keccak256(wire, 97, wire.length - 97);
109
110 ECKey outKey = null;
111 try {
112 outKey = Secp256k1.getInstance().signatureToKey(msgHash, ECDSASignature.fromComponents(r, s, v));
113 } catch (SignatureException e) {
114 logger.error("Error generating key from message", e);
115 }
116
117 return outKey;
118 }
119
120 public OptionalInt getNetworkId() {
121 return this.networkId;
122 }
123
124 protected void setNetworkId(final OptionalInt networkId) {
125 this.networkId = networkId;
126 }
127
128 protected void setNetworkIdWithRLP(final RLPElement networkId) {
129 Integer setValue = null;
130 if (networkId != null) {
131 setValue = ByteUtil.byteArrayToInt(networkId.getRLPData());
132 }
133 this.setNetworkId(Optional.ofNullable(setValue).map(OptionalInt::of).orElseGet(OptionalInt::empty));
134 }
135
136 public NodeID getNodeId() {
137 byte[] nodeID = new byte[64];
138
139 System.arraycopy(getKey().getPubKey(), 1, nodeID, 0, 64);
140
141 return new NodeID(nodeID);
142 }
143
144 public byte[] getPacket() {
145 return wire;
146 }
147
148 public byte[] getMdc() {
149 return mdc;
150 }
151
152 public byte[] getSignature() {
153 return signature;
154 }
155
156 public byte[] getType() {
157 return type;
158 }
159
160 public byte[] getData() {
161 return data;
162 }
163
164 public abstract void parse(byte[] data);
165
166 public DiscoveryMessageType getMessageType() {
167 return null;
168 }
169
170 @Override
171 public String toString() {
172 return new ToStringBuilder(this)
173 .append("mdc", ByteUtil.toHexString(mdc))
174 .append("signature", ByteUtil.toHexString(signature))
175 .append("type", ByteUtil.toHexString(type))
176 .append("data", ByteUtil.toHexString(data)).toString();
177 }
178 }