Skip to content

Commit

Permalink
Updating documentation in general + intellij suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
ruvmello committed Dec 22, 2023
1 parent b0b2477 commit bb144c5
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 21 deletions.
3 changes: 1 addition & 2 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ fun main(args: Array<String>) {
var noCrc = false
var numThreads = Runtime.getRuntime().availableProcessors()
while(arguments.isNotEmpty()) {
val option = arguments.removeAt(0)
when(option) {
when(val option = arguments.removeAt(0)) {
"--help", "-h" -> {
println("This program aims to create a zip quine.")
println("The created zip contains the input file, as well as the zip itself.")
Expand Down
21 changes: 18 additions & 3 deletions src/main/kotlin/zip/CRC32Bruteforcer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,28 @@ import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.CountDownLatch
import java.util.concurrent.atomic.AtomicLong

/**
* This class takes care of the brute-forcing of the CRC-32 checksum
*
* @param numThreads is the number of threads used for the brute-forcing
*/
class CRC32Bruteforcer(private val numThreads: Int) {
private val crc32Table = IntArray(256)

init {
this.calculateTable()
}

/**
* This method tries to bruteforce the CRC-32 checksum and uses multithreading to do so.
*
* @param fullZipFile The zip file for which we want to bruteforce the CRC-32
* @param quine is the quine itself
* @param backupSize is the size of the header before the quine itself
* @param lhQuineSize is the size of the local file header of the quine itself
* @param cdSize is the size of the central directory
* @return the ByteArray of the full file that contains the right checksum, if no checksum is found we just use 0
*/
fun bruteforce(fullZipFile: ByteArray, quine: ByteArray, backupSize: Int, lhQuineSize: Int, cdSize: Int): ByteArray {
val range = Int.MIN_VALUE..Int.MAX_VALUE
val segmentSize: Int = ((range.last.toLong() - range.first.toLong() + 1) / numThreads).toInt()
Expand All @@ -33,7 +48,7 @@ class CRC32Bruteforcer(private val numThreads: Int) {
val result = AtomicReference<ByteArray>()

val latch = CountDownLatch(numThreads)
print("Starting bruteforcing the CRC32 using ${numThreads} threads... (0.00%)\r")
print("Starting brute-forcing the CRC32 using $numThreads threads... (0.00%)\r")
for (i in 0 until numThreads) {
val start = range.first + i * segmentSize
val end = if (i == numThreads - 1) range.last else start + segmentSize - 1
Expand All @@ -59,7 +74,7 @@ class CRC32Bruteforcer(private val numThreads: Int) {
val iter = doneIterations.incrementAndGet()
if (System.currentTimeMillis() - currentTime > 10000) {
currentTime = System.currentTimeMillis()
print("Starting bruteforcing the CRC32 using ${numThreads} threads... (${(iter.toDouble() * 100 / totalIterations).toString().take(4)}%)\r")
print("Starting brute-forcing the CRC32 using $numThreads threads... (${(iter.toDouble() * 100 / totalIterations).toString().take(4)}%)\r")
}
}

Expand All @@ -75,7 +90,7 @@ class CRC32Bruteforcer(private val numThreads: Int) {
e.printStackTrace()
}

println("Starting bruteforcing the CRC32... Done (${doneIterations.get()} / ${totalIterations} - ${(doneIterations.get().toDouble() * 100 / totalIterations).toString().take(4)}%)")
println("Starting brute-forcing the CRC32... Done (${doneIterations.get()} / $totalIterations - ${(doneIterations.get().toDouble() * 100 / totalIterations).toString().take(4)}%)")

return if (resultFound.get()) {
result.get()
Expand Down
32 changes: 16 additions & 16 deletions src/main/kotlin/zip/ZIPArchiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,32 +77,32 @@ class ZIPArchiver(private val zipName: String = "test.zip",
// Generate quine of the right size, but the local file header will still be wrong
// Create right size header
var offset = this.zip.length().toInt()
var lh_quine = this.getLocalFileHeader(this.zipName, 0, 0)
this.zip.appendBytes(lh_quine)
var lhQuine = this.getLocalFileHeader(this.zipName, 0, 0)
this.zip.appendBytes(lhQuine)

// Create right size footer
var cd_quine = this.getCentralDirectoryFileHeader(this.zipName, 0, 0, 0)
var cdQuine = this.getCentralDirectoryFileHeader(this.zipName, 0, 0, 0)
var endCd = this.getEndOfCentralDirectoryRecord(1, this.zip.length().toInt() - offset, offset)
var footer = cd + cd_quine + endCd
var footer = cd + cdQuine + endCd

var quine = this.generateQuine(this.zip.readBytes(), footer)
this.zip.appendBytes(quine)
offset = this.zip.length().toInt()

// Now that we know the compressed size, make quine with the right local file header and calculate right crc
var fullZipFile = backup.copyOf()
val totalSize = backup.size + lh_quine.size + quine.size + footer.size
val totalSize = backup.size + lhQuine.size + quine.size + footer.size

lh_quine = this.getLocalFileHeader(this.zipName, quine.size, totalSize)
fullZipFile += lh_quine
lhQuine = this.getLocalFileHeader(this.zipName, quine.size, totalSize)
fullZipFile += lhQuine

cd_quine = this.getCentralDirectoryFileHeader(this.zipName, quine.size, backup.size, totalSize)
cdQuine = this.getCentralDirectoryFileHeader(this.zipName, quine.size, backup.size, totalSize)
endCd = this.getEndOfCentralDirectoryRecord(
inputFiles.size + 1,
fullZipFile.size + quine.size + cd.size + cd_quine.size - offset,
fullZipFile.size + quine.size + cd.size + cdQuine.size - offset,
offset
)
footer = cd + cd_quine + endCd
footer = cd + cdQuine + endCd

quine = this.generateQuine(fullZipFile, footer)
fullZipFile += quine
Expand All @@ -113,7 +113,7 @@ class ZIPArchiver(private val zipName: String = "test.zip",

// Bruteforce zip without recalculating the quine each time
if (!noCrc) {
val finalFile = crc32Bruteforcer.bruteforce(fullZipFile, quine, backup.size, lh_quine.size, cd.size)
val finalFile = crc32Bruteforcer.bruteforce(fullZipFile, quine, backup.size, lhQuine.size, cd.size)
this.zip.writeBytes(finalFile)
} else {
this.zip.writeBytes(fullZipFile)
Expand All @@ -129,7 +129,7 @@ class ZIPArchiver(private val zipName: String = "test.zip",
* @param footer is the footer of the quine. This is shown as [S] in the quine.
* @return the generated quine
*/
fun generateQuine(zipPrefix: ByteArray, footer: ByteArray): ByteArray {
private fun generateQuine(zipPrefix: ByteArray, footer: ByteArray): ByteArray {
var quineData = byteArrayOf()

val huffman = HuffmanCompressor()
Expand Down Expand Up @@ -202,7 +202,7 @@ class ZIPArchiver(private val zipName: String = "test.zip",
bytesToAdd = huffman.encodeRepeatStaticBlock(repeats, false)

if (repeats.size == 1 && bytesToAdd.size != 5) {
val repeat: LZ77Repeat = repeats.get(0)
val repeat: LZ77Repeat = repeats[0]
bytesToAdd = getFiveByteRepeat(repeat)
}

Expand Down Expand Up @@ -296,7 +296,7 @@ class ZIPArchiver(private val zipName: String = "test.zip",
* @param token the token that needs to be split in two to fit in 5 bytes
* @return the ByteArray that is exactly five bytes
*/
fun getFiveByteRepeat(token: LZ77Repeat): ByteArray {
private fun getFiveByteRepeat(token: LZ77Repeat): ByteArray {
val huffman = HuffmanCompressor()
val length = token.length
val distance = token.distance
Expand All @@ -321,7 +321,7 @@ class ZIPArchiver(private val zipName: String = "test.zip",
* @param footerSize the size of the footer
* @return The ByteArray that includes the last repeat token: Rs+y+2
*/
fun calculateLastQuineRepeat(footerSize: Int): ByteArray {
private fun calculateLastQuineRepeat(footerSize: Int): ByteArray {
val huffman = HuffmanCompressor()
var totalLiteralSize = footerSize + 2 * 5 // footer size + 2 * size L0
val totalRepeats = totalLiteralSize / 258
Expand Down Expand Up @@ -356,7 +356,7 @@ class ZIPArchiver(private val zipName: String = "test.zip",
* @param isLast indicates if it is the last block
* @return the ByteArray that contains the header of the stored block
*/
fun getLiteralWithSize(size: Int, isLast: Boolean = false): ByteArray {
private fun getLiteralWithSize(size: Int, isLast: Boolean = false): ByteArray {
return if(!isLast) byteArrayOf(0.toByte()) + getByteArrayOf2Bytes(size) +
getByteArrayOf2Bytes(size.inv()) else byteArrayOf(128.toByte()) + getByteArrayOf2Bytes(size) +
getByteArrayOf2Bytes(size.inv())
Expand Down

0 comments on commit bb144c5

Please sign in to comment.