protected override Recipient DeserializeEntity(XmlElement element, XmlNamespaceManager namespaces) { // First, just extract the X.509 certificate. It must exist or we will consider the delivery data invalid. var certificateNode = element.SelectSingleNode("cpix:DeliveryKey/ds:X509Data/ds:X509Certificate", namespaces); if (certificateNode == null) { throw new InvalidCpixDataException("Found a delivery data element with no X.509 certificate embedded. This is not supported."); } var certificate = new X509Certificate2(Convert.FromBase64String(certificateNode.InnerText)); // If we do not already have the document secrets available, try to load them. if (Document.DocumentKey == null) { var matchingRecipientCertificate = Document.RecipientCertificates.FirstOrDefault(c => c.Thumbprint == certificate.Thumbprint); if (matchingRecipientCertificate != null) { // Yes, we have a delivery key! Use this delivery key to load the delivery data. var deliveryData = XmlHelpers.Deserialize <DeliveryDataElement>(element); deliveryData.LoadTimeValidate(); var rsa = matchingRecipientCertificate.GetRSAPrivateKey(); var macKey = rsa.Decrypt(deliveryData.MacMethod.Key.CipherData.CipherValue, RSAEncryptionPadding.OaepSHA1); var documentKey = rsa.Decrypt(deliveryData.DocumentKey.Data.Secret.EncryptedValue.CipherData.CipherValue, RSAEncryptionPadding.OaepSHA1); Document.ImportKeys(documentKey, macKey); } } return(new Recipient(certificate)); }
protected override ContentKey DeserializeEntity(XmlElement element, XmlNamespaceManager namespaces) { var contentKey = XmlHelpers.Deserialize <ContentKeyElement>(element); contentKey.LoadTimeValidate(); if (contentKey.HasPlainValue && Document.Recipients.Any()) { throw new InvalidCpixDataException("A content key was delivered in the clear but delivery data was defined. Malformed CPIX!?"); } byte[] value = null; if (contentKey.HasEncryptedValue && Document.ContentKeysAreReadable) { var mac = new HMACSHA512(Document.MacKey); var calculatedMac = mac.ComputeHash(contentKey.Data.Secret.EncryptedValue.CipherData.CipherValue); if (!calculatedMac.SequenceEqual(contentKey.Data.Secret.ValueMAC)) { throw new SecurityException("MAC validation failed - a content key value has been tampered with!"); } var iv = contentKey.Data.Secret.EncryptedValue.CipherData.CipherValue.Take(128 / 8).ToArray(); var encryptedKey = contentKey.Data.Secret.EncryptedValue.CipherData.CipherValue.Skip(128 / 8).ToArray(); var aes = new AesManaged { BlockSize = 128, KeySize = 256, Key = Document.DocumentKey, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, IV = iv }; using (var decryptor = aes.CreateDecryptor()) { value = decryptor.TransformFinalBlock(encryptedKey, 0, encryptedKey.Length); } } else if (contentKey.HasPlainValue) { value = contentKey.Data.Secret.PlainValue; } else { // Value is encrypted and we cannot read it. Nothing to do here. } return(new ContentKey { Id = contentKey.KeyId, ExplicitIv = contentKey.ExplicitIv, Value = value, IsLoadedEncryptedKey = contentKey.HasEncryptedValue }); }
protected override DrmSystem DeserializeEntity(XmlElement element, XmlNamespaceManager namespaces) { var drmSystemElement = XmlHelpers.Deserialize <DrmSystemElement>(element); drmSystemElement.LoadTimeValidate(); var drmSystem = new DrmSystem { SystemId = drmSystemElement.SystemId, KeyId = drmSystemElement.KeyId, Pssh = drmSystemElement.Pssh, SmoothStreamingProtectionHeaderData = drmSystemElement.SmoothStreamingProtectionHeaderData }; if (drmSystemElement.ContentProtectionData != null) { drmSystem.ContentProtectionData = Encoding.UTF8.GetString(Convert.FromBase64String(drmSystemElement.ContentProtectionData)); } if (drmSystemElement.HdsSignalingData != null) { drmSystem.HdsSignalingData = Encoding.UTF8.GetString(Convert.FromBase64String(drmSystemElement.HdsSignalingData)); } if (drmSystemElement.HlsSignalingData.Count > 0) { drmSystem.HlsSignalingData = new HlsSignalingData(); var mediaPlaylistDataAsBase64 = drmSystemElement.HlsSignalingData .SingleOrDefault(d => d.Playlist == null || string.Equals(d.Playlist, HlsPlaylistType.Media, StringComparison.InvariantCulture))?.Value; var masterPlaylistDataAsBase64 = drmSystemElement.HlsSignalingData .SingleOrDefault(d => string.Equals(d.Playlist, HlsPlaylistType.Master, StringComparison.InvariantCulture))?.Value; if (mediaPlaylistDataAsBase64 != null) { drmSystem.HlsSignalingData.MediaPlaylistData = Encoding.UTF8.GetString(Convert.FromBase64String(mediaPlaylistDataAsBase64)); } if (masterPlaylistDataAsBase64 != null) { drmSystem.HlsSignalingData.MasterPlaylistData = Encoding.UTF8.GetString(Convert.FromBase64String(masterPlaylistDataAsBase64)); } } return(drmSystem); }
protected override UsageRule DeserializeEntity(XmlElement element, XmlNamespaceManager namespaces) { var raw = XmlHelpers.Deserialize <UsageRuleElement>(element); raw.LoadTimeValidate(); var rule = new UsageRule { KeyId = raw.KeyId }; // This disables all usage rule processing, basically, and treats this particular rule as read-only. // The unknown filters will be preserved unless the rule is removed, just no rules from this document can be used. if (raw.UnknownFilters?.Any() == true) { rule.ContainsUnsupportedFilters = true; } if (raw.VideoFilters?.Length > 0) { rule.VideoFilters = raw.VideoFilters .Select(f => new VideoFilter { MinPixels = f.MinPixels, MaxPixels = f.MaxPixels, MinFramesPerSecond = f.MinFps, MaxFramesPerSecond = f.MaxFps, WideColorGamut = f.Wcg, HighDynamicRange = f.Hdr }) .ToList(); } if (raw.AudioFilters?.Length > 0) { rule.AudioFilters = raw.AudioFilters .Select(f => new AudioFilter { MinChannels = f.MinChannels, MaxChannels = f.MaxChannels }) .ToList(); } if (raw.BitrateFilters?.Length > 0) { rule.BitrateFilters = raw.BitrateFilters .Select(f => new BitrateFilter { MinBitrate = f.MinBitrate, MaxBitrate = f.MaxBitrate }) .ToList(); } if (raw.LabelFilters?.Length > 0) { rule.LabelFilters = raw.LabelFilters .Select(f => new LabelFilter { Label = f.Label }) .ToList(); } return(rule); }