summaryrefslogtreecommitdiffstats
path: root/media/crypto/aes_decryptor.cc
blob: cbb75b37bd33457f74b9f540d652ae01bbd77c19 (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
// Copyright (c) 2012 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.

#include "media/crypto/aes_decryptor.h"

#include "base/logging.h"
#include "base/stl_util.h"
#include "base/string_piece.h"
#include "crypto/encryptor.h"
#include "crypto/symmetric_key.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"

namespace media {

// TODO(xhwang): Get real IV from frames.
static const char kInitialCounter[] = "0000000000000000";

// Decrypt |input| using |key|.
// Return a DecoderBuffer with the decrypted data if decryption succeeded.
// Return NULL if decryption failed.
static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input,
                                                crypto::SymmetricKey* key) {
  CHECK(input.GetDataSize());
  CHECK(key);

  // Initialize encryption data.
  // The IV must be exactly as long as the cipher block size.
  crypto::Encryptor encryptor;
  if (!encryptor.Init(key, crypto::Encryptor::CBC, kInitialCounter)) {
    DVLOG(1) << "Could not initialize encryptor.";
    return NULL;
  }

  std::string decrypted_text;
  base::StringPiece encrypted_text(
      reinterpret_cast<const char*>(input.GetData()),
      input.GetDataSize());
  if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) {
    DVLOG(1) << "Could not decrypt data.";
    return NULL;
  }

  // TODO(xhwang): Find a way to avoid this data copy.
  return DecoderBuffer::CopyFrom(
      reinterpret_cast<const uint8*>(decrypted_text.data()),
      decrypted_text.size());
}

AesDecryptor::AesDecryptor() {}

AesDecryptor::~AesDecryptor() {
  STLDeleteValues(&key_map_);
}

void AesDecryptor::AddKey(const uint8* key_id, int key_id_size,
                          const uint8* key, int key_size) {
  CHECK(key_id && key);
  CHECK_GT(key_id_size, 0);
  CHECK_GT(key_size, 0);

  std::string key_id_string(reinterpret_cast<const char*>(key_id), key_id_size);
  std::string key_string(reinterpret_cast<const char*>(key) , key_size);

  crypto::SymmetricKey* symmetric_key = crypto::SymmetricKey::Import(
      crypto::SymmetricKey::AES, key_string);
  if (!symmetric_key) {
    DVLOG(1) << "Could not import key.";
    return;
  }

  base::AutoLock auto_lock(lock_);
  KeyMap::iterator found = key_map_.find(key_id_string);
  if (found != key_map_.end()) {
    delete found->second;
    key_map_.erase(found);
  }
  key_map_[key_id_string] = symmetric_key;
}

scoped_refptr<DecoderBuffer> AesDecryptor::Decrypt(
    const scoped_refptr<DecoderBuffer>& encrypted) {
  CHECK(encrypted->GetDecryptConfig());
  const uint8* key_id = encrypted->GetDecryptConfig()->key_id();
  const int key_id_size = encrypted->GetDecryptConfig()->key_id_size();

  // TODO(xhwang): Avoid always constructing a string with StringPiece?
  std::string key_id_string(reinterpret_cast<const char*>(key_id), key_id_size);

  crypto::SymmetricKey* key = NULL;
  {
    base::AutoLock auto_lock(lock_);
    KeyMap::const_iterator found = key_map_.find(key_id_string);
    if (found == key_map_.end()) {
      DVLOG(1) << "Could not find a matching key for given key ID.";
      return NULL;
    }
    key = found->second;
  }

  scoped_refptr<DecoderBuffer> decrypted = DecryptData(*encrypted, key);

  if (decrypted) {
    decrypted->SetTimestamp(encrypted->GetTimestamp());
    decrypted->SetDuration(encrypted->GetDuration());
  }

  return decrypted;
}

}  // namespace media