package com.castlabs.dash.dashfragmenter.cmdlines; import com.castlabs.dash.dashfragmenter.Command; import org.apache.commons.io.FileUtils; import org.apache.xmlbeans.XmlOptions; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Localizable; import org.kohsuke.args4j.Option; import org.kohsuke.args4j.spi.UuidOptionHandler; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.io.File; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Locale; import java.util.UUID; /** * Future super class of all commands. */ public abstract class AbstractEncryptOrNotCommand implements Command { protected SecretKey videoKey; protected SecretKey audioKey; @Option(name = "--encrypt", aliases = {"-1", "-e"}, forbids = "--encrypt-separate-keys", usage = "If option is set a single key for audio and video will be generated." ) protected boolean encryptSingleKey = false; @Option(name = "--encrypt-separate-keys", aliases = "-2", forbids = "--encrypt", usage = "If set different keys will be used for audio and video. When setting keys explicitly this option is not used." ) protected boolean encryptSeparateKey = false; @Option(name = "--uuid:v", aliases = {"-u", "-u:v", "--uuid"}, forbids = {"--encrypt", "--encrypt-separate-keys"}, handler = UuidOptionHandler.class, usage = "Key ID for video tracks - in case no dedicated audio key ID is set it will also used for audio. Format is '01010101-0101-0101-0101-010101010101'" ) protected UUID videoKeyId = null; @Option(name = "--secretKey:v", aliases = {"-k", "-k:v", "--secretKey"}, depends = {"--uuid:v"}, forbids = {"--secretKeyFile:v"}, usage = "Content Encryption Key for video tracks - in case no dedicated audio key/key ID is given it will also used for audio tracks. Format is '01010101010101010101010101010101'" ) protected String encKeySecretKeyVideo = null; @Option(name = "--secretKeyFile:v", aliases = {"-f", "-f:v", "--secretKeyFile"}, depends = {"--setKeys", "--uuid:v"}, forbids = {"--keyseed", "--secretKey:v"}, usage = "Path to a file containing the Content Encryption Key for video tracks - in case no dedicated audio key/key ID is given it will also used for audio tracks. Format is '01010101010101010101010101010101'" ) protected File encKeySecretKeyFileVideo = null; @Option(name = "--uuid:a", aliases = "-u:a", usage = "Key ID for audio tracks. The default value is random.", handler = UuidOptionHandler.class, depends = {"--uuid:v"} ) protected UUID audioKeyId = null; @Option(name = "--secretKey:a", aliases = "-k:a", usage = "Content Encryption Key for audio tracks. Format is '01010101010101010101010101010101'", depends = {"--secretKey:v", "--uuid:a"}, forbids = {"--keyseed", "--secretKeyFile:a"} ) protected String encKeySecretKeyAudio = null; @Option(name = "--secretKeyFile:a", aliases = "-f:a", usage = "Path to a file containing the Content Encryption Key for audio tracks. Format is '01010101010101010101010101010101'", depends = {"--secretKeyFile:v", "--uuid:a"}, forbids = {"--keyseed", "--secretKey:a"} ) protected File encKeySecretKeyFileAudio = null; public void postProcessCmdLineArgs(CmdLineParser cmdLineParser) throws CmdLineException { try { if (encryptSingleKey || encryptSeparateKey) { videoKey = audioKey = KeyGenerator.getInstance("AES").generateKey(); videoKeyId = audioKeyId = UUID.randomUUID(); } if (encryptSeparateKey) { audioKey = KeyGenerator.getInstance("AES").generateKey(); audioKeyId = UUID.randomUUID(); } } catch (NoSuchAlgorithmException e) { throw new CmdLineException(cmdLineParser, new Message("The AES encryption algorithm is not supported by your VM")); } if (audioKeyId != null) { if (encKeySecretKeyAudio == null && encKeySecretKeyFileAudio == null && audioKey == null) { throw new CmdLineException(cmdLineParser, new Message("--uuid:a requires either --secretKeyFile:a, --secretKey:a or --keyseed")); } } if (videoKeyId != null) { if (encKeySecretKeyVideo == null && encKeySecretKeyFileVideo == null && videoKey == null) { throw new CmdLineException(cmdLineParser, new Message("--uuid:v requires either --secretKeyFile:v, --secretKey:v or --keyseed")); } } if (this.encKeySecretKeyVideo != null) { videoKey = new SecretKeySpec(com.coremedia.iso.Hex.decodeHex(this.encKeySecretKeyVideo), "AES"); } else if (this.encKeySecretKeyFileVideo != null) { try { videoKey = new SecretKeySpec(com.coremedia.iso.Hex.decodeHex(FileUtils.readFileToString(this.encKeySecretKeyFileVideo)), "AES"); } catch (IOException e) { throw new CmdLineException(cmdLineParser, new Message("Content Encryption Key file " + this.encKeySecretKeyFileAudio.getAbsolutePath() + " could not be read")); } } if (this.encKeySecretKeyAudio != null) { audioKey = new SecretKeySpec(com.coremedia.iso.Hex.decodeHex(this.encKeySecretKeyAudio), "AES"); } else if (this.encKeySecretKeyFileAudio != null) { try { audioKey = new SecretKeySpec(com.coremedia.iso.Hex.decodeHex(FileUtils.readFileToString((this.encKeySecretKeyFileAudio))), "AES"); } catch (IOException e) { throw new CmdLineException(cmdLineParser, new Message("Content Encryption Key file " + this.encKeySecretKeyFileAudio.getAbsolutePath() + " could not be read")); } } if (audioKeyId == null && videoKeyId != null) { audioKeyId = videoKeyId; } if (videoKeyId == null && audioKeyId != null) { videoKeyId = audioKeyId; } if (audioKey == null && videoKey != null) { audioKey = videoKey; } if (videoKey == null && audioKey != null) { videoKey = audioKey; } } static class Message implements Localizable { private String message; public String formatWithLocale(Locale locale, Object... args) { return format(args); } public String format(Object... args) { return String.format(message, args); } public Message(String message) { this.message = message; } } }