Crypto api changes (#102)

* remove pubKey from Signature, change crypto api

* refactoring dependent modules
This commit is contained in:
Constantine Solovev 2018-04-02 10:38:25 +04:00 committed by GitHub
parent 69d3eb50c1
commit 994194b31f
12 changed files with 86 additions and 34 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)"
}

View File

@ -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"))
}

View File

@ -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]
}

View File

@ -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))

View File

@ -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)

View File

@ -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))
}

View File

@ -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]
}

View File

@ -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))
}
}