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

72 lines
2.6 KiB
Kotlin
Raw Normal View History

2020-11-30 20:49:50 +00:00
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
2020-11-30 23:55:26 +00:00
import java.nio.charset.Charset
import java.security.MessageDigest
2020-11-30 20:49:50 +00:00
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) {
2020-12-02 17:49:22 +00:00
System.err.println("Either the Key-Exchange or the nonce must be provided!")
2020-11-30 20:49:50 +00:00
exitProcess(1)
}
if (cloudPassword == null) {
2020-12-02 17:49:22 +00:00
System.err.println("Cloud password not provided, using the default one for unprovisioned cameras")
2020-11-30 20:49:50 +00:00
}
if (isatty(STDIN_FILENO) == 1) {
2020-12-02 17:49:22 +00:00
System.err.println("Data to ${if (encrypt) "encrypt" else "decrypt"} must be sent to standard input!")
2020-11-30 20:49:50 +00:00
exitProcess(1)
}
val toProcess = System.`in`.readAllBytesCompat()
if (toProcess == null) {
2020-12-02 17:49:22 +00:00
System.err.println("Unable to read data from stdin!")
2020-11-30 20:49:50 +00:00
exitProcess(1)
}
2020-11-30 23:55:26 +00:00
val hashedPassword: String? = cloudPassword?.let {
MessageDigest
.getInstance("MD5")
.apply { update(it.toByteArray(Charset.forName("UTF-8"))) }
.digest()
.toHexString()
}
2020-11-30 20:49:50 +00:00
val aes = if (keyExchange != null) {
2020-11-30 23:55:26 +00:00
StreamAesUtils.generateFromExchangeKeyAndSuperSecretKey(keyExchange, hashedPassword)
2020-11-30 20:49:50 +00:00
} else {
2020-11-30 23:55:26 +00:00
StreamAesUtils.fromUserNonceSuperSecretKey(username, nonce, hashedPassword)
2020-11-30 20:49:50 +00:00
}
val output = if (encrypt) {
aes.encrypt(toProcess)
} else {
aes.decrypt(toProcess)
}
System.out.write(output)
}
}