1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "crypto/rsa_private_key.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/string_util.h"
13 #pragma comment(lib, "crypt32.lib")
16 // Helper for error handling during key import.
17 #define READ_ASSERT(truth) \
27 RSAPrivateKey
* RSAPrivateKey::Create(uint16 num_bits
) {
28 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
29 if (!result
->InitProvider())
32 DWORD flags
= CRYPT_EXPORTABLE
;
34 // The size is encoded as the upper 16 bits of the flags. :: sigh ::.
35 flags
|= (num_bits
<< 16);
36 if (!CryptGenKey(result
->provider_
, CALG_RSA_SIGN
, flags
,
37 result
->key_
.receive()))
40 return result
.release();
44 RSAPrivateKey
* RSAPrivateKey::CreateSensitive(uint16 num_bits
) {
50 RSAPrivateKey
* RSAPrivateKey::CreateFromPrivateKeyInfo(
51 const std::vector
<uint8
>& input
) {
52 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
53 if (!result
->InitProvider())
56 PrivateKeyInfoCodec
pki(false); // Little-Endian
59 int blob_size
= sizeof(PUBLICKEYSTRUC
) +
61 pki
.modulus()->size() +
62 pki
.prime1()->size() +
63 pki
.prime2()->size() +
64 pki
.exponent1()->size() +
65 pki
.exponent2()->size() +
66 pki
.coefficient()->size() +
67 pki
.private_exponent()->size();
68 scoped_array
<BYTE
> blob(new BYTE
[blob_size
]);
70 uint8
* dest
= blob
.get();
71 PUBLICKEYSTRUC
* public_key_struc
= reinterpret_cast<PUBLICKEYSTRUC
*>(dest
);
72 public_key_struc
->bType
= PRIVATEKEYBLOB
;
73 public_key_struc
->bVersion
= 0x02;
74 public_key_struc
->reserved
= 0;
75 public_key_struc
->aiKeyAlg
= CALG_RSA_SIGN
;
76 dest
+= sizeof(PUBLICKEYSTRUC
);
78 RSAPUBKEY
* rsa_pub_key
= reinterpret_cast<RSAPUBKEY
*>(dest
);
79 rsa_pub_key
->magic
= 0x32415352;
80 rsa_pub_key
->bitlen
= pki
.modulus()->size() * 8;
81 int public_exponent_int
= 0;
82 for (size_t i
= pki
.public_exponent()->size(); i
> 0; --i
) {
83 public_exponent_int
<<= 8;
84 public_exponent_int
|= (*pki
.public_exponent())[i
- 1];
86 rsa_pub_key
->pubexp
= public_exponent_int
;
87 dest
+= sizeof(RSAPUBKEY
);
89 memcpy(dest
, &pki
.modulus()->front(), pki
.modulus()->size());
90 dest
+= pki
.modulus()->size();
91 memcpy(dest
, &pki
.prime1()->front(), pki
.prime1()->size());
92 dest
+= pki
.prime1()->size();
93 memcpy(dest
, &pki
.prime2()->front(), pki
.prime2()->size());
94 dest
+= pki
.prime2()->size();
95 memcpy(dest
, &pki
.exponent1()->front(), pki
.exponent1()->size());
96 dest
+= pki
.exponent1()->size();
97 memcpy(dest
, &pki
.exponent2()->front(), pki
.exponent2()->size());
98 dest
+= pki
.exponent2()->size();
99 memcpy(dest
, &pki
.coefficient()->front(), pki
.coefficient()->size());
100 dest
+= pki
.coefficient()->size();
101 memcpy(dest
, &pki
.private_exponent()->front(),
102 pki
.private_exponent()->size());
103 dest
+= pki
.private_exponent()->size();
105 READ_ASSERT(dest
== blob
.get() + blob_size
);
106 if (!CryptImportKey(result
->provider_
,
107 reinterpret_cast<uint8
*>(public_key_struc
), blob_size
, 0,
108 CRYPT_EXPORTABLE
, result
->key_
.receive()))
111 return result
.release();
115 RSAPrivateKey
* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
116 const std::vector
<uint8
>& input
) {
122 RSAPrivateKey
* RSAPrivateKey::FindFromPublicKeyInfo(
123 const std::vector
<uint8
>& input
) {
128 RSAPrivateKey::RSAPrivateKey() : provider_(NULL
), key_(NULL
) {}
130 RSAPrivateKey::~RSAPrivateKey() {}
132 bool RSAPrivateKey::InitProvider() {
133 return FALSE
!= CryptAcquireContext(provider_
.receive(), NULL
, NULL
,
134 PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
);
137 RSAPrivateKey
* RSAPrivateKey::Copy() const {
138 scoped_ptr
<RSAPrivateKey
> copy(new RSAPrivateKey());
139 if (!CryptContextAddRef(provider_
, NULL
, 0)) {
143 copy
->provider_
.reset(provider_
.get());
144 if (!CryptDuplicateKey(key_
.get(), NULL
, 0, copy
->key_
.receive()))
146 return copy
.release();
149 bool RSAPrivateKey::ExportPrivateKey(std::vector
<uint8
>* output
) const {
151 DWORD blob_length
= 0;
152 if (!CryptExportKey(key_
, 0, PRIVATEKEYBLOB
, 0, NULL
, &blob_length
)) {
157 scoped_array
<uint8
> blob(new uint8
[blob_length
]);
158 if (!CryptExportKey(key_
, 0, PRIVATEKEYBLOB
, 0, blob
.get(), &blob_length
)) {
163 uint8
* pos
= blob
.get();
164 PUBLICKEYSTRUC
*publickey_struct
= reinterpret_cast<PUBLICKEYSTRUC
*>(pos
);
165 pos
+= sizeof(PUBLICKEYSTRUC
);
167 RSAPUBKEY
*rsa_pub_key
= reinterpret_cast<RSAPUBKEY
*>(pos
);
168 pos
+= sizeof(RSAPUBKEY
);
170 int mod_size
= rsa_pub_key
->bitlen
/ 8;
171 int primes_size
= rsa_pub_key
->bitlen
/ 16;
173 PrivateKeyInfoCodec
pki(false); // Little-Endian
175 pki
.modulus()->assign(pos
, pos
+ mod_size
);
178 pki
.prime1()->assign(pos
, pos
+ primes_size
);
180 pki
.prime2()->assign(pos
, pos
+ primes_size
);
183 pki
.exponent1()->assign(pos
, pos
+ primes_size
);
185 pki
.exponent2()->assign(pos
, pos
+ primes_size
);
188 pki
.coefficient()->assign(pos
, pos
+ primes_size
);
191 pki
.private_exponent()->assign(pos
, pos
+ mod_size
);
194 pki
.public_exponent()->assign(reinterpret_cast<uint8
*>(&rsa_pub_key
->pubexp
),
195 reinterpret_cast<uint8
*>(&rsa_pub_key
->pubexp
) + 4);
197 CHECK_EQ(pos
- blob_length
, reinterpret_cast<BYTE
*>(publickey_struct
));
199 return pki
.Export(output
);
202 bool RSAPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) const {
204 if (!CryptExportPublicKeyInfo(
205 provider_
, AT_SIGNATURE
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
206 NULL
, &key_info_len
)) {
211 scoped_array
<uint8
> key_info(new uint8
[key_info_len
]);
212 if (!CryptExportPublicKeyInfo(
213 provider_
, AT_SIGNATURE
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
214 reinterpret_cast<CERT_PUBLIC_KEY_INFO
*>(key_info
.get()), &key_info_len
)) {
219 DWORD encoded_length
;
220 if (!CryptEncodeObject(
221 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, X509_PUBLIC_KEY_INFO
,
222 reinterpret_cast<CERT_PUBLIC_KEY_INFO
*>(key_info
.get()), NULL
,
228 scoped_array
<BYTE
> encoded(new BYTE
[encoded_length
]);
229 if (!CryptEncodeObject(
230 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, X509_PUBLIC_KEY_INFO
,
231 reinterpret_cast<CERT_PUBLIC_KEY_INFO
*>(key_info
.get()), encoded
.get(),
237 output
->assign(encoded
.get(), encoded
.get() + encoded_length
);
241 } // namespace crypto