Refactor ASN1 parsing/serialization

Review URL: http://codereview.chromium.org/242136

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28223 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/base.gyp b/base/base.gyp
index c1d7a8b9..2f0e9da 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -20,6 +20,7 @@
         'crypto/cssm_init.cc',
         'crypto/cssm_init.h',
         'crypto/rsa_private_key.h',
+        'crypto/rsa_private_key.cc',
         'crypto/rsa_private_key_mac.cc',
         'crypto/rsa_private_key_nss.cc',
         'crypto/rsa_private_key_win.cc',
diff --git a/base/crypto/rsa_private_key.cc b/base/crypto/rsa_private_key.cc
new file mode 100644
index 0000000..e6faa3e
--- /dev/null
+++ b/base/crypto/rsa_private_key.cc
@@ -0,0 +1,375 @@
+// Copyright (c) 2009 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 "base/crypto/rsa_private_key.h"
+
+#include <iostream>
+#include <list>
+
+#include "base/logging.h"
+#include "base/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 base {
+
+const uint8 PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = {
+  0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
+  0x05, 0x00
+};
+
+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(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;
+}
+
+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::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 the sequence with n and e into a buffer.
+  std::vector<uint8> bit_string;
+  for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
+    bit_string.push_back(*i);
+  content.clear();
+  // Add the sequence as the contents of a bit string.
+  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::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::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;
+}
+
+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;
+}
+
+}  // namespace base
diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h
index a6b0e20..3f07188c 100644
--- a/base/crypto/rsa_private_key.h
+++ b/base/crypto/rsa_private_key.h
@@ -17,12 +17,139 @@
 #include <wincrypt.h>
 #endif
 
+#include <list>
 #include <vector>
 
 #include "base/basictypes.h"
 
 namespace base {
 
+// Used internally by RSAPrivateKey for serializing and deserializing
+// PKCS #8 PrivateKeyInfo and PublicKeyInfo.
+class PrivateKeyInfoCodec {
+ public:
+
+  // ASN.1 encoding of the AlgorithmIdentifier from PKCS #8.
+  static const uint8 kRsaAlgorithmIdentifier[];
+
+  // ASN.1 tags for some types we use.
+  static const uint8 kBitStringTag = 0x03;
+  static const uint8 kIntegerTag = 0x02;
+  static const uint8 kNullTag = 0x05;
+  static const uint8 kOctetStringTag = 0x04;
+  static const uint8 kSequenceTag = 0x30;
+  
+  // |big_endian| here specifies the byte-significance of the integer components
+  // that will be parsed & serialized (modulus(), etc...) during Import(),
+  // Export() and ExportPublicKeyInfo() -- not the ASN.1 DER encoding of the
+  // PrivateKeyInfo/PublicKeyInfo (which is always big-endian).
+  explicit PrivateKeyInfoCodec(bool big_endian) : big_endian_(big_endian) {}
+
+  // Exports the contents of the integer components to the ASN.1 DER encoding
+  // of the PrivateKeyInfo structure to |output|.
+  bool Export(std::vector<uint8>* output);
+
+  // Exports the contents of the integer components to the ASN.1 DER encoding
+  // of the PublicKeyInfo structure to |output|.
+  bool ExportPublicKeyInfo(std::vector<uint8>* output);
+
+  // Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input|
+  // and populates the integer components with |big_endian_| byte-significance.
+  bool Import(const std::vector<uint8>& input);
+
+  // Accessors to the contents of the integer components of the PrivateKeyInfo
+  // structure.
+  std::vector<uint8>* modulus() { return &modulus_; };
+  std::vector<uint8>* public_exponent() { return &public_exponent_; };
+  std::vector<uint8>* private_exponent() { return &private_exponent_; };
+  std::vector<uint8>* prime1() { return &prime1_; };
+  std::vector<uint8>* prime2() { return &prime2_; };
+  std::vector<uint8>* exponent1() { return &exponent1_; };
+  std::vector<uint8>* exponent2() { return &exponent2_; };
+  std::vector<uint8>* coefficient() { return &coefficient_; };
+
+ private:
+  // Utility wrappers for PrependIntegerImpl that use the class's |big_endian_|
+  // value.
+  void PrependInteger(const std::vector<uint8>& in, std::list<uint8>* out);
+  void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data);
+  
+  // Prepends the integer stored in |val| - |val + num_bytes| with |big_endian|
+  // byte-significance into |data| as an ASN.1 integer.
+  void PrependIntegerImpl(uint8* val,
+                          int num_bytes,
+                          std::list<uint8>* data,
+                          bool big_endian);
+
+  // Utility wrappers for ReadIntegerImpl that use the class's |big_endian_|
+  // value.
+  bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out);
+  bool ReadIntegerWithExpectedSize(uint8** pos,
+                                   uint8* end,
+                                   size_t expected_size,
+                                   std::vector<uint8>* out);
+
+  // Reads an ASN.1 integer from |pos|, and stores the result into |out| with
+  // |big_endian| byte-significance.
+  bool ReadIntegerImpl(uint8** pos,
+                       uint8* end,
+                       std::vector<uint8>* out, 
+                       bool big_endian);
+  
+  // Prepends the integer stored in |val|, starting a index |start|, for
+  // |num_bytes| bytes onto |data|.
+  void PrependBytes(uint8* val,
+                    int start,
+                    int num_bytes,
+                    std::list<uint8>* data);
+
+  // Helper to prepend an ASN.1 length field.
+  void PrependLength(size_t size, std::list<uint8>* data);
+
+  // Helper to prepend an ASN.1 type header.
+  void PrependTypeHeaderAndLength(uint8 type,
+                                  uint32 length,
+                                  std::list<uint8>* output);
+
+  // Helper to prepend an ASN.1 bit string
+  void PrependBitString(uint8* val, int num_bytes, std::list<uint8>* output);
+
+  // Read an ASN.1 length field. This also checks that the length does not
+  // extend beyond |end|.
+  bool ReadLength(uint8** pos, uint8* end, uint32* result);
+
+  // Read an ASN.1 type header and its length.
+  bool ReadTypeHeaderAndLength(uint8** pos,
+                               uint8* end,
+                               uint8 expected_tag,
+                               uint32* length);
+
+  // Read an ASN.1 sequence declaration. This consumes the type header and
+  // length field, but not the contents of the sequence.
+  bool ReadSequence(uint8** pos, uint8* end);
+
+  // Read the RSA AlgorithmIdentifier.
+  bool ReadAlgorithmIdentifier(uint8** pos, uint8* end);
+
+  // Read one of the two version fields in PrivateKeyInfo.
+  bool ReadVersion(uint8** pos, uint8* end);
+
+  // The byte-significance of the stored components (modulus, etc..).
+  bool big_endian_;
+
+  // Component integers of the PrivateKeyInfo
+  std::vector<uint8> modulus_;
+  std::vector<uint8> public_exponent_;
+  std::vector<uint8> private_exponent_;
+  std::vector<uint8> prime1_;
+  std::vector<uint8> prime2_;
+  std::vector<uint8> exponent1_;
+  std::vector<uint8> exponent2_;
+  std::vector<uint8> coefficient_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrivateKeyInfoCodec);
+};
+
 // Encapsulates an RSA private key. Can be used to generate new keys, export
 // keys to other formats, or to extract a public key.
 class RSAPrivateKey {
diff --git a/base/crypto/rsa_private_key_mac.cc b/base/crypto/rsa_private_key_mac.cc
index f44115c..61845e34 100644
--- a/base/crypto/rsa_private_key_mac.cc
+++ b/base/crypto/rsa_private_key_mac.cc
@@ -10,187 +10,6 @@
 #include "base/logging.h"
 #include "base/scoped_ptr.h"
 
-namespace {
-
-// ASN.1 encoding of the AlgorithmIdentifier from PKCS #8.
-const uint8 kRsaAlgorithmIdentifier[] = {
-  0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
-  0x05, 0x00
-};
-
-// ASN.1 tags for some types we use.
-const uint8 kSequenceTag = 0x30;
-const uint8 kIntegerTag = 0x02;
-const uint8 kNullTag = 0x05;
-const uint8 kOctetStringTag = 0x04;
-const uint8 kBitStringTag = 0x03;
-
-// Helper for error handling during key import.
-#define READ_ASSERT(truth) \
-  if (!(truth)) { \
-    NOTREACHED(); \
-    return false; \
-  }
-
-static void PrependBytesInOrder(uint8* val, int start, int num_bytes,
-                                std::list<uint8>* data) {
-  while(num_bytes > start) {
-    --num_bytes;
-    data->push_front(val[num_bytes]);
-  }
-}
-
-// Helper to prepend an ASN.1 length field.
-static void 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(num_bytes <= 4);
-    data->push_front(0x80 | num_bytes);
-  }
-}
-
-// Helper to prepend an ASN.1 type header.
-static void PrependTypeHeaderAndLength(uint8 type, uint32 length,
-                                       std::list<uint8>* output) {
-  PrependLength(length, output);
-  output->push_front(type);
-}
-
-// Helper to prepend an ASN.1 bit string
-static void PrependBitString(uint8* val, int num_bytes,
-                             std::list<uint8>* output) {
-  // Start with the data.
-  PrependBytesInOrder(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(kBitStringTag);
-}
-
-// Helper to prepend an ASN.1 integer.
-static void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data) {
-  // 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++;
-
-  PrependBytesInOrder(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.
-  if ((val[start] & 0x80) != 0) {
-    data->push_front(0x00);
-    num_bytes++;
-  }
-
-  PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data);
-}
-
-// Read an ASN.1 length field. This also checks that the length does not extend
-// beyond |end|.
-static bool 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;
-}
-
-// Read an ASN.1 type header and its length.
-static bool 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);
-}
-
-// Read an ASN.1 sequence declaration. This consumes the type header and length
-// field, but not the contents of the sequence.
-static bool ReadSequence(uint8** pos, uint8* end) {
-  return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL);
-}
-
-// Read the RSA AlgorithmIdentifier.
-static bool ReadAlgorithmIdentifier(uint8** pos, uint8* end) {
-  READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end);
-  READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier,
-                     sizeof(kRsaAlgorithmIdentifier)) == 0);
-  (*pos) += sizeof(kRsaAlgorithmIdentifier);
-  return true;
-}
-
-// Read one of the two version fields in PrivateKeyInfo.
-static bool 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;
-}
-
-// Read an ASN.1 integer.
-static bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out) {
-  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;
-  return true;
-}
-
-}  // namespace
-
 namespace base {
 
 // static
@@ -318,55 +137,12 @@
 }
 
 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
-  if (!key_.KeyData.Data || !key_.KeyData.Length) {
-    return false;
-  }
-
-  // Parse the private key info up to the public key values, ignoring
-  // the subsequent private key values.
-  uint8* src = key_.KeyData.Data;
-  uint8* end = src + key_.KeyData.Length;
-  std::vector<uint8> modulus;
-  std::vector<uint8> public_exponent;
-  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) ||
-      !ReadInteger(&src, end, &public_exponent))
-    return false;
-
-  // 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 the sequence with n and e into a buffer.
-  std::vector<uint8> bit_string;
-  for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
-    bit_string.push_back(*i);
-  content.clear();
-  // Add the sequence as the contents of a bit string.
-  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;
+  PrivateKeyInfoCodec private_key_info(true);
+  std::vector<uint8> private_key_data;
+  private_key_data.assign(key_.KeyData.Data,
+                          key_.KeyData.Data + key_.KeyData.Length);
+  return (private_key_info.Import(private_key_data) &&
+          private_key_info.ExportPublicKeyInfo(output));
 }
 
 }  // namespace base
diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc
index f9f9a73..7e10b36 100644
--- a/base/crypto/rsa_private_key_nss.cc
+++ b/base/crypto/rsa_private_key_nss.cc
@@ -20,76 +20,9 @@
 // rsa_private_key_win.cc or using NSS's ASN.1 encoder.
 namespace {
 
-// ASN.1 encoding of the AlgorithmIdentifier from PKCS #8.
-const uint8 kRsaAlgorithmIdentifier[] = {
-  0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
-  0x05, 0x00
-};
-
-// ASN.1 tags for some types we use.
-const uint8 kSequenceTag = 0x30;
-const uint8 kIntegerTag = 0x02;
-const uint8 kNullTag = 0x05;
-const uint8 kOctetStringTag = 0x04;
-
-static void PrependBytesInOrder(uint8* val, int start, int num_bytes,
-                                std::list<uint8>* data) {
-  while(num_bytes > start) {
-    --num_bytes;
-    data->push_front(val[num_bytes]);
-  }
-}
-
-// Helper to prepend an ASN.1 length field.
-static void 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(num_bytes <= 4);
-    data->push_front(0x80 | num_bytes);
-  }
-}
-
-// Helper to prepend an ASN.1 type header.
-static void PrependTypeHeaderAndLength(uint8 type, uint32 length,
-                                       std::list<uint8>* output) {
-  PrependLength(length, output);
-  output->push_front(type);
-}
-
-// Helper to prepend an ASN.1 integer.
-static void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data) {
-  // 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++;
-
-  PrependBytesInOrder(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.
-  if ((val[start] & 0x80) != 0) {
-    data->push_front(0x00);
-    num_bytes++;
-  }
-
-  PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data);
-}
-
-static bool ReadAttributeAndPrependInteger(SECKEYPrivateKey* key,
-                                           CK_ATTRIBUTE_TYPE type,
-                                           std::list<uint8>* output) {
+static bool ReadAttribute(SECKEYPrivateKey* key,
+                          CK_ATTRIBUTE_TYPE type,
+                          std::vector<uint8>* output) {
   SECItem item;
   SECStatus rv;
   rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
@@ -98,14 +31,13 @@
     return false;
   }
 
-  PrependInteger(item.data, item.len, output);
+  output->assign(item.data, item.data + item.len);
   SECITEM_FreeItem(&item, PR_FALSE);
   return true;
 }
 
 }  // namespace
 
