Skip to content

Instantly share code, notes, and snippets.

@anler
Created June 15, 2017 23:31
Show Gist options
  • Save anler/c684766fd95ace050a911f426aea6c71 to your computer and use it in GitHub Desktop.
Save anler/c684766fd95ace050a911f426aea6c71 to your computer and use it in GitHub Desktop.
@scala.annotation.implicitNotFound("${EncryptKeyType} encrypted messages cannot be decrypted with ${DecryptKeyType}")
trait CanDecrypt[DecryptKeyType, EncryptKeyType]
object CanDecrypt {
implicit val pkOnSk = new CanDecrypt[PK, SK] {}
implicit val skOnPk = new CanDecrypt[SK, PK] {}
}
sealed trait PK // public key type
sealed trait SK // private key type
final case class Key [KeyType](jkey: java.security.Key)
// carries key type info ^^^^^^
final case class Secret[KeyType](bytes: Array[Byte])
// ^^^^^^^
// carries key type used for encryption
def generateKeyPair: (Key[PK], Key[SK]) = {
val gen = java.security.KeyPairGenerator.getInstance("RSA")
val pair = gen.generateKeyPair
(Key(pair.getPublic), Key(pair.getPrivate))
}
def encrypt[A](key: Key[A], data: Array[Byte]): Secret[A] = {
val cipher = javax.crypto.Cipher.getInstance("RSA")
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key.jkey)
Secret(cipher.doFinal(data))
}
def decrypt[A, B](key: Key[A], secret: Secret[B])(implicit ev: CanDecrypt[A, B]): Array[Byte] = {
val cipher = javax.crypto.Cipher.getInstance("RSA")
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key.jkey)
cipher.doFinal(secret.bytes)
}
val data = "phantom".getBytes
val (pk, sk) = generateKeyPair
val secret = encrypt(pk, data)
decrypt(sk, encrypt(pk, data)).toVector == data.toVector // true
decrypt(pk, encrypt(sk, data)).toVector == data.toVector // true
// If we try to decrypt with the same encryption key:
// decrypt(sk, encrypt(sk, data)).toVector == data.toVector)
// we will get a compile error with the message:
// SK encrypted messages cannot be decrypted with SK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment