123 lines
4.6 KiB
Kotlin
123 lines
4.6 KiB
Kotlin
/*
|
|
* 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)
|
|
}
|
|
}
|