Skip to content

Instantly share code, notes, and snippets.

@davideicardi
Last active December 30, 2022 18:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save davideicardi/bcc8a44413d196a92372da8805f0f04f to your computer and use it in GitHub Desktop.
Save davideicardi/bcc8a44413d196a92372da8805f0f04f to your computer and use it in GitHub Desktop.
Scala AES-CTR encryption, MAC, HMAC, ... with Bouncy Castle example

Scala AES-CTR encryption Bouncy Castle example

Add the following library:

libraryDependencies += "org.bouncycastle" % "bcprov-jdk16" % "1.46"

AESCTR.scala

import javax.crypto.spec.SecretKeySpec
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec

object AESCTR {
  def encrypt(input: Array[Byte], key: Array[Byte], iv: Array[Byte]): Array[Byte] = {
    val keySpec = new SecretKeySpec(key, "AES")
    val ivSpec = new IvParameterSpec(iv)

    val cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC")

    cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)

    cipher.doFinal(input)
  }

  def decrypt(input: Array[Byte], key: Array[Byte], iv: Array[Byte]): Array[Byte] = {
    val keySpec = new SecretKeySpec(key, "AES")
    val ivSpec = new IvParameterSpec(iv)

    val cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC")

    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)

    cipher.doFinal(input)
  }
}

HMAC.scala

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

object HMAC {
  def computeSHA256(key: Array[Byte], data: Array[Byte]): Array[Byte] = {
    val keySpec = new SecretKeySpec(key, "HmacSHA256")

    val mac = Mac.getInstance("HmacSHA256", "BC")
    mac.init(keySpec)
    mac.update(data)

    mac.doFinal()
  }
}

MAC.scala

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

object MAC {
  def compute(key: Array[Byte], data: Array[Byte]): Array[Byte] = {
    val keySpec = new SecretKeySpec(key, "AES")

    val mac = Mac.getInstance("AESCMAC", "BC")
    mac.init(keySpec)
    mac.update(data)

    mac.doFinal()
  }
}

Example app

import org.bouncycastle.util.encoders.Hex
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.Security

object App {
  def main(args: Array[String]): Unit = {
    initBouncyCastle()

    val input = "my super secret input!".getBytes("UTF-8")
    // For key consider using a "Password Based Key Generation", like PBKDF2, SCRIPT, ...
    val key = Hex.decode("000102030405060708090a0b0c0d0e0f")
    val iv = Hex.decode("01020304050607080910111201010101")

    val encrypted = AESCTR.encrypt(input, key, iv)
    val decrypted = AESCTR.decrypt(encrypted, key, iv)
    val mac = MAC.compute(key, input)
    val hmac = HMAC.computeSHA256(key, input)

    println("input: " + new String(input, "UTF-8"))
    println("decrypted: " + new String(decrypted, "UTF-8"))
    println("mac: " + toHex(mac))
    println("hmac: " + toHex(hmac))
  }

  def initBouncyCastle(): Unit = {
    Security.addProvider(new BouncyCastleProvider)

    if (Security.getProvider("BC") == null)
      throw new Exception("Provider BC not installed")
  }

  def toHex(value: Array[Byte]): String = {
    value.map("%02X" format _).mkString
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment