diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-06 15:23:02 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-06 15:23:02 +0000 |
commit | b00a46023e5ca59e7ec7d4cee84fb1aaf416f0e8 (patch) | |
tree | 5338b22f073c4a9b329b04b53916ba6451d07617 /crypto/openpgp_symmetric_encryption.cc | |
parent | 51aa0dde5ac8945cebcfa6b183ab644c5ded9a07 (diff) | |
download | chromium_src-b00a46023e5ca59e7ec7d4cee84fb1aaf416f0e8.zip chromium_src-b00a46023e5ca59e7ec7d4cee84fb1aaf416f0e8.tar.gz chromium_src-b00a46023e5ca59e7ec7d4cee84fb1aaf416f0e8.tar.bz2 |
Revert "crypto: convert OpenPGP code to NSS"
This reverts commit r91559. Broke the Windows shared build.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91561 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'crypto/openpgp_symmetric_encryption.cc')
-rw-r--r-- | crypto/openpgp_symmetric_encryption.cc | 790 |
1 files changed, 0 insertions, 790 deletions
diff --git a/crypto/openpgp_symmetric_encryption.cc b/crypto/openpgp_symmetric_encryption.cc deleted file mode 100644 index 62223f9..0000000 --- a/crypto/openpgp_symmetric_encryption.cc +++ /dev/null @@ -1,790 +0,0 @@ -// 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/openpgp_symmetric_encryption.h" - -#include <stdlib.h> - -#include <sechash.h> -#include <cryptohi.h> - -#include <vector> - -#include "base/logging.h" -#include "base/rand_util.h" -#include "crypto/scoped_nss_types.h" - -namespace crypto { - -namespace { - -// Reader wraps a StringPiece and provides methods to read several datatypes -// while advancing the StringPiece. -class Reader { - public: - Reader(base::StringPiece input) - : data_(input) { - } - - bool U8(uint8* out) { - if (data_.size() < 1) - return false; - *out = static_cast<uint8>(data_[0]); - data_.remove_prefix(1); - return true; - } - - bool U32(uint32* out) { - if (data_.size() < 4) - return false; - *out = static_cast<uint32>(data_[0]) << 24 | - static_cast<uint32>(data_[1]) << 16 | - static_cast<uint32>(data_[2]) << 8 | - static_cast<uint32>(data_[3]); - data_.remove_prefix(4); - return true; - } - - // Prefix sets |*out| to the first |n| bytes of the StringPiece and advances - // the StringPiece by |n|. - bool Prefix(size_t n, base::StringPiece *out) { - if (data_.size() < n) - return false; - *out = base::StringPiece(data_.data(), n); - data_.remove_prefix(n); - return true; - } - - // Remainder returns the remainer of the StringPiece and advances it to the - // end. - base::StringPiece Remainder() { - base::StringPiece ret = data_; - data_ = base::StringPiece(); - return ret; - } - - typedef base::StringPiece Position; - - Position tell() const { - return data_; - } - - void Seek(Position p) { - data_ = p; - } - - bool Skip(size_t n) { - if (data_.size() < n) - return false; - data_.remove_prefix(n); - return true; - } - - bool empty() const { - return data_.empty(); - } - - size_t size() const { - return data_.size(); - } - - private: - base::StringPiece data_; -}; - -// SaltedIteratedS2K implements the salted and iterated string-to-key -// convertion. See RFC 4880, section 3.7.1.3. -void SaltedIteratedS2K(unsigned cipher_key_length, - HASH_HashType hash_function, - base::StringPiece passphrase, - base::StringPiece salt, - unsigned count, - uint8 *out_key) { - const std::string combined = salt.as_string() + passphrase.as_string(); - const size_t combined_len = combined.size(); - - unsigned done = 0; - uint8 zero[1] = {0}; - - HASHContext* hash_context = HASH_Create(hash_function); - - for (unsigned i = 0; done < cipher_key_length; i++) { - HASH_Begin(hash_context); - - for (unsigned j = 0; j < i; j++) - HASH_Update(hash_context, zero, sizeof(zero)); - - unsigned written = 0; - while (written < count) { - if (written + combined_len > count) { - unsigned todo = count - written; - HASH_Update(hash_context, - reinterpret_cast<const uint8*>(combined.data()), - todo); - written = count; - } else { - HASH_Update(hash_context, - reinterpret_cast<const uint8*>(combined.data()), - combined_len); - written += combined_len; - } - } - - unsigned num_hash_bytes; - uint8 digest[HASH_LENGTH_MAX]; - HASH_End(hash_context, digest, &num_hash_bytes, sizeof(digest)); - - unsigned todo = cipher_key_length - done; - if (todo > num_hash_bytes) - todo = num_hash_bytes; - memcpy(out_key + done, digest, todo); - done += todo; - } - - HASH_Destroy(hash_context); -} - -// CreateAESContext sets up |out_key| to be an AES context, with the given key, -// in ECB mode and with no IV. -bool CreateAESContext(const uint8* key, unsigned key_len, - ScopedPK11Context* out_decryption_context) { - ScopedPK11Slot slot(PK11_GetBestSlot(CKM_AES_ECB, NULL)); - if (!slot.get()) - return false; - SECItem key_item; - key_item.type = siBuffer; - key_item.data = const_cast<uint8*>(key); - key_item.len = key_len; - ScopedPK11SymKey pk11_key(PK11_ImportSymKey( - slot.get(), CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, - NULL)); - if (!pk11_key.get()) - return false; - ScopedSECItem iv_param(PK11_ParamFromIV(CKM_AES_ECB, NULL)); - out_decryption_context->reset( - PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, pk11_key.get(), - iv_param.get())); - return out_decryption_context->get() != NULL; -} - - -// These constants are the tag numbers for the various packet types that we -// use. -static const unsigned kSymmetricKeyEncryptedTag = 3; -static const unsigned kSymmetricallyEncryptedTag = 18; -static const unsigned kCompressedTag = 8; -static const unsigned kLiteralDataTag = 11; - -class Decrypter { - public: - ~Decrypter() { - for (std::vector<void*>::iterator - i = arena_.begin(); i != arena_.end(); i++) { - free(*i); - } - arena_.clear(); - } - - OpenPGPSymmetricEncrytion::Result Decrypt(base::StringPiece in, - base::StringPiece passphrase, - base::StringPiece *out_contents) { - Reader reader(in); - unsigned tag; - base::StringPiece contents; - ScopedPK11Context decryption_context; - - if (!ParsePacket(&reader, &tag, &contents)) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - if (tag != kSymmetricKeyEncryptedTag) - return OpenPGPSymmetricEncrytion::NOT_SYMMETRICALLY_ENCRYPTED; - Reader inner(contents); - OpenPGPSymmetricEncrytion::Result result = - ParseSymmetricKeyEncrypted(&inner, passphrase, &decryption_context); - if (result != OpenPGPSymmetricEncrytion::OK) - return result; - - if (!ParsePacket(&reader, &tag, &contents)) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - if (tag != kSymmetricallyEncryptedTag) - return OpenPGPSymmetricEncrytion::NOT_SYMMETRICALLY_ENCRYPTED; - if (!reader.empty()) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - inner = Reader(contents); - if (!ParseSymmetricallyEncrypted(&inner, &decryption_context, &contents)) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - - reader = Reader(contents); - if (!ParsePacket(&reader, &tag, &contents)) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - if (tag == kCompressedTag) - return OpenPGPSymmetricEncrytion::COMPRESSED; - if (tag != kLiteralDataTag) - return OpenPGPSymmetricEncrytion::NOT_SYMMETRICALLY_ENCRYPTED; - inner = Reader(contents); - if (!ParseLiteralData(&inner, out_contents)) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - - return OpenPGPSymmetricEncrytion::OK; - } - - private: - // ParsePacket parses an OpenPGP packet from reader. See RFC 4880, section - // 4.2.2. - bool ParsePacket(Reader *reader, - unsigned *out_tag, - base::StringPiece *out_contents) { - uint8 header; - if (!reader->U8(&header)) - return false; - if ((header & 0x80) == 0) { - // Tag byte must have MSB set. - return false; - } - - if ((header & 0x40) == 0) { - // Old format packet. - *out_tag = (header & 0x3f) >> 2; - - uint8 length_type = header & 3; - if (length_type == 3) { - *out_contents = reader->Remainder(); - return true; - } - - const unsigned length_bytes = 1 << length_type; - size_t length = 0; - for (unsigned i = 0; i < length_bytes; i++) { - uint8 length_byte; - if (!reader->U8(&length_byte)) - return false; - length <<= 8; - length |= length_byte; - } - - return reader->Prefix(length, out_contents); - } - - // New format packet. - *out_tag = header & 0x3f; - size_t length; - bool is_partial; - if (!ParseLength(reader, &length, &is_partial)) - return false; - if (is_partial) - return ParseStreamContents(reader, length, out_contents); - return reader->Prefix(length, out_contents); - } - - // ParseStreamContents parses all the chunks of a partial length stream from - // reader. See http://tools.ietf.org/html/rfc4880#section-4.2.2.4 - bool ParseStreamContents(Reader *reader, - size_t length, - base::StringPiece *out_contents) { - const Reader::Position beginning_of_stream = reader->tell(); - const size_t first_chunk_length = length; - - // First we parse the stream to find its length. - if (!reader->Skip(length)) - return false; - - for (;;) { - size_t chunk_length; - bool is_partial; - - if (!ParseLength(reader, &chunk_length, &is_partial)) - return false; - if (length + chunk_length < length) - return false; - length += chunk_length; - if (!reader->Skip(chunk_length)) - return false; - if (!is_partial) - break; - } - - // Now we have the length of the whole stream in |length|. - char* buf = reinterpret_cast<char*>(malloc(length)); - arena_.push_back(buf); - size_t j = 0; - reader->Seek(beginning_of_stream); - - base::StringPiece first_chunk; - if (!reader->Prefix(first_chunk_length, &first_chunk)) - return false; - memcpy(buf + j, first_chunk.data(), first_chunk_length); - j += first_chunk_length; - - // Now we parse the stream again, this time copying into |buf| - for (;;) { - size_t chunk_length; - bool is_partial; - - if (!ParseLength(reader, &chunk_length, &is_partial)) - return false; - base::StringPiece chunk; - if (!reader->Prefix(chunk_length, &chunk)) - return false; - memcpy(buf + j, chunk.data(), chunk_length); - j += chunk_length; - if (!is_partial) - break; - } - - *out_contents = base::StringPiece(buf, length); - return true; - } - - // ParseLength parses an OpenPGP length from reader. See RFC 4880, section - // 4.2.2. - bool ParseLength(Reader *reader, size_t *out_length, bool *out_is_prefix) { - uint8 length_spec; - if (!reader->U8(&length_spec)) - return false; - - *out_is_prefix = false; - if (length_spec < 192) { - *out_length = length_spec; - return true; - } else if (length_spec < 224) { - uint8 next_byte; - if (!reader->U8(&next_byte)) - return false; - - *out_length = (length_spec - 192) << 8; - *out_length += next_byte; - return true; - } else if (length_spec < 255) { - *out_length = 1u << (length_spec & 0x1f); - *out_is_prefix = true; - return true; - } else { - uint32 length32; - if (!reader->U32(&length32)) - return false; - *out_length = length32; - return true; - } - } - - // ParseSymmetricKeyEncrypted parses a passphrase protected session key. See - // RFC 4880, section 5.3. - OpenPGPSymmetricEncrytion::Result ParseSymmetricKeyEncrypted( - Reader *reader, - base::StringPiece passphrase, - ScopedPK11Context *decryption_context) { - uint8 version, cipher, s2k_type, hash_func_id; - if (!reader->U8(&version) || version != 4) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - - if (!reader->U8(&cipher) || - !reader->U8(&s2k_type) || - !reader->U8(&hash_func_id)) { - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - } - - uint8 cipher_key_length = OpenPGPCipherIdToKeyLength(cipher); - if (cipher_key_length == 0) - return OpenPGPSymmetricEncrytion::UNKNOWN_CIPHER; - - HASH_HashType hash_function; - switch (hash_func_id) { - case 2: // SHA-1 - hash_function = HASH_AlgSHA1; - break; - case 8: // SHA-256 - hash_function = HASH_AlgSHA256; - break; - default: - return OpenPGPSymmetricEncrytion::UNKNOWN_HASH; - } - - // This chunk of code parses the S2K specifier. See RFC 4880, section 3.7.1. - base::StringPiece salt; - uint8 key[32]; - uint8 count_spec; - switch (s2k_type) { - case 1: - if (!reader->Prefix(8, &salt)) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - // Fall through. - case 0: - SaltedIteratedS2K(cipher_key_length, hash_function, passphrase, salt, - passphrase.size() + salt.size(), key); - break; - case 3: - if (!reader->Prefix(8, &salt) || - !reader->U8(&count_spec)) { - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - } - SaltedIteratedS2K( - cipher_key_length, hash_function, passphrase, salt, - static_cast<unsigned>( - 16 + (count_spec&15)) << ((count_spec >> 4) + 6), key); - break; - default: - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - } - - if (!CreateAESContext(key, cipher_key_length, decryption_context)) - return OpenPGPSymmetricEncrytion::INTERNAL_ERROR; - - if (reader->empty()) { - // The resulting key is used directly. - return OpenPGPSymmetricEncrytion::OK; - } - - // The S2K derived key encrypts another key that follows: - base::StringPiece encrypted_key = reader->Remainder(); - if (encrypted_key.size() < 1) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - - uint8* plaintext_key = reinterpret_cast<uint8*>( - malloc(encrypted_key.size())); - arena_.push_back(plaintext_key); - - CFBDecrypt(encrypted_key, decryption_context, plaintext_key); - - cipher_key_length = OpenPGPCipherIdToKeyLength(plaintext_key[0]); - if (cipher_key_length == 0) - return OpenPGPSymmetricEncrytion::UNKNOWN_CIPHER; - if (encrypted_key.size() != 1u + cipher_key_length) - return OpenPGPSymmetricEncrytion::PARSE_ERROR; - if (!CreateAESContext(plaintext_key + 1, cipher_key_length, - decryption_context)) { - return OpenPGPSymmetricEncrytion::INTERNAL_ERROR; - } - return OpenPGPSymmetricEncrytion::OK; - } - - // CFBDecrypt decrypts the cipher-feedback encrypted data in |in| to |out| - // using |decryption_context| and assumes an IV of all zeros. - void CFBDecrypt(base::StringPiece in, ScopedPK11Context* decryption_context, - uint8* out) { - // We need this for PK11_CipherOp to write to, but we never check it as we - // work in ECB mode, one block at a time. - int out_len; - - uint8 mask[AES_BLOCK_SIZE]; - memset(mask, 0, sizeof(mask)); - - unsigned used = AES_BLOCK_SIZE; - - for (size_t i = 0; i < in.size(); i++) { - if (used == AES_BLOCK_SIZE) { - PK11_CipherOp(decryption_context->get(), mask, &out_len, sizeof(mask), - mask, AES_BLOCK_SIZE); - used = 0; - } - - uint8 t = in[i]; - out[i] = t ^ mask[used]; - mask[used] = t; - used++; - } - } - - // OpenPGPCipherIdToKeyLength converts an OpenPGP cipher id (see RFC 4880, - // section 9.2) to the key length of that cipher. It returns 0 on error. - unsigned OpenPGPCipherIdToKeyLength(uint8 cipher) { - switch (cipher) { - case 7: // AES-128 - return 16; - case 8: // AES-192 - return 24; - case 9: // AES-256 - return 32; - default: - return 0; - } - } - - // ParseSymmetricallyEncrypted parses a Symmetrically Encrypted packet. See - // RFC 4880, sections 5.7 and 5.13. - bool ParseSymmetricallyEncrypted(Reader *reader, - ScopedPK11Context *decryption_context, - base::StringPiece *out_plaintext) { - // We need this for PK11_CipherOp to write to, but we never check it as we - // work in ECB mode, one block at a time. - int out_len; - - uint8 version; - if (!reader->U8(&version) || version != 1) - return false; - - base::StringPiece prefix_sp; - if (!reader->Prefix(AES_BLOCK_SIZE + 2, &prefix_sp)) - return false; - uint8 prefix[AES_BLOCK_SIZE + 2]; - memcpy(prefix, prefix_sp.data(), sizeof(prefix)); - - uint8 prefix_copy[AES_BLOCK_SIZE + 2]; - uint8 fre[AES_BLOCK_SIZE]; - - memset(prefix_copy, 0, AES_BLOCK_SIZE); - PK11_CipherOp(decryption_context->get(), fre, &out_len, sizeof(fre), - prefix_copy, AES_BLOCK_SIZE); - for (unsigned i = 0; i < AES_BLOCK_SIZE; i++) - prefix_copy[i] = fre[i] ^ prefix[i]; - PK11_CipherOp(decryption_context->get(), fre, &out_len, sizeof(fre), prefix, - AES_BLOCK_SIZE); - prefix_copy[AES_BLOCK_SIZE] = prefix[AES_BLOCK_SIZE] ^ fre[0]; - prefix_copy[AES_BLOCK_SIZE + 1] = prefix[AES_BLOCK_SIZE + 1] ^ fre[1]; - - if (prefix_copy[AES_BLOCK_SIZE - 2] != prefix_copy[AES_BLOCK_SIZE] || - prefix_copy[AES_BLOCK_SIZE - 1] != prefix_copy[AES_BLOCK_SIZE + 1]) { - return false; - } - - fre[0] = prefix[AES_BLOCK_SIZE]; - fre[1] = prefix[AES_BLOCK_SIZE + 1]; - - unsigned out_used = 2; - - const size_t plaintext_size = reader->size(); - if (plaintext_size < SHA1_LENGTH + 2) { - // Too small to contain an MDC trailer. - return false; - } - - uint8* plaintext = reinterpret_cast<uint8*>(malloc(plaintext_size)); - arena_.push_back(plaintext); - - for (size_t i = 0; i < plaintext_size; i++) { - uint8 b; - if (!reader->U8(&b)) - return false; - if (out_used == AES_BLOCK_SIZE) { - PK11_CipherOp(decryption_context->get(), fre, &out_len, sizeof(fre), - fre, AES_BLOCK_SIZE); - out_used = 0; - } - - plaintext[i] = b ^ fre[out_used]; - fre[out_used++] = b; - } - - // The plaintext should be followed by a Modification Detection Code - // packet. This packet is specified such that the header is always - // serialized as exactly these two bytes: - if (plaintext[plaintext_size - SHA1_LENGTH - 2] != 0xd3 || - plaintext[plaintext_size - SHA1_LENGTH - 1] != 0x14) { - return false; - } - - HASHContext* hash_context = HASH_Create(HASH_AlgSHA1); - HASH_Begin(hash_context); - HASH_Update(hash_context, prefix_copy, sizeof(prefix_copy)); - HASH_Update(hash_context, plaintext, plaintext_size - SHA1_LENGTH); - uint8 digest[SHA1_LENGTH]; - unsigned num_hash_bytes; - HASH_End(hash_context, digest, &num_hash_bytes, sizeof(digest)); - HASH_Destroy(hash_context); - - if (memcmp(digest, &plaintext[plaintext_size - SHA1_LENGTH], - SHA1_LENGTH) != 0) { - return false; - } - - *out_plaintext = base::StringPiece(reinterpret_cast<char*>(plaintext), - plaintext_size - SHA1_LENGTH); - return true; - } - - // ParseLiteralData parses a Literal Data packet. See RFC 4880, section 5.9. - bool ParseLiteralData(Reader *reader, base::StringPiece *out_data) { - uint8 is_binary, filename_len; - if (!reader->U8(&is_binary) || - !reader->U8(&filename_len) || - !reader->Skip(filename_len) || - !reader->Skip(sizeof(uint32) /* mtime */)) { - return false; - } - - *out_data = reader->Remainder(); - return true; - } - - // arena_ contains malloced pointers that are used as temporary space during - // the decryption. - std::vector<void*> arena_; -}; - -class Encrypter { - public: - // ByteString is used throughout in order to avoid signedness issues with a - // std::string. - typedef std::basic_string<uint8> ByteString; - - static ByteString Encrypt(base::StringPiece plaintext, - base::StringPiece passphrase) { - ByteString key; - ByteString ske = SerializeSymmetricKeyEncrypted(passphrase, &key); - - ByteString literal_data = SerializeLiteralData(plaintext); - ByteString se = SerializeSymmetricallyEncrypted(literal_data, key); - return ske + se; - } - - private: - // MakePacket returns an OpenPGP packet tagged as type |tag|. It always uses - // new-format headers. See RFC 4880, section 4.2. - static ByteString MakePacket(unsigned tag, const ByteString& contents) { - ByteString header; - header.push_back(0x80 | 0x40 | tag); - - if (contents.size() < 192) { - header.push_back(contents.size()); - } else if (contents.size() < 8384) { - size_t length = contents.size(); - length -= 192; - header.push_back(192 + (length >> 8)); - header.push_back(length & 0xff); - } else { - size_t length = contents.size(); - header.push_back(255); - header.push_back(length >> 24); - header.push_back(length >> 16); - header.push_back(length >> 8); - header.push_back(length); - } - - return header + contents; - } - - // SerializeLiteralData returns a Literal Data packet containing |contents| - // as binary data with no filename nor mtime specified. See RFC 4880, section - // 5.9. - static ByteString SerializeLiteralData(base::StringPiece contents) { - ByteString literal_data; - literal_data.push_back(0x74); // text mode - literal_data.push_back(0x00); // no filename - literal_data.push_back(0x00); // zero mtime - literal_data.push_back(0x00); - literal_data.push_back(0x00); - literal_data.push_back(0x00); - literal_data += ByteString(reinterpret_cast<const uint8*>(contents.data()), - contents.size()); - return MakePacket(kLiteralDataTag, literal_data); - } - - // SerializeSymmetricKeyEncrypted generates a random AES-128 key from - // |passphrase|, sets |out_key| to it and returns a Symmetric Key Encrypted - // packet. See RFC 4880, section 5.3. - static ByteString SerializeSymmetricKeyEncrypted(base::StringPiece passphrase, - ByteString *out_key) { - ByteString ske; - ske.push_back(4); // version 4 - ske.push_back(7); // AES-128 - ske.push_back(3); // iterated and salted S2K - ske.push_back(2); // SHA-1 - - uint64 salt64 = base::RandUint64(); - ByteString salt(sizeof(salt64), 0); - - // It's a random value, so endianness doesn't matter. - ske += ByteString(reinterpret_cast<uint8*>(&salt64), sizeof(salt64)); - ske.push_back(96); // iteration count of 65536 - - uint8 key[16]; - SaltedIteratedS2K( - sizeof(key), HASH_AlgSHA1, passphrase, - base::StringPiece(reinterpret_cast<char*>(&salt64), sizeof(salt64)), - 65536, key); - *out_key = ByteString(key, sizeof(key)); - return MakePacket(kSymmetricKeyEncryptedTag, ske); - } - - // SerializeSymmetricallyEncrypted encrypts |plaintext| with |key| and - // returns a Symmetrically Encrypted packet containing the ciphertext. See - // RFC 4880, section 5.7. - static ByteString SerializeSymmetricallyEncrypted(ByteString plaintext, - const ByteString& key) { - // We need this for PK11_CipherOp to write to, but we never check it as we - // work in ECB mode, one block at a time. - int out_len; - - ByteString packet; - packet.push_back(1); // version 1 - static const unsigned kBlockSize = 16; // AES block size - - uint8 prefix[kBlockSize + 2], fre[kBlockSize], iv[kBlockSize]; - base::RandBytes(iv, kBlockSize); - memset(fre, 0, sizeof(fre)); - - ScopedPK11Context aes_context; - CHECK(CreateAESContext(key.data(), key.size(), &aes_context)); - - PK11_CipherOp(aes_context.get(), fre, &out_len, sizeof(fre), fre, - AES_BLOCK_SIZE); - for (unsigned i = 0; i < 16; i++) - prefix[i] = iv[i] ^ fre[i]; - PK11_CipherOp(aes_context.get(), fre, &out_len, sizeof(fre), prefix, - AES_BLOCK_SIZE); - prefix[kBlockSize] = iv[kBlockSize - 2] ^ fre[0]; - prefix[kBlockSize + 1] = iv[kBlockSize - 1] ^ fre[1]; - - packet += ByteString(prefix, sizeof(prefix)); - - ByteString plaintext_copy = plaintext; - plaintext_copy.push_back(0xd3); // MDC packet - plaintext_copy.push_back(20); // packet length (20 bytes) - - HASHContext* hash_context = HASH_Create(HASH_AlgSHA1); - HASH_Begin(hash_context); - HASH_Update(hash_context, iv, sizeof(iv)); - HASH_Update(hash_context, iv + kBlockSize - 2, 2); - HASH_Update(hash_context, plaintext_copy.data(), plaintext_copy.size()); - uint8 digest[SHA1_LENGTH]; - unsigned num_hash_bytes; - HASH_End(hash_context, digest, &num_hash_bytes, sizeof(digest)); - HASH_Destroy(hash_context); - - plaintext_copy += ByteString(digest, sizeof(digest)); - - fre[0] = prefix[kBlockSize]; - fre[1] = prefix[kBlockSize+1]; - unsigned out_used = 2; - - for (size_t i = 0; i < plaintext_copy.size(); i++) { - if (out_used == kBlockSize) { - PK11_CipherOp(aes_context.get(), fre, &out_len, sizeof(fre), fre, - AES_BLOCK_SIZE); - out_used = 0; - } - - uint8 c = plaintext_copy[i] ^ fre[out_used]; - fre[out_used++] = c; - packet.push_back(c); - } - - return MakePacket(kSymmetricallyEncryptedTag, packet); - } -}; - -} // anonymous namespace - -// static -OpenPGPSymmetricEncrytion::Result OpenPGPSymmetricEncrytion::Decrypt( - base::StringPiece encrypted, - base::StringPiece passphrase, - std::string *out) { - Decrypter decrypter; - - base::StringPiece result; - Result reader = decrypter.Decrypt(encrypted, passphrase, &result); - if (reader == OK) - *out = result.as_string(); - return reader; -} - -// static -std::string OpenPGPSymmetricEncrytion::Encrypt( - base::StringPiece plaintext, - base::StringPiece passphrase) { - Encrypter::ByteString b = - Encrypter::Encrypt(plaintext, passphrase); - return std::string(reinterpret_cast<const char*>(b.data()), b.size()); -} - -} // namespace crypto |