cdslogviewer/app/auth/HMAC.scala (61 lines of code) (raw):

package auth import play.api.{Configuration, Logger} import play.api.mvc.RequestHeader import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec import java.security._ import org.apache.commons.codec.binary.Hex import scala.jdk.CollectionConverters._ object HMAC { val logger: Logger = Logger(this.getClass) private val checksumXtractor = "^([\\w\\d\\-]+)=(.*)$".r /** * generate the HMAC digest of a string, given a shared secret to encrypt it with * @param sharedSecret passphrase to encrypt with * @param preHashString content to digest * @return Base64 encoded string of the hmac digest */ def generateHMAC(sharedSecret: String, preHashString: String): String = { val secret = new SecretKeySpec(sharedSecret.getBytes, "HmacSHA384") //Crypto Funs : 'SHA256' , 'HmacSHA1' val mac = Mac.getInstance("HmacSHA384") mac.init(secret) val hashString: Array[Byte] = mac.doFinal(preHashString.getBytes) val encoded = Hex.encodeHexString(hashString) //new String(hashString.map(_.toChar)) return encoded } def extract_checksum(digestHeader:String) = { val matches = checksumXtractor.findAllIn(digestHeader) if(matches.nonEmpty) { if(matches.group(1)!="SHA-384") { logger.error(s"Only SHA-384 digest is accepted, got ${matches.group(1)}") None } else { Some(matches.group(2)) } } else { None } } /** * Take the relevant request headers and calculate what the digest should be * @param request Play request, must contain the headers Date, Content-Length, X-Sha384-Checksum * @param sharedSecret passphrase to encrypt with * @return Option containing the hmac digest, or None if any headers were missing */ def calculateHmac(request: RequestHeader, sharedSecret: String, prependDeploymentPath:Boolean=true)(implicit config:Configuration):Option[String] = try { request.headers.get("Digest").flatMap(extract_checksum).map(checksum=>{ val full_uri = prependDeploymentPath match { case true=>config.getOptional[String]("deployment-root").getOrElse("") + request.uri case false=>request.uri } logger.debug(s"full_uri: $full_uri") logger.debug(s"date: ${request.headers.get("Date")}") logger.debug(s"content-type: ${request.headers.get("Content-Type")}") logger.debug(s"checksum: $checksum") logger.debug(s"method: ${request.method}") val string_to_sign = s"$full_uri\n${request.headers.get("Date").get}\n${request.headers.get("Content-Type").getOrElse("")}\n$checksum\n${request.method}" logger.debug(s"Incoming request, string to sign: $string_to_sign") val hmac = generateHMAC(sharedSecret, string_to_sign) logger.debug(s"HMAC generated: $hmac") hmac }) } catch { case e:java.util.NoSuchElementException=> logger.debug(e.toString) None } /** * Returns information about the available crypto algorithms on this platform * @return */ def getAlgos:Array[(String,String,String)] = { for { provider <- Security.getProviders key <- provider.stringPropertyNames.asScala } yield Tuple3(provider.getName, key, provider.getProperty(key)) } }