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

scodec.codecs.ChecksumFactory.scala Maven / Gradle / Ivy

There is a newer version: 1.11.3
Show newest version
package scodec
package codecs

import java.security.MessageDigest
import java.util.Arrays
import java.util.zip.{ CRC32, Adler32, Checksum }
import scodec.bits.ByteVector

/**
 * Creates checksum implementations of [[SignerFactory]].
 */
object ChecksumFactory {

  /** Creates a `java.security.Digest` factory for the specified algorithm. */
  def digest(algorithm: String): SignerFactory = new ChecksumFactory {
    def newSigner: Signer = new DigestSigner(MessageDigest.getInstance(algorithm))
  }

  /** Signer factory that does not have a distinct verifier. */
  private trait ChecksumFactory extends SignerFactory {
    def newVerifier: Signer = newSigner
  }

  /** Fletcher-16 checksum. */
  val fletcher16: SignerFactory = new ChecksumFactory {
    def newSigner = new Fletcher16Checksum
  }

  /** CRC-32 checksum. */
  val crc32: SignerFactory = new ChecksumFactory {
    def newSigner = new ZipChecksumSigner(new CRC32())
  }

  /** Adler-32 checksum. */
  val adler32: SignerFactory = new ChecksumFactory {
    def newSigner = new ZipChecksumSigner(new Adler32())
  }

  /** xor checksum. */
  val xor: SignerFactory = new ChecksumFactory {
    def newSigner = new XorSigner
  }

  /** `java.security.Digest` implementation of Signer. */
  private class DigestSigner(impl: MessageDigest) extends Signer {
    def update(data: Array[Byte]): Unit = impl.update(data)
    def sign: Array[Byte] = impl.digest
    def verify(signature: Array[Byte]): Boolean = MessageDigest.isEqual(impl.digest(), signature)
  }

  /** http://en.wikipedia.org/wiki/Fletcher's_checksum */
  private class Fletcher16Checksum extends Signer {
    var checksum = (0, 0)
    def update(data: Array[Byte]): Unit = {
      checksum = data.foldLeft(checksum) { (p, b) =>
        val lsb = (p._2 + (0xff & b)) % 255
        ((p._1 + lsb) % 255, lsb)
      }
    }
    def sign: Array[Byte] = Array(checksum._1.asInstanceOf[Byte], checksum._2.asInstanceOf[Byte])
    def verify(signature: Array[Byte]): Boolean = Arrays.equals(sign, signature)
  }

  /** `java.util.zip.Checksum` implementation of Signer. */
  private class ZipChecksumSigner(impl: Checksum) extends Signer {
    def update(data: Array[Byte]): Unit = impl.update(data, 0, data.length)
    def sign: Array[Byte] = ByteVector.fromLong(impl.getValue()).drop(4).toArray
    def verify(signature: Array[Byte]): Boolean = MessageDigest.isEqual(sign, signature)
  }

  private class XorSigner extends Signer {
    var data: Array[Byte] = _

    def update(data: Array[Byte]): Unit = this.data = data
    def sign: Array[Byte] = Array(data.reduce((b1, b2) => (b1 ^ b2).toByte))
    def verify(signature: Array[Byte]): Boolean = sign sameElements signature
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy