168 lines
5.4 KiB
Text
168 lines
5.4 KiB
Text
// version 1.0.6
|
|
|
|
import java.security.MessageDigest
|
|
|
|
class MD4() : MessageDigest("MD4"), Cloneable {
|
|
private val blockLength = 64
|
|
private var context = IntArray(4)
|
|
private var count = 0L
|
|
private var buffer = ByteArray(blockLength)
|
|
private var x = IntArray(16)
|
|
|
|
init {
|
|
engineReset()
|
|
}
|
|
|
|
private constructor(md: MD4): this() {
|
|
context = md.context.clone()
|
|
buffer = md.buffer.clone()
|
|
count = md.count
|
|
}
|
|
|
|
override fun clone(): Any = MD4(this)
|
|
|
|
override fun engineReset() {
|
|
context[0] = 0x67452301
|
|
context[1] = 0xefcdab89.toInt()
|
|
context[2] = 0x98badcfe.toInt()
|
|
context[3] = 0x10325476
|
|
count = 0L
|
|
for (i in 0 until blockLength) buffer[i] = 0
|
|
}
|
|
|
|
override fun engineUpdate(b: Byte) {
|
|
val i = (count % blockLength).toInt()
|
|
count++
|
|
buffer[i] = b
|
|
if (i == blockLength - 1) transform(buffer, 0)
|
|
}
|
|
|
|
override fun engineUpdate(input: ByteArray, offset: Int, len: Int) {
|
|
if (offset < 0 || len < 0 || offset.toLong() + len > input.size.toLong())
|
|
throw ArrayIndexOutOfBoundsException()
|
|
var bufferNdx = (count % blockLength).toInt()
|
|
count += len
|
|
val partLen = blockLength - bufferNdx
|
|
var i = 0
|
|
if (len >= partLen) {
|
|
System.arraycopy(input, offset, buffer, bufferNdx, partLen)
|
|
transform(buffer, 0)
|
|
i = partLen
|
|
while (i + blockLength - 1 < len) {
|
|
transform(input, offset + i)
|
|
i += blockLength
|
|
}
|
|
bufferNdx = 0
|
|
}
|
|
if (i < len) System.arraycopy(input, offset + i, buffer, bufferNdx, len - i)
|
|
}
|
|
|
|
override fun engineDigest(): ByteArray {
|
|
val bufferNdx = (count % blockLength).toInt()
|
|
val padLen = if (bufferNdx < 56) 56 - bufferNdx else 120 - bufferNdx
|
|
val tail = ByteArray(padLen + 8)
|
|
tail[0] = 0x80.toByte()
|
|
for (i in 0..7) tail[padLen + i] = ((count * 8) ushr (8 * i)).toByte()
|
|
engineUpdate(tail, 0, tail.size)
|
|
val result = ByteArray(16)
|
|
for (i in 0..3)
|
|
for (j in 0..3)
|
|
result[i * 4 + j] = (context[i] ushr (8 * j)).toByte()
|
|
engineReset()
|
|
return result
|
|
}
|
|
|
|
private fun transform (block: ByteArray, offset: Int) {
|
|
var offset2 = offset
|
|
for (i in 0..15)
|
|
x[i] = ((block[offset2++].toInt() and 0xff) ) or
|
|
((block[offset2++].toInt() and 0xff) shl 8 ) or
|
|
((block[offset2++].toInt() and 0xff) shl 16) or
|
|
((block[offset2++].toInt() and 0xff) shl 24)
|
|
|
|
var a = context[0]
|
|
var b = context[1]
|
|
var c = context[2]
|
|
var d = context[3]
|
|
|
|
a = ff(a, b, c, d, x[ 0], 3)
|
|
d = ff(d, a, b, c, x[ 1], 7)
|
|
c = ff(c, d, a, b, x[ 2], 11)
|
|
b = ff(b, c, d, a, x[ 3], 19)
|
|
a = ff(a, b, c, d, x[ 4], 3)
|
|
d = ff(d, a, b, c, x[ 5], 7)
|
|
c = ff(c, d, a, b, x[ 6], 11)
|
|
b = ff(b, c, d, a, x[ 7], 19)
|
|
a = ff(a, b, c, d, x[ 8], 3)
|
|
d = ff(d, a, b, c, x[ 9], 7)
|
|
c = ff(c, d, a, b, x[10], 11)
|
|
b = ff(b, c, d, a, x[11], 19)
|
|
a = ff(a, b, c, d, x[12], 3)
|
|
d = ff(d, a, b, c, x[13], 7)
|
|
c = ff(c, d, a, b, x[14], 11)
|
|
b = ff(b, c, d, a, x[15], 19)
|
|
|
|
a = gg(a, b, c, d, x[ 0], 3)
|
|
d = gg(d, a, b, c, x[ 4], 5)
|
|
c = gg(c, d, a, b, x[ 8], 9)
|
|
b = gg(b, c, d, a, x[12], 13)
|
|
a = gg(a, b, c, d, x[ 1], 3)
|
|
d = gg(d, a, b, c, x[ 5], 5)
|
|
c = gg(c, d, a, b, x[ 9], 9)
|
|
b = gg(b, c, d, a, x[13], 13)
|
|
a = gg(a, b, c, d, x[ 2], 3)
|
|
d = gg(d, a, b, c, x[ 6], 5)
|
|
c = gg(c, d, a, b, x[10], 9)
|
|
b = gg(b, c, d, a, x[14], 13)
|
|
a = gg(a, b, c, d, x[ 3], 3)
|
|
d = gg(d, a, b, c, x[ 7], 5)
|
|
c = gg(c, d, a, b, x[11], 9)
|
|
b = gg(b, c, d, a, x[15], 13)
|
|
|
|
a = hh(a, b, c, d, x[ 0], 3)
|
|
d = hh(d, a, b, c, x[ 8], 9)
|
|
c = hh(c, d, a, b, x[ 4], 11)
|
|
b = hh(b, c, d, a, x[12], 15)
|
|
a = hh(a, b, c, d, x[ 2], 3)
|
|
d = hh(d, a, b, c, x[10], 9)
|
|
c = hh(c, d, a, b, x[ 6], 11)
|
|
b = hh(b, c, d, a, x[14], 15)
|
|
a = hh(a, b, c, d, x[ 1], 3)
|
|
d = hh(d, a, b, c, x[ 9], 9)
|
|
c = hh(c, d, a, b, x[ 5], 11)
|
|
b = hh(b, c, d, a, x[13], 15)
|
|
a = hh(a, b, c, d, x[ 3], 3)
|
|
d = hh(d, a, b, c, x[11], 9)
|
|
c = hh(c, d, a, b, x[ 7], 11)
|
|
b = hh(b, c, d, a, x[15], 15)
|
|
|
|
context[0] += a
|
|
context[1] += b
|
|
context[2] += c
|
|
context[3] += d
|
|
}
|
|
|
|
private fun ff(a: Int, b: Int, c: Int, d: Int, x: Int, s: Int): Int {
|
|
val t = a + ((b and c) or (b.inv() and d)) + x
|
|
return (t shl s) or (t ushr (32 - s))
|
|
}
|
|
|
|
private fun gg(a: Int, b: Int, c: Int, d: Int, x: Int, s: Int): Int {
|
|
val t = a + ((b and (c or d)) or (c and d)) + x + 0x5a827999
|
|
return (t shl s) or (t ushr (32 - s))
|
|
}
|
|
|
|
private fun hh(a: Int, b: Int, c: Int, d: Int, x: Int, s: Int): Int {
|
|
val t = a + (b xor c xor d) + x + 0x6ed9eba1
|
|
return (t shl s) or (t ushr (32 - s))
|
|
}
|
|
}
|
|
|
|
fun main(args: Array<String>) {
|
|
val text = "Rosetta Code"
|
|
val bytes = text.toByteArray(Charsets.US_ASCII)
|
|
val md: MessageDigest = MD4()
|
|
val digest = md.digest(bytes)
|
|
for (byte in digest) print("%02x".format(byte))
|
|
println()
|
|
}
|