-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSteganographer.kt
102 lines (86 loc) · 3.64 KB
/
Steganographer.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package cryptography
import java.awt.Color
import java.io.File
import java.io.IOException
import javax.imageio.ImageIO
const val MSB = 0x10000000
const val LSB = 0x00000001
class Steganographer {
fun hide() {
try {
println("Input image file:")
val inputFileName = readln().trim()
val inputFile = File(inputFileName)
val image = ImageIO.read(inputFile)
println("Output image file:")
val outputFileName = readln().trim()
val outputFile = File(outputFileName)
println("Message to hide:")
val message = readln().trim()
val byteArrayMessage = message.encodeToByteArray()
println("Password:")
val password = readln().trim()
val byteArrayPassword = password.encodeToByteArray()
val encryptedMessage =
byteArrayMessage.mapIndexed { index, byteMessage ->
(byteMessage.toInt() xor byteArrayPassword[index % byteArrayPassword.size].toInt()).toByte()
}
val byteArrayEncryptedMessage = byteArrayOf(*encryptedMessage.toByteArray(), 0, 0, 3)
val messageBits = byteArrayEncryptedMessage.map { byte ->
(0 until Byte.SIZE_BITS).map { (byte.rotateLeft(it).toInt() and MSB) / MSB }
}.flatten()
if (image.width * image.height < messageBits.size) {
println("The input image is not large enough to hold this message.")
return
}
messageBits.forEachIndexed { index, bit ->
val x = index % image.width
val y = index / image.width
val color = Color(image.getRGB(x, y))
val newColor = Color(color.red, color.green, color.blue and 1.inv() or bit)
image.setRGB(x, y, newColor.rgb)
}
ImageIO.write(image, "png", outputFile)
println("Message saved in $outputFileName image.")
} catch (e: IOException) {
println("Can't write output file!")
} catch (e: Exception) {
println(e.message)
}
}
fun show() {
try {
println("Input image file:")
val inputFileName = readln().trim()
val inputFile = File(inputFileName)
val image = ImageIO.read(inputFile)
println("Password:")
val password = readln().trim()
val byteArrayPassword = password.encodeToByteArray()
val byteMessage = mutableListOf<Byte>()
for (byte in (0 until image.width * image.height)
.map { pixelPosition ->
Color(
image.getRGB(
pixelPosition % image.width,
pixelPosition / image.width
)
).blue and LSB
}
.chunked(Byte.SIZE_BITS)
.map { byteList -> byteList.reduce { byte, bit -> (byte shl 1) or bit } }) {
byteMessage.add(byte.toByte())
if (byteMessage.size >= 3 && byteMessage.takeLast(3) == listOf<Byte>(0, 0, 3)) {
byteMessage.dropLast(3)
break
}
}
val decryptedByteMessage = byteMessage.mapIndexed { index, byte ->
(byte.toInt() xor byteArrayPassword[index % byteArrayPassword.size].toInt()).toByte()
}
println("Message: ${decryptedByteMessage.toByteArray().toString(Charsets.UTF_8)}")
} catch (e: IOException) {
println("Can't write output file!")
}
}
}