-
 namespace base {
 
 // static
@@ -170,42 +102,25 @@
 }
 
 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
-  std::list<uint8> content;
+  PrivateKeyInfoCodec private_key_info(true);
 
-  // Version (always zero)
-  uint8 version = 0;
-
-  // Manually read the component attributes of the private key and build up the
-  // output in reverse order to prevent having to do copies to figure out the
-  // length.
-  if (!ReadAttributeAndPrependInteger(key_, CKA_COEFFICIENT, &content) ||
-      !ReadAttributeAndPrependInteger(key_, CKA_EXPONENT_2, &content) ||
-      !ReadAttributeAndPrependInteger(key_, CKA_EXPONENT_1, &content) ||
-      !ReadAttributeAndPrependInteger(key_, CKA_PRIME_2, &content) ||
-      !ReadAttributeAndPrependInteger(key_, CKA_PRIME_1, &content) ||
-      !ReadAttributeAndPrependInteger(key_, CKA_PRIVATE_EXPONENT, &content) ||
-      !ReadAttributeAndPrependInteger(key_, CKA_PUBLIC_EXPONENT, &content) ||
-      !ReadAttributeAndPrependInteger(key_, CKA_MODULUS, &content)) {
+  // Manually read the component attributes of the private key and build up
+  // the PrivateKeyInfo.
+  if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
+      !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
+          private_key_info.public_exponent()) ||
+      !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
+          private_key_info.private_exponent()) ||
+      !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
+      !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
+      !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
+      !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
+      !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
     NOTREACHED();
     return false;
   }
