From dc8806de44a3be33865a82a41a820eba463a49b1 Mon Sep 17 00:00:00 2001 From: Dmitry Kurinskiy Date: Fri, 6 Apr 2018 13:11:49 +0300 Subject: [PATCH] WIP: scodec and circe implementations of PureCodec's (#104) * Introducing codec-bits * Introducing codec-circe * PureCodec in AesCrypt --- .../scala/fluence/crypto/FileKeyStorage.scala | 2 +- .../fluence/crypto/algorithm/AesCrypt.scala | 17 +++++++++-------- src/main/scala/fluence/crypto/KeyStore.scala | 2 -- .../fluence/crypto/algorithm/CryptoErr.scala | 9 ++++++--- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/jvm/src/main/scala/fluence/crypto/FileKeyStorage.scala b/jvm/src/main/scala/fluence/crypto/FileKeyStorage.scala index e6a39c6..68e997e 100644 --- a/jvm/src/main/scala/fluence/crypto/FileKeyStorage.scala +++ b/jvm/src/main/scala/fluence/crypto/FileKeyStorage.scala @@ -18,7 +18,7 @@ package fluence.crypto import java.io.File -import java.nio.file.{Files, Paths} +import java.nio.file.Files import cats.MonadError import cats.syntax.flatMap._ diff --git a/jvm/src/main/scala/fluence/crypto/algorithm/AesCrypt.scala b/jvm/src/main/scala/fluence/crypto/algorithm/AesCrypt.scala index 67913a5..29735c9 100644 --- a/jvm/src/main/scala/fluence/crypto/algorithm/AesCrypt.scala +++ b/jvm/src/main/scala/fluence/crypto/algorithm/AesCrypt.scala @@ -18,10 +18,9 @@ package fluence.crypto.algorithm import cats.data.EitherT -import cats.syntax.applicative._ import cats.syntax.flatMap._ import cats.{Applicative, Monad, MonadError} -import fluence.codec.Codec +import fluence.codec.PureCodec import fluence.crypto.cipher.Crypt import org.bouncycastle.crypto.{CipherParameters, PBEParametersGenerator} import org.bouncycastle.crypto.digests.SHA256Digest @@ -52,7 +51,7 @@ case class DataWithParams(data: Array[Byte], params: CipherParameters) */ class AesCrypt[F[_]: Monad, T](password: Array[Char], withIV: Boolean, config: AesConfig)( implicit ME: MonadError[F, Throwable], - codec: Codec[F, T, Array[Byte]] + codec: PureCodec[T, Array[Byte]] ) extends Crypt[F, T, Array[Byte]] with JavaAlgorithm { import CryptoErr._ @@ -72,7 +71,9 @@ class AesCrypt[F[_]: Monad, T](password: Array[Char], withIV: Boolean, config: A override def encrypt(plainText: T): F[Array[Byte]] = { val e = for { - data ← EitherT.liftF(codec.encode(plainText)) + data ← codec + .direct[F](plainText) + .leftMap(err ⇒ CryptoErr("Cannot encode plain text to bytes to encrypt it", Some(err))) key ← initSecretKey(password, salt) extDataWithParams ← extDataWithParams(key) encData ← processData(DataWithParams(data, extDataWithParams._2), extDataWithParams._1, encrypt = true) @@ -85,7 +86,7 @@ class AesCrypt[F[_]: Monad, T](password: Array[Char], withIV: Boolean, config: A val e = for { dataWithParams ← detachDataAndGetParams(cipherText, password, salt, withIV) decData ← processData(dataWithParams, None, encrypt = false) - plain ← EitherT.liftF[F, CryptoErr, T](codec.decode(decData)) + plain ← codec.inverse[F](decData).leftMap(err ⇒ CryptoErr("Cannot decode decrypted text", Some(err))) } yield plain e.value.flatMap(ME.fromEither) @@ -219,14 +220,14 @@ object AesCrypt extends slogging.LazyLogging { def forString[F[_]: Applicative](password: ByteVector, withIV: Boolean, config: AesConfig)( implicit ME: MonadError[F, Throwable] ): AesCrypt[F, String] = { - implicit val codec: Codec[F, String, Array[Byte]] = - Codec[F, String, Array[Byte]](_.getBytes.pure[F], bytes ⇒ new String(bytes).pure[F]) + implicit val codec: PureCodec[String, Array[Byte]] = + PureCodec.liftB[String, Array[Byte]](_.getBytes, new String(_)) apply[F, String](password, withIV, config) } def apply[F[_]: Applicative, T](password: ByteVector, withIV: Boolean, config: AesConfig)( implicit ME: MonadError[F, Throwable], - codec: Codec[F, T, Array[Byte]] + codec: PureCodec[T, Array[Byte]] ): AesCrypt[F, T] = new AesCrypt(password.toHex.toCharArray, withIV, config) } diff --git a/src/main/scala/fluence/crypto/KeyStore.scala b/src/main/scala/fluence/crypto/KeyStore.scala index 6944597..69db7ba 100644 --- a/src/main/scala/fluence/crypto/KeyStore.scala +++ b/src/main/scala/fluence/crypto/KeyStore.scala @@ -18,8 +18,6 @@ package fluence.crypto import cats.Monad -import cats.syntax.functor._ -import cats.syntax.flatMap._ import cats.data.EitherT import fluence.crypto.keypair.KeyPair import io.circe.parser.decode diff --git a/src/main/scala/fluence/crypto/algorithm/CryptoErr.scala b/src/main/scala/fluence/crypto/algorithm/CryptoErr.scala index bcc4a28..1bbba44 100644 --- a/src/main/scala/fluence/crypto/algorithm/CryptoErr.scala +++ b/src/main/scala/fluence/crypto/algorithm/CryptoErr.scala @@ -23,8 +23,11 @@ import cats.data.EitherT import scala.language.higherKinds import scala.util.control.{NoStackTrace, NonFatal} -// TODO: it could be useful to add smth like "source" or "trace" field, to help understand where exactly the check happened -case class CryptoErr(errorMessage: String) extends Throwable(errorMessage) with NoStackTrace +case class CryptoErr(errorMessage: String, causedBy: Option[Throwable] = None) + extends Throwable(errorMessage) with NoStackTrace { + + override def getCause: Throwable = causedBy getOrElse super.getCause +} object CryptoErr { @@ -32,7 +35,7 @@ object CryptoErr { def nonFatalHandling[F[_]: Applicative, A](a: ⇒ A)(errorText: String): EitherT[F, CryptoErr, A] = { try EitherT.pure(a) catch { - case NonFatal(e) ⇒ EitherT.leftT(CryptoErr(errorText + ": " + e.getLocalizedMessage)) + case NonFatal(e) ⇒ EitherT.leftT(CryptoErr(errorText + ": " + e.getLocalizedMessage, Some(e))) } } }