Migrated cryptography and some improvements
This commit is contained in:
		@@ -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
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.InternalContext
 | 
			
		||||
import ch.dissem.bitmessage.cryptography.sc.SpongyCryptography
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage
 | 
			
		||||
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.utils.CallbackWaiter
 | 
			
		||||
import ch.dissem.bitmessage.utils.Singleton
 | 
			
		||||
import ch.dissem.bitmessage.utils.TestUtils
 | 
			
		||||
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.MINUTE
 | 
			
		||||
import org.hamcrest.CoreMatchers.`is`
 | 
			
		||||
import org.junit.Assert.*
 | 
			
		||||
import org.mockito.Mockito.mock
 | 
			
		||||
import org.mockito.Mockito.`when`
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
import java.io.ByteArrayInputStream
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
import javax.xml.bind.DatatypeConverter
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Christian Basler
 | 
			
		||||
@@ -168,7 +162,7 @@ class CryptographyTest {
 | 
			
		||||
        val TEST_RIPEMD160 = DatatypeConverter.parseHexBinary(""
 | 
			
		||||
            + "cd566972b5e50104011a92b59fa8e0b1234851ae")
 | 
			
		||||
 | 
			
		||||
        private val crypto = SpongyCryptography()
 | 
			
		||||
        private val crypto = SpongyCryptography
 | 
			
		||||
 | 
			
		||||
        init {
 | 
			
		||||
            Singleton.initialize(crypto)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user