diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala
index a35d2e7..a9caac9 100644
--- a/js/src/main/scala/Main.scala
+++ b/js/src/main/scala/Main.scala
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
object Main {
def main(args: Array[String]): Unit = {
println("Hello world!")
diff --git a/jvm/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala b/jvm/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala
index 4c3c414..f892a7a 100644
--- a/jvm/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala
+++ b/jvm/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala
@@ -21,7 +21,8 @@ import java.math.BigInteger
import java.security._
import java.security.interfaces.ECPrivateKey
-import cats.MonadError
+import cats.data.EitherT
+import cats.{ Applicative, Monad, MonadError }
import cats.syntax.flatMap._
import cats.syntax.functor._
import fluence.crypto.keypair.KeyPair
@@ -42,47 +43,62 @@ import scala.util.control.NonFatal
class Ecdsa(curveType: String, scheme: String) extends JavaAlgorithm
with SignatureFunctions with KeyGenerator {
import Ecdsa._
- private def nonFatalHandling[F[_], A](a: ⇒ A)(errorText: String)(implicit F: MonadError[F, Throwable]): F[A] = {
- try F.pure(a)
+
+ private def nonFatalHandling[F[_] : Applicative, A](a: ⇒ A)(errorText: String): EitherT[F, CryptoErr, A] = {
+ try EitherT.pure(a)
catch {
- case NonFatal(e) ⇒ F.raiseError(CryptoErr(errorText + " " + e.getLocalizedMessage))
+ case NonFatal(e) ⇒ EitherT.leftT(CryptoErr(errorText + " " + e.getLocalizedMessage))
}
}
- override def generateKeyPair[F[_]](random: SecureRandom)(implicit F: MonadError[F, Throwable]): F[KeyPair] = {
+ override def generateKeyPair[F[_] : Monad](random: SecureRandom): EitherT[F, CryptoErr, KeyPair] =
for {
- ecSpecOp ← F.pure(Option(ECNamedCurveTable.getParameterSpec(curveType)))
- ecSpec ← ecSpecOp match {
- case Some(ecs) ⇒ F.pure(ecs)
- case None ⇒ F.raiseError[ECNamedCurveParameterSpec](CryptoErr("Parameter spec for the curve is not available."))
- }
+ ecSpec ← EitherT.fromOption[F](
+ Option(ECNamedCurveTable.getParameterSpec(curveType)),
+ CryptoErr("Parameter spec for the curve is not available."))
g ← getKeyPairGenerator
_ ← nonFatalHandling(g.initialize(ecSpec, random))("Could not initialize KeyPairGenerator.")
- keyPair ← Option(g.generateKeyPair()) match {
- case Some(p) ⇒
- //store S number for private key and compressed Q point on curve for public key
- val pk = p.getPublic.asInstanceOf[ECPublicKey].getQ.getEncoded(true)
- val sk = p.getPrivate.asInstanceOf[ECPrivateKey].getS.toByteArray
- F.pure(KeyPair.fromBytes(pk, sk))
- case None ⇒ F.raiseError[KeyPair](CryptoErr("Could not generate KeyPair. Unexpected."))
- }
+ p ← EitherT.fromOption(
+ Option(g.generateKeyPair()),
+ CryptoErr("Could not generate KeyPair. Unexpected."))
+
+ keyPair ← nonFatalHandling {
+ //store S number for private key and compressed Q point on curve for public key
+ val pk = p.getPublic.asInstanceOf[ECPublicKey].getQ.getEncoded(true)
+ val sk = p.getPrivate.asInstanceOf[ECPrivateKey].getS.toByteArray
+ KeyPair.fromBytes(pk, sk)
+ }("Can't get public/private key from generated keypair")
} yield keyPair
- }
- override def generateKeyPair[F[_]]()(implicit F: MonadError[F, Throwable]): F[KeyPair] = {
+ override def generateKeyPair[F[_] : Monad](): EitherT[F, CryptoErr, KeyPair] =
generateKeyPair(new SecureRandom())
- }
- override def sign[F[_]](keyPair: KeyPair, message: ByteVector)(implicit F: MonadError[F, Throwable]): F[fluence.crypto.signature.Signature] = {
+ override def sign[F[_] : Monad](keyPair: KeyPair, message: ByteVector): EitherT[F, CryptoErr, fluence.crypto.signature.Signature] =
signMessage(keyPair.secretKey.value.toArray, message.toArray)
.map(bb ⇒ fluence.crypto.signature.Signature(keyPair.publicKey, ByteVector(bb)))
+
+ override def verify[F[_] : Monad](signature: fluence.crypto.signature.Signature, message: ByteVector): EitherT[F, CryptoErr, Unit] = {
+ val publicKey = signature.publicKey.value.toArray
+ val messageBytes = message.toArray
+ val signatureBytes = signature.sign.toArray
+
+ for {
+ ec ← curveSpec
+ keySpec ← nonFatalHandling(new ECPublicKeySpec(ec.getCurve.decodePoint(publicKey), ec))("Cannot read public key.")
+ keyFactory ← getKeyFactory
+ signProvider ← getSignatureProvider
+ verify ← {
+ nonFatalHandling {
+ signProvider.initVerify(keyFactory.generatePublic(keySpec))
+ signProvider.update(messageBytes)
+ signProvider.verify(signatureBytes)
+ }("Cannot verify message.")
+ }
+ _ ← EitherT.cond[F](verify, (), CryptoErr("Signature is not verified"))
+ } yield ()
}
- override def verify[F[_]](signature: fluence.crypto.signature.Signature, message: ByteVector)(implicit F: MonadError[F, Throwable]): F[Boolean] = {
- verifySign(signature.publicKey.value.toArray, message.toArray, signature.sign.toArray)
- }
-
- private def signMessage[F[_]](privateKey: Array[Byte], message: Array[Byte])(implicit F: MonadError[F, Throwable]): F[Array[Byte]] = {
+ private def signMessage[F[_] : Monad](privateKey: Array[Byte], message: Array[Byte]): EitherT[F, CryptoErr, Array[Byte]] = {
for {
ec ← curveSpec
keySpec ← nonFatalHandling(new ECPrivateKeySpec(new BigInteger(privateKey), ec))("Cannot read private key.")
@@ -98,32 +114,16 @@ class Ecdsa(curveType: String, scheme: String) extends JavaAlgorithm
} yield sign
}
- private def verifySign[F[_]](publicKey: Array[Byte], message: Array[Byte], signature: Array[Byte])(implicit F: MonadError[F, Throwable]): F[Boolean] = {
- for {
- ec ← curveSpec
- keySpec ← nonFatalHandling(new ECPublicKeySpec(ec.getCurve.decodePoint(publicKey), ec))("Cannot read public key.")
- keyFactory ← getKeyFactory
- signProvider ← getSignatureProvider
- verify ← {
- nonFatalHandling {
- signProvider.initVerify(keyFactory.generatePublic(keySpec))
- signProvider.update(message)
- signProvider.verify(signature)
- }("Cannot verify message.")
- }
- } yield verify
- }
-
- private def curveSpec[F[_]](implicit F: MonadError[F, Throwable]) =
+ private def curveSpec[F[_] : Monad] =
nonFatalHandling(ECNamedCurveTable.getParameterSpec(curveType).asInstanceOf[ECParameterSpec])("Cannot get curve parameters.")
- private def getKeyPairGenerator[F[_]](implicit F: MonadError[F, Throwable]) =
+ private def getKeyPairGenerator[F[_] : Monad] =
nonFatalHandling(KeyPairGenerator.getInstance(ECDSA, BouncyCastleProvider.PROVIDER_NAME))("Cannot get key pair generator.")
- private def getKeyFactory[F[_]](implicit F: MonadError[F, Throwable]) =
+ private def getKeyFactory[F[_] : Monad] =
nonFatalHandling(KeyFactory.getInstance(ECDSA, BouncyCastleProvider.PROVIDER_NAME))("Cannot get key factory instance.")
- private def getSignatureProvider[F[_]](implicit F: MonadError[F, Throwable]) =
+ private def getSignatureProvider[F[_] : Monad] =
nonFatalHandling(Signature.getInstance(scheme, BouncyCastleProvider.PROVIDER_NAME))("Cannot get signature instance.")
}
diff --git a/jvm/src/test/scala/fluence/crypto/SignatureSpec.scala b/jvm/src/test/scala/fluence/crypto/SignatureSpec.scala
index 661e1a1..7248996 100644
--- a/jvm/src/test/scala/fluence/crypto/SignatureSpec.scala
+++ b/jvm/src/test/scala/fluence/crypto/SignatureSpec.scala
@@ -18,68 +18,74 @@
package fluence.crypto
import java.io.File
-import java.security.SecureRandom
+import cats.data.EitherT
import cats.instances.try_._
import fluence.crypto.algorithm.{ CryptoErr, Ecdsa }
-import fluence.crypto.keypair.KeyPair
import org.scalatest.{ BeforeAndAfterAll, Matchers, WordSpec }
import scodec.bits.ByteVector
-import scala.util.Random
+import scala.util.{ Random, Try }
class SignatureSpec extends WordSpec with Matchers with BeforeAndAfterAll {
def rndBytes(size: Int) = Random.nextString(10).getBytes
+
def rndByteVector(size: Int) = ByteVector(rndBytes(size))
+ private implicit class TryEitherTExtractor[A, B](et: EitherT[Try, A, B]) {
+ def extract: B = et.value.get.right.get
+
+ def isOk: Boolean = et.value.fold(_ ⇒ false, _.isRight)
+ }
+
"ecdsa algorithm" should {
"correct sign and verify data" in {
val algorithm = Ecdsa.ecdsa_secp256k1_sha256
- val keys = algorithm.generateKeyPair().get
+ val keys = algorithm.generateKeyPair[Try]().extract
val data = rndByteVector(10)
- val sign = algorithm.sign(keys, data).get
+ val sign = algorithm.sign[Try](keys, data).extract
- algorithm.verify(sign, data).get shouldBe true
+ algorithm.verify[Try](sign, data).isOk shouldBe true
val randomData = rndByteVector(10)
- val randomSign = algorithm.sign(keys, randomData).get
+ val randomSign = algorithm.sign(keys, randomData).extract
- algorithm.verify(sign.copy(sign = randomSign.sign), data).get shouldBe false
+ algorithm.verify(sign.copy(sign = randomSign.sign), data).isOk shouldBe false
- algorithm.verify(sign, randomData).get shouldBe false
+ algorithm.verify(sign, randomData).isOk shouldBe false
}
"correctly work with signer and checker" in {
val algo = new SignAlgo(Ecdsa.ecdsa_secp256k1_sha256)
- val keys = algo.generateKeyPair().get
+ val keys = algo.generateKeyPair().extract
val signer = algo.signer(keys)
val data = rndByteVector(10)
- val sign = signer.sign(data).get
+ val sign = signer.sign(data).extract
- algo.checker.check(sign, data).get shouldBe true
+ algo.checker.check(sign, data).isOk shouldBe true
- val randomSign = signer.sign(rndByteVector(10)).get
- algo.checker.check(randomSign, data).get shouldBe false
+ val randomSign = signer.sign(rndByteVector(10)).extract
+ algo.checker.check(randomSign, data).isOk shouldBe false
}
"throw an errors on invalid data" in {
val algo = new SignAlgo(Ecdsa.ecdsa_secp256k1_sha256)
- val keys = algo.generateKeyPair().get
+ val keys = algo.generateKeyPair().extract
val signer = algo.signer(keys)
val data = rndByteVector(10)
- val sign = signer.sign(data).get
+ val sign = signer.sign(data).extract
- the[CryptoErr] thrownBy algo.checker.check(sign.copy(sign = rndByteVector(10)), data).get
- the[CryptoErr] thrownBy algo.checker.check(sign.copy(publicKey = sign.publicKey.copy(value = rndByteVector(10))), data).get
+ the[CryptoErr] thrownBy algo.checker.check(sign.copy(sign = rndByteVector(10)), data).value.flatMap(_.toTry).get
+ the[CryptoErr] thrownBy algo.checker.check(sign.copy(publicKey = sign.publicKey.copy(value = rndByteVector(10))), data).value.flatMap(_.toTry).get
}
"store and read key from file" in {
val algo = new SignAlgo(Ecdsa.ecdsa_secp256k1_sha256)
- val keys = algo.generateKeyPair().get
+ val keys = algo.generateKeyPair().extract
val keyFile = File.createTempFile("test", "")
if (keyFile.exists()) keyFile.delete()
@@ -92,10 +98,10 @@ class SignatureSpec extends WordSpec with Matchers with BeforeAndAfterAll {
val signer = algo.signer(keys)
val data = rndByteVector(10)
- val sign = signer.sign(data).get
+ val sign = signer.sign(data).extract
- algo.checker.check(sign.copy(publicKey = keysRead.publicKey), data).get shouldBe true
- algo.checker.check(sign, data).get shouldBe true
+ algo.checker.check(sign.copy(publicKey = keysRead.publicKey), data).isOk shouldBe true
+ algo.checker.check(sign, data).isOk shouldBe true
//try to store key into previously created file
storage.storeSecretKey(keys).isFailure shouldBe true
diff --git a/src/main/scala/fluence/crypto/SignAlgo.scala b/src/main/scala/fluence/crypto/SignAlgo.scala
index 32fd9f9..7c3b55b 100644
--- a/src/main/scala/fluence/crypto/SignAlgo.scala
+++ b/src/main/scala/fluence/crypto/SignAlgo.scala
@@ -19,8 +19,9 @@ package fluence.crypto
import java.security.SecureRandom
-import cats.MonadError
-import fluence.crypto.algorithm.{ DumbSign, KeyGenerator, SignatureFunctions }
+import cats.data.EitherT
+import cats.{ Monad, MonadError }
+import fluence.crypto.algorithm.{ CryptoErr, DumbSign, KeyGenerator, SignatureFunctions }
import fluence.crypto.keypair.KeyPair
import fluence.crypto.signature.{ Signature, SignatureChecker, Signer }
import scodec.bits.ByteVector
@@ -33,15 +34,17 @@ import scala.language.higherKinds
*/
class SignAlgo(algo: KeyGenerator with SignatureFunctions) {
- def generateKeyPair[F[_]]()(implicit F: MonadError[F, Throwable]): F[KeyPair] = algo.generateKeyPair()
- def generateKeyPair[F[_]](seed: ByteVector)(implicit F: MonadError[F, Throwable]): F[KeyPair] = algo.generateKeyPair(new SecureRandom(seed.toArray))
+ def generateKeyPair[F[_] : Monad](): EitherT[F, CryptoErr, KeyPair] = algo.generateKeyPair()
+ def generateKeyPair[F[_] : Monad](seed: ByteVector): EitherT[F, CryptoErr, KeyPair] = algo.generateKeyPair(new SecureRandom(seed.toArray))
- def signer[F[_]](kp: KeyPair)(implicit F: MonadError[F, Throwable]): Signer[F] = new Signer[F] {
- override def sign(plain: ByteVector): F[Signature] = algo.sign(kp, plain)
+ def signer(kp: KeyPair): Signer = new Signer {
override def publicKey: KeyPair.Public = kp.publicKey
+ override def sign[F[_] : Monad](plain: ByteVector): EitherT[F, CryptoErr, Signature] = algo.sign(kp, plain)
}
- def checker[F[_]](implicit F: MonadError[F, Throwable]): SignatureChecker[F] = (signature: Signature, plain: ByteVector) ⇒ algo.verify(signature, plain)
+ def checker: SignatureChecker = new SignatureChecker {
+ override def check[F[_] : Monad](signature: Signature, plain: ByteVector): EitherT[F, CryptoErr, Unit] = algo.verify(signature, plain)
+ }
}
object SignAlgo {
diff --git a/src/main/scala/fluence/crypto/algorithm/DumbSign.scala b/src/main/scala/fluence/crypto/algorithm/DumbSign.scala
index ed52bda..22bcd81 100644
--- a/src/main/scala/fluence/crypto/algorithm/DumbSign.scala
+++ b/src/main/scala/fluence/crypto/algorithm/DumbSign.scala
@@ -1,8 +1,26 @@
+/*
+ * 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 .
+ */
+
package fluence.crypto.algorithm
import java.security.SecureRandom
-import cats.MonadError
+import cats.Monad
+import cats.data.EitherT
import fluence.crypto.keypair.KeyPair
import fluence.crypto.signature.Signature
import scodec.bits.ByteVector
@@ -10,15 +28,15 @@ import scodec.bits.ByteVector
import scala.language.higherKinds
class DumbSign extends KeyGenerator with SignatureFunctions {
- override def generateKeyPair[F[_]](random: SecureRandom)(implicit F: MonadError[F, Throwable]): F[KeyPair] =
- F.pure(KeyPair.fromBytes(random.generateSeed(10), random.generateSeed(10)))
+ override def generateKeyPair[F[_] : Monad](random: SecureRandom): EitherT[F, CryptoErr, KeyPair] =
+ EitherT.pure(KeyPair.fromBytes(random.generateSeed(10), random.generateSeed(10)))
- override def generateKeyPair[F[_]]()(implicit F: MonadError[F, Throwable]): F[KeyPair] =
+ override def generateKeyPair[F[_] : Monad](): EitherT[F, CryptoErr, KeyPair] =
generateKeyPair(new SecureRandom())
- override def sign[F[_]](keyPair: KeyPair, message: ByteVector)(implicit F: MonadError[F, Throwable]): F[Signature] =
- F.pure(Signature(keyPair.publicKey, message.reverse))
+ override def sign[F[_] : Monad](keyPair: KeyPair, message: ByteVector): EitherT[F, CryptoErr, Signature] =
+ EitherT.pure(Signature(keyPair.publicKey, message.reverse))
- override def verify[F[_]](signature: Signature, message: ByteVector)(implicit F: MonadError[F, Throwable]): F[Boolean] =
- F.pure(signature.sign == message.reverse)
+ override def verify[F[_] : Monad](signature: Signature, message: ByteVector): EitherT[F, CryptoErr, Unit] =
+ EitherT.cond[F](signature.sign == message.reverse, (), CryptoErr("Invalid Signature"))
}
diff --git a/src/main/scala/fluence/crypto/algorithm/KeyGenerator.scala b/src/main/scala/fluence/crypto/algorithm/KeyGenerator.scala
index 7a33bea..e30574b 100644
--- a/src/main/scala/fluence/crypto/algorithm/KeyGenerator.scala
+++ b/src/main/scala/fluence/crypto/algorithm/KeyGenerator.scala
@@ -19,12 +19,14 @@ package fluence.crypto.algorithm
import java.security.SecureRandom
-import cats.MonadError
+import cats.Monad
+import cats.data.EitherT
import fluence.crypto.keypair.KeyPair
import scala.language.higherKinds
trait KeyGenerator {
- def generateKeyPair[F[_]](random: SecureRandom)(implicit F: MonadError[F, Throwable]): F[KeyPair]
- def generateKeyPair[F[_]]()(implicit F: MonadError[F, Throwable]): F[KeyPair]
+ def generateKeyPair[F[_] : Monad](random: SecureRandom): EitherT[F, CryptoErr, KeyPair]
+
+ def generateKeyPair[F[_] : Monad](): EitherT[F, CryptoErr, KeyPair]
}
diff --git a/src/main/scala/fluence/crypto/algorithm/SignatureFunctions.scala b/src/main/scala/fluence/crypto/algorithm/SignatureFunctions.scala
index a76740f..7b97174 100644
--- a/src/main/scala/fluence/crypto/algorithm/SignatureFunctions.scala
+++ b/src/main/scala/fluence/crypto/algorithm/SignatureFunctions.scala
@@ -17,7 +17,8 @@
package fluence.crypto.algorithm
-import cats.MonadError
+import cats.Monad
+import cats.data.EitherT
import fluence.crypto.keypair.KeyPair
import fluence.crypto.signature.Signature
import scodec.bits.ByteVector
@@ -25,6 +26,7 @@ import scodec.bits.ByteVector
import scala.language.higherKinds
trait SignatureFunctions {
- def sign[F[_]](keyPair: KeyPair, message: ByteVector)(implicit F: MonadError[F, Throwable]): F[Signature]
- def verify[F[_]](signature: Signature, message: ByteVector)(implicit F: MonadError[F, Throwable]): F[Boolean]
+ def sign[F[_] : Monad](keyPair: KeyPair, message: ByteVector): EitherT[F, CryptoErr, Signature]
+
+ def verify[F[_] : Monad](signature: Signature, message: ByteVector): EitherT[F, CryptoErr, Unit]
}
diff --git a/src/main/scala/fluence/crypto/signature/SignatureChecker.scala b/src/main/scala/fluence/crypto/signature/SignatureChecker.scala
index 2a55a76..75cf39b 100644
--- a/src/main/scala/fluence/crypto/signature/SignatureChecker.scala
+++ b/src/main/scala/fluence/crypto/signature/SignatureChecker.scala
@@ -17,10 +17,13 @@
package fluence.crypto.signature
+import cats.Monad
+import cats.data.EitherT
+import fluence.crypto.algorithm.CryptoErr
import scodec.bits.ByteVector
import scala.language.higherKinds
-trait SignatureChecker[F[_]] {
- def check(signature: Signature, plain: ByteVector): F[Boolean]
+trait SignatureChecker {
+ def check[F[_] : Monad](signature: Signature, plain: ByteVector): EitherT[F, CryptoErr, Unit]
}
diff --git a/src/main/scala/fluence/crypto/signature/Signer.scala b/src/main/scala/fluence/crypto/signature/Signer.scala
index e70c171..3b3b435 100644
--- a/src/main/scala/fluence/crypto/signature/Signer.scala
+++ b/src/main/scala/fluence/crypto/signature/Signer.scala
@@ -17,23 +17,27 @@
package fluence.crypto.signature
-import cats.MonadError
+import cats.Monad
+import cats.data.EitherT
+import fluence.crypto.algorithm.CryptoErr
import fluence.crypto.keypair.KeyPair
import scodec.bits.ByteVector
import scala.language.higherKinds
-trait Signer[F[_]] {
+trait Signer {
def publicKey: KeyPair.Public
- def sign(plain: ByteVector): F[Signature]
+ def sign[F[_] : Monad](plain: ByteVector): EitherT[F, CryptoErr, Signature]
}
object Signer {
- class DumbSigner[F[_]](keyPair: KeyPair)(implicit F: MonadError[F, Throwable]) extends Signer[F] {
+
+ class DumbSigner(keyPair: KeyPair) extends Signer {
override def publicKey: KeyPair.Public = keyPair.publicKey
- override def sign(plain: ByteVector): F[Signature] =
- F.pure(Signature(keyPair.publicKey, plain.reverse))
+ override def sign[F[_] : Monad](plain: ByteVector): EitherT[F, CryptoErr, Signature] =
+ EitherT.pure(Signature(keyPair.publicKey, plain.reverse))
}
+
}