1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/rsa_private_key.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <list> 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/cssm_init.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace crypto { 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottRSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_CC_HANDLE cc_handle; 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_RETURN crtn; 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch crtn = CSSM_CSP_CreateKeyGenContext(GetSharedCSPHandle(), CSSM_ALGID_RSA, 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott num_bits, NULL, NULL, NULL, NULL, NULL, 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott &cc_handle); 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (crtn) { 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn; 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_DATA label = { 9, 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const_cast<uint8*>(reinterpret_cast<const uint8*>("temp_key")) }; 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott crtn = CSSM_GenerateKeyPair(cc_handle, 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_KEYUSE_VERIFY, 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result->public_key(), CSSM_KEYUSE_SIGN, 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, NULL, 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott result->key()); 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_DeleteContext(cc_handle); 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (crtn) { 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn; 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return result.release(); 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 473345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickRSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { 483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NOTIMPLEMENTED(); 493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return NULL; 503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottRSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::vector<uint8>& input) { 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (input.empty()) 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_KEY key; 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memset(&key, 0, sizeof(key)); 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyData.Data = const_cast<uint8*>(&input.front()); 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyData.Length = input.size(); 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION; 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.BlobType = CSSM_KEYBLOB_RAW; 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.AlgorithmId = CSSM_ALGID_RSA; 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE; 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.KeyUsage = CSSM_KEYUSE_ANY; 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_KEY_SIZE key_size; 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_RETURN crtn; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, &key, &key_size); 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (crtn) { 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn; 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key.KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits; 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Perform a NULL unwrap operation on the key so that result's key_ 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // instance variable points to a key that can be released via CSSM_FreeKey(). 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_ACCESS_CREDENTIALS creds; 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_CC_HANDLE cc_handle; 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch crtn = CSSM_CSP_CreateSymmetricContext(GetSharedCSPHandle(), CSSM_ALGID_NONE, 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_ALGMODE_NONE, &creds, NULL, NULL, CSSM_PADDING_NONE, 0, &cc_handle); 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (crtn) { 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "CSSM_CSP_CreateSymmetricContext failed: " << crtn; 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_DATA label_data, desc_data = { 0, NULL }; 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott label_data.Data = 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const_cast<uint8*>(reinterpret_cast<const uint8*>("unwrapped")); 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott label_data.Length = 9; 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott crtn = CSSM_UnwrapKey(cc_handle, NULL, &key, CSSM_KEYUSE_ANY, 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label_data, 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NULL, result->key(), &desc_data); 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (crtn) { 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "CSSM_UnwrapKey failed: " << crtn; 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Extract a public key from the private key. 10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Apple doesn't accept CSSM_KEYBLOB_RAW_FORMAT_X509 as a valid key 10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // format when attempting to generate certs, so use PKCS1 instead. 10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen PrivateKeyInfoCodec codec(true); 10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::vector<uint8> private_key_data; 10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen private_key_data.assign(key.KeyData.Data, 11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen key.KeyData.Data + key.KeyData.Length); 11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!codec.Import(private_key_data)) { 11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::vector<uint8> public_key_data; 11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!codec.ExportPublicKey(&public_key_data)) { 11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CSSM_KEY* public_key = result->public_key(); 12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen size_t size = public_key_data.size(); 12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyData.Data = reinterpret_cast<uint8*>(CSSMMalloc(size)); 12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!public_key->KeyData.Data) { 12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOTREACHED() << "CSSMMalloc failed"; 12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen memcpy(public_key->KeyData.Data, &public_key_data.front(), size); 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyData.Length = size; 12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; 12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION; 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.BlobType = CSSM_KEYBLOB_RAW; 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.AlgorithmId = CSSM_ALGID_RSA; 13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; 13372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE; 13472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY; 13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, public_key, 137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &key_size); 13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (crtn) { 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DLOG(ERROR) << "CSSM_QueryKeySizeInBits failed " << crtn; 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen public_key->KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits; 14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return result.release(); 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickRSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( 1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const std::vector<uint8>& input) { 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NOTIMPLEMENTED(); 1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return NULL; 1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickRSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( 1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const std::vector<uint8>& input) { 1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NOTIMPLEMENTED(); 1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return NULL; 1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochRSAPrivateKey::RSAPrivateKey() { 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memset(&key_, 0, sizeof(key_)); 16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen memset(&public_key_, 0, sizeof(public_key_)); 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EnsureCSSMInit(); 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottRSAPrivateKey::~RSAPrivateKey() { 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (key_.KeyData.Data) { 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_FreeKey(GetSharedCSPHandle(), NULL, &key_, CSSM_FALSE); 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (public_key_.KeyData.Data) { 17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key_, CSSM_FALSE); 17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) { 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!key_.KeyData.Data || !key_.KeyData.Length) { 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott output->clear(); 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott output->insert(output->end(), key_.KeyData.Data, 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_.KeyData.Data + key_.KeyData.Length); 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) { 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott PrivateKeyInfoCodec private_key_info(true); 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<uint8> private_key_data; 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private_key_data.assign(key_.KeyData.Data, 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_.KeyData.Data + key_.KeyData.Length); 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return (private_key_info.Import(private_key_data) && 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private_key_info.ExportPublicKeyInfo(output)); 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace crypto 197