-  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;
+  return private_key_info.Export(output);
 }
 
 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
diff --git a/base/crypto/rsa_private_key_win.cc b/base/crypto/rsa_private_key_win.cc
index b1846fa2..3683d86 100644
--- a/base/crypto/rsa_private_key_win.cc
+++ b/base/crypto/rsa_private_key_win.cc
@@ -11,215 +11,15 @@
 #include "base/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 {
-
-// ASN.1 encoding of the AlgorithmIdentifier from PKCS #8.
-const uint8 kRsaAlgorithmIdentifier[] = {
-  0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
-  0x05, 0x00
-};
-
-// ASN.1 tags for some types we use.
-const uint8 kSequenceTag = 0x30;
-const uint8 kIntegerTag = 0x02;
-const uint8 kNullTag = 0x05;
-const uint8 kOctetStringTag = 0x04;
-
-// Helper function to prepend an array of bytes into a list, reversing their
-// order. This is needed because ASN.1 integers are big-endian, while CryptoAPI
-// uses little-endian.
-static void PrependBytesInReverseOrder(uint8* val, int num_bytes,
-                                       std::list<uint8>* data) {
-  for (int i = 0; i < num_bytes; ++i)
-    data->push_front(val[i]);
-}
-
-// Helper to prepend an ASN.1 length field.
-static void 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(num_bytes <= 4);
-    data->push_front(0x80 | num_bytes);
-  }
-}
-
-// Helper to prepend an ASN.1 type header.
-static void PrependTypeHeaderAndLength(uint8 type, uint32 length,
-                                       std::list<uint8>* output) {
-  PrependLength(length, output);
-  output->push_front(type);
-}
-
-// Helper to prepend an ASN.1 integer.
-static void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data) {
-  // Skip trailing null bytes off the MSB end, which is the tail since the input
-  // is little endian.
-  while (num_bytes > 1 && val[num_bytes - 1] == 0x00)
-    num_bytes--;
-
-  PrependBytesInReverseOrder(val, num_bytes, data);
-
-  // If the MSB is set, we need to add an extra null byte, otherwise the integer
-  // could be interpreted as negative.
-  if ((val[num_bytes - 1] & 0x80) != 0) {
-    data->push_front(0x00);
-    num_bytes++;
-  }
-
-  PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data);
-}
-
-// Helper for error handling during key import.
+  // Helper for error handling during key import.
 #define READ_ASSERT(truth) \
   if (!(truth)) { \
-    NOTREACHED(); \
-    return false; \
+  NOTREACHED(); \
+  return false; \
   }
-
-// Read an ASN.1 length field. This also checks that the length does not extend
-// beyond |end|.
-static bool 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;
-}
-
-// Read an ASN.1 type header and its length.
-static bool 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);
-}
-
-// Read an ASN.1 sequence declaration. This consumes the type header and length
-// field, but not the contents of the sequence.
-static bool ReadSequence(uint8** pos, uint8* end) {
-  return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL);
-}
-
-// Read the RSA AlgorithmIdentifier.
-static bool ReadAlgorithmIdentifier(uint8** pos, uint8* end) {
-  READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end);
-  READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier,
-                     sizeof(kRsaAlgorithmIdentifier)) == 0);
-  (*pos) += sizeof(kRsaAlgorithmIdentifier);
-  return true;
-}
-
-// Read one of the two version fields in PrivateKeyInfo.
-static bool 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;
-}
-
-// Read an ASN.1 integer.
-static bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out) {
-  uint32 length = 0;
-  if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length))
-    return false;
-
-  // Read the bytes out in reverse order because of endianness.
-  for (uint32 i = length - 1; i > 0; --i)
-    out->push_back(*(*pos + i));
-
-  // The last byte can be zero to force positiveness. We can ignore this.
-  if (**pos != 0x00)
-    out->push_back(**pos);
-
-  (*pos) += length;
-  return true;
-}
-
-static bool ReadIntegerWithExpectedSize(uint8** pos, uint8* end,
-                                        int expected_size,
-                                        std::vector<uint8>* out) {
-  if (!ReadInteger(pos, end, out))
-    return false;
-
-  if (out->size() == expected_size + 1) {
-    READ_ASSERT(out->back() == 0x00);
-    out->pop_back();
-  } else {
-    READ_ASSERT(out->size() <= expected_size);
-  }
-
-  // Pad out any missing bytes with null.
-  for (size_t i = out->size(); i < expected_size; ++i)
-    out->push_back(0x00);
-
-  return true;
-}
-
 }  // namespace
 
-
 namespace base {
 
 // static
@@ -245,46 +45,18 @@
   if (!result->InitProvider())
     return NULL;
 
-  uint8* src = const_cast<uint8*>(&input.front());
-  uint8* end = src + input.size();
-  int version = -1;
-  std::vector<uint8> modulus;
-  std::vector<uint8> public_exponent;
-  std::vector<uint8> private_exponent;
-  std::vector<uint8> prime1;
-  std::vector<uint8> prime2;
-  std::vector<uint8> exponent1;
-  std::vector<uint8> exponent2;
-  std::vector<uint8> coefficient;
+  PrivateKeyInfoCodec pki(false);  // Little-Endian
+  pki.Import(input);
 
-  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);
-
-  int blob_size = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + modulus.size() +
-                  prime1.size() + prime2.size() +
-                  exponent1.size() + exponent2.size() +
-                  coefficient.size() + private_exponent.size();
+  int blob_size = sizeof(PUBLICKEYSTRUC) +
+                  sizeof(RSAPUBKEY) +
+                  pki.modulus()->size() +
+                  pki.prime1()->size() +
+                  pki.prime2()->size() +
+                  pki.exponent1()->size() +
+                  pki.exponent2()->size() +
+                  pki.coefficient()->size() +
+                  pki.private_exponent()->size();
   scoped_array<BYTE> blob(new BYTE[blob_size]);
 
   uint8* dest = blob.get();
@@ -297,29 +69,29 @@
 
   RSAPUBKEY* rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(dest);
   rsa_pub_key->magic = 0x32415352;
-  rsa_pub_key->bitlen = modulus.size() * 8;
+  rsa_pub_key->bitlen = pki.modulus()->size() * 8;
   int public_exponent_int = 0;
-  for (size_t i = public_exponent.size(); i > 0; --i) {
+  for (size_t i = pki.public_exponent()->size(); i > 0; --i) {
     public_exponent_int <<= 8;
-    public_exponent_int |= public_exponent[i - 1];
+    public_exponent_int |= (*pki.public_exponent())[i - 1];
   }
   rsa_pub_key->pubexp = public_exponent_int;
   dest += sizeof(RSAPUBKEY);
 
-  memcpy(dest, &modulus.front(), modulus.size());
-  dest += modulus.size();
-  memcpy(dest, &prime1.front(), prime1.size());
-  dest += prime1.size();
-  memcpy(dest, &prime2.front(), prime2.size());
-  dest += prime2.size();
-  memcpy(dest, &exponent1.front(), exponent1.size());
-  dest += exponent1.size();
-  memcpy(dest, &exponent2.front(), exponent2.size());
-  dest += exponent2.size();
-  memcpy(dest, &coefficient.front(), coefficient.size());
-  dest += coefficient.size();
-  memcpy(dest, &private_exponent.front(), private_exponent.size());
-  dest += private_exponent.size();
+  memcpy(dest, &pki.modulus()->front(), pki.modulus()->size());
+  dest += pki.modulus()->size();
+  memcpy(dest, &pki.prime1()->front(), pki.prime1()->size());
+  dest += pki.prime1()->size();
+  memcpy(dest, &pki.prime2()->front(), pki.prime2()->size());
+  dest += pki.prime2()->size();
+  memcpy(dest, &pki.exponent1()->front(), pki.exponent1()->size());
+  dest += pki.exponent1()->size();
+  memcpy(dest, &pki.exponent2()->front(), pki.exponent2()->size());
+  dest += pki.exponent2()->size();
+  memcpy(dest, &pki.coefficient()->front(), pki.coefficient()->size());
+  dest += pki.coefficient()->size();
+  memcpy(dest, &pki.private_exponent()->front(), pki.private_exponent()->size());
+  dest += pki.private_exponent()->size();
 
   READ_ASSERT(dest == blob.get() + blob_size);
   if (!CryptImportKey(
@@ -375,59 +147,33 @@
   int mod_size = rsa_pub_key->bitlen / 8;
   int primes_size = rsa_pub_key->bitlen / 16;
 
-  uint8* modulus = pos;
+  PrivateKeyInfoCodec pki(false);  // Little-Endian
+
+  pki.modulus()->assign(pos, pos + mod_size);
   pos += mod_size;
 
-  uint8* prime1 = pos;
+  pki.prime1()->assign(pos, pos + primes_size);
   pos += primes_size;
-  uint8* prime2 = pos;
+  pki.prime2()->assign(pos, pos + primes_size);
   pos += primes_size;
 
-  uint8* exponent1 = pos;
+  pki.exponent1()->assign(pos, pos + primes_size);
   pos += primes_size;
-  uint8* exponent2 = pos;
+  pki.exponent2()->assign(pos, pos + primes_size);
   pos += primes_size;
 
-  uint8* coefficient = pos;
+  pki.coefficient()->assign(pos, pos + primes_size);
   pos += primes_size;
 
-  uint8* private_exponent = pos;
+  pki.private_exponent()->assign(pos, pos + mod_size);
   pos += mod_size;
 
+  pki.public_exponent()->assign(reinterpret_cast<uint8*>(&rsa_pub_key->pubexp),
+      reinterpret_cast<uint8*>(&rsa_pub_key->pubexp) + 4);
+
   CHECK((pos - blob_length) == reinterpret_cast<BYTE*>(publickey_struct));
 
-  std::list<uint8> content;
-
-  // Version (always zero)
-  uint8 version = 0;
-
-  // We build up the output in reverse order to prevent having to do copies to
-  // figure out the length.
-  PrependInteger(coefficient, primes_size, &content);
-  PrependInteger(exponent2, primes_size, &content);
-  PrependInteger(exponent1, primes_size, &content);
-  PrependInteger(prime2, primes_size, &content);
-  PrependInteger(prime1, primes_size, &content);
-  PrependInteger(private_exponent, mod_size, &content);
-  PrependInteger(reinterpret_cast<uint8*>(&rsa_pub_key->pubexp), 4, &content);
-  PrependInteger(modulus, mod_size, &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;
+  return pki.Export(output);
 }
 
 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
diff --git a/base/crypto/signature_creator_unittest.cc b/base/crypto/signature_creator_unittest.cc
index 71aaba1f..11959cb9 100644
--- a/base/crypto/signature_creator_unittest.cc
+++ b/base/crypto/signature_creator_unittest.cc
@@ -19,6 +19,7 @@
   key_original->ExportPrivateKey(&key_info);
   scoped_ptr<base::RSAPrivateKey> key(
       base::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
+  ASSERT_TRUE(key.get());
 
   scoped_ptr<base::SignatureCreator> signer(
       base::SignatureCreator::Create(key.get()));