summaryrefslogtreecommitdiff
path: root/chromium/media/cdm/aes_decryptor.h
blob: 962c27a1aed3bde41c0463fbc24c1ca39ed62655 (plain)
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_CDM_AES_DECRYPTOR_H_
#define MEDIA_CDM_AES_DECRYPTOR_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "media/base/callback_registry.h"
#include "media/base/cdm_context.h"
#include "media/base/cdm_key_information.h"
#include "media/base/cdm_promise.h"
#include "media/base/content_decryption_module.h"
#include "media/base/decryptor.h"
#include "media/base/media_export.h"
#include "media/cdm/json_web_key.h"

namespace crypto {
class SymmetricKey;
}

namespace media {

// Decrypts an AES encrypted buffer into an unencrypted buffer. The AES
// encryption must be CTR with a key size of 128bits.
class MEDIA_EXPORT AesDecryptor : public ContentDecryptionModule,
                                  public CdmContext,
                                  public Decryptor {
 public:
  AesDecryptor(const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
               const SessionKeysChangeCB& session_keys_change_cb,
               const SessionExpirationUpdateCB& session_expiration_update_cb);

  // ContentDecryptionModule implementation.
  void SetServerCertificate(const std::vector<uint8_t>& certificate,
                            std::unique_ptr<SimpleCdmPromise> promise) override;
  void CreateSessionAndGenerateRequest(
      CdmSessionType session_type,
      EmeInitDataType init_data_type,
      const std::vector<uint8_t>& init_data,
      std::unique_ptr<NewSessionCdmPromise> promise) override;
  void LoadSession(CdmSessionType session_type,
                   const std::string& session_id,
                   std::unique_ptr<NewSessionCdmPromise> promise) override;
  void UpdateSession(const std::string& session_id,
                     const std::vector<uint8_t>& response,
                     std::unique_ptr<SimpleCdmPromise> promise) override;
  void CloseSession(const std::string& session_id,
                    std::unique_ptr<SimpleCdmPromise> promise) override;
  void RemoveSession(const std::string& session_id,
                     std::unique_ptr<SimpleCdmPromise> promise) override;
  CdmContext* GetCdmContext() override;

  // CdmContext implementation.
  std::unique_ptr<CallbackRegistration> RegisterEventCB(
      EventCB event_cb) override;
  Decryptor* GetDecryptor() override;

  // Decryptor implementation.
  void Decrypt(StreamType stream_type,
               scoped_refptr<DecoderBuffer> encrypted,
               DecryptCB decrypt_cb) override;
  void CancelDecrypt(StreamType stream_type) override;
  void InitializeAudioDecoder(const AudioDecoderConfig& config,
                              DecoderInitCB init_cb) override;
  void InitializeVideoDecoder(const VideoDecoderConfig& config,
                              DecoderInitCB init_cb) override;
  void DecryptAndDecodeAudio(scoped_refptr<DecoderBuffer> encrypted,
                             AudioDecodeCB audio_decode_cb) override;
  void DecryptAndDecodeVideo(scoped_refptr<DecoderBuffer> encrypted,
                             VideoDecodeCB video_decode_cb) override;
  void ResetDecoder(StreamType stream_type) override;
  void DeinitializeDecoder(StreamType stream_type) override;
  bool CanAlwaysDecrypt() override;

 private:
  // Testing classes that needs to manipulate internal states for testing.
  friend class ClearKeyPersistentSessionCdm;

  // Internally this class supports persistent license type sessions so that
  // it can be used by ClearKeyPersistentSessionCdm. The following methods
  // will be used from ClearKeyPersistentSessionCdm to create and update
  // persistent sessions. Note that ClearKeyPersistentSessionCdm is only used
  // for testing, so persistent sessions will not be available generally.

  // Creates a new session with ID |session_id| and type |session_type|, and
  // adds it to the list of active sessions. Returns false if the session ID
  // is already in the list.
  bool CreateSession(const std::string& session_id,
                     CdmSessionType session_type);

  // Gets the state of the session |session_id| as a JWK.
  std::string GetSessionStateAsJWK(const std::string& session_id);

  // Update session |session_id| with the JWK provided in |json_web_key_set|.
  // Returns true and sets |key_added| if successful, otherwise returns false
  // and |error_message| is the reason for failure.
  bool UpdateSessionWithJWK(const std::string& session_id,
                            const std::string& json_web_key_set,
                            bool* key_added,
                            CdmPromise::Exception* exception,
                            std::string* error_message);

  // Performs the final steps of UpdateSession (notify any listeners for keys
  // changed, resolve the promise, and generate a keys change event).
  void FinishUpdate(const std::string& session_id,
                    bool key_added,
                    std::unique_ptr<SimpleCdmPromise> promise);

  // TODO(fgalligan): Remove this and change KeyMap to use crypto::SymmetricKey
  // as there are no decryptors that are performing an integrity check.
  // Helper class that manages the decryption key.
  class DecryptionKey {
   public:
    explicit DecryptionKey(const std::string& secret);
    ~DecryptionKey();

    // Creates the encryption key.
    bool Init();

    const std::string& secret() { return secret_; }
    crypto::SymmetricKey* decryption_key() { return decryption_key_.get(); }

   private:
    // The base secret that is used to create the decryption key.
    const std::string secret_;

    // The key used to decrypt the data.
    std::unique_ptr<crypto::SymmetricKey> decryption_key_;

    DISALLOW_COPY_AND_ASSIGN(DecryptionKey);
  };

  // Keep track of the keys for a key ID. If multiple sessions specify keys
  // for the same key ID, then the last key inserted is used. The structure is
  // optimized so that Decrypt() has fast access, at the cost of slow deletion
  // of keys when a session is released.
  class SessionIdDecryptionKeyMap;

  // Key ID <-> SessionIdDecryptionKeyMap map.
  using KeyIdToSessionKeysMap =
      std::unordered_map<std::string,
                         std::unique_ptr<SessionIdDecryptionKeyMap>>;

  ~AesDecryptor() override;

  // Creates a DecryptionKey using |key_string| and associates it with |key_id|.
  // Returns true if successful.
  bool AddDecryptionKey(const std::string& session_id,
                        const std::string& key_id,
                        const std::string& key_string);

  // Gets a DecryptionKey associated with |key_id|. The AesDecryptor still owns
  // the key. Returns NULL if no key is associated with |key_id|.
  DecryptionKey* GetKey_Locked(const std::string& key_id) const
      EXCLUSIVE_LOCKS_REQUIRED(key_map_lock_);

  // Determines if |key_id| is already specified for |session_id|.
  bool HasKey(const std::string& session_id, const std::string& key_id);

  // Deletes all keys associated with |session_id|.
  void DeleteKeysForSession(const std::string& session_id);

  CdmKeysInfo GenerateKeysInfoList(const std::string& session_id,
                                   CdmKeyInformation::KeyStatus status);

  // Gets the record of key usage for persistent-usage-record session. Used
  // by ClearKeyPersistentSessionCdm.
  // Returns false if the session type is not Persistent-Usage-Record.
  bool GetRecordOfKeyUsage(const std::string& session_id,
                           KeyIdList& key_ids,
                           base::Time& first_decryption_time,
                           base::Time& latest_decryption_time);

  // Callbacks for firing session events. No SessionExpirationUpdateCB since
  // the keys never expire.
  SessionMessageCB session_message_cb_;
  SessionClosedCB session_closed_cb_;
  SessionKeysChangeCB session_keys_change_cb_;

  // Since only Decrypt() is called off the renderer thread, we only need to
  // protect |key_map_|, the only member variable that is shared between
  // Decrypt() and other methods.
  mutable base::Lock key_map_lock_;
  KeyIdToSessionKeysMap key_map_ GUARDED_BY(key_map_lock_);

  // Keeps track of current open sessions and their type. Although publicly
  // AesDecryptor only supports temporary sessions, ClearKeyPersistentSessionCdm
  // uses this class to also support persistent sessions, so save the
  // CdmSessionType for each session.
  std::map<std::string, CdmSessionType> open_sessions_;

  CallbackRegistry<EventCB::RunType> event_callbacks_;

  // First and latest decryption time for persistent-usage-record
  base::Time first_decryption_time_ GUARDED_BY(key_map_lock_);
  base::Time latest_decryption_time_ GUARDED_BY(key_map_lock_);

  DISALLOW_COPY_AND_ASSIGN(AesDecryptor);
};

}  // namespace media

#endif  // MEDIA_CDM_AES_DECRYPTOR_H_