Coverage Summary for Class: ECIESCoder (org.ethereum.crypto)
Class |
Class, %
|
Method, %
|
Line, %
|
ECIESCoder |
0%
(0/1)
|
0%
(0/9)
|
0%
(0/61)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.crypto;
21
22 import com.google.common.base.Throwables;
23 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
24 import org.bouncycastle.crypto.BufferedBlockCipher;
25 import org.bouncycastle.crypto.InvalidCipherTextException;
26 import org.bouncycastle.crypto.KeyGenerationParameters;
27 import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
28 import org.bouncycastle.crypto.digests.SHA1Digest;
29 import org.bouncycastle.crypto.digests.SHA256Digest;
30 import org.bouncycastle.crypto.engines.AESEngine;
31 import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
32 import org.bouncycastle.crypto.macs.HMac;
33 import org.bouncycastle.crypto.modes.SICBlockCipher;
34 import org.bouncycastle.crypto.params.*;
35 import org.bouncycastle.crypto.parsers.ECIESPublicKeyParser;
36 import org.bouncycastle.math.ec.ECPoint;
37 import org.ethereum.ConcatKDFBytesGenerator;
38
39 import java.io.ByteArrayInputStream;
40 import java.io.ByteArrayOutputStream;
41 import java.io.IOException;
42 import java.math.BigInteger;
43 import java.security.SecureRandom;
44
45 import static org.ethereum.crypto.ECKey.CURVE;
46
47 public class ECIESCoder {
48
49
50 public static final int KEY_SIZE = 128;
51
52 public static byte[] decrypt(BigInteger privKey, byte[] cipher) throws IOException, InvalidCipherTextException {
53 return decrypt(privKey, cipher, null);
54 }
55
56 public static byte[] decrypt(BigInteger privKey, byte[] cipher, byte[] macData) throws IOException, InvalidCipherTextException {
57
58 byte[] plaintext;
59
60 ByteArrayInputStream is = new ByteArrayInputStream(cipher);
61 byte[] ephemBytes = new byte[2*((CURVE.getCurve().getFieldSize()+7)/8) + 1];
62
63 is.read(ephemBytes);
64 ECPoint ephem = CURVE.getCurve().decodePoint(ephemBytes);
65 byte[] iv = new byte[KEY_SIZE /8];
66 is.read(iv);
67 byte[] cipherBody = new byte[is.available()];
68 is.read(cipherBody);
69
70 plaintext = decrypt(ephem, privKey, iv, cipherBody, macData);
71
72 return plaintext;
73 }
74
75 public static byte[] decrypt(ECPoint ephem, BigInteger prv, byte[] iv, byte[] cipher, byte[] macData) throws InvalidCipherTextException {
76 AESEngine aesEngine = new AESEngine();
77
78 EthereumIESEngine iesEngine = new EthereumIESEngine(
79 new ECDHBasicAgreement(),
80 new ConcatKDFBytesGenerator(new SHA256Digest()),
81 new HMac(new SHA256Digest()),
82 new SHA256Digest(),
83 new BufferedBlockCipher(new SICBlockCipher(aesEngine)));
84
85
86 byte[] d = new byte[] {};
87 byte[] e = new byte[] {};
88
89 IESParameters p = new IESWithCipherParameters(d, e, KEY_SIZE, KEY_SIZE);
90 ParametersWithIV parametersWithIV =
91 new ParametersWithIV(p, iv);
92
93 iesEngine.init(false, new ECPrivateKeyParameters(prv, CURVE), new ECPublicKeyParameters(ephem, CURVE), parametersWithIV);
94
95 return iesEngine.processBlock(cipher, 0, cipher.length, macData);
96 }
97
98 /**
99 * Encryption equivalent to the Crypto++ default ECIES<ECP> settings:
100 *
101 * DL_KeyAgreementAlgorithm: DL_KeyAgreementAlgorithm_DH<struct ECPPoint,struct EnumToType<enum CofactorMultiplicationOption,0> >
102 * DL_KeyDerivationAlgorithm: DL_KeyDerivationAlgorithm_P1363<struct ECPPoint,0,class P1363_KDF2<class SHA1> >
103 * DL_SymmetricEncryptionAlgorithm: DL_EncryptionAlgorithm_Xor<class HMAC<class SHA1>,0>
104 * DL_PrivateKey: DL_Key<ECPPoint>
105 * DL_PrivateKey_EC<class ECP>
106 *
107 * Used for Whisper V3
108 */
109 public static byte[] decryptSimple(BigInteger privKey, byte[] cipher) throws IOException, InvalidCipherTextException {
110 EthereumIESEngine iesEngine = new EthereumIESEngine(
111 new ECDHBasicAgreement(),
112 new MGF1BytesGeneratorExt(new SHA1Digest(), 1),
113 new HMac(new SHA1Digest()),
114 new SHA1Digest(),
115 null);
116
117 IESParameters p = new IESParameters(null, null, KEY_SIZE);
118 ParametersWithIV parametersWithIV = new ParametersWithIV(p, new byte[0]);
119
120 iesEngine.setHashMacKey(false);
121
122 iesEngine.init(new ECPrivateKeyParameters(privKey, CURVE), parametersWithIV,
123 new ECIESPublicKeyParser(ECKey.CURVE));
124
125 return iesEngine.processBlock(cipher, 0, cipher.length);
126 }
127
128 public static byte[] encrypt(ECPoint toPub, byte[] plaintext) {
129 return encrypt(toPub, plaintext, null);
130 }
131
132 public static byte[] encrypt(ECPoint toPub, byte[] plaintext, byte[] macData) {
133
134 ECKeyPairGenerator eGen = new ECKeyPairGenerator();
135 SecureRandom random = new SecureRandom();
136 KeyGenerationParameters gParam = new ECKeyGenerationParameters(CURVE, random);
137
138 eGen.init(gParam);
139
140 byte[] iv = new byte[KEY_SIZE/8];
141 new SecureRandom().nextBytes(iv);
142
143 AsymmetricCipherKeyPair ephemPair = eGen.generateKeyPair();
144 BigInteger prv = ((ECPrivateKeyParameters)ephemPair.getPrivate()).getD();
145 ECPoint pub = ((ECPublicKeyParameters)ephemPair.getPublic()).getQ();
146 EthereumIESEngine iesEngine = makeIESEngine(true, toPub, prv, iv);
147
148
149 ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(CURVE, random);
150 ECKeyPairGenerator generator = new ECKeyPairGenerator();
151 generator.init(keygenParams);
152
153 ECKeyPairGenerator gen = new ECKeyPairGenerator();
154 gen.init(new ECKeyGenerationParameters(ECKey.CURVE, random));
155
156 byte[] cipher;
157 try {
158 cipher = iesEngine.processBlock(plaintext, 0, plaintext.length, macData);
159 ByteArrayOutputStream bos = new ByteArrayOutputStream();
160 bos.write(pub.getEncoded(false));
161 bos.write(iv);
162 bos.write(cipher);
163 return bos.toByteArray();
164 } catch (InvalidCipherTextException e) {
165 throw Throwables.propagate(e);
166 } catch (IOException e) {
167 throw Throwables.propagate(e);
168 }
169 }
170
171 private static EthereumIESEngine makeIESEngine(boolean isEncrypt, ECPoint pub, BigInteger prv, byte[] iv) {
172 AESEngine aesEngine = new AESEngine();
173
174 EthereumIESEngine iesEngine = new EthereumIESEngine(
175 new ECDHBasicAgreement(),
176 new ConcatKDFBytesGenerator(new SHA256Digest()),
177 new HMac(new SHA256Digest()),
178 new SHA256Digest(),
179 new BufferedBlockCipher(new SICBlockCipher(aesEngine)));
180
181
182 byte[] d = new byte[] {};
183 byte[] e = new byte[] {};
184
185 IESParameters p = new IESWithCipherParameters(d, e, KEY_SIZE, KEY_SIZE);
186 ParametersWithIV parametersWithIV = new ParametersWithIV(p, iv);
187
188 iesEngine.init(isEncrypt, new ECPrivateKeyParameters(prv, CURVE), new ECPublicKeyParameters(pub, CURVE), parametersWithIV);
189 return iesEngine;
190 }
191
192 public static int getOverhead() {
193 // 256 bit EC public key, IV, 256 bit MAC
194 return 65 + KEY_SIZE/8 + 32;
195 }
196 }