Shaka Packager SDK
Loading...
Searching...
No Matches
rsa_key.cc
1// Copyright 2014 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6//
7// RSA signature details:
8// Algorithm: RSASSA-PSS
9// Hash algorithm: SHA1
10// Mask generation function: mgf1SHA1
11// Salt length: 20 bytes
12// Trailer field: 0xbc
13//
14// RSA encryption details:
15// Algorithm: RSA-OAEP
16// Mask generation function: mgf1SHA1
17// Label (encoding paramter): empty std::string
18
19#include <packager/media/base/rsa_key.h>
20
21#include <cstddef>
22#include <cstdint>
23#include <memory>
24#include <string>
25
26#include <absl/log/check.h>
27#include <absl/log/log.h>
28#include <mbedtls/ctr_drbg.h>
29#include <mbedtls/entropy.h>
30#include <mbedtls/error.h>
31#include <mbedtls/md.h>
32#include <mbedtls/pk.h>
33#include <mbedtls/rsa.h>
34
35namespace {
36
37const size_t kPssSaltLength = 20u;
38
39std::string mbedtls_strerr(int rv) {
40 // There is always a "high level" error.
41 std::string output(mbedtls_high_level_strerr(rv));
42
43 // Some errors have a "low level" error, which is like an inner error code
44 // with a deeper explanation. But on mac and Windows, ostream crashes if you
45 // give it NULL. So we combine them ourselves with a NULL check.
46 const char* low_level_error = mbedtls_low_level_strerr(rv);
47 if (low_level_error) {
48 output += ": ";
49 output += low_level_error;
50 }
51
52 return output;
53}
54
55std::string sha1(const std::string& message) {
56 const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
57 DCHECK(md_info);
58
59 std::string hash(mbedtls_md_get_size(md_info), 0);
60 CHECK_EQ(0,
61 mbedtls_md(md_info, reinterpret_cast<const uint8_t*>(message.data()),
62 message.size(), reinterpret_cast<uint8_t*>(hash.data())));
63
64 return hash;
65}
66
67} // namespace
68
69namespace shaka {
70namespace media {
71
72RsaPrivateKey::RsaPrivateKey() {
73 mbedtls_pk_init(&pk_context_);
74 mbedtls_entropy_init(&entropy_context_);
75 mbedtls_ctr_drbg_init(&prng_context_);
76}
77
78RsaPrivateKey::~RsaPrivateKey() {
79 mbedtls_pk_free(&pk_context_);
80 mbedtls_entropy_free(&entropy_context_);
81 mbedtls_ctr_drbg_free(&prng_context_);
82}
83
84RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_key) {
85 std::unique_ptr<RsaPrivateKey> key(new RsaPrivateKey());
86 if (!key->Deserialize(serialized_key)) {
87 return NULL;
88 }
89 return key.release();
90}
91
92bool RsaPrivateKey::Deserialize(const std::string& serialized_key) {
93 const mbedtls_pk_info_t* pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
94 DCHECK(pk_info);
95
96 CHECK_EQ(mbedtls_ctr_drbg_seed(&prng_context_, mbedtls_entropy_func,
97 &entropy_context_, /* custom= */ NULL,
98 /* custom_len= */ 0),
99 0);
100
101 int rv = mbedtls_pk_parse_key(
102 &pk_context_, reinterpret_cast<const uint8_t*>(serialized_key.data()),
103 serialized_key.size(),
104 /* password= */ NULL,
105 /* password_len= */ 0, mbedtls_ctr_drbg_random, &prng_context_);
106 if (rv != 0) {
107 LOG(ERROR) << "RSA private key failed to load: " << mbedtls_strerr(rv);
108 return false;
109 }
110
111 // Set the padding mode and digest mode.
112 mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_);
113 rv = mbedtls_rsa_set_padding(rsa_context, MBEDTLS_RSA_PKCS_V21,
114 MBEDTLS_MD_SHA1);
115 if (rv != 0) {
116 LOG(ERROR) << "RSA private key failed to set padding: "
117 << mbedtls_strerr(rv);
118 return false;
119 }
120
121 return true;
122}
123
124bool RsaPrivateKey::Decrypt(const std::string& encrypted_message,
125 std::string* decrypted_message) {
126 DCHECK(decrypted_message);
127
128 mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_);
129
130 size_t rsa_size = mbedtls_rsa_get_len(rsa_context);
131 if (encrypted_message.size() != rsa_size) {
132 LOG(ERROR) << "Encrypted RSA message has the wrong size (expected "
133 << rsa_size << ", actual " << encrypted_message.size() << ").";
134 return false;
135 }
136 decrypted_message->resize(encrypted_message.size());
137
138 size_t decrypted_size = 0;
139 int rv = mbedtls_rsa_rsaes_oaep_decrypt(
140 rsa_context, mbedtls_ctr_drbg_random, &prng_context_,
141 /* label= */ NULL,
142 /* label_len= */ 0, &decrypted_size,
143 reinterpret_cast<const uint8_t*>(encrypted_message.data()),
144 reinterpret_cast<uint8_t*>(decrypted_message->data()),
145 decrypted_message->size());
146
147 if (rv != 0) {
148 LOG(ERROR) << "RSA private decrypt failure: " << mbedtls_strerr(rv);
149 return false;
150 }
151 decrypted_message->resize(decrypted_size);
152 return true;
153}
154
155bool RsaPrivateKey::GenerateSignature(const std::string& message,
156 std::string* signature) {
157 DCHECK(signature);
158 if (message.empty()) {
159 LOG(ERROR) << "Message to be signed is empty.";
160 return false;
161 }
162
163 mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_);
164
165 size_t rsa_size = mbedtls_rsa_get_len(rsa_context);
166 signature->resize(rsa_size);
167
168 std::string hash = sha1(message);
169 int rv = mbedtls_rsa_rsassa_pss_sign_ext(
170 rsa_context, mbedtls_ctr_drbg_random, &prng_context_, MBEDTLS_MD_SHA1,
171 static_cast<unsigned int>(hash.size()),
172 reinterpret_cast<const uint8_t*>(hash.data()), kPssSaltLength,
173 reinterpret_cast<uint8_t*>(signature->data()));
174
175 if (rv != 0) {
176 LOG(ERROR) << "RSA sign failure: " << mbedtls_strerr(rv);
177 return false;
178 }
179 return true;
180}
181
182RsaPublicKey::RsaPublicKey() {
183 mbedtls_pk_init(&pk_context_);
184 mbedtls_entropy_init(&entropy_context_);
185 mbedtls_ctr_drbg_init(&prng_context_);
186}
187
188RsaPublicKey::~RsaPublicKey() {
189 mbedtls_pk_free(&pk_context_);
190 mbedtls_entropy_free(&entropy_context_);
191 mbedtls_ctr_drbg_free(&prng_context_);
192}
193
194RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_key) {
195 std::unique_ptr<RsaPublicKey> key(new RsaPublicKey());
196 if (!key->Deserialize(serialized_key)) {
197 return NULL;
198 }
199 return key.release();
200}
201
202bool RsaPublicKey::Deserialize(const std::string& serialized_key) {
203 const mbedtls_pk_info_t* pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
204 DCHECK(pk_info);
205
206 CHECK_EQ(mbedtls_ctr_drbg_seed(&prng_context_, mbedtls_entropy_func,
207 &entropy_context_, /* custom= */ NULL,
208 /* custom_len= */ 0),
209 0);
210
211 int rv = mbedtls_pk_parse_public_key(
212 &pk_context_, reinterpret_cast<const uint8_t*>(serialized_key.data()),
213 serialized_key.size());
214 if (rv != 0) {
215 LOG(ERROR) << "RSA public key failed to load: " << mbedtls_strerr(rv);
216 return false;
217 }
218
219 // Set the padding mode and digest mode.
220 mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_);
221 rv = mbedtls_rsa_set_padding(rsa_context, MBEDTLS_RSA_PKCS_V21,
222 MBEDTLS_MD_SHA1);
223 if (rv != 0) {
224 LOG(ERROR) << "RSA public key failed to set padding: "
225 << mbedtls_strerr(rv);
226 return false;
227 }
228
229 return true;
230}
231
232bool RsaPublicKey::Encrypt(const std::string& clear_message,
233 std::string* encrypted_message) {
234 DCHECK(encrypted_message);
235 if (clear_message.empty()) {
236 LOG(ERROR) << "Message to be encrypted is empty.";
237 return false;
238 }
239
240 mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_);
241
242 size_t rsa_size = mbedtls_rsa_get_len(rsa_context);
243 encrypted_message->resize(rsa_size);
244
245 int rv = mbedtls_rsa_rsaes_oaep_encrypt(
246 rsa_context, mbedtls_ctr_drbg_random, &prng_context_,
247 /* label= */ NULL,
248 /* label_len= */ 0, clear_message.size(),
249 reinterpret_cast<const uint8_t*>(clear_message.data()),
250 reinterpret_cast<uint8_t*>(encrypted_message->data()));
251
252 if (rv != 0) {
253 LOG(ERROR) << "RSA public encrypt failure: " << mbedtls_strerr(rv);
254 return false;
255 }
256 return true;
257}
258
259bool RsaPublicKey::VerifySignature(const std::string& message,
260 const std::string& signature) {
261 if (message.empty()) {
262 LOG(ERROR) << "Signed message is empty.";
263 return false;
264 }
265
266 mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_);
267
268 size_t rsa_size = mbedtls_rsa_get_len(rsa_context);
269 if (signature.size() != rsa_size) {
270 LOG(ERROR) << "Message signature is of the wrong size (expected "
271 << rsa_size << ", actual " << signature.size() << ").";
272 return false;
273 }
274
275 // Verify the signature.
276 std::string hash = sha1(message);
277 int rv = mbedtls_rsa_rsassa_pss_verify_ext(
278 rsa_context, MBEDTLS_MD_SHA1, static_cast<unsigned int>(hash.size()),
279 reinterpret_cast<const uint8_t*>(hash.data()), MBEDTLS_MD_SHA1,
280 kPssSaltLength, reinterpret_cast<const uint8_t*>(signature.data()));
281
282 if (rv != 0) {
283 LOG(ERROR) << "RSA signature verification failed: " << mbedtls_strerr(rv);
284 return false;
285 }
286 return true;
287}
288
289} // namespace media
290} // namespace shaka
Rsa private key, used for message signing and decryption.
Definition rsa_key.h:25
bool Decrypt(const std::string &encrypted_message, std::string *decrypted_message)
Definition rsa_key.cc:124
bool GenerateSignature(const std::string &message, std::string *signature)
Definition rsa_key.cc:155
static RsaPrivateKey * Create(const std::string &serialized_key)
Definition rsa_key.cc:84
Rsa public key, used for signature verification and encryption.
Definition rsa_key.h:57
bool VerifySignature(const std::string &message, const std::string &signature)
Definition rsa_key.cc:259
static RsaPublicKey * Create(const std::string &serialized_key)
Definition rsa_key.cc:194
bool Encrypt(const std::string &clear_message, std::string *encrypted_message)
Definition rsa_key.cc:232
All the methods that are virtual are virtual for mocking.