Home | History | Annotate | Download | only in crypto
      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.
      4 
      5 #include "crypto/openpgp_symmetric_encryption.h"
      6 
      7 #include <stdlib.h>
      8 
      9 #include <sechash.h>
     10 #include <cryptohi.h>
     11 
     12 #include <vector>
     13 
     14 #include "base/logging.h"
     15 #include "crypto/random.h"
     16 #include "crypto/scoped_nss_types.h"
     17 #include "crypto/nss_util.h"
     18 
     19 namespace crypto {
     20 
     21 namespace {
     22 
     23 // Reader wraps a StringPiece and provides methods to read several datatypes
     24 // while advancing the StringPiece.
     25 class Reader {
     26  public:
     27   Reader(base::StringPiece input)
     28       : data_(input) {
     29   }
     30 
     31   bool U8(uint8* out) {
     32     if (data_.size() < 1)
     33       return false;
     34     *out = static_cast<uint8>(data_[0]);
     35     data_.remove_prefix(1);
     36     return true;
     37   }
     38 
     39   bool U32(uint32* out) {
     40     if (data_.size() < 4)
     41       return false;
     42     *out = static_cast<uint32>(data_[0]) << 24 |
     43            static_cast<uint32>(data_[1]) << 16 |
     44            static_cast<uint32>(data_[2]) << 8 |
     45            static_cast<uint32>(data_[3]);
     46     data_.remove_prefix(4);
     47     return true;
     48   }
     49 
     50   // Prefix sets |*out| to the first |n| bytes of the StringPiece and advances
     51   // the StringPiece by |n|.
     52   bool Prefix(size_t n, base::StringPiece *out) {
     53     if (data_.size() < n)
     54       return false;
     55     *out = base::StringPiece(data_.data(), n);
     56     data_.remove_prefix(n);
     57     return true;
     58   }
     59 
     60   // Remainder returns the remainer of the StringPiece and advances it to the
     61   // end.
     62   base::StringPiece Remainder() {
     63     base::StringPiece ret = data_;
     64     data_ = base::StringPiece();
     65     return ret;
     66   }
     67 
     68   typedef base::StringPiece Position;
     69 
     70   Position tell() const {
     71     return data_;
     72   }
     73 
     74   void Seek(Position p) {
     75     data_ = p;
     76   }
     77 
     78   bool Skip(size_t n) {
     79     if (data_.size() < n)
     80       return false;
     81     data_.remove_prefix(n);
     82     return true;
     83   }
     84 
     85   bool empty() const {
     86     return data_.empty();
     87   }
     88 
     89   size_t size() const {
     90     return data_.size();
     91   }
     92 
     93  private:
     94   base::StringPiece data_;
     95 };
     96 
     97 // SaltedIteratedS2K implements the salted and iterated string-to-key
     98 // convertion. See RFC 4880, section 3.7.1.3.
     99 void SaltedIteratedS2K(unsigned cipher_key_length,
    100                        HASH_HashType hash_function,
    101                        base::StringPiece passphrase,
    102                        base::StringPiece salt,
    103                        unsigned count,
    104                        uint8 *out_key) {
    105   const std::string combined = salt.as_string() + passphrase.as_string();
    106   const size_t combined_len = combined.size();
    107 
    108   unsigned done = 0;
    109   uint8 zero[1] = {0};
    110 
    111   HASHContext* hash_context = HASH_Create(hash_function);
    112 
    113   for (unsigned i = 0; done < cipher_key_length; i++) {
    114     HASH_Begin(hash_context);
    115 
    116     for (unsigned j = 0; j < i; j++)
    117       HASH_Update(hash_context, zero, sizeof(zero));
    118 
    119     unsigned written = 0;
    120     while (written < count) {
    121       if (written + combined_len > count) {
    122         unsigned todo = count - written;
    123         HASH_Update(hash_context,
    124                      reinterpret_cast<const uint8*>(combined.data()),
    125                      todo);
    126         written = count;
    127       } else {
    128         HASH_Update(hash_context,
    129                      reinterpret_cast<const uint8*>(combined.data()),
    130                      combined_len);
    131         written += combined_len;
    132       }
    133     }
    134 
    135     unsigned num_hash_bytes;
    136     uint8 digest[HASH_LENGTH_MAX];
    137     HASH_End(hash_context, digest, &num_hash_bytes, sizeof(digest));
    138 
    139     unsigned todo = cipher_key_length - done;
    140     if (todo > num_hash_bytes)
    141       todo = num_hash_bytes;
    142     memcpy(out_key + done, digest, todo);
    143     done += todo;
    144   }
    145 
    146   HASH_Destroy(hash_context);
    147 }
    148 
    149 // CreateAESContext sets up |out_key| to be an AES context, with the given key,
    150 // in ECB mode and with no IV.
    151 bool CreateAESContext(const uint8* key, unsigned key_len,
    152                       ScopedPK11Context* out_decryption_context) {
    153   ScopedPK11Slot slot(PK11_GetInternalSlot());
    154   if (!slot.get())
    155     return false;
    156   SECItem key_item;
    157   key_item.type = siBuffer;
    158   key_item.data = const_cast<uint8*>(key);
    159   key_item.len = key_len;
    160   ScopedPK11SymKey pk11_key(PK11_ImportSymKey(
    161       slot.get(), CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item,
    162       NULL));
    163   if (!pk11_key.get())
    164     return false;
    165   ScopedSECItem iv_param(PK11_ParamFromIV(CKM_AES_ECB, NULL));
    166   out_decryption_context->reset(
    167       PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, pk11_key.get(),
    168                                  iv_param.get()));
    169   return out_decryption_context->get() != NULL;
    170 }
    171 
    172 
    173 // These constants are the tag numbers for the various packet types that we
    174 // use.
    175 static const unsigned kSymmetricKeyEncryptedTag = 3;
    176 static const unsigned kSymmetricallyEncryptedTag = 18;
    177 static const unsigned kCompressedTag = 8;
    178 static const unsigned kLiteralDataTag = 11;
    179 
    180 class Decrypter {
    181  public:
    182   ~Decrypter() {
    183     for (std::vector<void*>::iterator
    184          i = arena_.begin(); i != arena_.end(); i++) {
    185       free(*i);
    186     }
    187     arena_.clear();
    188   }
    189 
    190   OpenPGPSymmetricEncrytion::Result Decrypt(base::StringPiece in,
    191                                             base::StringPiece passphrase,
    192                                             base::StringPiece *out_contents) {
    193     Reader reader(in);
    194     unsigned tag;
    195     base::StringPiece contents;
    196     ScopedPK11Context decryption_context;
    197 
    198     if (!ParsePacket(&reader, &tag, &contents))
    199       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    200     if (tag != kSymmetricKeyEncryptedTag)
    201       return OpenPGPSymmetricEncrytion::NOT_SYMMETRICALLY_ENCRYPTED;
    202     Reader inner(contents);
    203     OpenPGPSymmetricEncrytion::Result result =
    204       ParseSymmetricKeyEncrypted(&inner, passphrase, &decryption_context);
    205     if (result != OpenPGPSymmetricEncrytion::OK)
    206       return result;
    207 
    208     if (!ParsePacket(&reader, &tag, &contents))
    209       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    210     if (tag != kSymmetricallyEncryptedTag)
    211       return OpenPGPSymmetricEncrytion::NOT_SYMMETRICALLY_ENCRYPTED;
    212     if (!reader.empty())
    213       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    214     inner = Reader(contents);
    215     if (!ParseSymmetricallyEncrypted(&inner, &decryption_context, &contents))
    216       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    217 
    218     reader = Reader(contents);
    219     if (!ParsePacket(&reader, &tag, &contents))
    220       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    221     if (tag == kCompressedTag)
    222       return OpenPGPSymmetricEncrytion::COMPRESSED;
    223     if (tag != kLiteralDataTag)
    224       return OpenPGPSymmetricEncrytion::NOT_SYMMETRICALLY_ENCRYPTED;
    225     inner = Reader(contents);
    226     if (!ParseLiteralData(&inner, out_contents))
    227       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    228 
    229     return OpenPGPSymmetricEncrytion::OK;
    230   }
    231 
    232  private:
    233   // ParsePacket parses an OpenPGP packet from reader. See RFC 4880, section
    234   // 4.2.2.
    235   bool ParsePacket(Reader *reader,
    236                    unsigned *out_tag,
    237                    base::StringPiece *out_contents) {
    238     uint8 header;
    239     if (!reader->U8(&header))
    240       return false;
    241     if ((header & 0x80) == 0) {
    242       // Tag byte must have MSB set.
    243       return false;
    244     }
    245 
    246     if ((header & 0x40) == 0) {
    247       // Old format packet.
    248       *out_tag = (header & 0x3f) >> 2;
    249 
    250       uint8 length_type = header & 3;
    251       if (length_type == 3) {
    252         *out_contents = reader->Remainder();
    253         return true;
    254       }
    255 
    256       const unsigned length_bytes = 1 << length_type;
    257       size_t length = 0;
    258       for (unsigned i = 0; i < length_bytes; i++) {
    259         uint8 length_byte;
    260         if (!reader->U8(&length_byte))
    261           return false;
    262         length <<= 8;
    263         length |= length_byte;
    264       }
    265 
    266       return reader->Prefix(length, out_contents);
    267     }
    268 
    269     // New format packet.
    270     *out_tag = header & 0x3f;
    271     size_t length;
    272     bool is_partial;
    273     if (!ParseLength(reader, &length, &is_partial))
    274       return false;
    275     if (is_partial)
    276       return ParseStreamContents(reader, length, out_contents);
    277     return reader->Prefix(length, out_contents);
    278   }
    279 
    280   // ParseStreamContents parses all the chunks of a partial length stream from
    281   // reader. See http://tools.ietf.org/html/rfc4880#section-4.2.2.4
    282   bool ParseStreamContents(Reader *reader,
    283                            size_t length,
    284                            base::StringPiece *out_contents) {
    285     const Reader::Position beginning_of_stream = reader->tell();
    286     const size_t first_chunk_length = length;
    287 
    288     // First we parse the stream to find its length.
    289     if (!reader->Skip(length))
    290       return false;
    291 
    292     for (;;) {
    293       size_t chunk_length;
    294       bool is_partial;
    295 
    296       if (!ParseLength(reader, &chunk_length, &is_partial))
    297         return false;
    298       if (length + chunk_length < length)
    299         return false;
    300       length += chunk_length;
    301       if (!reader->Skip(chunk_length))
    302         return false;
    303       if (!is_partial)
    304         break;
    305     }
    306 
    307     // Now we have the length of the whole stream in |length|.
    308     char* buf = reinterpret_cast<char*>(malloc(length));
    309     arena_.push_back(buf);
    310     size_t j = 0;
    311     reader->Seek(beginning_of_stream);
    312 
    313     base::StringPiece first_chunk;
    314     if (!reader->Prefix(first_chunk_length, &first_chunk))
    315       return false;
    316     memcpy(buf + j, first_chunk.data(), first_chunk_length);
    317     j += first_chunk_length;
    318 
    319     // Now we parse the stream again, this time copying into |buf|
    320     for (;;) {
    321       size_t chunk_length;
    322       bool is_partial;
    323 
    324       if (!ParseLength(reader, &chunk_length, &is_partial))
    325         return false;
    326       base::StringPiece chunk;
    327       if (!reader->Prefix(chunk_length, &chunk))
    328         return false;
    329       memcpy(buf + j, chunk.data(), chunk_length);
    330       j += chunk_length;
    331       if (!is_partial)
    332         break;
    333     }
    334 
    335     *out_contents = base::StringPiece(buf, length);
    336     return true;
    337   }
    338 
    339   // ParseLength parses an OpenPGP length from reader. See RFC 4880, section
    340   // 4.2.2.
    341   bool ParseLength(Reader *reader, size_t *out_length, bool *out_is_prefix) {
    342     uint8 length_spec;
    343     if (!reader->U8(&length_spec))
    344       return false;
    345 
    346     *out_is_prefix = false;
    347     if (length_spec < 192) {
    348       *out_length = length_spec;
    349       return true;
    350     } else if (length_spec < 224) {
    351       uint8 next_byte;
    352       if (!reader->U8(&next_byte))
    353         return false;
    354 
    355       *out_length = (length_spec - 192) << 8;
    356       *out_length += next_byte;
    357       return true;
    358     } else if (length_spec < 255) {
    359       *out_length = 1u << (length_spec & 0x1f);
    360       *out_is_prefix = true;
    361       return true;
    362     } else {
    363       uint32 length32;
    364       if (!reader->U32(&length32))
    365         return false;
    366       *out_length = length32;
    367       return true;
    368     }
    369   }
    370 
    371   // ParseSymmetricKeyEncrypted parses a passphrase protected session key. See
    372   // RFC 4880, section 5.3.
    373   OpenPGPSymmetricEncrytion::Result ParseSymmetricKeyEncrypted(
    374       Reader *reader,
    375       base::StringPiece passphrase,
    376       ScopedPK11Context *decryption_context) {
    377     uint8 version, cipher, s2k_type, hash_func_id;
    378     if (!reader->U8(&version) || version != 4)
    379       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    380 
    381     if (!reader->U8(&cipher) ||
    382         !reader->U8(&s2k_type) ||
    383         !reader->U8(&hash_func_id)) {
    384       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    385     }
    386 
    387     uint8 cipher_key_length = OpenPGPCipherIdToKeyLength(cipher);
    388     if (cipher_key_length == 0)
    389       return OpenPGPSymmetricEncrytion::UNKNOWN_CIPHER;
    390 
    391     HASH_HashType hash_function;
    392     switch (hash_func_id) {
    393     case 2:  // SHA-1
    394       hash_function = HASH_AlgSHA1;
    395       break;
    396     case 8:  // SHA-256
    397       hash_function = HASH_AlgSHA256;
    398       break;
    399     default:
    400       return OpenPGPSymmetricEncrytion::UNKNOWN_HASH;
    401     }
    402 
    403     // This chunk of code parses the S2K specifier. See RFC 4880, section 3.7.1.
    404     base::StringPiece salt;
    405     uint8 key[32];
    406     uint8 count_spec;
    407     switch (s2k_type) {
    408     case 1:
    409       if (!reader->Prefix(8, &salt))
    410         return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    411       // Fall through.
    412     case 0:
    413       SaltedIteratedS2K(cipher_key_length, hash_function, passphrase, salt,
    414                         passphrase.size() + salt.size(), key);
    415       break;
    416     case 3:
    417       if (!reader->Prefix(8, &salt) ||
    418           !reader->U8(&count_spec)) {
    419         return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    420       }
    421       SaltedIteratedS2K(
    422           cipher_key_length, hash_function, passphrase, salt,
    423           static_cast<unsigned>(
    424             16 + (count_spec&15)) << ((count_spec >> 4) + 6), key);
    425       break;
    426     default:
    427       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    428     }
    429 
    430     if (!CreateAESContext(key, cipher_key_length, decryption_context))
    431       return OpenPGPSymmetricEncrytion::INTERNAL_ERROR;
    432 
    433     if (reader->empty()) {
    434       // The resulting key is used directly.
    435       return OpenPGPSymmetricEncrytion::OK;
    436     }
    437 
    438     // The S2K derived key encrypts another key that follows:
    439     base::StringPiece encrypted_key = reader->Remainder();
    440     if (encrypted_key.size() < 1)
    441       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    442 
    443     uint8* plaintext_key = reinterpret_cast<uint8*>(
    444         malloc(encrypted_key.size()));
    445     arena_.push_back(plaintext_key);
    446 
    447     CFBDecrypt(encrypted_key, decryption_context, plaintext_key);
    448 
    449     cipher_key_length = OpenPGPCipherIdToKeyLength(plaintext_key[0]);
    450     if (cipher_key_length == 0)
    451       return OpenPGPSymmetricEncrytion::UNKNOWN_CIPHER;
    452     if (encrypted_key.size() != 1u + cipher_key_length)
    453       return OpenPGPSymmetricEncrytion::PARSE_ERROR;
    454     if (!CreateAESContext(plaintext_key + 1, cipher_key_length,
    455                           decryption_context)) {
    456       return OpenPGPSymmetricEncrytion::INTERNAL_ERROR;
    457     }
    458     return OpenPGPSymmetricEncrytion::OK;
    459   }
    460 
    461   // CFBDecrypt decrypts the cipher-feedback encrypted data in |in| to |out|
    462   // using |decryption_context| and assumes an IV of all zeros.
    463   void CFBDecrypt(base::StringPiece in, ScopedPK11Context* decryption_context,
    464                   uint8* out) {
    465     // We need this for PK11_CipherOp to write to, but we never check it as we
    466     // work in ECB mode, one block at a time.
    467     int out_len;
    468 
    469     uint8 mask[AES_BLOCK_SIZE];
    470     memset(mask, 0, sizeof(mask));
    471 
    472     unsigned used = AES_BLOCK_SIZE;
    473 
    474     for (size_t i = 0; i < in.size(); i++) {
    475       if (used == AES_BLOCK_SIZE) {
    476         PK11_CipherOp(decryption_context->get(), mask, &out_len, sizeof(mask),
    477                       mask, AES_BLOCK_SIZE);
    478         used = 0;
    479       }
    480 
    481       uint8 t = in[i];
    482       out[i] = t ^ mask[used];
    483       mask[used] = t;
    484       used++;
    485     }
    486   }
    487 
    488   // OpenPGPCipherIdToKeyLength converts an OpenPGP cipher id (see RFC 4880,
    489   // section 9.2) to the key length of that cipher. It returns 0 on error.
    490   unsigned OpenPGPCipherIdToKeyLength(uint8 cipher) {
    491     switch (cipher) {
    492     case 7:  // AES-128
    493       return 16;
    494     case 8:  // AES-192
    495       return 24;
    496     case 9:  // AES-256
    497       return 32;
    498     default:
    499       return 0;
    500     }
    501   }
    502 
    503   // ParseSymmetricallyEncrypted parses a Symmetrically Encrypted packet. See
    504   // RFC 4880, sections 5.7 and 5.13.
    505   bool ParseSymmetricallyEncrypted(Reader *reader,
    506                                    ScopedPK11Context *decryption_context,
    507                                    base::StringPiece *out_plaintext) {
    508     // We need this for PK11_CipherOp to write to, but we never check it as we
    509     // work in ECB mode, one block at a time.
    510     int out_len;
    511 
    512     uint8 version;
    513     if (!reader->U8(&version) || version != 1)
    514       return false;
    515 
    516     base::StringPiece prefix_sp;
    517     if (!reader->Prefix(AES_BLOCK_SIZE + 2, &prefix_sp))
    518       return false;
    519     uint8 prefix[AES_BLOCK_SIZE + 2];
    520     memcpy(prefix, prefix_sp.data(), sizeof(prefix));
    521 
    522     uint8 prefix_copy[AES_BLOCK_SIZE + 2];
    523     uint8 fre[AES_BLOCK_SIZE];
    524 
    525     memset(prefix_copy, 0, AES_BLOCK_SIZE);
    526     PK11_CipherOp(decryption_context->get(), fre, &out_len, sizeof(fre),
    527                   prefix_copy, AES_BLOCK_SIZE);
    528     for (unsigned i = 0; i < AES_BLOCK_SIZE; i++)
    529       prefix_copy[i] = fre[i] ^ prefix[i];
    530     PK11_CipherOp(decryption_context->get(), fre, &out_len, sizeof(fre), prefix,
    531                   AES_BLOCK_SIZE);
    532     prefix_copy[AES_BLOCK_SIZE] = prefix[AES_BLOCK_SIZE] ^ fre[0];
    533     prefix_copy[AES_BLOCK_SIZE + 1] = prefix[AES_BLOCK_SIZE + 1] ^ fre[1];
    534 
    535     if (prefix_copy[AES_BLOCK_SIZE - 2] != prefix_copy[AES_BLOCK_SIZE] ||
    536         prefix_copy[AES_BLOCK_SIZE - 1] != prefix_copy[AES_BLOCK_SIZE + 1]) {
    537       return false;
    538     }
    539 
    540     fre[0] = prefix[AES_BLOCK_SIZE];
    541     fre[1] = prefix[AES_BLOCK_SIZE + 1];
    542 
    543     unsigned out_used = 2;
    544 
    545     const size_t plaintext_size = reader->size();
    546     if (plaintext_size < SHA1_LENGTH + 2) {
    547       // Too small to contain an MDC trailer.
    548       return false;
    549     }
    550 
    551     uint8* plaintext = reinterpret_cast<uint8*>(malloc(plaintext_size));
    552     arena_.push_back(plaintext);
    553 
    554     for (size_t i = 0; i < plaintext_size; i++) {
    555       uint8 b;
    556       if (!reader->U8(&b))
    557         return false;
    558       if (out_used == AES_BLOCK_SIZE) {
    559         PK11_CipherOp(decryption_context->get(), fre, &out_len, sizeof(fre),
    560                       fre, AES_BLOCK_SIZE);
    561         out_used = 0;
    562       }
    563 
    564       plaintext[i] = b ^ fre[out_used];
    565       fre[out_used++] = b;
    566     }
    567 
    568     // The plaintext should be followed by a Modification Detection Code
    569     // packet. This packet is specified such that the header is always
    570     // serialized as exactly these two bytes:
    571     if (plaintext[plaintext_size - SHA1_LENGTH - 2] != 0xd3 ||
    572         plaintext[plaintext_size - SHA1_LENGTH - 1] != 0x14) {
    573       return false;
    574     }
    575 
    576     HASHContext* hash_context = HASH_Create(HASH_AlgSHA1);
    577     HASH_Begin(hash_context);
    578     HASH_Update(hash_context, prefix_copy, sizeof(prefix_copy));
    579     HASH_Update(hash_context, plaintext, plaintext_size - SHA1_LENGTH);
    580     uint8 digest[SHA1_LENGTH];
    581     unsigned num_hash_bytes;
    582     HASH_End(hash_context, digest, &num_hash_bytes, sizeof(digest));
    583     HASH_Destroy(hash_context);
    584 
    585     if (memcmp(digest, &plaintext[plaintext_size - SHA1_LENGTH],
    586                SHA1_LENGTH) != 0) {
    587       return false;
    588     }
    589 
    590     *out_plaintext = base::StringPiece(reinterpret_cast<char*>(plaintext),
    591                                        plaintext_size - SHA1_LENGTH);
    592     return true;
    593   }
    594 
    595   // ParseLiteralData parses a Literal Data packet. See RFC 4880, section 5.9.
    596   bool ParseLiteralData(Reader *reader, base::StringPiece *out_data) {
    597     uint8 is_binary, filename_len;
    598     if (!reader->U8(&is_binary) ||
    599         !reader->U8(&filename_len) ||
    600         !reader->Skip(filename_len) ||
    601         !reader->Skip(sizeof(uint32) /* mtime */)) {
    602       return false;
    603     }
    604 
    605     *out_data = reader->Remainder();
    606     return true;
    607   }
    608 
    609   // arena_ contains malloced pointers that are used as temporary space during
    610   // the decryption.
    611   std::vector<void*> arena_;
    612 };
    613 
    614 class Encrypter {
    615  public:
    616   // ByteString is used throughout in order to avoid signedness issues with a
    617   // std::string.
    618   typedef std::basic_string<uint8> ByteString;
    619 
    620   static ByteString Encrypt(base::StringPiece plaintext,
    621                             base::StringPiece passphrase) {
    622     ByteString key;
    623     ByteString ske = SerializeSymmetricKeyEncrypted(passphrase, &key);
    624 
    625     ByteString literal_data = SerializeLiteralData(plaintext);
    626     ByteString se = SerializeSymmetricallyEncrypted(literal_data, key);
    627     return ske + se;
    628   }
    629 
    630  private:
    631   // MakePacket returns an OpenPGP packet tagged as type |tag|. It always uses
    632   // new-format headers. See RFC 4880, section 4.2.
    633   static ByteString MakePacket(unsigned tag, const ByteString& contents) {
    634     ByteString header;
    635     header.push_back(0x80 | 0x40 | tag);
    636 
    637     if (contents.size() < 192) {
    638       header.push_back(contents.size());
    639     } else if (contents.size() < 8384) {
    640       size_t length = contents.size();
    641       length -= 192;
    642       header.push_back(192 + (length >> 8));
    643       header.push_back(length & 0xff);
    644     } else {
    645       size_t length = contents.size();
    646       header.push_back(255);
    647       header.push_back(length >> 24);
    648       header.push_back(length >> 16);
    649       header.push_back(length >> 8);
    650       header.push_back(length);
    651     }
    652 
    653     return header + contents;
    654   }
    655 
    656   // SerializeLiteralData returns a Literal Data packet containing |contents|
    657   // as binary data with no filename nor mtime specified. See RFC 4880, section
    658   // 5.9.
    659   static ByteString SerializeLiteralData(base::StringPiece contents) {
    660     ByteString literal_data;
    661     literal_data.push_back(0x74);  // text mode
    662     literal_data.push_back(0x00);  // no filename
    663     literal_data.push_back(0x00);  // zero mtime
    664     literal_data.push_back(0x00);
    665     literal_data.push_back(0x00);
    666     literal_data.push_back(0x00);
    667     literal_data += ByteString(reinterpret_cast<const uint8*>(contents.data()),
    668                                contents.size());
    669     return MakePacket(kLiteralDataTag, literal_data);
    670   }
    671 
    672   // SerializeSymmetricKeyEncrypted generates a random AES-128 key from
    673   // |passphrase|, sets |out_key| to it and returns a Symmetric Key Encrypted
    674   // packet. See RFC 4880, section 5.3.
    675   static ByteString SerializeSymmetricKeyEncrypted(base::StringPiece passphrase,
    676                                                    ByteString *out_key) {
    677     ByteString ske;
    678     ske.push_back(4);  // version 4
    679     ske.push_back(7);  // AES-128
    680     ske.push_back(3);  // iterated and salted S2K
    681     ske.push_back(2);  // SHA-1
    682 
    683     uint64 salt64;
    684     crypto::RandBytes(&salt64, sizeof(salt64));
    685     ByteString salt(sizeof(salt64), 0);
    686 
    687     // It's a random value, so endianness doesn't matter.
    688     ske += ByteString(reinterpret_cast<uint8*>(&salt64), sizeof(salt64));
    689     ske.push_back(96);  // iteration count of 65536
    690 
    691     uint8 key[16];
    692     SaltedIteratedS2K(
    693         sizeof(key), HASH_AlgSHA1, passphrase,
    694         base::StringPiece(reinterpret_cast<char*>(&salt64), sizeof(salt64)),
    695         65536, key);
    696     *out_key = ByteString(key, sizeof(key));
    697     return MakePacket(kSymmetricKeyEncryptedTag, ske);
    698   }
    699 
    700   // SerializeSymmetricallyEncrypted encrypts |plaintext| with |key| and
    701   // returns a Symmetrically Encrypted packet containing the ciphertext. See
    702   // RFC 4880, section 5.7.
    703   static ByteString SerializeSymmetricallyEncrypted(ByteString plaintext,
    704                                                     const ByteString& key) {
    705     // We need this for PK11_CipherOp to write to, but we never check it as we
    706     // work in ECB mode, one block at a time.
    707     int out_len;
    708 
    709     ByteString packet;
    710     packet.push_back(1);  // version 1
    711     static const unsigned kBlockSize = 16;  // AES block size
    712 
    713     uint8 prefix[kBlockSize + 2], fre[kBlockSize], iv[kBlockSize];
    714     crypto::RandBytes(iv, kBlockSize);
    715     memset(fre, 0, sizeof(fre));
    716 
    717     ScopedPK11Context aes_context;
    718     CHECK(CreateAESContext(key.data(), key.size(), &aes_context));
    719 
    720     PK11_CipherOp(aes_context.get(), fre, &out_len, sizeof(fre), fre,
    721                   AES_BLOCK_SIZE);
    722     for (unsigned i = 0; i < 16; i++)
    723       prefix[i] = iv[i] ^ fre[i];
    724     PK11_CipherOp(aes_context.get(), fre, &out_len, sizeof(fre), prefix,
    725                   AES_BLOCK_SIZE);
    726     prefix[kBlockSize] = iv[kBlockSize - 2] ^ fre[0];
    727     prefix[kBlockSize + 1] = iv[kBlockSize - 1] ^ fre[1];
    728 
    729     packet += ByteString(prefix, sizeof(prefix));
    730 
    731     ByteString plaintext_copy = plaintext;
    732     plaintext_copy.push_back(0xd3);  // MDC packet
    733     plaintext_copy.push_back(20);  // packet length (20 bytes)
    734 
    735     HASHContext* hash_context = HASH_Create(HASH_AlgSHA1);
    736     HASH_Begin(hash_context);
    737     HASH_Update(hash_context, iv, sizeof(iv));
    738     HASH_Update(hash_context, iv + kBlockSize - 2, 2);
    739     HASH_Update(hash_context, plaintext_copy.data(), plaintext_copy.size());
    740     uint8 digest[SHA1_LENGTH];
    741     unsigned num_hash_bytes;
    742     HASH_End(hash_context, digest, &num_hash_bytes, sizeof(digest));
    743     HASH_Destroy(hash_context);
    744 
    745     plaintext_copy += ByteString(digest, sizeof(digest));
    746 
    747     fre[0] = prefix[kBlockSize];
    748     fre[1] = prefix[kBlockSize+1];
    749     unsigned out_used = 2;
    750 
    751     for (size_t i = 0; i < plaintext_copy.size(); i++) {
    752       if (out_used == kBlockSize) {
    753         PK11_CipherOp(aes_context.get(), fre, &out_len, sizeof(fre), fre,
    754                       AES_BLOCK_SIZE);
    755         out_used = 0;
    756       }
    757 
    758       uint8 c = plaintext_copy[i] ^ fre[out_used];
    759       fre[out_used++] = c;
    760       packet.push_back(c);
    761     }
    762 
    763     return MakePacket(kSymmetricallyEncryptedTag, packet);
    764   }
    765 };
    766 
    767 }  // anonymous namespace
    768 
    769 // static
    770 OpenPGPSymmetricEncrytion::Result OpenPGPSymmetricEncrytion::Decrypt(
    771     base::StringPiece encrypted,
    772     base::StringPiece passphrase,
    773     std::string *out) {
    774   EnsureNSSInit();
    775 
    776   Decrypter decrypter;
    777   base::StringPiece result;
    778   Result reader = decrypter.Decrypt(encrypted, passphrase, &result);
    779   if (reader == OK)
    780     *out = result.as_string();
    781   return reader;
    782 }
    783 
    784 // static
    785 std::string OpenPGPSymmetricEncrytion::Encrypt(
    786     base::StringPiece plaintext,
    787     base::StringPiece passphrase) {
    788   EnsureNSSInit();
    789 
    790   Encrypter::ByteString b =
    791       Encrypter::Encrypt(plaintext, passphrase);
    792   return std::string(reinterpret_cast<const char*>(b.data()), b.size());
    793 }
    794 
    795 }  // namespace crypto
    796