All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.beangle.security.codec.PasswordEncoder.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2005, The Beangle Software.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package org.beangle.security.codec

import java.security.MessageDigest

import org.beangle.commons.codec.binary.{Base64, Hex}
import org.beangle.commons.lang.Arrays

/**
 * @author chaostone
 */
trait PasswordEncoder {
  def verify(digest: String, password: String): Boolean

  def generate(password: String, saltHex: String, algorithm: String): String
}

object DefaultPasswordEncoder extends PasswordEncoder {

  override def verify(digest: String, password: String): Boolean = {
    var alg: String = null
    var size = 0
    var digestContent = digest
    if (digest.regionMatches(true, 0, "{SHA}", 0, 5)) {
      digestContent = digest.substring(5)
      alg = "SHA-1"
      size = 20
    } else if (digest.regionMatches(true, 0, "{SSHA}", 0, 6)) {
      digestContent = digest.substring(6)
      alg = "SHA-1"
      size = 20
    } else if (digest.regionMatches(true, 0, "{MD5}", 0, 5)) {
      digestContent = digest.substring(5)
      alg = "MD5"
      size = 16
    } else if (digest.regionMatches(true, 0, "{SMD5}", 0, 6)) {
      digestContent = digest.substring(6)
      alg = "MD5"
      size = 16
    } else {
      return digestContent.equals(password)
    }

    val msgDigest = MessageDigest.getInstance(alg)

    val hs =
      if (alg.contains("MD5")) {
        if (digestContent.length == 32 && !digestContent.contains("=")) {
          split(Hex.decode(digestContent), size)
        } else {
          split(Base64.decode(digestContent), size)
        }
      } else {
        split(Base64.decode(digestContent), size)
      }

    msgDigest.reset()
    msgDigest.update(password.getBytes)
    msgDigest.update(hs._2)
    MessageDigest.isEqual(hs._1, msgDigest.digest())
  }

  def generate(password: String, salts: String, algorithm: String): String = {
    val alg =
      if (algorithm.equalsIgnoreCase("sha")) "SHA-1"
      else if (algorithm.equalsIgnoreCase("md5")) "MD5"
      else algorithm

    val msgDigest = MessageDigest.getInstance(alg)
    val salt = if (salts == null) new Array[Byte](0) else salts.getBytes
    val label =
      if (alg.startsWith("SHA")) {
        if (salt.length <= 0) "{SHA}" else "{SSHA}"
      }
      else if (alg.startsWith("MD5")) {
        if (salt.length <= 0) "{MD5}" else "{SMD5}"
      }
      else null
    msgDigest.reset()
    msgDigest.update(password.getBytes)
    msgDigest.update(salt)
    val pwhash = msgDigest.digest()
    val digest = new StringBuilder(if (null == label) "" else label)
    val hash =
      if (alg.contains("MD5")) {
        Hex.encode(Arrays.concat(pwhash, salt))
      } else {
        Base64.encode(Arrays.concat(pwhash, salt))
      }
    digest.append(hash)
    digest.toString
  }

  private def split(src: Array[Byte], n: Int): (Array[Byte], Array[Byte]) = {
    var l: Array[Byte] = null
    var r: Array[Byte] = null
    if (src.length <= n) {
      l = src
      r = new Array(0)
    } else {
      l = new Array[Byte](n)
      r = new Array[Byte](src.length - n)
      System.arraycopy(src, 0, l, 0, n)
      System.arraycopy(src, n, r, 0, r.length)
    }
    (l, r)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy