tapo-decrypt-poc/src/main/java/main.kt

72 lines
2.6 KiB
Kotlin

import com.xenomachina.argparser.ArgParser
import com.xenomachina.argparser.default
import com.xenomachina.argparser.mainBody
import org.fusesource.jansi.internal.CLibrary.STDIN_FILENO
import org.fusesource.jansi.internal.CLibrary.isatty
import java.nio.charset.Charset
import java.security.MessageDigest
import kotlin.system.exitProcess
class Args(parser: ArgParser) {
val encrypt by parser.flagging("-e", "--encrypt", help = "Encrypt stdin instead of decrypting")
val keyExchange by parser
.storing("-k", "--key-exchange", help = "Key-Exchange header value, required if nonce is not provided")
.default<String?>(null)
val cloudPassword by parser
.storing("-p", "--password", help = "Cloud password, if camera has been provisioned")
.default<String?>(null)
val username by parser
.storing("-u", "--username", help = "User name, either admin or none. Default admin")
.default<String>("admin")
val nonce by parser
.storing("-n", "--nonce", help = "Nonce, required if key-exchange is not provided")
.default<String?>(null)
}
fun main(args: Array<String>) = mainBody {
ArgParser(args).parseInto(::Args).run {
if (keyExchange == null && nonce == null) {
System.err.println("Either the Key-Exchange or the nonce must be provided!")
exitProcess(1)
}
if (cloudPassword == null) {
System.err.println("Cloud password not provided, using the default one for unprovisioned cameras")
}
if (isatty(STDIN_FILENO) == 1) {
System.err.println("Data to ${if (encrypt) "encrypt" else "decrypt"} must be sent to standard input!")
exitProcess(1)
}
val toProcess = System.`in`.readAllBytesCompat()
if (toProcess == null) {
System.err.println("Unable to read data from stdin!")
exitProcess(1)
}
val hashedPassword: String? = cloudPassword?.let {
MessageDigest
.getInstance("MD5")
.apply { update(it.toByteArray(Charset.forName("UTF-8"))) }
.digest()
.toHexString()
}
val aes = if (keyExchange != null) {
StreamAesUtils.generateFromExchangeKeyAndSuperSecretKey(keyExchange, hashedPassword)
} else {
StreamAesUtils.fromUserNonceSuperSecretKey(username, nonce, hashedPassword)
}
val output = if (encrypt) {
aes.encrypt(toProcess)
} else {
aes.decrypt(toProcess)
}
System.out.write(output)
}
}