1 // Copyright (c) 2012 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/strings/string_util.h"
13 #pragma comment(lib, "crypt32.lib")
18 RSAPrivateKey
* RSAPrivateKey::Create(uint16 num_bits
) {
19 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
20 if (!result
->InitProvider())
23 DWORD flags
= CRYPT_EXPORTABLE
;
25 // The size is encoded as the upper 16 bits of the flags. :: sigh ::.
26 flags
|= (num_bits
<< 16);
27 if (!CryptGenKey(result
->provider_
, CALG_RSA_SIGN
, flags
,
28 result
->key_
.receive()))
31 return result
.release();
35 RSAPrivateKey
* RSAPrivateKey::CreateSensitive(uint16 num_bits
) {
41 RSAPrivateKey
* RSAPrivateKey::CreateFromPrivateKeyInfo(
42 const std::vector
<uint8
>& input
) {
43 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
44 if (!result
->InitProvider())
47 PrivateKeyInfoCodec
pki(false); // Little-Endian
48 if (!pki
.Import(input
))
51 size_t blob_size
= sizeof(PUBLICKEYSTRUC
) +
53 pki
.modulus()->size() +
54 pki
.prime1()->size() +
55 pki
.prime2()->size() +
56 pki
.exponent1()->size() +
57 pki
.exponent2()->size() +
58 pki
.coefficient()->size() +
59 pki
.private_exponent()->size();
60 scoped_ptr
<BYTE
[]> blob(new BYTE
[blob_size
]);
62 uint8
* dest
= blob
.get();
63 PUBLICKEYSTRUC
* public_key_struc
= reinterpret_cast<PUBLICKEYSTRUC
*>(dest
);
64 public_key_struc
->bType
= PRIVATEKEYBLOB
;
65 public_key_struc
->bVersion
= 0x02;
66 public_key_struc
->reserved
= 0;
67 public_key_struc
->aiKeyAlg
= CALG_RSA_SIGN
;
68 dest
+= sizeof(PUBLICKEYSTRUC
);
70 RSAPUBKEY
* rsa_pub_key
= reinterpret_cast<RSAPUBKEY
*>(dest
);
71 rsa_pub_key
->magic
= 0x32415352;
72 rsa_pub_key
->bitlen
= pki
.modulus()->size() * 8;
73 int public_exponent_int
= 0;
74 for (size_t i
= pki
.public_exponent()->size(); i
> 0; --i
) {
75 public_exponent_int
<<= 8;
76 public_exponent_int
|= (*pki
.public_exponent())[i
- 1];
78 rsa_pub_key
->pubexp
= public_exponent_int
;
79 dest
+= sizeof(RSAPUBKEY
);
81 memcpy(dest
, &pki
.modulus()->front(), pki
.modulus()->size());
82 dest
+= pki
.modulus()->size();
83 memcpy(dest
, &pki
.prime1()->front(), pki
.prime1()->size());
84 dest
+= pki
.prime1()->size();
85 memcpy(dest
, &pki
.prime2()->front(), pki
.prime2()->size());
86 dest
+= pki
.prime2()->size();
87 memcpy(dest
, &pki
.exponent1()->front(), pki
.exponent1()->size());
88 dest
+= pki
.exponent1()->size();
89 memcpy(dest
, &pki
.exponent2()->front(), pki
.exponent2()->size());
90 dest
+= pki
.exponent2()->size();
91 memcpy(dest
, &pki
.coefficient()->front(), pki
.coefficient()->size());
92 dest
+= pki
.coefficient()->size();
93 memcpy(dest
, &pki
.private_exponent()->front(),
94 pki
.private_exponent()->size());
95 dest
+= pki
.private_exponent()->size();
97 if (dest
!= blob
.get() + blob_size
) {
101 if (!CryptImportKey(result
->provider_
,
102 reinterpret_cast<uint8
*>(public_key_struc
),
103 static_cast<DWORD
>(blob_size
), 0, CRYPT_EXPORTABLE
,
104 result
->key_
.receive())) {
108 return result
.release();
112 RSAPrivateKey
* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
113 const std::vector
<uint8
>& input
) {
119 RSAPrivateKey
* RSAPrivateKey::FindFromPublicKeyInfo(
120 const std::vector
<uint8
>& input
) {
125 RSAPrivateKey::RSAPrivateKey() : provider_(NULL
), key_(NULL
) {}
127 RSAPrivateKey::~RSAPrivateKey() {}
129 bool RSAPrivateKey::InitProvider() {
130 return FALSE
!= CryptAcquireContext(provider_
.receive(), NULL
, NULL
,
131 PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
);
134 RSAPrivateKey
* RSAPrivateKey::Copy() const {
135 scoped_ptr
<RSAPrivateKey
> copy(new RSAPrivateKey());
136 if (!CryptContextAddRef(provider_
, NULL
, 0)) {
140 copy
->provider_
.reset(provider_
.get());
141 if (!CryptDuplicateKey(key_
.get(), NULL
, 0, copy
->key_
.receive()))
143 return copy
.release();
146 bool RSAPrivateKey::ExportPrivateKey(std::vector
<uint8
>* output
) const {
148 DWORD blob_length
= 0;
149 if (!CryptExportKey(key_
, 0, PRIVATEKEYBLOB
, 0, NULL
, &blob_length
)) {
154 scoped_ptr
<uint8
[]> blob(new uint8
[blob_length
]);
155 if (!CryptExportKey(key_
, 0, PRIVATEKEYBLOB
, 0, blob
.get(), &blob_length
)) {
160 uint8
* pos
= blob
.get();
161 PUBLICKEYSTRUC
*publickey_struct
= reinterpret_cast<PUBLICKEYSTRUC
*>(pos
);
162 pos
+= sizeof(PUBLICKEYSTRUC
);
164 RSAPUBKEY
*rsa_pub_key
= reinterpret_cast<RSAPUBKEY
*>(pos
);
165 pos
+= sizeof(RSAPUBKEY
);
167 int mod_size
= rsa_pub_key
->bitlen
/ 8;
168 int primes_size
= rsa_pub_key
->bitlen
/ 16;
170 PrivateKeyInfoCodec
pki(false); // Little-Endian
172 pki
.modulus()->assign(pos
, pos
+ mod_size
);
175 pki
.prime1()->assign(pos
, pos
+ primes_size
);
177 pki
.prime2()->assign(pos
, pos
+ primes_size
);
180 pki
.exponent1()->assign(pos
, pos
+ primes_size
);
182 pki
.exponent2()->assign(pos
, pos
+ primes_size
);
185 pki
.coefficient()->assign(pos
, pos
+ primes_size
);
188 pki
.private_exponent()->assign(pos
, pos
+ mod_size
);
191 pki
.public_exponent()->assign(reinterpret_cast<uint8
*>(&rsa_pub_key
->pubexp
),
192 reinterpret_cast<uint8
*>(&rsa_pub_key
->pubexp
) + 4);
194 CHECK_EQ(pos
- blob_length
, reinterpret_cast<BYTE
*>(publickey_struct
));
196 return pki
.Export(output
);
199 bool RSAPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) const {
201 if (!CryptExportPublicKeyInfo(
202 provider_
, AT_SIGNATURE
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
203 NULL
, &key_info_len
)) {
208 scoped_ptr
<uint8
[]> key_info(new uint8
[key_info_len
]);
209 if (!CryptExportPublicKeyInfo(
210 provider_
, AT_SIGNATURE
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
211 reinterpret_cast<CERT_PUBLIC_KEY_INFO
*>(key_info
.get()), &key_info_len
)) {
216 DWORD encoded_length
;
217 if (!CryptEncodeObject(
218 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, X509_PUBLIC_KEY_INFO
,
219 reinterpret_cast<CERT_PUBLIC_KEY_INFO
*>(key_info
.get()), NULL
,
225 scoped_ptr
<BYTE
[]> encoded(new BYTE
[encoded_length
]);
226 if (!CryptEncodeObject(
227 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, X509_PUBLIC_KEY_INFO
,
228 reinterpret_cast<CERT_PUBLIC_KEY_INFO
*>(key_info
.get()), encoded
.get(),
234 output
->assign(encoded
.get(), encoded
.get() + encoded_length
);
238 } // namespace crypto