3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-12 10:15:52 +00:00

ECKey: preserve compression state when deserializing from ASN.1.

Resolves issue 528.
This commit is contained in:
Mike Hearn 2014-03-17 17:42:56 +01:00
parent f27558bcd2
commit e397928ec3
2 changed files with 20 additions and 7 deletions

View File

@ -143,7 +143,7 @@ public class ECKey implements Serializable {
* reference implementation in its wallet. Note that this is slow because it requires an EC point multiply.
*/
public static ECKey fromASN1(byte[] asn1privkey) {
return new ECKey(extractPrivateKeyFromASN1(asn1privkey));
return extractKeyFromASN1(asn1privkey);
}
/** Creates an ECKey given the private key only. The public key is calculated from it (this is slow) */
@ -559,7 +559,7 @@ public class ECKey implements Serializable {
return true;
}
private static BigInteger extractPrivateKeyFromASN1(byte[] asn1privkey) {
private static ECKey extractKeyFromASN1(byte[] asn1privkey) {
// To understand this code, see the definition of the ASN.1 format for EC private keys in the OpenSSL source
// code in ec_asn1.c:
//
@ -577,9 +577,18 @@ public class ECKey implements Serializable {
checkArgument(((DERInteger) seq.getObjectAt(0)).getValue().equals(BigInteger.ONE),
"Input is of wrong version");
Object obj = seq.getObjectAt(1);
byte[] bits = ((ASN1OctetString) obj).getOctets();
byte[] privbits = ((ASN1OctetString) obj).getOctets();
decoder.close();
return new BigInteger(1, bits);
BigInteger privkey = new BigInteger(1, privbits);
byte[] pubbits = ((DERBitString)((ASN1TaggedObject)seq.getObjectAt(3)).getObject()).getBytes();
// Now sanity check to ensure the pubkey bytes match the privkey.
byte[] compressed = publicKeyFromPrivate(privkey, true);
if (Arrays.equals(pubbits, compressed))
return new ECKey(privkey, compressed);
byte[] uncompressed = publicKeyFromPrivate(privkey, false);
if (Arrays.equals(pubbits, uncompressed))
return new ECKey(privkey, uncompressed);
throw new IllegalArgumentException("Public key in ASN.1 structure does not match private key.");
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen, reading from memory stream.
}

View File

@ -39,15 +39,14 @@ import org.slf4j.LoggerFactory;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.util.encoders.Hex;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static com.google.bitcoin.core.Utils.reverseBytes;
@ -171,6 +170,11 @@ public class ECKeyTest {
"11da3761e86431e4a54c176789e41f1651b324d240d599a7067bee23d328ec2a"));
assertTrue(roundtripKey.verify(message, decodedKey.sign(new Sha256Hash(message)).encodeToDER()));
assertTrue(decodedKey.verify(message, roundtripKey.sign(new Sha256Hash(message)).encodeToDER()));
// Verify bytewise equivalence of public keys (i.e. compression state is preserved)
ECKey key = new ECKey();
ECKey key2 = ECKey.fromASN1(key.toASN1());
assertArrayEquals(key.getPubKey(), key2.getPubKey());
}
@Test
@ -367,7 +371,7 @@ public class ECKeyTest {
public void keyRecoveryWithEncryptedKey() throws Exception {
ECKey unencryptedKey = new ECKey();
KeyParameter aesKey = keyCrypter.deriveKey(PASSWORD1);
ECKey encryptedKey = unencryptedKey.encrypt(keyCrypter,aesKey);
ECKey encryptedKey = unencryptedKey.encrypt(keyCrypter, aesKey);
String message = "Goodbye Jupiter!";
Sha256Hash hash = Sha256Hash.create(message.getBytes());