mirror of
https://github.com/fluencelabs/crypto
synced 2025-04-24 14:22:18 +00:00
Crypto api changes (#102)
* remove pubKey from Signature, change crypto api * refactoring dependent modules
This commit is contained in:
parent
69d3eb50c1
commit
994194b31f
@ -17,8 +17,8 @@
|
||||
|
||||
package fluence.crypto.algorithm
|
||||
|
||||
import cats.data.EitherT
|
||||
import cats.Monad
|
||||
import cats.data.EitherT
|
||||
import fluence.crypto.SignAlgo
|
||||
import fluence.crypto.facade.ecdsa.EC
|
||||
import fluence.crypto.hash.{CryptoHasher, JsCryptoHasher}
|
||||
@ -58,7 +58,7 @@ class Ecdsa(ec: EC, hasher: Option[CryptoHasher[Array[Byte], Array[Byte]]])
|
||||
}("Cannot get private key from key pair.")
|
||||
hash ← hash(message)
|
||||
signHex ← nonFatalHandling(secret.sign(new Uint8Array(hash)).toDER("hex"))("Cannot sign message")
|
||||
} yield Signature(keyPair.publicKey, ByteVector.fromValidHex(signHex))
|
||||
} yield Signature(ByteVector.fromValidHex(signHex))
|
||||
}
|
||||
|
||||
def hash[F[_]: Monad](message: ByteVector): EitherT[F, CryptoErr, js.Array[Byte]] = {
|
||||
@ -72,10 +72,14 @@ class Ecdsa(ec: EC, hasher: Option[CryptoHasher[Array[Byte], Array[Byte]]])
|
||||
.map(_.toJSArray)
|
||||
}
|
||||
|
||||
override def verify[F[_]: Monad](signature: Signature, message: ByteVector): EitherT[F, CryptoErr, Unit] = {
|
||||
override def verify[F[_]: Monad](
|
||||
pubKey: KeyPair.Public,
|
||||
signature: Signature,
|
||||
message: ByteVector
|
||||
): EitherT[F, CryptoErr, Unit] = {
|
||||
for {
|
||||
public ← nonFatalHandling {
|
||||
val hex = signature.publicKey.value.toHex
|
||||
val hex = pubKey.value.toHex
|
||||
ec.keyFromPublic(hex, "hex")
|
||||
}("Incorrect public key format.")
|
||||
hash ← hash(message)
|
||||
|
@ -21,6 +21,7 @@ import cats.data.EitherT
|
||||
import cats.instances.try_._
|
||||
import fluence.crypto.algorithm.{CryptoErr, Ecdsa}
|
||||
import fluence.crypto.keypair.KeyPair
|
||||
import fluence.crypto.signature.Signature
|
||||
import org.scalatest.{Matchers, WordSpec}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
@ -48,17 +49,18 @@ class EcdsaSpec extends WordSpec with Matchers {
|
||||
val algorithm = Ecdsa.ecdsa_secp256k1_sha256
|
||||
|
||||
val keys = algorithm.generateKeyPair[Try]().extract
|
||||
val pubKey = keys.publicKey
|
||||
val data = rndByteVector(10)
|
||||
val sign = algorithm.sign[Try](keys, data).extract
|
||||
|
||||
algorithm.verify[Try](sign, data).isOk shouldBe true
|
||||
algorithm.verify[Try](pubKey, sign, data).isOk shouldBe true
|
||||
|
||||
val randomData = rndByteVector(10)
|
||||
val randomSign = algorithm.sign(keys, randomData).extract
|
||||
|
||||
algorithm.verify(sign.copy(sign = randomSign.sign), data).isOk shouldBe false
|
||||
algorithm.verify(pubKey, randomSign, data).isOk shouldBe false
|
||||
|
||||
algorithm.verify(sign, randomData).isOk shouldBe false
|
||||
algorithm.verify(pubKey, sign, randomData).isOk shouldBe false
|
||||
}
|
||||
|
||||
"correctly work with signer and checker" in {
|
||||
@ -70,10 +72,10 @@ class EcdsaSpec extends WordSpec with Matchers {
|
||||
val data = rndByteVector(10)
|
||||
val sign = signer.sign(data).extract
|
||||
|
||||
checker.check(sign.sign, data).isOk shouldBe true
|
||||
checker.check(sign, data).isOk shouldBe true
|
||||
|
||||
val randomSign = signer.sign(rndByteVector(10)).extract
|
||||
checker.check(randomSign.sign, data).isOk shouldBe false
|
||||
checker.check(randomSign, data).isOk shouldBe false
|
||||
}
|
||||
|
||||
"throw an errors on invalid data" in {
|
||||
@ -85,10 +87,10 @@ class EcdsaSpec extends WordSpec with Matchers {
|
||||
|
||||
val sign = signer.sign(data).extract
|
||||
|
||||
the[CryptoErr] thrownBy checker.check(rndByteVector(10), data).value.flatMap(_.toTry).get
|
||||
the[CryptoErr] thrownBy checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get
|
||||
val invalidChecker = algo.checker(KeyPair.fromByteVectors(rndByteVector(10), rndByteVector(10)).publicKey)
|
||||
the[CryptoErr] thrownBy invalidChecker
|
||||
.check(sign.sign, data)
|
||||
.check(sign, data)
|
||||
.value
|
||||
.flatMap(_.toTry)
|
||||
.get
|
||||
|
@ -72,14 +72,15 @@ class Ecdsa(curveType: String, scheme: String, hasher: Option[CryptoHasher[Array
|
||||
message: ByteVector
|
||||
): EitherT[F, CryptoErr, fluence.crypto.signature.Signature] = {
|
||||
signMessage(new BigInteger(keyPair.secretKey.value.toHex, HEXradix), message.toArray)
|
||||
.map(bb ⇒ fluence.crypto.signature.Signature(keyPair.publicKey, ByteVector(bb)))
|
||||
.map(bb ⇒ fluence.crypto.signature.Signature(ByteVector(bb)))
|
||||
}
|
||||
|
||||
override def verify[F[_]: Monad](
|
||||
publicKey: KeyPair.Public,
|
||||
signature: fluence.crypto.signature.Signature,
|
||||
message: ByteVector
|
||||
): EitherT[F, CryptoErr, Unit] = {
|
||||
verifySign(signature.publicKey.value.toArray, message.toArray, signature.sign.toArray)
|
||||
verifySign(publicKey.bytes, signature.bytes, message.toArray)
|
||||
}
|
||||
|
||||
private def signMessage[F[_]: Monad](
|
||||
@ -103,8 +104,8 @@ class Ecdsa(curveType: String, scheme: String, hasher: Option[CryptoHasher[Array
|
||||
|
||||
private def verifySign[F[_]: Monad](
|
||||
publicKey: Array[Byte],
|
||||
signature: Array[Byte],
|
||||
message: Array[Byte],
|
||||
signature: Array[Byte]
|
||||
): EitherT[F, CryptoErr, Unit] = {
|
||||
for {
|
||||
ec ← curveSpec
|
||||
|
@ -23,6 +23,7 @@ import cats.data.EitherT
|
||||
import cats.instances.try_._
|
||||
import fluence.crypto.algorithm.{CryptoErr, Ecdsa}
|
||||
import fluence.crypto.keypair.KeyPair
|
||||
import fluence.crypto.signature.Signature
|
||||
import org.scalatest.{Matchers, WordSpec}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
@ -50,17 +51,18 @@ class SignatureSpec extends WordSpec with Matchers {
|
||||
val algorithm = Ecdsa.ecdsa_secp256k1_sha256
|
||||
|
||||
val keys = algorithm.generateKeyPair[Try]().extract
|
||||
val pubKey = keys.publicKey
|
||||
val data = rndByteVector(10)
|
||||
val sign = algorithm.sign[Try](keys, data).extract
|
||||
|
||||
algorithm.verify[Try](sign, data).isOk shouldBe true
|
||||
algorithm.verify[Try](pubKey, sign, data).isOk shouldBe true
|
||||
|
||||
val randomData = rndByteVector(10)
|
||||
val randomSign = algorithm.sign(keys, randomData).extract
|
||||
|
||||
algorithm.verify(sign.copy(sign = randomSign.sign), data).isOk shouldBe false
|
||||
algorithm.verify(pubKey, randomSign, data).isOk shouldBe false
|
||||
|
||||
algorithm.verify(sign, randomData).isOk shouldBe false
|
||||
algorithm.verify(pubKey, sign, randomData).isOk shouldBe false
|
||||
}
|
||||
|
||||
"correctly work with signer and checker" in {
|
||||
@ -70,11 +72,11 @@ class SignatureSpec extends WordSpec with Matchers {
|
||||
val checker = algo.checker(keys.publicKey)
|
||||
|
||||
val data = rndByteVector(10)
|
||||
val sign = signer.sign(data).extract.sign
|
||||
val sign = signer.sign(data).extract
|
||||
|
||||
checker.check(sign, data).isOk shouldBe true
|
||||
|
||||
val randomSign = signer.sign(rndByteVector(10)).extract.sign
|
||||
val randomSign = signer.sign(rndByteVector(10)).extract
|
||||
checker.check(randomSign, data).isOk shouldBe false
|
||||
}
|
||||
|
||||
@ -85,10 +87,10 @@ class SignatureSpec extends WordSpec with Matchers {
|
||||
val checker = algo.checker(keys.publicKey)
|
||||
val data = rndByteVector(10)
|
||||
|
||||
val sign = signer.sign(data).extract.sign
|
||||
val sign = signer.sign(data).extract
|
||||
|
||||
the[CryptoErr] thrownBy {
|
||||
checker.check(rndByteVector(10), data).value.flatMap(_.toTry).get
|
||||
checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get
|
||||
}
|
||||
val invalidChecker = algo.checker(KeyPair.fromByteVectors(rndByteVector(10), rndByteVector(10)).publicKey)
|
||||
the[CryptoErr] thrownBy {
|
||||
@ -115,7 +117,7 @@ class SignatureSpec extends WordSpec with Matchers {
|
||||
|
||||
val signer = algo.signer(keys)
|
||||
val data = rndByteVector(10)
|
||||
val sign = signer.sign(data).extract.sign
|
||||
val sign = signer.sign(data).extract
|
||||
|
||||
algo.checker(keys.publicKey).check(sign, data).isOk shouldBe true
|
||||
algo.checker(keysRead.publicKey).check(sign, data).isOk shouldBe true
|
||||
|
@ -55,8 +55,8 @@ class SignAlgo(name: String, algo: KeyGenerator with SignatureFunctions) {
|
||||
* @return
|
||||
*/
|
||||
def checker(publicKey: KeyPair.Public): SignatureChecker = new SignatureChecker {
|
||||
override def check[F[_]: Monad](signature: ByteVector, plain: ByteVector): EitherT[F, CryptoErr, Unit] =
|
||||
algo.verify(Signature(publicKey, signature), plain)
|
||||
override def check[F[_]: Monad](signature: Signature, plain: ByteVector): EitherT[F, CryptoErr, Unit] =
|
||||
algo.verify(publicKey, signature, plain)
|
||||
|
||||
override def toString: String = s"SignatureChecker($name)"
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ class DumbSign extends KeyGenerator with SignatureFunctions {
|
||||
}
|
||||
|
||||
override def sign[F[_]: Monad](keyPair: KeyPair, message: ByteVector): EitherT[F, CryptoErr, Signature] =
|
||||
EitherT.pure(Signature(keyPair.publicKey, message.reverse))
|
||||
EitherT.pure(Signature(message.reverse))
|
||||
|
||||
override def verify[F[_]: Monad](signature: Signature, message: ByteVector): EitherT[F, CryptoErr, Unit] =
|
||||
override def verify[F[_]: Monad](pubKey: KeyPair.Public, signature: Signature, message: ByteVector): EitherT[F, CryptoErr, Unit] =
|
||||
EitherT.cond[F](signature.sign == message.reverse, (), CryptoErr("Invalid Signature"))
|
||||
}
|
||||
|
@ -28,5 +28,5 @@ import scala.language.higherKinds
|
||||
trait SignatureFunctions {
|
||||
def sign[F[_]: Monad](keyPair: KeyPair, message: ByteVector): EitherT[F, CryptoErr, Signature]
|
||||
|
||||
def verify[F[_]: Monad](signature: Signature, message: ByteVector): EitherT[F, CryptoErr, Unit]
|
||||
def verify[F[_]: Monad](pubKey: KeyPair.Public, signature: Signature, message: ByteVector): EitherT[F, CryptoErr, Unit]
|
||||
}
|
||||
|
@ -22,8 +22,14 @@ import scodec.bits.ByteVector
|
||||
case class KeyPair(publicKey: KeyPair.Public, secretKey: KeyPair.Secret)
|
||||
|
||||
object KeyPair {
|
||||
case class Public(value: ByteVector) extends AnyVal
|
||||
case class Secret(value: ByteVector) extends AnyVal
|
||||
|
||||
case class Public(value: ByteVector) extends AnyVal {
|
||||
def bytes: Array[Byte] = value.toArray
|
||||
}
|
||||
|
||||
case class Secret(value: ByteVector) extends AnyVal {
|
||||
def bytes: Array[Byte] = value.toArray
|
||||
}
|
||||
|
||||
def fromBytes(pk: Array[Byte], sk: Array[Byte]): KeyPair = fromByteVectors(ByteVector(pk), ByteVector(sk))
|
||||
def fromByteVectors(pk: ByteVector, sk: ByteVector): KeyPair = KeyPair(Public(pk), Secret(sk))
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Fluence Labs Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package fluence.crypto.signature
|
||||
|
||||
import fluence.crypto.keypair.KeyPair
|
||||
|
||||
/**
|
||||
* Container for public key of signer and a signature.
|
||||
*
|
||||
* @param publicKey Public key of signature maker
|
||||
* @param signature Some signature
|
||||
*/
|
||||
case class PubKeyAndSignature(publicKey: KeyPair.Public, signature: Signature)
|
@ -17,8 +17,17 @@
|
||||
|
||||
package fluence.crypto.signature
|
||||
|
||||
import fluence.crypto.keypair.KeyPair
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
// todo remove PubKey from signature
|
||||
case class Signature(publicKey: KeyPair.Public, sign: ByteVector)
|
||||
/** Container for a signature. */
|
||||
case class Signature private (sign: ByteVector) extends AnyVal {
|
||||
def bytes: Array[Byte] = sign.toArray
|
||||
}
|
||||
|
||||
object Signature {
|
||||
|
||||
def apply(sign: ByteVector): Signature = new Signature(sign)
|
||||
|
||||
def apply(sign: Array[Byte]): Signature = new Signature(ByteVector(sign))
|
||||
|
||||
}
|
||||
|
@ -25,5 +25,5 @@ import scodec.bits.ByteVector
|
||||
import scala.language.higherKinds
|
||||
|
||||
trait SignatureChecker {
|
||||
def check[F[_]: Monad](signature: ByteVector, plain: ByteVector): EitherT[F, CryptoErr, Unit]
|
||||
def check[F[_]: Monad](signature: Signature, plain: ByteVector): EitherT[F, CryptoErr, Unit]
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ object Signer {
|
||||
override def publicKey: KeyPair.Public = keyPair.publicKey
|
||||
|
||||
override def sign[F[_]: Monad](plain: ByteVector): EitherT[F, CryptoErr, Signature] =
|
||||
EitherT.pure(Signature(keyPair.publicKey, plain.reverse))
|
||||
EitherT.pure(Signature(plain.reverse))
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user