diff options
author | davidben <davidben@chromium.org> | 2016-01-21 16:10:26 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-22 00:12:34 +0000 |
commit | 626e8fad1311d7f5c51b809268f7c01d54bb8e9b (patch) | |
tree | 8ab9edd0f3822cf32f3d3bda55677b98ccebb158 | |
parent | 494a77059cf199de5a6e11912fce2a155c868a26 (diff) | |
download | chromium_src-626e8fad1311d7f5c51b809268f7c01d54bb8e9b.zip chromium_src-626e8fad1311d7f5c51b809268f7c01d54bb8e9b.tar.gz chromium_src-626e8fad1311d7f5c51b809268f7c01d54bb8e9b.tar.bz2 |
Remove crypto::GaloisHash.
This is no longer needed now that the Chimera has shipped. (iOS uses
third_party/nss's AES-GCM implementation.)
BUG=519504
Review URL: https://codereview.chromium.org/1616743003
Cr-Commit-Position: refs/heads/master@{#370842}
-rw-r--r-- | crypto/BUILD.gn | 3 | ||||
-rw-r--r-- | crypto/crypto.gyp | 1 | ||||
-rw-r--r-- | crypto/crypto.gypi | 2 | ||||
-rw-r--r-- | crypto/ghash.cc | 262 | ||||
-rw-r--r-- | crypto/ghash.h | 88 | ||||
-rw-r--r-- | crypto/ghash_unittest.cc | 149 |
6 files changed, 0 insertions, 505 deletions
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn index 8d24e60..34deeae 100644 --- a/crypto/BUILD.gn +++ b/crypto/BUILD.gn @@ -34,8 +34,6 @@ component("crypto") { "encryptor.h", "encryptor_nss.cc", "encryptor_openssl.cc", - "ghash.cc", - "ghash.h", "hkdf.cc", "hkdf.h", "hmac.cc", @@ -244,7 +242,6 @@ test("crypto_unittests") { "ec_private_key_unittest.cc", "ec_signature_creator_unittest.cc", "encryptor_unittest.cc", - "ghash_unittest.cc", "hkdf_unittest.cc", "hmac_unittest.cc", "nss_key_util_unittest.cc", diff --git a/crypto/crypto.gyp b/crypto/crypto.gyp index 2590c4f..f8b7967 100644 --- a/crypto/crypto.gyp +++ b/crypto/crypto.gyp @@ -169,7 +169,6 @@ 'ec_private_key_unittest.cc', 'ec_signature_creator_unittest.cc', 'encryptor_unittest.cc', - 'ghash_unittest.cc', 'hkdf_unittest.cc', 'hmac_unittest.cc', 'nss_key_util_unittest.cc', diff --git a/crypto/crypto.gypi b/crypto/crypto.gypi index e5cc4f44..2b9ce67 100644 --- a/crypto/crypto.gypi +++ b/crypto/crypto.gypi @@ -41,8 +41,6 @@ 'curve25519.h', 'curve25519_nss.cc', 'curve25519_openssl.cc', - 'ghash.cc', - 'ghash.h', 'ec_private_key.h', 'ec_private_key_nss.cc', 'ec_private_key_openssl.cc', diff --git a/crypto/ghash.cc b/crypto/ghash.cc deleted file mode 100644 index fcd513e..0000000 --- a/crypto/ghash.cc +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright (c) 2012 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/ghash.h" - -#include <stddef.h> -#include <stdint.h> - -#include <algorithm> - -#include "base/logging.h" -#include "base/sys_byteorder.h" - -namespace crypto { - -// GaloisHash is a polynomial authenticator that works in GF(2^128). -// -// Elements of the field are represented in `little-endian' order (which -// matches the description in the paper[1]), thus the most significant bit is -// the right-most bit. (This is backwards from the way that everybody else does -// it.) -// -// We store field elements in a pair of such `little-endian' uint64s. So the -// value one is represented by {low = 2**63, high = 0} and doubling a value -// involves a *right* shift. -// -// [1] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf - -namespace { - -// Get64 reads a 64-bit, big-endian number from |bytes|. -uint64_t Get64(const uint8_t bytes[8]) { - uint64_t t; - memcpy(&t, bytes, sizeof(t)); - return base::NetToHost64(t); -} - -// Put64 writes |x| to |bytes| as a 64-bit, big-endian number. -void Put64(uint8_t bytes[8], uint64_t x) { - x = base::HostToNet64(x); - memcpy(bytes, &x, sizeof(x)); -} - -// Reverse reverses the order of the bits of 4-bit number in |i|. -int Reverse(int i) { - i = ((i << 2) & 0xc) | ((i >> 2) & 0x3); - i = ((i << 1) & 0xa) | ((i >> 1) & 0x5); - return i; -} - -} // namespace - -GaloisHash::GaloisHash(const uint8_t key[16]) { - Reset(); - - // We precompute 16 multiples of |key|. However, when we do lookups into this - // table we'll be using bits from a field element and therefore the bits will - // be in the reverse order. So normally one would expect, say, 4*key to be in - // index 4 of the table but due to this bit ordering it will actually be in - // index 0010 (base 2) = 2. - FieldElement x = {Get64(key), Get64(key+8)}; - product_table_[0].low = 0; - product_table_[0].hi = 0; - product_table_[Reverse(1)] = x; - - for (int i = 0; i < 16; i += 2) { - product_table_[Reverse(i)] = Double(product_table_[Reverse(i/2)]); - product_table_[Reverse(i+1)] = Add(product_table_[Reverse(i)], x); - } -} - -void GaloisHash::Reset() { - state_ = kHashingAdditionalData; - additional_bytes_ = 0; - ciphertext_bytes_ = 0; - buf_used_ = 0; - y_.low = 0; - y_.hi = 0; -} - -void GaloisHash::UpdateAdditional(const uint8_t* data, size_t length) { - DCHECK_EQ(state_, kHashingAdditionalData); - additional_bytes_ += length; - Update(data, length); -} - -void GaloisHash::UpdateCiphertext(const uint8_t* data, size_t length) { - if (state_ == kHashingAdditionalData) { - // If there's any remaining additional data it's zero padded to the next - // full block. - if (buf_used_ > 0) { - memset(&buf_[buf_used_], 0, sizeof(buf_)-buf_used_); - UpdateBlocks(buf_, 1); - buf_used_ = 0; - } - state_ = kHashingCiphertext; - } - - DCHECK_EQ(state_, kHashingCiphertext); - ciphertext_bytes_ += length; - Update(data, length); -} - -void GaloisHash::Finish(void* output, size_t len) { - DCHECK(state_ != kComplete); - - if (buf_used_ > 0) { - // If there's any remaining data (additional data or ciphertext), it's zero - // padded to the next full block. - memset(&buf_[buf_used_], 0, sizeof(buf_)-buf_used_); - UpdateBlocks(buf_, 1); - buf_used_ = 0; - } - - state_ = kComplete; - - // The lengths of the additional data and ciphertext are included as the last - // block. The lengths are the number of bits. - y_.low ^= additional_bytes_*8; - y_.hi ^= ciphertext_bytes_*8; - MulAfterPrecomputation(product_table_, &y_); - - uint8_t *result, result_tmp[16]; - if (len >= 16) { - result = reinterpret_cast<uint8_t*>(output); - } else { - result = result_tmp; - } - - Put64(result, y_.low); - Put64(result + 8, y_.hi); - - if (len < 16) - memcpy(output, result_tmp, len); -} - -// static -GaloisHash::FieldElement GaloisHash::Add( - const FieldElement& x, - const FieldElement& y) { - // Addition in a characteristic 2 field is just XOR. - FieldElement z = {x.low^y.low, x.hi^y.hi}; - return z; -} - -// static -GaloisHash::FieldElement GaloisHash::Double(const FieldElement& x) { - const bool msb_set = x.hi & 1; - - FieldElement xx; - // Because of the bit-ordering, doubling is actually a right shift. - xx.hi = x.hi >> 1; - xx.hi |= x.low << 63; - xx.low = x.low >> 1; - - // If the most-significant bit was set before shifting then it, conceptually, - // becomes a term of x^128. This is greater than the irreducible polynomial - // so the result has to be reduced. The irreducible polynomial is - // 1+x+x^2+x^7+x^128. We can subtract that to eliminate the term at x^128 - // which also means subtracting the other four terms. In characteristic 2 - // fields, subtraction == addition == XOR. - if (msb_set) - xx.low ^= 0xe100000000000000ULL; - - return xx; -} - -void GaloisHash::MulAfterPrecomputation(const FieldElement* table, - FieldElement* x) { - FieldElement z = {0, 0}; - - // In order to efficiently multiply, we use the precomputed table of i*key, - // for i in 0..15, to handle four bits at a time. We could obviously use - // larger tables for greater speedups but the next convenient table size is - // 4K, which is a little large. - // - // In other fields one would use bit positions spread out across the field in - // order to reduce the number of doublings required. However, in - // characteristic 2 fields, repeated doublings are exceptionally cheap and - // it's not worth spending more precomputation time to eliminate them. - for (unsigned i = 0; i < 2; i++) { - uint64_t word; - if (i == 0) { - word = x->hi; - } else { - word = x->low; - } - - for (unsigned j = 0; j < 64; j += 4) { - Mul16(&z); - // the values in |table| are ordered for little-endian bit positions. See - // the comment in the constructor. - const FieldElement& t = table[word & 0xf]; - z.low ^= t.low; - z.hi ^= t.hi; - word >>= 4; - } - } - - *x = z; -} - -// kReductionTable allows for rapid multiplications by 16. A multiplication by -// 16 is a right shift by four bits, which results in four bits at 2**128. -// These terms have to be eliminated by dividing by the irreducible polynomial. -// In GHASH, the polynomial is such that all the terms occur in the -// least-significant 8 bits, save for the term at x^128. Therefore we can -// precompute the value to be added to the field element for each of the 16 bit -// patterns at 2**128 and the values fit within 12 bits. -static const uint16_t kReductionTable[16] = { - 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, - 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0, -}; - -// static -void GaloisHash::Mul16(FieldElement* x) { - const unsigned msw = x->hi & 0xf; - x->hi >>= 4; - x->hi |= x->low << 60; - x->low >>= 4; - x->low ^= static_cast<uint64_t>(kReductionTable[msw]) << 48; -} - -void GaloisHash::UpdateBlocks(const uint8_t* bytes, size_t num_blocks) { - for (size_t i = 0; i < num_blocks; i++) { - y_.low ^= Get64(bytes); - bytes += 8; - y_.hi ^= Get64(bytes); - bytes += 8; - MulAfterPrecomputation(product_table_, &y_); - } -} - -void GaloisHash::Update(const uint8_t* data, size_t length) { - if (buf_used_ > 0) { - const size_t n = std::min(length, sizeof(buf_) - buf_used_); - memcpy(&buf_[buf_used_], data, n); - buf_used_ += n; - length -= n; - data += n; - - if (buf_used_ == sizeof(buf_)) { - UpdateBlocks(buf_, 1); - buf_used_ = 0; - } - } - - if (length >= 16) { - const size_t n = length / 16; - UpdateBlocks(data, n); - length -= n*16; - data += n*16; - } - - if (length > 0) { - memcpy(buf_, data, length); - buf_used_ = length; - } -} - -} // namespace crypto diff --git a/crypto/ghash.h b/crypto/ghash.h deleted file mode 100644 index b123dfe..0000000 --- a/crypto/ghash.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2012 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 <stddef.h> -#include <stdint.h> - -#include "crypto/crypto_export.h" - -namespace crypto { - -// GaloisHash implements the polynomial authenticator part of GCM as specified -// in http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf -// Specifically it implements the GHASH function, defined in section 2.3 of -// that document. -// -// In SP-800-38D, GHASH is defined differently and takes only a single data -// argument. But it is always called with an argument of a certain form: -// GHASH_H (A || 0^v || C || 0^u || [len(A)]_64 || [len(C)]_64) -// This mirrors how the gcm-revised-spec.pdf version of GHASH handles its two -// data arguments. The two GHASH functions therefore differ only in whether the -// data is formatted inside or outside of the function. -// -// WARNING: do not use this as a generic authenticator. Polynomial -// authenticators must be used in the correct manner and any use outside of GCM -// requires careful consideration. -// -// WARNING: this code is not constant time. However, in all likelihood, nor is -// the implementation of AES that is used. -class CRYPTO_EXPORT GaloisHash { - public: - explicit GaloisHash(const uint8_t key[16]); - - // Reset prepares to digest a fresh message with the same key. This is more - // efficient than creating a fresh object. - void Reset(); - - // UpdateAdditional hashes in `additional' data. This is data that is not - // encrypted, but is covered by the authenticator. All additional data must - // be written before any ciphertext is written. - void UpdateAdditional(const uint8_t* data, size_t length); - - // UpdateCiphertext hashes in ciphertext to be authenticated. - void UpdateCiphertext(const uint8_t* data, size_t length); - - // Finish completes the hash computation and writes at most |len| bytes of - // the result to |output|. - void Finish(void* output, size_t len); - - private: - enum State { - kHashingAdditionalData, - kHashingCiphertext, - kComplete, - }; - - struct FieldElement { - uint64_t low, hi; - }; - - // Add returns |x|+|y|. - static FieldElement Add(const FieldElement& x, const FieldElement& y); - // Double returns 2*|x|. - static FieldElement Double(const FieldElement& x); - // MulAfterPrecomputation sets |x| = |x|*h where h is |table[1]| and - // table[i] = i*h for i=0..15. - static void MulAfterPrecomputation(const FieldElement* table, - FieldElement* x); - // Mul16 sets |x| = 16*|x|. - static void Mul16(FieldElement* x); - - // UpdateBlocks processes |num_blocks| 16-bytes blocks from |bytes|. - void UpdateBlocks(const uint8_t* bytes, size_t num_blocks); - // Update processes |length| bytes from |bytes| and calls UpdateBlocks on as - // much data as possible. It uses |buf_| to buffer any remaining data and - // always consumes all of |bytes|. - void Update(const uint8_t* bytes, size_t length); - - FieldElement y_; - State state_; - size_t additional_bytes_; - size_t ciphertext_bytes_; - uint8_t buf_[16]; - size_t buf_used_; - FieldElement product_table_[16]; -}; - -} // namespace crypto diff --git a/crypto/ghash_unittest.cc b/crypto/ghash_unittest.cc deleted file mode 100644 index 01f9cf4..0000000 --- a/crypto/ghash_unittest.cc +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2012 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/ghash.h" - -#include <stddef.h> -#include <stdint.h> - -#include <algorithm> - -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace crypto { - -namespace { - -// Test vectors are taken from Appendix B of -// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf - -static const uint8_t kKey1[16] = { - 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, - 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e, -}; - -static const uint8_t kCiphertext2[] = { - 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, - 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78, -}; - -static const uint8_t kKey3[16] = { - 0xb8, 0x3b, 0x53, 0x37, 0x08, 0xbf, 0x53, 0x5d, - 0x0a, 0xa6, 0xe5, 0x29, 0x80, 0xd5, 0x3b, 0x78, -}; - -static const uint8_t kCiphertext3[] = { - 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, - 0xb7, 0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, - 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, - 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, - 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, - 0x97, 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85, -}; - -static const uint8_t kAdditional4[] = { - 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, - 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, -}; - -struct TestCase { - const uint8_t* key; - const uint8_t* additional; - unsigned additional_length; - const uint8_t* ciphertext; - unsigned ciphertext_length; - const uint8_t expected[16]; -}; - -static const TestCase kTestCases[] = { - { - kKey1, - NULL, - 0, - NULL, - 0, - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - }, - { - kKey1, - NULL, - 0, - kCiphertext2, - sizeof(kCiphertext2), - { - 0xf3, 0x8c, 0xbb, 0x1a, 0xd6, 0x92, 0x23, 0xdc, - 0xc3, 0x45, 0x7a, 0xe5, 0xb6, 0xb0, 0xf8, 0x85, - }, - }, - { - kKey3, - NULL, - 0, - kCiphertext3, - sizeof(kCiphertext3), - { - 0x7f, 0x1b, 0x32, 0xb8, 0x1b, 0x82, 0x0d, 0x02, - 0x61, 0x4f, 0x88, 0x95, 0xac, 0x1d, 0x4e, 0xac, - }, - }, - { - kKey3, - kAdditional4, - sizeof(kAdditional4), - kCiphertext3, - sizeof(kCiphertext3) - 4, - { - 0x69, 0x8e, 0x57, 0xf7, 0x0e, 0x6e, 0xcc, 0x7f, - 0xd9, 0x46, 0x3b, 0x72, 0x60, 0xa9, 0xae, 0x5f, - }, - }, -}; - -TEST(GaloisHash, TestCases) { - uint8_t out[16]; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - const TestCase& test = kTestCases[i]; - - GaloisHash hash(test.key); - if (test.additional_length) - hash.UpdateAdditional(test.additional, test.additional_length); - if (test.ciphertext_length) - hash.UpdateCiphertext(test.ciphertext, test.ciphertext_length); - hash.Finish(out, sizeof(out)); - EXPECT_TRUE(0 == memcmp(out, test.expected, 16)); - } -} - -TEST(GaloisHash, VaryLengths) { - uint8_t out[16]; - - for (size_t chunk_size = 1; chunk_size < 16; chunk_size++) { - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - const TestCase& test = kTestCases[i]; - - GaloisHash hash(test.key); - for (size_t i = 0; i < test.additional_length;) { - size_t n = std::min(test.additional_length - i, chunk_size); - hash.UpdateAdditional(test.additional + i, n); - i += n; - } - for (size_t i = 0; i < test.ciphertext_length;) { - size_t n = std::min(test.ciphertext_length - i, chunk_size); - hash.UpdateCiphertext(test.ciphertext + i, n); - i += n; - } - hash.Finish(out, sizeof(out)); - EXPECT_TRUE(0 == memcmp(out, test.expected, 16)); - } - } -} - -} // namespace - -} // namespace crypto |