Migrated cryptography and some improvements
This commit is contained in:
parent
83e50e1ad1
commit
1d3340a547
@ -84,7 +84,7 @@ BitmessageContext ctx = new BitmessageContext.Builder()
|
|||||||
.powRepo(new JdbcProofOfWorkRepository(jdbcConfig))
|
.powRepo(new JdbcProofOfWorkRepository(jdbcConfig))
|
||||||
.nodeRegistry(new JdbcNodeRegistry(jdbcConfig))
|
.nodeRegistry(new JdbcNodeRegistry(jdbcConfig))
|
||||||
.networkHandler(new NioNetworkHandler())
|
.networkHandler(new NioNetworkHandler())
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.listener(System.out::println)
|
.listener(System.out::println)
|
||||||
.build();
|
.build();
|
||||||
```
|
```
|
||||||
|
@ -311,7 +311,6 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
LOG.debug(e.message, e)
|
LOG.debug(e.message, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,6 +409,15 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun listener(listener: (Plaintext) -> Unit): Builder {
|
||||||
|
this.listener = object : Listener {
|
||||||
|
override fun receive(plaintext: Plaintext) {
|
||||||
|
listener.invoke(plaintext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun connectionLimit(connectionLimit: Int): Builder {
|
fun connectionLimit(connectionLimit: Int): Builder {
|
||||||
this.connectionLimit = connectionLimit
|
this.connectionLimit = connectionLimit
|
||||||
return this
|
return this
|
||||||
|
@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Christian Basler
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ch.dissem.bitmessage.cryptography.bc;
|
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
|
||||||
import ch.dissem.bitmessage.exception.ApplicationException;
|
|
||||||
import ch.dissem.bitmessage.ports.AbstractCryptography;
|
|
||||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
|
||||||
import org.bouncycastle.crypto.BufferedBlockCipher;
|
|
||||||
import org.bouncycastle.crypto.CipherParameters;
|
|
||||||
import org.bouncycastle.crypto.InvalidCipherTextException;
|
|
||||||
import org.bouncycastle.crypto.ec.CustomNamedCurves;
|
|
||||||
import org.bouncycastle.crypto.engines.AESEngine;
|
|
||||||
import org.bouncycastle.crypto.modes.CBCBlockCipher;
|
|
||||||
import org.bouncycastle.crypto.paddings.PKCS7Padding;
|
|
||||||
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
|
|
||||||
import org.bouncycastle.crypto.params.KeyParameter;
|
|
||||||
import org.bouncycastle.crypto.params.ParametersWithIV;
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
|
||||||
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
|
|
||||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
|
||||||
import org.bouncycastle.math.ec.ECPoint;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.*;
|
|
||||||
import java.security.spec.KeySpec;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* As Spongycastle can't be used on the Oracle JVM, and Bouncycastle doesn't work properly on Android (thanks, Google),
|
|
||||||
* this is the Bouncycastle implementation.
|
|
||||||
*/
|
|
||||||
public class BouncyCryptography extends AbstractCryptography {
|
|
||||||
private static final X9ECParameters EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1");
|
|
||||||
|
|
||||||
public BouncyCryptography() {
|
|
||||||
super(new BouncyCastleProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] crypt(boolean encrypt, byte[] data, byte[] key_e, byte[] initializationVector) {
|
|
||||||
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
|
|
||||||
new CBCBlockCipher(new AESEngine()),
|
|
||||||
new PKCS7Padding()
|
|
||||||
);
|
|
||||||
CipherParameters params = new ParametersWithIV(new KeyParameter(key_e), initializationVector);
|
|
||||||
|
|
||||||
cipher.init(encrypt, params);
|
|
||||||
|
|
||||||
byte[] buffer = new byte[cipher.getOutputSize(data.length)];
|
|
||||||
int length = cipher.processBytes(data, 0, data.length, buffer, 0);
|
|
||||||
try {
|
|
||||||
length += cipher.doFinal(buffer, length);
|
|
||||||
} catch (InvalidCipherTextException e) {
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
if (length < buffer.length) {
|
|
||||||
return Arrays.copyOfRange(buffer, 0, length);
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] createPublicKey(byte[] privateKey) {
|
|
||||||
return EC_CURVE_PARAMETERS.getG().multiply(keyToBigInt(privateKey)).normalize().getEncoded(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ECPoint keyToPoint(byte[] publicKey) {
|
|
||||||
BigInteger x = new BigInteger(1, Arrays.copyOfRange(publicKey, 1, 33));
|
|
||||||
BigInteger y = new BigInteger(1, Arrays.copyOfRange(publicKey, 33, 65));
|
|
||||||
return EC_CURVE_PARAMETERS.getCurve().createPoint(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSignatureValid(byte[] data, byte[] signature, Pubkey pubkey) {
|
|
||||||
try {
|
|
||||||
ECParameterSpec spec = new ECParameterSpec(
|
|
||||||
EC_CURVE_PARAMETERS.getCurve(),
|
|
||||||
EC_CURVE_PARAMETERS.getG(),
|
|
||||||
EC_CURVE_PARAMETERS.getN(),
|
|
||||||
EC_CURVE_PARAMETERS.getH(),
|
|
||||||
EC_CURVE_PARAMETERS.getSeed()
|
|
||||||
);
|
|
||||||
|
|
||||||
ECPoint Q = keyToPoint(pubkey.getSigningKey());
|
|
||||||
KeySpec keySpec = new ECPublicKeySpec(Q, spec);
|
|
||||||
PublicKey publicKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider).generatePublic(keySpec);
|
|
||||||
|
|
||||||
return doCheckSignature(data, signature, publicKey);
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
throw new ApplicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getSignature(byte[] data, PrivateKey privateKey) {
|
|
||||||
try {
|
|
||||||
ECParameterSpec spec = new ECParameterSpec(
|
|
||||||
EC_CURVE_PARAMETERS.getCurve(),
|
|
||||||
EC_CURVE_PARAMETERS.getG(),
|
|
||||||
EC_CURVE_PARAMETERS.getN(),
|
|
||||||
EC_CURVE_PARAMETERS.getH(),
|
|
||||||
EC_CURVE_PARAMETERS.getSeed()
|
|
||||||
);
|
|
||||||
|
|
||||||
BigInteger d = keyToBigInt(privateKey.getPrivateSigningKey());
|
|
||||||
KeySpec keySpec = new ECPrivateKeySpec(d, spec);
|
|
||||||
java.security.PrivateKey privKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider)
|
|
||||||
.generatePrivate(keySpec);
|
|
||||||
|
|
||||||
return doSign(data, privKey);
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
throw new ApplicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] multiply(byte[] K, byte[] r) {
|
|
||||||
return keyToPoint(K).multiply(keyToBigInt(r)).normalize().getEncoded(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] createPoint(byte[] x, byte[] y) {
|
|
||||||
return EC_CURVE_PARAMETERS.getCurve().createPoint(
|
|
||||||
new BigInteger(1, x),
|
|
||||||
new BigInteger(1, y)
|
|
||||||
).getEncoded(false);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Christian Basler
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.dissem.bitmessage.cryptography.bc
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Pubkey
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey
|
||||||
|
import ch.dissem.bitmessage.ports.AbstractCryptography
|
||||||
|
import org.bouncycastle.crypto.InvalidCipherTextException
|
||||||
|
import org.bouncycastle.crypto.ec.CustomNamedCurves
|
||||||
|
import org.bouncycastle.crypto.engines.AESEngine
|
||||||
|
import org.bouncycastle.crypto.modes.CBCBlockCipher
|
||||||
|
import org.bouncycastle.crypto.paddings.PKCS7Padding
|
||||||
|
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher
|
||||||
|
import org.bouncycastle.crypto.params.KeyParameter
|
||||||
|
import org.bouncycastle.crypto.params.ParametersWithIV
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec
|
||||||
|
import org.bouncycastle.jce.spec.ECPrivateKeySpec
|
||||||
|
import org.bouncycastle.jce.spec.ECPublicKeySpec
|
||||||
|
import org.bouncycastle.math.ec.ECPoint
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.security.KeyFactory
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As Spongycastle can't be used on the Oracle JVM, and Bouncycastle doesn't work properly on Android (thanks, Google),
|
||||||
|
* this is the Bouncycastle implementation.
|
||||||
|
*/
|
||||||
|
object BouncyCryptography : AbstractCryptography(BouncyCastleProvider()) {
|
||||||
|
private val EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1")
|
||||||
|
|
||||||
|
override fun crypt(encrypt: Boolean, data: ByteArray, key_e: ByteArray, initializationVector: ByteArray): ByteArray {
|
||||||
|
val cipher = PaddedBufferedBlockCipher(
|
||||||
|
CBCBlockCipher(AESEngine()),
|
||||||
|
PKCS7Padding()
|
||||||
|
)
|
||||||
|
val params = ParametersWithIV(KeyParameter(key_e), initializationVector)
|
||||||
|
|
||||||
|
cipher.init(encrypt, params)
|
||||||
|
|
||||||
|
val buffer = ByteArray(cipher.getOutputSize(data.size))
|
||||||
|
var length = cipher.processBytes(data, 0, data.size, buffer, 0)
|
||||||
|
try {
|
||||||
|
length += cipher.doFinal(buffer, length)
|
||||||
|
} catch (e: InvalidCipherTextException) {
|
||||||
|
throw IllegalArgumentException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < buffer.size) {
|
||||||
|
return Arrays.copyOfRange(buffer, 0, length)
|
||||||
|
}
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createPublicKey(privateKey: ByteArray): ByteArray {
|
||||||
|
return EC_CURVE_PARAMETERS.g.multiply(keyToBigInt(privateKey)).normalize().getEncoded(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun keyToPoint(publicKey: ByteArray): ECPoint {
|
||||||
|
val x = BigInteger(1, Arrays.copyOfRange(publicKey, 1, 33))
|
||||||
|
val y = BigInteger(1, Arrays.copyOfRange(publicKey, 33, 65))
|
||||||
|
return EC_CURVE_PARAMETERS.curve.createPoint(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSignatureValid(data: ByteArray, signature: ByteArray, pubkey: Pubkey): Boolean {
|
||||||
|
val spec = ECParameterSpec(
|
||||||
|
EC_CURVE_PARAMETERS.curve,
|
||||||
|
EC_CURVE_PARAMETERS.g,
|
||||||
|
EC_CURVE_PARAMETERS.n,
|
||||||
|
EC_CURVE_PARAMETERS.h,
|
||||||
|
EC_CURVE_PARAMETERS.seed
|
||||||
|
)
|
||||||
|
|
||||||
|
val Q = keyToPoint(pubkey.signingKey)
|
||||||
|
val keySpec = ECPublicKeySpec(Q, spec)
|
||||||
|
val publicKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider).generatePublic(keySpec)
|
||||||
|
|
||||||
|
return doCheckSignature(data, signature, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSignature(data: ByteArray, privateKey: PrivateKey): ByteArray {
|
||||||
|
val spec = ECParameterSpec(
|
||||||
|
EC_CURVE_PARAMETERS.curve,
|
||||||
|
EC_CURVE_PARAMETERS.g,
|
||||||
|
EC_CURVE_PARAMETERS.n,
|
||||||
|
EC_CURVE_PARAMETERS.h,
|
||||||
|
EC_CURVE_PARAMETERS.seed
|
||||||
|
)
|
||||||
|
|
||||||
|
val d = keyToBigInt(privateKey.privateSigningKey)
|
||||||
|
val keySpec = ECPrivateKeySpec(d, spec)
|
||||||
|
val privKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider)
|
||||||
|
.generatePrivate(keySpec)
|
||||||
|
|
||||||
|
return doSign(data, privKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun multiply(k: ByteArray, r: ByteArray): ByteArray {
|
||||||
|
return keyToPoint(k).multiply(keyToBigInt(r)).normalize().getEncoded(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createPoint(x: ByteArray, y: ByteArray): ByteArray {
|
||||||
|
return EC_CURVE_PARAMETERS.curve.createPoint(
|
||||||
|
BigInteger(1, x),
|
||||||
|
BigInteger(1, y)
|
||||||
|
).getEncoded(false)
|
||||||
|
}
|
||||||
|
}
|
@ -163,7 +163,7 @@ class CryptographyTest {
|
|||||||
val TEST_RIPEMD160 = DatatypeConverter.parseHexBinary(""
|
val TEST_RIPEMD160 = DatatypeConverter.parseHexBinary(""
|
||||||
+ "cd566972b5e50104011a92b59fa8e0b1234851ae")
|
+ "cd566972b5e50104011a92b59fa8e0b1234851ae")
|
||||||
|
|
||||||
private val crypto = BouncyCryptography()
|
private val crypto = BouncyCryptography
|
||||||
|
|
||||||
init {
|
init {
|
||||||
Singleton.initialize(crypto)
|
Singleton.initialize(crypto)
|
||||||
|
@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Christian Basler
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ch.dissem.bitmessage.cryptography.sc;
|
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
|
||||||
import ch.dissem.bitmessage.exception.ApplicationException;
|
|
||||||
import ch.dissem.bitmessage.ports.AbstractCryptography;
|
|
||||||
import org.spongycastle.asn1.x9.X9ECParameters;
|
|
||||||
import org.spongycastle.crypto.BufferedBlockCipher;
|
|
||||||
import org.spongycastle.crypto.CipherParameters;
|
|
||||||
import org.spongycastle.crypto.InvalidCipherTextException;
|
|
||||||
import org.spongycastle.crypto.ec.CustomNamedCurves;
|
|
||||||
import org.spongycastle.crypto.engines.AESEngine;
|
|
||||||
import org.spongycastle.crypto.modes.CBCBlockCipher;
|
|
||||||
import org.spongycastle.crypto.paddings.PKCS7Padding;
|
|
||||||
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
|
|
||||||
import org.spongycastle.crypto.params.KeyParameter;
|
|
||||||
import org.spongycastle.crypto.params.ParametersWithIV;
|
|
||||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
import org.spongycastle.jce.spec.ECParameterSpec;
|
|
||||||
import org.spongycastle.jce.spec.ECPrivateKeySpec;
|
|
||||||
import org.spongycastle.jce.spec.ECPublicKeySpec;
|
|
||||||
import org.spongycastle.math.ec.ECPoint;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.spec.KeySpec;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* As Spongycastle can't be used on the Oracle JVM, and Bouncycastle doesn't work properly on Android (thanks, Google),
|
|
||||||
* this is the Spongycastle implementation.
|
|
||||||
*/
|
|
||||||
public class SpongyCryptography extends AbstractCryptography {
|
|
||||||
private static final X9ECParameters EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1");
|
|
||||||
|
|
||||||
public SpongyCryptography() {
|
|
||||||
super(new BouncyCastleProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] crypt(boolean encrypt, byte[] data, byte[] key_e, byte[] initializationVector) {
|
|
||||||
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
|
|
||||||
new CBCBlockCipher(new AESEngine()),
|
|
||||||
new PKCS7Padding()
|
|
||||||
);
|
|
||||||
CipherParameters params = new ParametersWithIV(new KeyParameter(key_e), initializationVector);
|
|
||||||
|
|
||||||
cipher.init(encrypt, params);
|
|
||||||
|
|
||||||
byte[] buffer = new byte[cipher.getOutputSize(data.length)];
|
|
||||||
int length = cipher.processBytes(data, 0, data.length, buffer, 0);
|
|
||||||
try {
|
|
||||||
length += cipher.doFinal(buffer, length);
|
|
||||||
} catch (InvalidCipherTextException e) {
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
if (length < buffer.length) {
|
|
||||||
return Arrays.copyOfRange(buffer, 0, length);
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] createPublicKey(byte[] privateKey) {
|
|
||||||
return EC_CURVE_PARAMETERS.getG().multiply(keyToBigInt(privateKey)).normalize().getEncoded(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ECPoint keyToPoint(byte[] publicKey) {
|
|
||||||
BigInteger x = new BigInteger(1, Arrays.copyOfRange(publicKey, 1, 33));
|
|
||||||
BigInteger y = new BigInteger(1, Arrays.copyOfRange(publicKey, 33, 65));
|
|
||||||
return EC_CURVE_PARAMETERS.getCurve().createPoint(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSignatureValid(byte[] data, byte[] signature, Pubkey pubkey) {
|
|
||||||
try {
|
|
||||||
ECParameterSpec spec = new ECParameterSpec(
|
|
||||||
EC_CURVE_PARAMETERS.getCurve(),
|
|
||||||
EC_CURVE_PARAMETERS.getG(),
|
|
||||||
EC_CURVE_PARAMETERS.getN(),
|
|
||||||
EC_CURVE_PARAMETERS.getH(),
|
|
||||||
EC_CURVE_PARAMETERS.getSeed()
|
|
||||||
);
|
|
||||||
|
|
||||||
ECPoint Q = keyToPoint(pubkey.getSigningKey());
|
|
||||||
KeySpec keySpec = new ECPublicKeySpec(Q, spec);
|
|
||||||
PublicKey publicKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider).generatePublic(keySpec);
|
|
||||||
|
|
||||||
return doCheckSignature(data, signature, publicKey);
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
throw new ApplicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getSignature(byte[] data, PrivateKey privateKey) {
|
|
||||||
try {
|
|
||||||
ECParameterSpec spec = new ECParameterSpec(
|
|
||||||
EC_CURVE_PARAMETERS.getCurve(),
|
|
||||||
EC_CURVE_PARAMETERS.getG(),
|
|
||||||
EC_CURVE_PARAMETERS.getN(),
|
|
||||||
EC_CURVE_PARAMETERS.getH(),
|
|
||||||
EC_CURVE_PARAMETERS.getSeed()
|
|
||||||
);
|
|
||||||
|
|
||||||
BigInteger d = keyToBigInt(privateKey.getPrivateSigningKey());
|
|
||||||
KeySpec keySpec = new ECPrivateKeySpec(d, spec);
|
|
||||||
java.security.PrivateKey privKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider)
|
|
||||||
.generatePrivate(keySpec);
|
|
||||||
|
|
||||||
return doSign(data, privKey);
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
throw new ApplicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] multiply(byte[] K, byte[] r) {
|
|
||||||
return keyToPoint(K).multiply(keyToBigInt(r)).normalize().getEncoded(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] createPoint(byte[] x, byte[] y) {
|
|
||||||
return EC_CURVE_PARAMETERS.getCurve().createPoint(
|
|
||||||
new BigInteger(1, x),
|
|
||||||
new BigInteger(1, y)
|
|
||||||
).getEncoded(false);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Christian Basler
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.dissem.bitmessage.cryptography.sc
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Pubkey
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey
|
||||||
|
import ch.dissem.bitmessage.ports.AbstractCryptography
|
||||||
|
import org.spongycastle.crypto.InvalidCipherTextException
|
||||||
|
import org.spongycastle.crypto.ec.CustomNamedCurves
|
||||||
|
import org.spongycastle.crypto.engines.AESEngine
|
||||||
|
import org.spongycastle.crypto.modes.CBCBlockCipher
|
||||||
|
import org.spongycastle.crypto.paddings.PKCS7Padding
|
||||||
|
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher
|
||||||
|
import org.spongycastle.crypto.params.KeyParameter
|
||||||
|
import org.spongycastle.crypto.params.ParametersWithIV
|
||||||
|
import org.spongycastle.jce.provider.BouncyCastleProvider
|
||||||
|
import org.spongycastle.jce.spec.ECParameterSpec
|
||||||
|
import org.spongycastle.jce.spec.ECPrivateKeySpec
|
||||||
|
import org.spongycastle.jce.spec.ECPublicKeySpec
|
||||||
|
import org.spongycastle.math.ec.ECPoint
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.security.KeyFactory
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As Spongycastle can't be used on the Oracle JVM, and Bouncycastle doesn't work properly on Android (thanks, Google),
|
||||||
|
* this is the Spongycastle implementation.
|
||||||
|
*/
|
||||||
|
object SpongyCryptography : AbstractCryptography(BouncyCastleProvider()) {
|
||||||
|
private val EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1")
|
||||||
|
|
||||||
|
override fun crypt(encrypt: Boolean, data: ByteArray, key_e: ByteArray, initializationVector: ByteArray): ByteArray {
|
||||||
|
val cipher = PaddedBufferedBlockCipher(
|
||||||
|
CBCBlockCipher(AESEngine()),
|
||||||
|
PKCS7Padding()
|
||||||
|
)
|
||||||
|
val params = ParametersWithIV(KeyParameter(key_e), initializationVector)
|
||||||
|
|
||||||
|
cipher.init(encrypt, params)
|
||||||
|
|
||||||
|
val buffer = ByteArray(cipher.getOutputSize(data.size))
|
||||||
|
var length = cipher.processBytes(data, 0, data.size, buffer, 0)
|
||||||
|
try {
|
||||||
|
length += cipher.doFinal(buffer, length)
|
||||||
|
} catch (e: InvalidCipherTextException) {
|
||||||
|
throw IllegalArgumentException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < buffer.size) {
|
||||||
|
return Arrays.copyOfRange(buffer, 0, length)
|
||||||
|
}
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createPublicKey(privateKey: ByteArray): ByteArray {
|
||||||
|
return EC_CURVE_PARAMETERS.g.multiply(keyToBigInt(privateKey)).normalize().getEncoded(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun keyToPoint(publicKey: ByteArray): ECPoint {
|
||||||
|
val x = BigInteger(1, Arrays.copyOfRange(publicKey, 1, 33))
|
||||||
|
val y = BigInteger(1, Arrays.copyOfRange(publicKey, 33, 65))
|
||||||
|
return EC_CURVE_PARAMETERS.curve.createPoint(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSignatureValid(data: ByteArray, signature: ByteArray, pubkey: Pubkey): Boolean {
|
||||||
|
val spec = ECParameterSpec(
|
||||||
|
EC_CURVE_PARAMETERS.curve,
|
||||||
|
EC_CURVE_PARAMETERS.g,
|
||||||
|
EC_CURVE_PARAMETERS.n,
|
||||||
|
EC_CURVE_PARAMETERS.h,
|
||||||
|
EC_CURVE_PARAMETERS.seed
|
||||||
|
)
|
||||||
|
|
||||||
|
val Q = keyToPoint(pubkey.signingKey)
|
||||||
|
val keySpec = ECPublicKeySpec(Q, spec)
|
||||||
|
val publicKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider).generatePublic(keySpec)
|
||||||
|
|
||||||
|
return doCheckSignature(data, signature, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSignature(data: ByteArray, privateKey: PrivateKey): ByteArray {
|
||||||
|
val spec = ECParameterSpec(
|
||||||
|
EC_CURVE_PARAMETERS.curve,
|
||||||
|
EC_CURVE_PARAMETERS.g,
|
||||||
|
EC_CURVE_PARAMETERS.n,
|
||||||
|
EC_CURVE_PARAMETERS.h,
|
||||||
|
EC_CURVE_PARAMETERS.seed
|
||||||
|
)
|
||||||
|
|
||||||
|
val d = keyToBigInt(privateKey.privateSigningKey)
|
||||||
|
val keySpec = ECPrivateKeySpec(d, spec)
|
||||||
|
val privKey = KeyFactory.getInstance(ALGORITHM_ECDSA, provider)
|
||||||
|
.generatePrivate(keySpec)
|
||||||
|
|
||||||
|
return doSign(data, privKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun multiply(k: ByteArray, r: ByteArray): ByteArray {
|
||||||
|
return keyToPoint(k).multiply(keyToBigInt(r)).normalize().getEncoded(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createPoint(x: ByteArray, y: ByteArray): ByteArray {
|
||||||
|
return EC_CURVE_PARAMETERS.curve.createPoint(
|
||||||
|
BigInteger(1, x),
|
||||||
|
BigInteger(1, y)
|
||||||
|
).getEncoded(false)
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.security
|
package ch.dissem.bitmessage.security
|
||||||
|
|
||||||
import ch.dissem.bitmessage.InternalContext
|
|
||||||
import ch.dissem.bitmessage.cryptography.sc.SpongyCryptography
|
import ch.dissem.bitmessage.cryptography.sc.SpongyCryptography
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage
|
import ch.dissem.bitmessage.entity.ObjectMessage
|
||||||
import ch.dissem.bitmessage.entity.payload.GenericPayload
|
import ch.dissem.bitmessage.entity.payload.GenericPayload
|
||||||
@ -26,21 +25,16 @@ import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine
|
|||||||
import ch.dissem.bitmessage.ports.ProofOfWorkEngine
|
import ch.dissem.bitmessage.ports.ProofOfWorkEngine
|
||||||
import ch.dissem.bitmessage.utils.CallbackWaiter
|
import ch.dissem.bitmessage.utils.CallbackWaiter
|
||||||
import ch.dissem.bitmessage.utils.Singleton
|
import ch.dissem.bitmessage.utils.Singleton
|
||||||
|
import ch.dissem.bitmessage.utils.TestUtils
|
||||||
import ch.dissem.bitmessage.utils.UnixTime
|
import ch.dissem.bitmessage.utils.UnixTime
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.BeforeClass
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
import ch.dissem.bitmessage.utils.UnixTime.DAY
|
import ch.dissem.bitmessage.utils.UnixTime.DAY
|
||||||
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
|
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
|
||||||
import org.hamcrest.CoreMatchers.`is`
|
import org.hamcrest.CoreMatchers.`is`
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.*
|
||||||
import org.mockito.Mockito.mock
|
import org.junit.Test
|
||||||
import org.mockito.Mockito.`when`
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import javax.xml.bind.DatatypeConverter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christian Basler
|
* @author Christian Basler
|
||||||
@ -168,7 +162,7 @@ class CryptographyTest {
|
|||||||
val TEST_RIPEMD160 = DatatypeConverter.parseHexBinary(""
|
val TEST_RIPEMD160 = DatatypeConverter.parseHexBinary(""
|
||||||
+ "cd566972b5e50104011a92b59fa8e0b1234851ae")
|
+ "cd566972b5e50104011a92b59fa8e0b1234851ae")
|
||||||
|
|
||||||
private val crypto = SpongyCryptography()
|
private val crypto = SpongyCryptography
|
||||||
|
|
||||||
init {
|
init {
|
||||||
Singleton.initialize(crypto)
|
Singleton.initialize(crypto)
|
||||||
|
@ -61,7 +61,7 @@ public class Main {
|
|||||||
.messageRepo(new JdbcMessageRepository(jdbcConfig))
|
.messageRepo(new JdbcMessageRepository(jdbcConfig))
|
||||||
.powRepo(new JdbcProofOfWorkRepository(jdbcConfig))
|
.powRepo(new JdbcProofOfWorkRepository(jdbcConfig))
|
||||||
.networkHandler(new NioNetworkHandler())
|
.networkHandler(new NioNetworkHandler())
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.port(48444);
|
.port(48444);
|
||||||
if (options.localPort != null) {
|
if (options.localPort != null) {
|
||||||
ctxBuilder.nodeRegistry(new NodeRegistry() {
|
ctxBuilder.nodeRegistry(new NodeRegistry() {
|
||||||
|
@ -94,7 +94,7 @@ public class SystemTest {
|
|||||||
.port(alicePort)
|
.port(alicePort)
|
||||||
.nodeRegistry(new TestNodeRegistry(bobPort))
|
.nodeRegistry(new TestNodeRegistry(bobPort))
|
||||||
.networkHandler(aliceNetworkHandler)
|
.networkHandler(aliceNetworkHandler)
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.listener(aliceListener)
|
.listener(aliceListener)
|
||||||
.labeler(aliceLabeler)
|
.labeler(aliceLabeler)
|
||||||
.build();
|
.build();
|
||||||
@ -110,7 +110,7 @@ public class SystemTest {
|
|||||||
.port(bobPort)
|
.port(bobPort)
|
||||||
.nodeRegistry(new TestNodeRegistry(alicePort))
|
.nodeRegistry(new TestNodeRegistry(alicePort))
|
||||||
.networkHandler(bobNetworkHandler)
|
.networkHandler(bobNetworkHandler)
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.listener(bobListener)
|
.listener(bobListener)
|
||||||
.labeler(new DebugLabeler("Bob"))
|
.labeler(new DebugLabeler("Bob"))
|
||||||
.build();
|
.build();
|
||||||
|
@ -98,7 +98,7 @@ public class NetworkHandlerTest {
|
|||||||
.port(peerAddress.getPort())
|
.port(peerAddress.getPort())
|
||||||
.nodeRegistry(new TestNodeRegistry())
|
.nodeRegistry(new TestNodeRegistry())
|
||||||
.networkHandler(peerNetworkHandler)
|
.networkHandler(peerNetworkHandler)
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.listener(mock(BitmessageContext.Listener.class))
|
.listener(mock(BitmessageContext.Listener.class))
|
||||||
.customCommandHandler(new CustomCommandHandler() {
|
.customCommandHandler(new CustomCommandHandler() {
|
||||||
@Override
|
@Override
|
||||||
@ -133,7 +133,7 @@ public class NetworkHandlerTest {
|
|||||||
.port(6002)
|
.port(6002)
|
||||||
.nodeRegistry(new TestNodeRegistry(peerAddress))
|
.nodeRegistry(new TestNodeRegistry(peerAddress))
|
||||||
.networkHandler(nodeNetworkHandler)
|
.networkHandler(nodeNetworkHandler)
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.listener(mock(BitmessageContext.Listener.class))
|
.listener(mock(BitmessageContext.Listener.class))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public class WifExporterTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
ctx = new BitmessageContext.Builder()
|
ctx = new BitmessageContext.Builder()
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.networkHandler(mock(NetworkHandler.class))
|
.networkHandler(mock(NetworkHandler.class))
|
||||||
.inventory(mock(Inventory.class))
|
.inventory(mock(Inventory.class))
|
||||||
.messageRepo(mock(MessageRepository.class))
|
.messageRepo(mock(MessageRepository.class))
|
||||||
@ -104,4 +104,4 @@ public class WifExporterTest {
|
|||||||
exporter.addIdentity(chan);
|
exporter.addIdentity(chan);
|
||||||
assertEquals(expected, exporter.toString());
|
assertEquals(expected, exporter.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public class WifImporterTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
ctx = new BitmessageContext.Builder()
|
ctx = new BitmessageContext.Builder()
|
||||||
.cryptography(new BouncyCryptography())
|
.cryptography(BouncyCryptography.INSTANCE)
|
||||||
.networkHandler(mock(NetworkHandler.class))
|
.networkHandler(mock(NetworkHandler.class))
|
||||||
.inventory(mock(Inventory.class))
|
.inventory(mock(Inventory.class))
|
||||||
.messageRepo(mock(MessageRepository.class))
|
.messageRepo(mock(MessageRepository.class))
|
||||||
@ -113,4 +113,4 @@ public class WifImporterTest {
|
|||||||
BitmessageAddress chan = importer.getIdentities().get(0);
|
BitmessageAddress chan = importer.getIdentities().get(0);
|
||||||
assertTrue(chan.isChan());
|
assertTrue(chan.isChan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user