Skip to content

Instantly share code, notes, and snippets.

@hilios
Last active June 27, 2019 20:04
Show Gist options
  • Save hilios/190ab993e7d195754ed3a4f92c790bd4 to your computer and use it in GitHub Desktop.
Save hilios/190ab993e7d195754ed3a4f92c790bd4 to your computer and use it in GitHub Desktop.
Simple HMAC 236 hasher
import cats.data.Kleisli
import cats.effect.Sync
import com.google.common.io.BaseEncoding
import javax.crypto.spec.{IvParameterSpec, PBEKeySpec, SecretKeySpec}
import javax.crypto.{Cipher, SecretKeyFactory}
object Hasher {
type Key = (String, String)
final case class InvalidInputException(hash: String, ex: Throwable) extends IllegalArgumentException(s"Could not decrypt [$hash]", ex)
private val iv: Array[Byte] = Array.fill(16)(0)
private val serde = BaseEncoding.base64Url().omitPadding()
private def secretKey[F[_]](implicit F: Sync[F]): Kleisli[F, Key, SecretKeySpec] = Kleisli(config => F.delay {
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val spec = new PBEKeySpec(config._1.toCharArray, config._2.getBytes(), 65536, 256)
val tmp = factory.generateSecret(spec)
new SecretKeySpec(tmp.getEncoded, "AES")
})
def encrypt[F[_]](input: String)(implicit F: Sync[F]): Kleisli[F, Key, String] = for {
secret <- secretKey
iparam <- Kleisli.liftF(F.pure(new IvParameterSpec(iv)))
cipher <- Kleisli.liftF(F.delay {
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.ENCRYPT_MODE, secret, iparam)
cipher.doFinal(input.getBytes)
})
hash <- Kleisli.liftF(F.delay(serde.encode(cipher)))
} yield hash
def decrypt[F[_]](input: String)(implicit F: Sync[F]): Kleisli[F, Key, String] = for {
secret <- secretKey
hash <- Kleisli.liftF(F.delay(serde.decode(input)))
iparam <- Kleisli.liftF(F.pure(new IvParameterSpec(iv)))
cipher <- Kleisli.liftF(F.delay {
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, secret, iparam)
cipher.doFinal(hash)
})
value <- Kleisli.liftF(F.delay {
new String(cipher)
})
} yield value
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment