javax.crypto.spec.SecretKeySpec Scala Examples

The following examples show how to use javax.crypto.spec.SecretKeySpec. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: Enigma.scala    From matcher   with MIT License 6 votes vote down vote up
package com.wavesplatform.dex.crypto

import java.nio.charset.StandardCharsets
import java.security.NoSuchAlgorithmException
import java.security.spec.InvalidKeySpecException

import javax.crypto.spec.{PBEKeySpec, SecretKeySpec}
import javax.crypto.{Cipher, SecretKeyFactory}

import scala.util.control.NonFatal

object Enigma {

  private[this] val KeySalt           = "0495c728-1614-41f6-8ac3-966c22b4a62d".getBytes(StandardCharsets.UTF_8)
  private[this] val AES               = "AES"
  private[this] val Algorithm         = AES + "/ECB/PKCS5Padding"
  private[this] val HashingIterations = 999999
  private[this] val KeySizeBits       = 128

  def hashPassword(password: Array[Char],
                   salt: Array[Byte],
                   iterations: Int = HashingIterations,
                   keyLength: Int = KeySizeBits,
                   hashingAlgorithm: String = "PBKDF2WithHmacSHA512"): Array[Byte] =
    try {
      val keyFactory = SecretKeyFactory.getInstance(hashingAlgorithm)
      val keySpec    = new PBEKeySpec(password, salt, iterations, keyLength)
      val key        = keyFactory.generateSecret(keySpec)
      key.getEncoded
    } catch {
      case e @ (_: NoSuchAlgorithmException | _: InvalidKeySpecException) => throw new RuntimeException("Password hashing error", e)
    }

  def prepareDefaultKey(password: String): SecretKeySpec = new SecretKeySpec(hashPassword(password.toCharArray, KeySalt), AES)

  def encrypt(key: SecretKeySpec, bytes: Array[Byte]): Array[Byte] =
    try {
      val cipher = Cipher.getInstance(Algorithm)
      cipher.init(Cipher.ENCRYPT_MODE, key)
      cipher.doFinal(bytes)
    } catch {
      case NonFatal(e) => throw new RuntimeException("Encrypt error", e)
    }

  def decrypt(key: SecretKeySpec, encryptedBytes: Array[Byte]): Array[Byte] =
    try {
      val cipher: Cipher = Cipher.getInstance(Algorithm)
      cipher.init(Cipher.DECRYPT_MODE, key)
      cipher.doFinal(encryptedBytes)
    } catch {
      case NonFatal(e) => throw new RuntimeException("Decrypt error", e)
    }
} 
Example 2
Source File: Utils.scala    From akka-pusher   with MIT License 5 votes vote down vote up
package com.github.dtaniwaki.akka_pusher

import java.math.BigInteger
import java.security.MessageDigest
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

import akka.http.scaladsl.model.Uri

object Utils {
  val HEX = 16
  val LENGTH = 32

  def byteArrayToString(data: Array[Byte]): String = {
    val bigInteger = new BigInteger(1, data)
    var hash = bigInteger.toString(HEX)

    while (hash.length() < LENGTH) {
      hash = "0" + hash
    }

    hash
  }

  def md5(string: String): String = {
    val bytesOfMessage = string.getBytes("UTF-8")
    val md = MessageDigest.getInstance("MD5")
    val digest = md.digest(bytesOfMessage)
    byteArrayToString(digest)
  }

  def sha256(secret: String, string: String): String = {
    val signingKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256")

    val mac = Mac.getInstance("HmacSHA256")
    mac.init(signingKey)

    val digest = mac.doFinal(string.getBytes("UTF-8"))

    val bigInteger = new BigInteger(1, digest)
    String.format("%0" + (digest.length << 1) + "x", bigInteger)
  }

  def normalizeQuery(query: Uri.Query): Uri.Query = {
    Uri.Query(query.map { case (k, v) => (k.toString.toLowerCase, v) }.sortBy(_._1): _*)
  }
} 
Example 3
Source File: CryptoStreamUtils.scala    From drizzle-spark   with Apache License 2.0 5 votes vote down vote up
package org.apache.spark.security

import java.io.{InputStream, OutputStream}
import java.util.Properties
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec}

import org.apache.commons.crypto.random._
import org.apache.commons.crypto.stream._
import org.apache.hadoop.io.Text

import org.apache.spark.SparkConf
import org.apache.spark.deploy.SparkHadoopUtil
import org.apache.spark.internal.Logging
import org.apache.spark.internal.config._


  private[this] def createInitializationVector(properties: Properties): Array[Byte] = {
    val iv = new Array[Byte](IV_LENGTH_IN_BYTES)
    val initialIVStart = System.currentTimeMillis()
    CryptoRandomFactory.getCryptoRandom(properties).nextBytes(iv)
    val initialIVFinish = System.currentTimeMillis()
    val initialIVTime = initialIVFinish - initialIVStart
    if (initialIVTime > 2000) {
      logWarning(s"It costs ${initialIVTime} milliseconds to create the Initialization Vector " +
        s"used by CryptoStream")
    }
    iv
  }
} 
Example 4
Source File: Encoder.scala    From twitter4s   with Apache License 2.0 5 votes vote down vote up
package com.danielasfregola.twitter4s.util

import java.security.MessageDigest
import java.util.Base64
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

private[twitter4s] trait Encoder {

  def toHmacSha1(base: String, secret: String): String = {
    val HMAC_SHA1 = "HmacSHA1"
    val UTF8 = "UTF-8"
    val secretKeySpec = new SecretKeySpec(secret.getBytes(UTF8), HMAC_SHA1)
    val mac = Mac.getInstance(HMAC_SHA1)
    mac.init(secretKeySpec)
    val bytesToSign = base.getBytes(UTF8)
    val digest = mac.doFinal(bytesToSign)
    Base64.getEncoder.encodeToString(digest)
  }

  def toBase64(data: Array[Byte]): String =
    Base64.getEncoder.encodeToString(data)

  def toSha1(base: String): String = {
    val SHA1 = "SHA-1"
    val messageDigest = MessageDigest.getInstance(SHA1)
    val bytes = messageDigest.digest(base.getBytes)

    val stringBuffer = new StringBuffer
    bytes.foreach { byte =>
      stringBuffer.append(Integer.toString((byte & 0xff) + 0x100, 16).substring(1))
    }
    stringBuffer.toString
  }

} 
Example 5
Source File: crypto.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package shop.algebras

import cats.effect.Sync
import cats.implicits._
import javax.crypto.spec.{ PBEKeySpec, SecretKeySpec }
import javax.crypto.{ Cipher, SecretKeyFactory }
import shop.config.data.PasswordSalt
import shop.domain.auth._

trait Crypto {
  def encrypt(value: Password): EncryptedPassword
  def decrypt(value: EncryptedPassword): Password
}

object LiveCrypto {
  def make[F[_]: Sync](secret: PasswordSalt): F[Crypto] =
    Sync[F]
      .delay {
        val salt     = secret.value.value.value.getBytes("UTF-8")
        val keySpec  = new PBEKeySpec("password".toCharArray(), salt, 65536, 256)
        val factory  = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
        val bytes    = factory.generateSecret(keySpec).getEncoded
        val sKeySpec = new SecretKeySpec(bytes, "AES")
        val eCipher  = EncryptCipher(Cipher.getInstance("AES"))
        eCipher.value.init(Cipher.ENCRYPT_MODE, sKeySpec)
        val dCipher = DecryptCipher(Cipher.getInstance("AES"))
        dCipher.value.init(Cipher.DECRYPT_MODE, sKeySpec)
        (eCipher, dCipher)
      }
      .map {
        case (ec, dc) =>
          new LiveCrypto(ec, dc)
      }
}

final class LiveCrypto private (
    eCipher: EncryptCipher,
    dCipher: DecryptCipher
) extends Crypto {

  // Workaround for PostgreSQL ERROR: invalid byte sequence for encoding "UTF8": 0x00
  private val Key = "=DownInAHole="

  def encrypt(password: Password): EncryptedPassword = {
    val bytes      = password.value.getBytes("UTF-8")
    val result     = new String(eCipher.value.doFinal(bytes), "UTF-8")
    val removeNull = result.replaceAll("\\u0000", Key)
    EncryptedPassword(removeNull)
  }

  def decrypt(password: EncryptedPassword): Password = {
    val bytes      = password.value.getBytes("UTF-8")
    val result     = new String(dCipher.value.doFinal(bytes), "UTF-8")
    val insertNull = result.replaceAll(Key, "\\u0000")
    Password(insertNull)
  }

} 
Example 6
Source File: JsonFileStorage.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.utils

import java.io.{File, PrintWriter}

import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import play.api.libs.json.{Json, Reads, Writes}
import java.util.Base64

import scala.io.Source
import scala.util.control.NonFatal

object JsonFileStorage {
  private[this] val KeySalt           = "0495c728-1614-41f6-8ac3-966c22b4a62d"
  private[this] val AES               = "AES"
  private[this] val Algorithm         = AES + "/ECB/PKCS5Padding"
  private[this] val HashingAlgorithm  = "PBKDF2WithHmacSHA512"
  private[this] val HashingIterations = 999999
  private[this] val KeySizeBits       = 128

  def prepareKey(key: String): SecretKeySpec = {
    import java.security.NoSuchAlgorithmException
    import java.security.spec.InvalidKeySpecException

    import javax.crypto.SecretKeyFactory
    import javax.crypto.spec.PBEKeySpec

    def hashPassword(password: Array[Char], salt: Array[Byte], iterations: Int, keyLength: Int): Array[Byte] =
      try {
        val keyFactory = SecretKeyFactory.getInstance(HashingAlgorithm)
        val keySpec    = new PBEKeySpec(password, salt, iterations, keyLength)
        val key        = keyFactory.generateSecret(keySpec)
        key.getEncoded
      } catch {
        case e @ (_: NoSuchAlgorithmException | _: InvalidKeySpecException) =>
          throw new RuntimeException("Password hashing error", e)
      }

    new SecretKeySpec(hashPassword(key.toCharArray, KeySalt.utf8Bytes, HashingIterations, KeySizeBits), AES)
  }

  def save[T](value: T, path: String, key: Option[SecretKeySpec])(implicit w: Writes[T]): Unit = {
    val folder = new File(path).getParentFile
    if (!folder.exists()) folder.mkdirs()

    val file = new PrintWriter(path)
    try {
      val json = Json.toJson(value).toString()
      val data = key.fold(json)(k => encrypt(k, json))
      file.write(data)
    } finally file.close()
  }

  def save[T](value: T, path: String)(implicit w: Writes[T]): Unit =
    save(value, path, None)

  def load[T](path: String, key: Option[SecretKeySpec] = None)(implicit r: Reads[T]): T = {
    val file = Source.fromFile(path)
    try {
      val dataStr = file.mkString
      Json.parse(key.fold(dataStr)(k => decrypt(k, dataStr))).as[T]
    } finally file.close()
  }

  def load[T](path: String)(implicit r: Reads[T]): T =
    load(path, Option.empty[SecretKeySpec])(r)

  private[this] def encrypt(key: SecretKeySpec, value: String): String = {
    try {
      val cipher: Cipher = Cipher.getInstance(Algorithm)
      cipher.init(Cipher.ENCRYPT_MODE, key)
      new String(Base64.getEncoder.encode(cipher.doFinal(value.utf8Bytes)))
    } catch {
      case NonFatal(e) =>
        throw new RuntimeException("File storage encrypt error", e)
    }
  }

  private[this] def decrypt(key: SecretKeySpec, encryptedValue: String): String = {
    try {
      val cipher: Cipher = Cipher.getInstance(Algorithm)
      cipher.init(Cipher.DECRYPT_MODE, key)
      new String(cipher.doFinal(Base64.getDecoder.decode(encryptedValue)))
    } catch {
      case NonFatal(e) =>
        throw new RuntimeException("File storage decrypt error", e)
    }
  }
} 
Example 7
Source File: Hmac.scala    From incubator-toree   with Apache License 2.0 5 votes vote down vote up
package org.apache.toree.communication.security

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

import org.apache.toree.communication.security.HmacAlgorithm.HmacAlgorithm

object HmacAlgorithm extends Enumeration {
  type HmacAlgorithm = Value

  def apply(key: String) = Value(key)

  val MD5     = Value("HmacMD5")
  val SHA1    = Value("HmacSHA1")
  val SHA256  = Value("HmacSHA256")
}

object Hmac {
  
  def apply(key: String, algorithm: HmacAlgorithm = HmacAlgorithm.SHA256) =
    new Hmac(key, algorithm)
  
  def newMD5(key: String): Hmac     = this(key, HmacAlgorithm.MD5)
  def newSHA1(key: String): Hmac    = this(key, HmacAlgorithm.SHA1)
  def newSHA256(key: String): Hmac  = this(key, HmacAlgorithm.SHA256)
}

class Hmac(
  val key: String,
  val algorithm: HmacAlgorithm = HmacAlgorithm.SHA256
) {

  private var mac: Mac = _
  private var secretKeySpec: SecretKeySpec = _

  if (key.nonEmpty) {
    mac = Mac.getInstance(algorithm.toString)
    secretKeySpec = new SecretKeySpec(key.getBytes, algorithm.toString)
    mac.init(secretKeySpec)
  }

  def apply(items: String*): String = digest(items)

  def digest(items: Seq[String]): String = if (key.nonEmpty) {
    mac synchronized {
      items.map(_.getBytes("UTF-8")).foreach(mac.update)
      mac.doFinal().map("%02x" format _).mkString
    }
  } else ""
} 
Example 8
Source File: HasEncryption.scala    From recogito2   with Apache License 2.0 5 votes vote down vote up
package services.user

import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import org.apache.commons.codec.binary.Base64
import java.security.MessageDigest
import java.util.Arrays
import controllers.HasConfig

trait HasEncryption { self: HasConfig =>

  private val CIPHER = "AES/ECB/PKCS5Padding"

  private lazy val keySpec = self.config.getOptional[String]("recogito.email.key").flatMap { key =>
    if (key.isEmpty) {
      None
    } else {
      val md = MessageDigest.getInstance("SHA-1")
      val keyDigest = md.digest(key.getBytes)
      Some(new SecretKeySpec(Arrays.copyOf(keyDigest, 16), "AES"))
    }
  }

  def encrypt(plaintext: String) = keySpec match {
    case Some(spec) => {
      val cipher = Cipher.getInstance(CIPHER)
      cipher.init(Cipher.ENCRYPT_MODE, spec)
      Base64.encodeBase64String(cipher.doFinal(plaintext.getBytes("UTF-8")))
    }

    case None => plaintext
  }

  def decrypt(encrypted: String) = keySpec match {
    case Some(spec) => {
      val cipher = Cipher.getInstance(CIPHER)
      cipher.init(Cipher.DECRYPT_MODE, spec)
      new String(cipher.doFinal(Base64.decodeBase64(encrypted)))
    }

    case None => encrypted
  }

} 
Example 9
Source File: Crypto.scala    From akka-http-extensions   with Mozilla Public License 2.0 5 votes vote down vote up
package akka.http.extensions.security

import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec}

import org.apache.commons.codec.binary.Base64

object CryptoConfig {

  implicit def fromString(secret:String): CryptoConfig = CryptoConfig(secret)
}

case class CryptoConfig( secret: String, transformation: String = "AES/CTR/NoPadding")

class CryptoException(val message: String = null, val throwable: Throwable = null)
  extends RuntimeException(message, throwable)

trait Encryption {

  def algorithm:String

  def encrypt(value: String, config:CryptoConfig): String

  def decrypt(value: String, config:CryptoConfig): String
}

object AES extends Encryption {

  val algorithm = "AES"

  protected def secretKeyWithSha256(privateKey: String) = {
    val messageDigest = MessageDigest.getInstance("SHA-256")
    messageDigest.update(privateKey.getBytes("utf-8"))
    // max allowed length in bits / (8 bits to a byte)
    val maxAllowedKeyLength = Cipher.getMaxAllowedKeyLength(algorithm) / 8
    val raw = messageDigest.digest().slice(0, maxAllowedKeyLength)
    new SecretKeySpec(raw, algorithm)
  }


  def encrypt(value: String, config:CryptoConfig): String = {
    val skeySpec = secretKeyWithSha256(config.secret)
    val cipher = Cipher.getInstance(config.transformation)
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec)
    val encryptedValue = cipher.doFinal(value.getBytes("utf-8"))
    Option(cipher.getIV) match {
      case Some(iv) => s"2-${Base64.encodeBase64String(iv ++ encryptedValue)}"
      case None => s"1-${Base64.encodeBase64String(encryptedValue)}"
    }
  }



  def decrypt(value: String, config:CryptoConfig): String =  value.indexOf("-") match
  {
    case sepIndex if sepIndex<0=> throw new CryptoException("Outdated AES version")
    case sepIndex=>
      val data = value.substring(sepIndex + 1, value.length())
      val version = value.substring(0, sepIndex)
      version match {
        case "1" => decryptAES1(data, config)
        case "2" => decryptAES2(data, config)
        case _ =>  throw new CryptoException("Unknown version")
        }
  }


  
  private def decryptAES2(value: String, config:CryptoConfig): String = {
    val cipher = Cipher.getInstance(config.transformation)
    val blockSize = cipher.getBlockSize
    val data = Base64.decodeBase64(value)
    val iv = data.slice(0, blockSize)
    val payload = data.slice(blockSize, data.size)
    val skeySpec = secretKeyWithSha256(config.secret)
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(iv))
    new String(cipher.doFinal(payload), "utf-8")
  }

} 
Example 10
Source File: D3ESCBC.scala    From OUTDATED_ledger-wallet-android   with MIT License 5 votes vote down vote up
package co.ledger.wallet.core.crypto

import javax.crypto.Cipher
import javax.crypto.spec.{SecretKeySpec, IvParameterSpec}

class D3ESCBC(secret: Array[Byte], IV: Option[Array[Byte]] = None) {
  Crypto.ensureSpongyIsInserted()

  if (IV.isDefined && IV.get.length != 8) {
    throw new IllegalArgumentException("Initialization Vector must be a 8 bytes array")
  }
  private[this] val iv = new IvParameterSpec(IV.getOrElse(Array[Byte](0, 0, 0, 0, 0, 0, 0, 0)))
  private[this] val cipher = Cipher.getInstance("DESede/CBC/NoPadding", "BC")
  private[this] val secretKey = new SecretKeySpec(secret, "DESede")

  def encrypt(byte: Array[Byte]): Array[Byte] = {
    Crypto.ensureSpongyIsInserted()
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv)
    cipher.doFinal(byte)
  }

  def decrypt(byte: Array[Byte]): Array[Byte] = {
    Crypto.ensureSpongyIsInserted()
    cipher.init(Cipher.DECRYPT_MODE, secretKey, iv)
    cipher.doFinal(byte)
  }

} 
Example 11
Source File: CipherUtil.scala    From spark-highcharts   with Apache License 2.0 5 votes vote down vote up
package com.knockdata.spark.utils

import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec}

import sun.misc.{BASE64Decoder, BASE64Encoder}

object CipherUtil {
  val cipherName = "AES/CBC/PKCS5Padding"

  val ivspec = new IvParameterSpec(Array[Byte](0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))

  def getKey(key: String): Array[Byte] = {
    val raw = MessageDigest.getInstance("MD5").digest(key.getBytes)
    raw
  }

  def encrypt(key: String, password: String): String = {
    val spec = new SecretKeySpec(getKey(key), "AES")
    val cipher = Cipher.getInstance(cipherName)
    cipher.init(Cipher.ENCRYPT_MODE, spec, ivspec)

    val encrypted = cipher.doFinal(password.getBytes("UTF8"))

    new BASE64Encoder().encode(encrypted)
  }

  def decrypt(key: String, encryptedPassword: String): String = {
    val spec = new SecretKeySpec(getKey(key), "AES")
    val cipher = Cipher.getInstance(cipherName)
    cipher.init(Cipher.DECRYPT_MODE, spec, ivspec)

    val encrypted = new BASE64Decoder().decodeBuffer(encryptedPassword)

    val decrypted = cipher.doFinal(encrypted)
    new String(decrypted, "UTF8")
  }
} 
Example 12
Source File: AuthUtil.scala    From shield   with MIT License 5 votes vote down vote up
package shield.aws

import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

import org.apache.commons.codec.binary.Hex
import org.joda.time.format.DateTimeFormat
import org.joda.time.{DateTime, DateTimeZone}
import spray.http.HttpHeaders.RawHeader
import spray.http.HttpRequest


object HexBytesUtil {

  def hex2bytes(hex: String): Array[Byte] = {
    hex.replaceAll("[^0-9A-Fa-f]", "").sliding(2, 2).toArray.map(Integer.parseInt(_, 16).toByte)
  }

  def bytes2hex(bytes: Array[Byte], sep: Option[String] = None): String = {
    sep match {
      case None => bytes.map("%02x".format(_)).mkString
      case _ => bytes.map("%02x".format(_)).mkString(sep.get)
    }
  }
} 
Example 13
Source File: CryptoStreamUtils.scala    From multi-tenancy-spark   with Apache License 2.0 5 votes vote down vote up
package org.apache.spark.security

import java.io.{InputStream, OutputStream}
import java.util.Properties
import javax.crypto.KeyGenerator
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec}

import org.apache.commons.crypto.random._
import org.apache.commons.crypto.stream._

import org.apache.spark.SparkConf
import org.apache.spark.internal.Logging
import org.apache.spark.internal.config._


  private[this] def createInitializationVector(properties: Properties): Array[Byte] = {
    val iv = new Array[Byte](IV_LENGTH_IN_BYTES)
    val initialIVStart = System.currentTimeMillis()
    CryptoRandomFactory.getCryptoRandom(properties).nextBytes(iv)
    val initialIVFinish = System.currentTimeMillis()
    val initialIVTime = initialIVFinish - initialIVStart
    if (initialIVTime > 2000) {
      logWarning(s"It costs ${initialIVTime} milliseconds to create the Initialization Vector " +
        s"used by CryptoStream")
    }
    iv
  }
} 
Example 14
Source File: Crypto.scala    From tepkin   with Apache License 2.0 5 votes vote down vote up
package net.fehmicansaglam.tepkin.util

import java.security.MessageDigest
import javax.crypto.spec.{PBEKeySpec, SecretKeySpec}
import javax.crypto.{Mac, SecretKeyFactory}

import net.fehmicansaglam.bson.util.Codec

trait Crypto extends Codec {

  def sha1(value: String): String = {
    val digest = sha1(value.getBytes("UTF-8"))
    encodeBase64(digest)
  }

  def sha1(value: Array[Byte]): Array[Byte] = {
    MessageDigest.getInstance("SHA-1").digest(value)
  }

  def hmac(value: Array[Byte], key: String): Array[Byte] = {
    val signingKey = new SecretKeySpec(value, "HmacSHA1")
    val mac = Mac.getInstance("HmacSHA1")
    mac.init(signingKey)
    mac.doFinal(decodeUtf8(key))
  }

  def keyDerive(password: String, salt: Array[Byte], iterations: Int): Array[Byte] = {
    val spec = new PBEKeySpec(password.toCharArray, salt, iterations, 20 * 8 )
    val keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
    keyFactory.generateSecret(spec).getEncoded
  }

  def xor(as: Array[Byte], bs: Array[Byte]): Array[Byte] = {
    as.zip(bs).map { case (a, b) => (a ^ b).toByte }
  }
}

object Crypto extends Crypto 
Example 15
Source File: AuthToken.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.backend.auth

import java.time.Instant
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

import cats.effect._
import cats.implicits._

import docspell.backend.Common
import docspell.backend.auth.AuthToken._
import docspell.common._

import scodec.bits.ByteVector

case class AuthToken(millis: Long, account: AccountId, salt: String, sig: String) {
  def asString = s"$millis-${b64enc(account.asString)}-$salt-$sig"

  def sigValid(key: ByteVector): Boolean = {
    val newSig = AuthToken.sign(this, key)
    AuthToken.constTimeEq(sig, newSig)
  }
  def sigInvalid(key: ByteVector): Boolean =
    !sigValid(key)

  def notExpired(validity: Duration): Boolean =
    !isExpired(validity)

  def isExpired(validity: Duration): Boolean = {
    val ends = Instant.ofEpochMilli(millis).plusMillis(validity.millis)
    Instant.now.isAfter(ends)
  }

  def validate(key: ByteVector, validity: Duration): Boolean =
    sigValid(key) && notExpired(validity)
}

object AuthToken {
  private val utf8 = java.nio.charset.StandardCharsets.UTF_8

  def fromString(s: String): Either[String, AuthToken] =
    s.split("\\-", 4) match {
      case Array(ms, as, salt, sig) =>
        for {
          millis <- asInt(ms).toRight("Cannot read authenticator data")
          acc    <- b64dec(as).toRight("Cannot read authenticator data")
          accId  <- AccountId.parse(acc)
        } yield AuthToken(millis, accId, salt, sig)

      case _ =>
        Left("Invalid authenticator")
    }

  def user[F[_]: Sync](accountId: AccountId, key: ByteVector): F[AuthToken] =
    for {
      salt <- Common.genSaltString[F]
      millis = Instant.now.toEpochMilli
      cd     = AuthToken(millis, accountId, salt, "")
      sig    = sign(cd, key)
    } yield cd.copy(sig = sig)

  private def sign(cd: AuthToken, key: ByteVector): String = {
    val raw = cd.millis.toString + cd.account.asString + cd.salt
    val mac = Mac.getInstance("HmacSHA1")
    mac.init(new SecretKeySpec(key.toArray, "HmacSHA1"))
    ByteVector.view(mac.doFinal(raw.getBytes(utf8))).toBase64
  }

  private def b64enc(s: String): String =
    ByteVector.view(s.getBytes(utf8)).toBase64

  private def b64dec(s: String): Option[String] =
    ByteVector.fromValidBase64(s).decodeUtf8.toOption

  private def asInt(s: String): Option[Long] =
    Either.catchNonFatal(s.toLong).toOption

  private def constTimeEq(s1: String, s2: String): Boolean =
    s1.zip(s2)
      .foldLeft(true)({ case (r, (c1, c2)) => r & c1 == c2 }) & s1.length == s2.length

} 
Example 16
Source File: GameHeaderCryptWotLK.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

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

class GameHeaderCryptWotLK extends GameHeaderCrypt {

  private var clientCrypt: RC4 = _
  private var serverCrypt: RC4 = _

  protected val serverHmacSeed: Array[Byte] = Array(
    0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57
  ).map(_.toByte)

  protected val clientHmacSeed: Array[Byte] = Array(
    0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE
  ).map(_.toByte)

  override def decrypt(data: Array[Byte]): Array[Byte] = {
    if (!_initialized) {
      return data
    }

    serverCrypt.cryptToByteArray(data)
  }

  override def encrypt(data: Array[Byte]): Array[Byte] = {
    if (!_initialized) {
      return data
    }

    clientCrypt.cryptToByteArray(data)
  }

  override def init(key: Array[Byte]): Unit = {
    val md = Mac.getInstance("HmacSHA1")

    md.init(new SecretKeySpec(serverHmacSeed, "HmacSHA1"))
    md.update(key)
    val serverKey = md.doFinal()

    md.init(new SecretKeySpec(clientHmacSeed, "HmacSHA1"))
    md.update(key)
    val clientKey = md.doFinal()

    serverCrypt = new RC4(serverKey)
    serverCrypt.cryptToByteArray(new Array[Byte](1024))
    clientCrypt = new RC4(clientKey)
    clientCrypt.cryptToByteArray(new Array[Byte](1024))

    _initialized = true
  }
} 
Example 17
Source File: GameHeaderCryptTBC.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

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

class GameHeaderCryptTBC extends GameHeaderCrypt {

  override def init(key: Array[Byte]): Unit = {
    super.init(key)

    val hmacSeed = Array(
      0x38, 0xA7, 0x83, 0x15, 0xF8, 0x92, 0x25, 0x30, 0x71, 0x98, 0x67, 0xB1, 0x8C, 0x04, 0xE2, 0xAA
    ).map(_.toByte)
    val md = Mac.getInstance("HmacSHA1")
    md.init(new SecretKeySpec(hmacSeed, "HmacSHA1"))
    md.update(key)
    _key = md.doFinal()
  }
} 
Example 18
Source File: data.scala    From redis4cats   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.redis4cats

import cats.effect.Sync
import cats.syntax.functor._
import dev.profunktor.redis4cats.JavaConversions._
import io.lettuce.core.{ ReadFrom => JReadFrom }
import io.lettuce.core.codec.{ ByteArrayCodec, CipherCodec, CompressionCodec, RedisCodec => JRedisCodec, StringCodec }
import io.lettuce.core.{ KeyScanCursor => JKeyScanCursor }
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec

object data {

  final case class RedisChannel[K](underlying: K) extends AnyVal

  final case class RedisCodec[K, V](underlying: JRedisCodec[K, V]) extends AnyVal
  final case class NodeId(value: String) extends AnyVal

  final case class KeyScanCursor[K](underlying: JKeyScanCursor[K]) extends AnyVal {
    def keys: List[K]  = underlying.getKeys.asScala.toList
    def cursor: String = underlying.getCursor
  }

  object RedisCodec {
    val Ascii: RedisCodec[String, String]           = RedisCodec(StringCodec.ASCII)
    val Utf8: RedisCodec[String, String]            = RedisCodec(StringCodec.UTF8)
    val Bytes: RedisCodec[Array[Byte], Array[Byte]] = RedisCodec(ByteArrayCodec.INSTANCE)

    
    def decryptSupplier[F[_]: Sync](key: SecretKeySpec): F[CipherCodec.CipherSupplier] =
      cipherSupplier[F](key, Cipher.DECRYPT_MODE)

    private def cipherSupplier[F[_]: Sync](key: SecretKeySpec, mode: Int): F[CipherCodec.CipherSupplier] = {
      val mkCipher =
        F.delay {
          val cipher: Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
          cipher.init(mode, key)
          cipher
        }

      mkCipher.map { cipher =>
        new CipherCodec.CipherSupplier {
          override def get(kd: CipherCodec.KeyDescriptor): Cipher = cipher
        }
      }
    }

  }

  object ReadFrom {
    val Master           = JReadFrom.MASTER
    val MasterPreferred  = JReadFrom.MASTER_PREFERRED
    val Nearest          = JReadFrom.NEAREST
    val Replica          = JReadFrom.REPLICA
    val ReplicaPreferred = JReadFrom.REPLICA_PREFERRED
  }

} 
Example 19
Source File: S3UploadController.scala    From scuruto   with MIT License 5 votes vote down vote up
package controller.upload

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

import _root_.controller.UploadController
import lib._
import model.Upload
import model.typebinder.UserId
import org.apache.commons.codec.binary.Base64
import org.joda.time.format.DateTimeFormat
import org.joda.time._
import skinny._

object S3UploadController extends UploadController {

  override def destination: UploadDestination = UploadDestination("s3")

  // --------------
  // sign
  val AWS_ACCESS_KEY = "AWS_ACCESS_KEY"
  val AWS_SECRET_KEY = "AWS_SECRET_KEY"
  def sign: String = {
    val userId = policiesParams.getAs[UserId]("user_id").get
    val filename = params("filename")
    val ext = filename.split('.').last
    val seed = userId.value + "_" + DateTime.now().toString + "_" + filename
    val baseDir = SkinnyConfig.stringConfigValue("upload.s3.baseDir").getOrElse("")
    val path = baseDir + new Sha1Digest(seed).digestString + "." + ext

    val bucket = SkinnyConfig.stringConfigValue("upload.s3.bucket").getOrElse(throw new IllegalArgumentException)
    val policyDocument = toJSONString(Map(
      "expiration" -> new DateTime(DateTimeZone.UTC).plusMinutes(1).toString(DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z")),
      "conditions" -> Array(
        Map("bucket" -> bucket),
        Map("key" -> path),
        Map("Content-Type" -> policiesParams.getAs("content_type")),
        Array("content-length-range", policiesParams.getAs("size"), policiesParams.getAs("size"))
      )
    ), underscoreKeys = false)
    val policy = Base64.encodeBase64String(policyDocument.getBytes("UTF-8"))
    val hmac = Mac.getInstance("HmacSHA1")
    hmac.init(new SecretKeySpec(sys.env(AWS_SECRET_KEY).getBytes("UTF-8"), "HmacSHA1"))
    val signature = Base64.encodeBase64String(hmac.doFinal(policy.getBytes("UTF-8")))

    // add to uploads table
    Upload.createWithAttributes(
      'user_id -> userId.value,
      'original_filename -> filename,
      'filename -> path
    )

    // response
    toJSONString(Map(
      "url" -> s"https://$bucket.s3.amazonaws.com/",
      "form" -> Map(
        "AWSAccessKeyId" -> sys.env(AWS_ACCESS_KEY),
        "signature" -> signature,
        "policy" -> policy,
        "key" -> path,
        "Content-Type" -> policiesParams.getAs("content_type")
      )
    ), underscoreKeys = false)
  }

  // --------------
  override def upload: Any = throw new UnsupportedOperationException

  // --------------
  override def uploadedFileBaseUrl: UploadedBaseURL = UploadedBaseURL("s3")

} 
Example 20
Source File: CryptoStreamUtils.scala    From sparkoscope   with Apache License 2.0 5 votes vote down vote up
package org.apache.spark.security

import java.io.{InputStream, OutputStream}
import java.util.Properties
import javax.crypto.KeyGenerator
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec}

import org.apache.commons.crypto.random._
import org.apache.commons.crypto.stream._

import org.apache.spark.SparkConf
import org.apache.spark.internal.Logging
import org.apache.spark.internal.config._


  private[this] def createInitializationVector(properties: Properties): Array[Byte] = {
    val iv = new Array[Byte](IV_LENGTH_IN_BYTES)
    val initialIVStart = System.currentTimeMillis()
    CryptoRandomFactory.getCryptoRandom(properties).nextBytes(iv)
    val initialIVFinish = System.currentTimeMillis()
    val initialIVTime = initialIVFinish - initialIVStart
    if (initialIVTime > 2000) {
      logWarning(s"It costs ${initialIVTime} milliseconds to create the Initialization Vector " +
        s"used by CryptoStream")
    }
    iv
  }
} 
Example 21
Source File: Crypto.scala    From akka-http-session   with Apache License 2.0 5 votes vote down vote up
package com.softwaremill.session

import java.security.MessageDigest
import java.util

import com.softwaremill.session.SessionUtil._
import javax.crypto.spec.SecretKeySpec
import javax.crypto.{Cipher, Mac}

object Crypto {
  def sign_HmacSHA1_hex(message: String, secret: String): String = {
    val key = secret.getBytes("UTF-8")
    val mac = Mac.getInstance("HmacSHA1")
    mac.init(new SecretKeySpec(key, "HmacSHA1"))
    toHexString(mac.doFinal(message.getBytes("utf-8")))
  }

  def sign_HmacSHA256_base64_v0_5_2(message: String, secret: String): String = {
    val key = secret.getBytes("UTF-8")
    val mac = Mac.getInstance("HmacSHA256")
    mac.init(new SecretKeySpec(key, "HmacSHA256"))
    SessionUtil.toBase64_v0_5_2(mac.doFinal(message.getBytes("utf-8")))
  }

  def encrypt_AES(value: String, secret: String): String = {
    val raw = util.Arrays.copyOf(secret.getBytes("utf-8"), 16)
    val skeySpec = new SecretKeySpec(raw, "AES")
    val cipher = Cipher.getInstance("AES")
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec)
    toHexString(cipher.doFinal(value.getBytes("utf-8")))
  }

  def decrypt_AES(value: String, secret: String): String = {
    val raw = util.Arrays.copyOf(secret.getBytes("utf-8"), 16)
    val skeySpec = new SecretKeySpec(raw, "AES")
    val cipher = Cipher.getInstance("AES")
    cipher.init(Cipher.DECRYPT_MODE, skeySpec)
    new String(cipher.doFinal(hexStringToByte(value)))
  }

  def hash_SHA256(value: String): String = {
    val digest = MessageDigest.getInstance("SHA-256")
    toHexString(digest.digest(value.getBytes("UTF-8")))
  }
} 
Example 22
Source File: JwsAlgorithm.scala    From akka-http-session   with Apache License 2.0 5 votes vote down vote up
package com.softwaremill.session

import java.nio.charset.StandardCharsets.UTF_8
import java.security.spec.PKCS8EncodedKeySpec
import java.security.{KeyFactory, PrivateKey, Signature}
import java.util.Base64

import com.typesafe.config.Config
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

import scala.util.{Failure, Success, Try}

sealed trait JwsAlgorithm {
  def value: String
  def sign(message: String): String

  protected def encode(bytes: Array[Byte]): String =
    Base64.getUrlEncoder.withoutPadding().encodeToString(bytes)
}

object JwsAlgorithm {

  case class Rsa(privateKey: PrivateKey) extends JwsAlgorithm {

    override val value: String = "RS256"

    override def sign(message: String): String = {
      val privateSignature: Signature = Signature.getInstance("SHA256withRSA")
      privateSignature.initSign(privateKey)
      privateSignature.update(message.getBytes(UTF_8))

      encode(privateSignature.sign())
    }
  }

  object Rsa {

    def fromConfig(jwsConfig: Config): Try[Rsa] = {

      def readKeyFromConf(): Try[String] = {
        val configKey = "rsa-private-key"
        Option(jwsConfig.hasPath(configKey))
          .filter(identity)
          .flatMap(_ => Option(jwsConfig.getString(configKey)))
          .filter(_.trim.nonEmpty)
          .map(_.replaceAll("\\s", "").replaceAll("-----[^-]+-----", ""))
          .map(Success(_))
          .getOrElse(Failure(new IllegalArgumentException(
            "akka.http.session.jws.rsa-private-key must be defined in order to use alg = RS256")))
      }

      readKeyFromConf()
        .flatMap { key =>
          Try {
            val keyFactory = KeyFactory.getInstance("RSA")
            val privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder.decode(key)))
            Rsa(privateKey)
          }.recoverWith {
            case ex => Failure(new IllegalArgumentException("Invalid RSA private key", ex))
          }
        }
    }
  }

  case class HmacSHA256(serverSecret: String) extends JwsAlgorithm {
    override val value: String = "HS256"
    override def sign(message: String): String = {
      val key = serverSecret.getBytes("UTF-8")
      val mac = Mac.getInstance("HmacSHA256")
      mac.init(new SecretKeySpec(key, "HmacSHA256"))
      encode(mac.doFinal(message.getBytes("utf-8")))
    }
  }

} 
Example 23
Source File: Hmac.scala    From incubator-toree   with Apache License 2.0 5 votes vote down vote up
package org.apache.toree.communication.security

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

import org.apache.toree.communication.security.HmacAlgorithm.HmacAlgorithm

object HmacAlgorithm extends Enumeration {
  type HmacAlgorithm = Value

  def apply(key: String) = Value(key)

  val MD5     = Value("HmacMD5")
  val SHA1    = Value("HmacSHA1")
  val SHA256  = Value("HmacSHA256")
}

object Hmac {
  
  def apply(key: String, algorithm: HmacAlgorithm = HmacAlgorithm.SHA256) =
    new Hmac(key, algorithm)
  
  def newMD5(key: String): Hmac     = this(key, HmacAlgorithm.MD5)
  def newSHA1(key: String): Hmac    = this(key, HmacAlgorithm.SHA1)
  def newSHA256(key: String): Hmac  = this(key, HmacAlgorithm.SHA256)
}

class Hmac(
  val key: String,
  val algorithm: HmacAlgorithm = HmacAlgorithm.SHA256
) {

  private var mac: Mac = _
  private var secretKeySpec: SecretKeySpec = _

  if (key.nonEmpty) {
    mac = Mac.getInstance(algorithm.toString)
    secretKeySpec = new SecretKeySpec(key.getBytes, algorithm.toString)
    mac.init(secretKeySpec)
  }

  def apply(items: String*): String = digest(items)

  def digest(items: Seq[String]): String = if (key.nonEmpty) {
    mac synchronized {
      items.map(_.getBytes("UTF-8")).foreach(mac.update)
      mac.doFinal().map("%02x" format _).mkString
    }
  } else ""
} 
Example 24
Source File: EncryptorActor.scala    From changestream   with MIT License 5 votes vote down vote up
package changestream.actors

import java.nio.charset.Charset
import java.util.Base64
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec

import akka.actor.Actor
import com.typesafe.config.{Config, ConfigFactory}
import kamon.Kamon
import org.slf4j.LoggerFactory
import spray.json._

object EncryptorActor {
  case class Plaintext(message: JsObject)
  case class Ciphertext(message: JsObject)
}

class EncryptorActor (
                        config: Config = ConfigFactory.load().getConfig("changestream.encryptor")
                      ) extends Actor {
  import EncryptorActor._

  protected val log = LoggerFactory.getLogger(getClass)
  protected val timingMetric = Kamon.timer("changestream.crypto_time")


  private val charset = Charset.forName("UTF-8")
  private val decoder = Base64.getDecoder
  private val encoder = Base64.getEncoder

  private val cipher = config.getString("cipher")
  private val decodedKey = decoder.decode(config.getString("key"))
  private val originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, cipher)
  private val encryptEngine = Cipher.getInstance(cipher)
  private val decryptEngine = Cipher.getInstance(cipher)

  private val encryptFields = config.getString("encrypt-fields").toLowerCase().split(',').map(_.trim)

  override def preStart() = {
    encryptEngine.init(Cipher.ENCRYPT_MODE, originalKey)
    decryptEngine.init(Cipher.DECRYPT_MODE, originalKey)
  }

  def receive = {
    case Plaintext(message) =>
      val timer = timingMetric.refine("mode" -> "encrypt").start()
      val result = encryptFields(message)
      timer.stop()

      sender() ! result

    case Ciphertext(message) =>
      val timer = timingMetric.refine("mode" -> "decrypt").start()
      val result = decryptFields(message)
      timer.stop()

      sender() ! result
  }

  private def encryptFields(message: JsObject, jsonPath: String = ""): JsObject = {
    JsObject(
      message.fields.map({
        case (k:String, plaintextValue:JsValue) if encryptFields.contains(getNextJsonPath(jsonPath, k)) =>
          val plaintextBytes = plaintextValue.compactPrint.getBytes(charset)
          val cipherText = encryptEngine.doFinal(plaintextBytes)
          val v = encoder.encodeToString(cipherText)
          k -> JsString(v)
        case (k:String, jsObj: JsObject) =>
          k -> encryptFields(jsObj, getNextJsonPath(jsonPath, k))
        case (k:String, v: JsValue) =>
          k -> v
      })
    )
  }

  private def decryptFields(message: JsObject, jsonPath: String = ""): JsObject = {
    JsObject(
      message.fields.map({
        case (k:String, JsString(ciphertextValue)) if encryptFields.contains(getNextJsonPath(jsonPath, k)) =>
          val ciphertextBytes = decoder.decode(ciphertextValue)
          val plaintextBytes = decryptEngine.doFinal(ciphertextBytes)
          val v = new String(plaintextBytes, charset).parseJson
          k -> v
        case (k:String, jsObj: JsObject) =>
          k -> decryptFields(jsObj, getNextJsonPath(jsonPath, k))
        case (k:String, v: JsValue) =>
          k -> v
      })
    )
  }

  private def getNextJsonPath(jsonPath: String, nextPath: String): String = {
    Seq(jsonPath, nextPath).filter(_.nonEmpty).mkString(".")
  }
} 
Example 25
Source File: WithMacSigningKey.scala    From tsec   with MIT License 5 votes vote down vote up
package tsec.mac.jca

import javax.crypto.{KeyGenerator, Mac, SecretKey}
import javax.crypto.spec.SecretKeySpec
import cats.Id
import cats.effect.Sync
import cats.instances.either._
import cats.syntax.either._
import tsec.keygen.symmetric.{IdKeyGen, SymmetricKeyGen}
import tsec.mac.{MAC, MacAPI}

protected[tsec] abstract class WithMacSigningKey[A](algo: String, keyLenBits: Int)
    extends MacKeyGenerator[A]
    with MacAPI[A, MacSigningKey] {

  implicit def syncMac[F[_]](implicit F: Sync[F]): JCAMessageAuth[F, A] =
    new JCAMessageAuth[F, A]() {

      def algorithm: String = algo

      protected[tsec] def genInstance: F[Mac] = F.delay(Mac.getInstance(algo))

      protected[tsec] def signInternal(m: Mac, k: SecretKey, content: Array[Byte]): F[MAC[A]] = F.delay {
        m.init(k)
        MAC[A](m.doFinal(content))
      }
    }

  implicit val macInstanceEither: JCAMessageAuth[MacErrorM, A] =
    new JCAMessageAuth[MacErrorM, A]() {

      def algorithm: String = algo

      protected[tsec] def genInstance: MacErrorM[Mac] = Either.catchNonFatal(Mac.getInstance(algo))

      protected[tsec] def signInternal(m: Mac, k: SecretKey, content: Array[Byte]): MacErrorM[MAC[A]] =
        Either.catchNonFatal {
          m.init(k)
          MAC[A](m.doFinal(content))
        }
    }

  implicit def genKeyMac[F[_]](implicit F: Sync[F]): MacKeyGen[F, A] =
    new SymmetricKeyGen[F, A, MacSigningKey] {
      def generateKey: F[MacSigningKey[A]] =
        F.delay(impl.generateKeyUnsafe())

      def build(rawKey: Array[Byte]): F[MacSigningKey[A]] =
        F.delay(MacSigningKey[A](new SecretKeySpec(rawKey, algo)))
    }

  implicit def genKeyMacError: MacKeyGen[MacErrorM, A] = new MacKeyGen[MacErrorM, A] {
    def generateKey: MacErrorM[MacSigningKey[A]] =
      Either.catchNonFatal(impl.generateKeyUnsafe())

    def build(rawKey: Array[Byte]): MacErrorM[MacSigningKey[A]] =
      Either.catchNonFatal(impl.buildKeyUnsafe(rawKey))
  }

  implicit val idKeygenMac: IdKeyGen[A, MacSigningKey] =
    new IdKeyGen[A, MacSigningKey] {
      def generateKey: Id[MacSigningKey[A]] =
        impl.generateKeyUnsafe()

      def build(rawKey: Array[Byte]): Id[MacSigningKey[A]] =
        impl.buildKeyUnsafe(rawKey)
    }

  object impl {
    def generator: KeyGenerator = KeyGenerator.getInstance(algo)

    def generateKeyUnsafe(): MacSigningKey[A] = MacSigningKey.fromJavaKey[A](generator.generateKey())

    def buildKeyUnsafe(key: Array[Byte]): MacSigningKey[A] =
      MacSigningKey.fromJavaKey[A](new SecretKeySpec(key, algo))
  }

  implicit def keyGen: MacKeyGenerator[A] = this
}