Index: crypto/rsa_private_key.cc |
=================================================================== |
--- crypto/rsa_private_key.cc (revision 0) |
+++ crypto/rsa_private_key.cc (revision 0) |
@@ -0,0 +1,390 @@ |
+// Copyright (c) 2011 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 "crypto/rsa_private_key.h" |
+ |
+#include <algorithm> |
+#include <list> |
+ |
+#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/string_util.h" |
+ |
+// This file manually encodes and decodes RSA private keys using PrivateKeyInfo |
+// from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are: |
+// |
+// PrivateKeyInfo ::= SEQUENCE { |
+// version Version, |
+// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, |
+// privateKey PrivateKey, |
+// attributes [0] IMPLICIT Attributes OPTIONAL |
+// } |
+// |
+// RSAPrivateKey ::= SEQUENCE { |
+// version Version, |
+// modulus INTEGER, |
+// publicExponent INTEGER, |
+// privateExponent INTEGER, |
+// prime1 INTEGER, |
+// prime2 INTEGER, |
+// exponent1 INTEGER, |
+// exponent2 INTEGER, |
+// coefficient INTEGER |
+// } |
+ |
+namespace { |
+// Helper for error handling during key import. |
+#define READ_ASSERT(truth) \ |
+ if (!(truth)) { \ |
+ NOTREACHED(); \ |
+ return false; \ |
+ } |
+} // namespace |
+ |
+namespace crypto { |
+ |
+const uint8 PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = { |
+ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, |
+ 0x05, 0x00 |
+}; |
+ |
+PrivateKeyInfoCodec::PrivateKeyInfoCodec(bool big_endian) |
+ : big_endian_(big_endian) {} |
+ |
+PrivateKeyInfoCodec::~PrivateKeyInfoCodec() {} |
+ |
+bool PrivateKeyInfoCodec::Export(std::vector<uint8>* output) { |
+ std::list<uint8> content; |
+ |
+ // Version (always zero) |
+ uint8 version = 0; |
+ |
+ PrependInteger(coefficient_, &content); |
+ PrependInteger(exponent2_, &content); |
+ PrependInteger(exponent1_, &content); |
+ PrependInteger(prime2_, &content); |
+ PrependInteger(prime1_, &content); |
+ PrependInteger(private_exponent_, &content); |
+ PrependInteger(public_exponent_, &content); |
+ PrependInteger(modulus_, &content); |
+ PrependInteger(&version, 1, &content); |
+ PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); |
+ PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content); |
+ |
+ // RSA algorithm OID |
+ for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) |
+ content.push_front(kRsaAlgorithmIdentifier[i - 1]); |
+ |
+ PrependInteger(&version, 1, &content); |
+ PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); |
+ |
+ // Copy everying into the output. |
+ output->reserve(content.size()); |
+ for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i) |
+ output->push_back(*i); |
+ |
+ return true; |
+} |
+ |
+bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) { |
+ // Create a sequence with the modulus (n) and public exponent (e). |
+ std::vector<uint8> bit_string; |
+ if (!ExportPublicKey(&bit_string)) |
+ return false; |
+ |
+ // Add the sequence as the contents of a bit string. |
+ std::list<uint8> content; |
+ PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()), |
+ &content); |
+ |
+ // Add the RSA algorithm OID. |
+ for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) |
+ content.push_front(kRsaAlgorithmIdentifier[i - 1]); |
+ |
+ // Finally, wrap everything in a sequence. |
+ PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); |
+ |
+ // Copy everything into the output. |
+ output->reserve(content.size()); |
+ for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i) |
+ output->push_back(*i); |
+ |
+ return true; |
+} |
+ |
+bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8>* output) { |
+ // Create a sequence with the modulus (n) and public exponent (e). |
+ std::list<uint8> content; |
+ PrependInteger(&public_exponent_[0], |
+ static_cast<int>(public_exponent_.size()), |
+ &content); |
+ PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content); |
+ PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); |
+ |
+ // Copy everything into the output. |
+ output->reserve(content.size()); |
+ for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i) |
+ output->push_back(*i); |
+ |
+ return true; |
+} |
+ |
+bool PrivateKeyInfoCodec::Import(const std::vector<uint8>& input) { |
+ if (input.empty()) { |
+ return false; |
+ } |
+ |
+ // Parse the private key info up to the public key values, ignoring |
+ // the subsequent private key values. |
+ uint8* src = const_cast<uint8*>(&input.front()); |
+ uint8* end = src + input.size(); |
+ if (!ReadSequence(&src, end) || |
+ !ReadVersion(&src, end) || |
+ !ReadAlgorithmIdentifier(&src, end) || |
+ !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) || |
+ !ReadSequence(&src, end) || |
+ !ReadVersion(&src, end) || |
+ !ReadInteger(&src, end, &modulus_)) |
+ return false; |
+ |
+ int mod_size = modulus_.size(); |
+ READ_ASSERT(mod_size % 2 == 0); |
+ int primes_size = mod_size / 2; |
+ |
+ if (!ReadIntegerWithExpectedSize(&src, end, 4, &public_exponent_) || |
+ !ReadIntegerWithExpectedSize(&src, end, mod_size, &private_exponent_) || |
+ !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime1_) || |
+ !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime2_) || |
+ !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent1_) || |
+ !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent2_) || |
+ !ReadIntegerWithExpectedSize(&src, end, primes_size, &coefficient_)) |
+ return false; |
+ |
+ READ_ASSERT(src == end); |
+ |
+ |
+ return true; |
+} |
+ |
+void PrivateKeyInfoCodec::PrependInteger(const std::vector<uint8>& in, |
+ std::list<uint8>* out) { |
+ uint8* ptr = const_cast<uint8*>(&in.front()); |
+ PrependIntegerImpl(ptr, in.size(), out, big_endian_); |
+} |
+ |
+// Helper to prepend an ASN.1 integer. |
+void PrivateKeyInfoCodec::PrependInteger(uint8* val, |
+ int num_bytes, |
+ std::list<uint8>* data) { |
+ PrependIntegerImpl(val, num_bytes, data, big_endian_); |
+} |
+ |
+void PrivateKeyInfoCodec::PrependIntegerImpl(uint8* val, |
+ int num_bytes, |
+ std::list<uint8>* data, |
+ bool big_endian) { |
+ // Reverse input if little-endian. |
+ std::vector<uint8> tmp; |
+ if (!big_endian) { |
+ tmp.assign(val, val + num_bytes); |
+ reverse(tmp.begin(), tmp.end()); |
+ val = &tmp.front(); |
+ } |
+ |
+ // ASN.1 integers are unpadded byte arrays, so skip any null padding bytes |
+ // from the most-significant end of the integer. |
+ int start = 0; |
+ while (start < (num_bytes - 1) && val[start] == 0x00) { |
+ start++; |
+ num_bytes--; |
+ } |
+ PrependBytes(val, start, num_bytes, data); |
+ |
+ // ASN.1 integers are signed. To encode a positive integer whose sign bit |
+ // (the most significant bit) would otherwise be set and make the number |
+ // negative, ASN.1 requires a leading null byte to force the integer to be |
+ // positive. |
+ uint8 front = data->front(); |
+ if ((front & 0x80) != 0) { |
+ data->push_front(0x00); |
+ num_bytes++; |
+ } |
+ |
+ PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadInteger(uint8** pos, |
+ uint8* end, |
+ std::vector<uint8>* out) { |
+ return ReadIntegerImpl(pos, end, out, big_endian_); |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize(uint8** pos, |
+ uint8* end, |
+ size_t expected_size, |
+ std::vector<uint8>* out) { |
+ std::vector<uint8> temp; |
+ if (!ReadIntegerImpl(pos, end, &temp, true)) // Big-Endian |
+ return false; |
+ |
+ int pad = expected_size - temp.size(); |
+ int index = 0; |
+ if (out->size() == expected_size + 1) { |
+ READ_ASSERT(out->front() == 0x00); |
+ pad++; |
+ index++; |
+ } else { |
+ READ_ASSERT(out->size() <= expected_size); |
+ } |
+ |
+ while (pad) { |
+ out->push_back(0x00); |
+ pad--; |
+ } |
+ out->insert(out->end(), temp.begin(), temp.end()); |
+ |
+ // Reverse output if little-endian. |
+ if (!big_endian_) |
+ reverse(out->begin(), out->end()); |
+ return true; |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8** pos, |
+ uint8* end, |
+ std::vector<uint8>* out, |
+ bool big_endian) { |
+ uint32 length = 0; |
+ if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length) || !length) |
+ return false; |
+ |
+ // The first byte can be zero to force positiveness. We can ignore this. |
+ if (**pos == 0x00) { |
+ ++(*pos); |
+ --length; |
+ } |
+ |
+ if (length) |
+ out->insert(out->end(), *pos, (*pos) + length); |
+ |
+ (*pos) += length; |
+ |
+ // Reverse output if little-endian. |
+ if (!big_endian) |
+ reverse(out->begin(), out->end()); |
+ return true; |
+} |
+ |
+void PrivateKeyInfoCodec::PrependBytes(uint8* val, |
+ int start, |
+ int num_bytes, |
+ std::list<uint8>* data) { |
+ while (num_bytes > 0) { |
+ --num_bytes; |
+ data->push_front(val[start + num_bytes]); |
+ } |
+} |
+ |
+void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8>* data) { |
+ // The high bit is used to indicate whether additional octets are needed to |
+ // represent the length. |
+ if (size < 0x80) { |
+ data->push_front(static_cast<uint8>(size)); |
+ } else { |
+ uint8 num_bytes = 0; |
+ while (size > 0) { |
+ data->push_front(static_cast<uint8>(size & 0xFF)); |
+ size >>= 8; |
+ num_bytes++; |
+ } |
+ CHECK_LE(num_bytes, 4); |
+ data->push_front(0x80 | num_bytes); |
+ } |
+} |
+ |
+void PrivateKeyInfoCodec::PrependTypeHeaderAndLength(uint8 type, |
+ uint32 length, |
+ std::list<uint8>* output) { |
+ PrependLength(length, output); |
+ output->push_front(type); |
+} |
+ |
+void PrivateKeyInfoCodec::PrependBitString(uint8* val, |
+ int num_bytes, |
+ std::list<uint8>* output) { |
+ // Start with the data. |
+ PrependBytes(val, 0, num_bytes, output); |
+ // Zero unused bits. |
+ output->push_front(0); |
+ // Add the length. |
+ PrependLength(num_bytes + 1, output); |
+ // Finally, add the bit string tag. |
+ output->push_front((uint8) kBitStringTag); |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadLength(uint8** pos, uint8* end, uint32* result) { |
+ READ_ASSERT(*pos < end); |
+ int length = 0; |
+ |
+ // If the MSB is not set, the length is just the byte itself. |
+ if (!(**pos & 0x80)) { |
+ length = **pos; |
+ (*pos)++; |
+ } else { |
+ // Otherwise, the lower 7 indicate the length of the length. |
+ int length_of_length = **pos & 0x7F; |
+ READ_ASSERT(length_of_length <= 4); |
+ (*pos)++; |
+ READ_ASSERT(*pos + length_of_length < end); |
+ |
+ length = 0; |
+ for (int i = 0; i < length_of_length; ++i) { |
+ length <<= 8; |
+ length |= **pos; |
+ (*pos)++; |
+ } |
+ } |
+ |
+ READ_ASSERT(*pos + length <= end); |
+ if (result) *result = length; |
+ return true; |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8** pos, |
+ uint8* end, |
+ uint8 expected_tag, |
+ uint32* length) { |
+ READ_ASSERT(*pos < end); |
+ READ_ASSERT(**pos == expected_tag); |
+ (*pos)++; |
+ |
+ return ReadLength(pos, end, length); |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadSequence(uint8** pos, uint8* end) { |
+ return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8** pos, uint8* end) { |
+ READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); |
+ READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, |
+ sizeof(kRsaAlgorithmIdentifier)) == 0); |
+ (*pos) += sizeof(kRsaAlgorithmIdentifier); |
+ return true; |
+} |
+ |
+bool PrivateKeyInfoCodec::ReadVersion(uint8** pos, uint8* end) { |
+ uint32 length = 0; |
+ if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) |
+ return false; |
+ |
+ // The version should be zero. |
+ for (uint32 i = 0; i < length; ++i) { |
+ READ_ASSERT(**pos == 0x00); |
+ (*pos)++; |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace crypto |
Property changes on: crypto\rsa_private_key.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |