Added Hashing for InputStreams
This commit is contained in:
parent
bdff9f7282
commit
72a1b21f3f
|
@ -15,10 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package dorkbox.bytes
|
package dorkbox.bytes
|
||||||
|
|
||||||
|
import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.close
|
||||||
import net.jpountz.xxhash.StreamingXXHash32
|
import net.jpountz.xxhash.StreamingXXHash32
|
||||||
import net.jpountz.xxhash.StreamingXXHash64
|
import net.jpountz.xxhash.StreamingXXHash64
|
||||||
import net.jpountz.xxhash.XXHashFactory
|
import net.jpountz.xxhash.XXHashFactory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
|
@ -236,6 +238,44 @@ private fun hash(byteArray: ByteArray, start: Int, length: Int, digest: MessageD
|
||||||
return digest.digest()
|
return digest.digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hash(string: String, start: Int, length: Int, digest: MessageDigest): ByteArray {
|
||||||
|
val charToBytes = string.toBytes16(start, length)
|
||||||
|
digest.reset()
|
||||||
|
digest.update(charToBytes, 0, charToBytes.size)
|
||||||
|
return digest.digest()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hash(inputStream: InputStream, bufferSize: Int = 4096, digest: MessageDigest): ByteArray {
|
||||||
|
val buffer = ByteArray(bufferSize)
|
||||||
|
var read: Int
|
||||||
|
|
||||||
|
digest.reset()
|
||||||
|
|
||||||
|
inputStream.use {
|
||||||
|
while (it.read(buffer).also { read = it } > 0) {
|
||||||
|
digest.update(buffer, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return digest.digest()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hash(file: File, start: Long, length: Long, bufferSize: Int, digest: MessageDigest): ByteArray {
|
||||||
|
require(file.isFile) { "Unable open as file: ${file.absolutePath}" }
|
||||||
|
require(file.canRead()) { "Unable to read file: ${file.absolutePath}" }
|
||||||
|
|
||||||
|
require(start >= 0) { "Start ($start) must be >= 0" }
|
||||||
|
require(length >= 0) { "Length ($length) must be >= 0" }
|
||||||
|
require(start < file.length()) { "Start ($start) position must be smaller than the size of the file" }
|
||||||
|
|
||||||
|
file.inputStream().use {
|
||||||
|
digest.reset()
|
||||||
|
updateDigest(digest, it, bufferSize, start, length)
|
||||||
|
return digest.digest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Deprecated("Do not use this, it is insecure and prone to attack!")
|
@Deprecated("Do not use this, it is insecure and prone to attack!")
|
||||||
fun ByteArray.md5(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digestMd5.get())
|
fun ByteArray.md5(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digestMd5.get())
|
||||||
fun ByteArray.sha1(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest1.get())
|
fun ByteArray.sha1(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest1.get())
|
||||||
|
@ -245,6 +285,7 @@ fun ByteArray.sha512(start: Int = 0, length: Int = this.size): ByteArray = hash(
|
||||||
fun ByteArray.sha3_256(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest3_256.get())
|
fun ByteArray.sha3_256(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest3_256.get())
|
||||||
fun ByteArray.sha3_384(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest3_384.get())
|
fun ByteArray.sha3_384(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest3_384.get())
|
||||||
fun ByteArray.sha3_512(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest3_512.get())
|
fun ByteArray.sha3_512(start: Int = 0, length: Int = this.size): ByteArray = hash(this, start, length, Hash.digest3_512.get())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param seed used to initialize the hash value (for the xxhash seed), use whatever value you want, but always the same
|
* @param seed used to initialize the hash value (for the xxhash seed), use whatever value you want, but always the same
|
||||||
*/
|
*/
|
||||||
|
@ -255,6 +296,7 @@ fun ByteArray.xxHash32(seed: Int = -0x31bf6a3c, start: Int = 0, length: Int = th
|
||||||
hash32.update(this, start, length)
|
hash32.update(this, start, length)
|
||||||
return hash32.value
|
return hash32.value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param seed used to initialize the hash value (for the xxhash seed), use whatever value you want, but always the same
|
* @param seed used to initialize the hash value (for the xxhash seed), use whatever value you want, but always the same
|
||||||
*/
|
*/
|
||||||
|
@ -267,13 +309,6 @@ fun ByteArray.xxHash64(seed: Long = -0x31bf6a3c, start: Int = 0, length: Int = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun hash(string: String, start: Int, length: Int, digest: MessageDigest): ByteArray {
|
|
||||||
val charToBytes = string.toCharArray().toBytes16(start, length)
|
|
||||||
digest.reset()
|
|
||||||
digest.update(charToBytes, 0, charToBytes.size)
|
|
||||||
return digest.digest()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the MD5 hash of the specified string, as UTF-16
|
* gets the MD5 hash of the specified string, as UTF-16
|
||||||
*/
|
*/
|
||||||
|
@ -307,6 +342,7 @@ fun String.sha3_384(start: Int = 0, length: Int = this.length): ByteArray = hash
|
||||||
* gets the SHA3_512 hash of the specified string, as UTF-16
|
* gets the SHA3_512 hash of the specified string, as UTF-16
|
||||||
*/
|
*/
|
||||||
fun String.sha3_512(start: Int = 0, length: Int = this.length): ByteArray = hash(this, start, length, Hash.digest3_512.get())
|
fun String.sha3_512(start: Int = 0, length: Int = this.length): ByteArray = hash(this, start, length, Hash.digest3_512.get())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the xxHash32 of the string, as UTF-16
|
* gets the xxHash32 of the string, as UTF-16
|
||||||
*
|
*
|
||||||
|
@ -320,6 +356,7 @@ fun String.xxHash32(seed: Int = -0x31bf6a3c, start: Int = 0, length: Int = this.
|
||||||
hash32.update(charToBytes, 0, charToBytes.size)
|
hash32.update(charToBytes, 0, charToBytes.size)
|
||||||
return hash32.value
|
return hash32.value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the xxHash64 of the string, as UTF-16
|
* gets the xxHash64 of the string, as UTF-16
|
||||||
*
|
*
|
||||||
|
@ -384,6 +421,7 @@ fun String.sha3_384WithSalt(saltBytes: ByteArray, start: Int = 0, length: Int =
|
||||||
*/
|
*/
|
||||||
fun String.sha3_512WithSalt(saltBytes: ByteArray, start: Int = 0, length: Int = this.length + saltBytes.size): ByteArray =
|
fun String.sha3_512WithSalt(saltBytes: ByteArray, start: Int = 0, length: Int = this.length + saltBytes.size): ByteArray =
|
||||||
hashWithSalt(this, saltBytes, start, length, Hash.digest3_512.get())
|
hashWithSalt(this, saltBytes, start, length, Hash.digest3_512.get())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the xxHash32 + SALT of the string, as UTF-16
|
* gets the xxHash32 + SALT of the string, as UTF-16
|
||||||
*
|
*
|
||||||
|
@ -403,6 +441,7 @@ fun String.xxHash32WithSalt(saltBytes: ByteArray, seed: Int = -0x31bf6a3c, start
|
||||||
hash32.update(saltBytes, 0, saltBytes.size)
|
hash32.update(saltBytes, 0, saltBytes.size)
|
||||||
return hash32.value
|
return hash32.value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the xxHash64 + SALT of the string, as UTF-16
|
* gets the xxHash64 + SALT of the string, as UTF-16
|
||||||
*
|
*
|
||||||
|
@ -471,6 +510,7 @@ fun ByteArray.sha3_384WithSalt(saltBytes: ByteArray, start: Int = 0, length: Int
|
||||||
*/
|
*/
|
||||||
fun ByteArray.sha3_512WithSalt(saltBytes: ByteArray, start: Int = 0, length: Int = this.size + saltBytes.size): ByteArray =
|
fun ByteArray.sha3_512WithSalt(saltBytes: ByteArray, start: Int = 0, length: Int = this.size + saltBytes.size): ByteArray =
|
||||||
hashWithSalt(this, saltBytes, start, length, Hash.digest3_512.get())
|
hashWithSalt(this, saltBytes, start, length, Hash.digest3_512.get())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the xxHash32 + SALT of the byte array
|
* gets the xxHash32 + SALT of the byte array
|
||||||
*
|
*
|
||||||
|
@ -484,6 +524,7 @@ fun ByteArray.xxHash32WithSalt(saltBytes: ByteArray, seed: Int = -0x31bf6a3c, st
|
||||||
hash32.update(saltBytes, 0, saltBytes.size)
|
hash32.update(saltBytes, 0, saltBytes.size)
|
||||||
return hash32.value
|
return hash32.value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the xxHash64 + SALT of the byte array
|
* gets the xxHash64 + SALT of the byte array
|
||||||
*
|
*
|
||||||
|
@ -499,25 +540,6 @@ fun ByteArray.xxHash64WithSalt(saltBytes: ByteArray, seed: Long = -0x31bf6a3c, s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun hash(file: File, start: Long, length: Long, bufferSize: Int, digest: MessageDigest): ByteArray {
|
|
||||||
require(file.isFile) { "Unable open as file: ${file.absolutePath}" }
|
|
||||||
require(file.canRead()) { "Unable to read file: ${file.absolutePath}" }
|
|
||||||
|
|
||||||
require(start >= 0) { "Start ($start) must be >= 0" }
|
|
||||||
require(length >= 0) { "Length ($length) must be >= 0" }
|
|
||||||
require(start < file.length()) { "Start ($start) position must be smaller than the size of the file" }
|
|
||||||
|
|
||||||
file.inputStream().use {
|
|
||||||
digest.reset()
|
|
||||||
updateDigest(digest, it, bufferSize, start, length)
|
|
||||||
return digest.digest()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the SHA1 hash of the file
|
* gets the SHA1 hash of the file
|
||||||
*/
|
*/
|
||||||
|
@ -597,3 +619,77 @@ fun File.xxHash64(start: Long = 0L, length: Long = this.length(), bufferSize: In
|
||||||
return hash64.value
|
return hash64.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the SHA1 hash of the input stream
|
||||||
|
*/
|
||||||
|
fun InputStream.sha1(bufferSize: Int = 4096): ByteArray = hash(this, bufferSize, Hash.digest1.get())
|
||||||
|
/**
|
||||||
|
* gets the SHA256 hash of the file
|
||||||
|
*/
|
||||||
|
fun InputStream.sha256(bufferSize: Int = 4096): ByteArray = hash(this, bufferSize, Hash.digest256.get())
|
||||||
|
/**
|
||||||
|
* gets the SHA384 hash of the file
|
||||||
|
*/
|
||||||
|
fun InputStream.sha384(bufferSize: Int = 4096): ByteArray = hash(this, bufferSize, Hash.digest384.get())
|
||||||
|
/**
|
||||||
|
* gets the SHA512 hash of the file
|
||||||
|
*/
|
||||||
|
fun InputStream.sha512(bufferSize: Int = 4096): ByteArray = hash(this, bufferSize, Hash.digest512.get())
|
||||||
|
/**
|
||||||
|
* gets the SHA3_256 hash of the file
|
||||||
|
*/
|
||||||
|
fun InputStream.sha3_256(bufferSize: Int = 4096): ByteArray = hash(this, bufferSize, Hash.digest3_256.get())
|
||||||
|
/**
|
||||||
|
* gets the SHA3_384 hash of the file
|
||||||
|
*/
|
||||||
|
fun InputStream.sha3_384(bufferSize: Int = 4096): ByteArray = hash(this, bufferSize, Hash.digest3_384.get())
|
||||||
|
/**
|
||||||
|
* gets the SHA3_512 hash of the file
|
||||||
|
*/
|
||||||
|
fun InputStream.sha3_512(bufferSize: Int = 4096): ByteArray = hash(this, bufferSize, Hash.digest3_512.get())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the xxhash32 of the InputStream
|
||||||
|
*
|
||||||
|
* @param seed used to initialize the hash value (for the xxhash seed), use whatever value you want, but always the same
|
||||||
|
*/
|
||||||
|
fun InputStream.xxHash32(bufferSize: Int = 4096, seed: Int = -0x31bf6a3c): Int {
|
||||||
|
val xxHash = Hash.xxHashFactory.get()
|
||||||
|
val hash32 = xxHash.newStreamingHash32(seed)!!
|
||||||
|
|
||||||
|
val buffer = ByteArray(bufferSize)
|
||||||
|
var read: Int
|
||||||
|
|
||||||
|
this.use {
|
||||||
|
while (it.read(buffer).also { read = it } > 0) {
|
||||||
|
hash32.update(buffer, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash32.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the xxhash64 of the InputStream
|
||||||
|
*
|
||||||
|
* @param seed used to initialize the hash value (for the xxhash seed), use whatever value you want, but always the same
|
||||||
|
*/
|
||||||
|
fun InputStream.xxHash64(bufferSize: Int = 4096, seed: Long = -0x31bf6a3c): Long {
|
||||||
|
val xxHash = Hash.xxHashFactory.get()
|
||||||
|
val hash64 = xxHash.newStreamingHash64(seed)!!
|
||||||
|
|
||||||
|
val buffer = ByteArray(bufferSize)
|
||||||
|
var read: Int
|
||||||
|
|
||||||
|
this.use {
|
||||||
|
while (it.read(buffer).also { read = it } > 0) {
|
||||||
|
hash64.update(buffer, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash64.value
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue