Keeps your secrets. Cryptic is a monad for encrypting and decryptic data. To use cryptic you must select a crypto and a serializer.
Cryptic supports several crypto libraries and serializers, select the modules you nedd or write your own
Module | Supports |
---|---|
crypto-javax | AES, RSA |
crypto-bouncycastle | EC (Elliptic curve) |
serialization-chill | Chill |
serialization-fst | Fst |
serialization-upickle | Upickle |
"scalacrypto" %% "core" % "1.0.0"
To encrypt with AES or RSA
"scalacrypto" %% "crypto-javax" % "1.0.0"
To encrypt with EC
"scalacrypto" %% "crypto-bouncycastle" % "1.0.0"
Select serializer one of
"scalacrypto" %% "serialization-chill" % "1.0.0"
"scalacrypto" %% "serialization-fst" % "1.0.0"
"scalacrypto" %% "serialization-upickle" % "1.0.0"
Import base package and syntax extension:
import cryptic._
import cryptic.syntax._
Define your data types:
case class EmailAddress(literal: String)
object EmailAddress {
val rw: ReadWriter[EmailAddress] = macroRW // If you use the Upickle serializer
}
case class User(id: Long, email: Encrypted[EmailAddress])
object User {
val rw: ReadWriter[User] = macroRW // If you use the Upickle serializer
}
Encrypt your data using convenient syntax, a crypto and a serializer must be available:
import java.security.{KeyPair, PrivateKey, PublicKey}
import cryptic.serialization.Chill._ // Brings the Chill serializer in scope
import cryptic.crypto.EC // Elliptic Curve encryption
// We need an implicit public key to enable encryption for EC
private val keyPair: KeyPair = EC.keygen(256)
implicit private val publicKey: PublicKey = keyPair.getPublic
val user = User(123, EmailAddress("[email protected]").encrypted)
To use the Upickle serializer:
import cryptic.serialization.Upickle
implicit def serializer[V](implicit rw: ReadWriter[V]): Serializer[V] = Upickle[V]
Access your data in encrypted form (can be done without crypto/serializer):
val bytes: Array[Byte] = user.email.bytes
Transform your data, can be done without crypto/serializer:
val lowered = user.email.
map(_.copy(literal = _.literal.toLower))
Run your staged transformations, a crypto and a serializer must be in scope:
import cryptic.crypto.RSA._
import cryptic.serialization.Chill._
val user2 = user.copy(email = lowered.run())
Decrypt your transformed data, a crypto and a serializer must be in scope:
import cryptic.crypto.RSA._
import cryptic.serialization.Fst._
val emailInLower = user2.email.decrypted
- AES
- RSA
- EC
- Chill
- Fst
- Upickle
Provide an implementation of the Serializer trait:
trait Serializer[V] {
def serialize(value: V): PlainText
def deserialize(plainText: PlainText): Either[String, V]
}
Example:
import scala.util.Try
object MySerializer {
implicit def serializer[V]: Serializer[V] = new Serializer[V] {
override def serialize(value: V): PlainText = ???
override def deserialize(plainText: PlainText): Either[String, V] = ???
}
}
Provide implementations of the Encrypt and Decrypt traits and probably a Key:
trait Encrypt {
def apply(plainText: PlainText): CipherText
}
trait Decrypt {
def apply(cipherText: CipherText): Either[String, PlainText]
}
Example Caesar crypto:
object Caesar {
case class Key(offset: Int) {
require(offset != 0)
}
implicit def encrypt(implicit key: Key): Encrypt = (plainText: PlainText) => {
val bytes = plainText.map(b ⇒ (b + key.offset).toByte)
CipherText(bytes)
}
implicit def decrypt(implicit key: Key): Decrypt = (cipherText: CipherText) =>
Right[String, PlainText](
PlainText(cipherText.bytes.map(b => (b - key.offset).toByte))
)
def keygen(offset: Int): Key = Key(offset)
}