1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
//! **GHASH**: universal hash over GF(2^128) used by AES-GCM for message
//! authentication (i.e. GMAC).
//!
//! ## Implementation Notes
//!
//! The implementation of GHASH found in this crate internally uses the
//! [`polyval`] crate, which provides a similar universal hash function used by
//! AES-GCM-SIV (RFC 8452).
//!
//! By implementing GHASH in terms of POLYVAL, the two universal hash functions
//! can share a common core, meaning any optimization work (e.g. CPU-specific
//! SIMD implementations) which happens upstream in the `polyval` crate
//! benefits GHASH as well.
//!
//! From RFC 8452 Appendix A:
//! <https://tools.ietf.org/html/rfc8452#appendix-A>
//!
//! > GHASH and POLYVAL both operate in GF(2^128), although with different
//! > irreducible polynomials: POLYVAL works modulo x^128 + x^127 + x^126 +
//! > x^121 + 1 and GHASH works modulo x^128 + x^7 + x^2 + x + 1. Note
//! > that these irreducible polynomials are the "reverse" of each other.
//!
//! [`polyval`]: https://github.com/RustCrypto/universal-hashes/tree/master/polyval
#![no_std]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]
#![warn(missing_docs, rust_2018_idioms)]
pub use polyval::universal_hash;
use polyval::Polyval;
use universal_hash::{
consts::U16,
crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser},
KeyInit, UhfBackend, UhfClosure, UniversalHash,
};
#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
/// GHASH keys (16-bytes)
pub type Key = universal_hash::Key<GHash>;
/// GHASH blocks (16-bytes)
pub type Block = universal_hash::Block<GHash>;
/// GHASH tags (16-bytes)
pub type Tag = universal_hash::Block<GHash>;
/// **GHASH**: universal hash over GF(2^128) used by AES-GCM.
///
/// GHASH is a universal hash function used for message authentication in
/// the AES-GCM authenticated encryption cipher.
#[derive(Clone)]
pub struct GHash(Polyval);
impl KeySizeUser for GHash {
type KeySize = U16;
}
impl GHash {
/// Initialize GHASH with the given `H` field element and initial block
#[inline]
pub fn new_with_init_block(h: &Key, init_block: u128) -> Self {
let mut h = *h;
h.reverse();
#[allow(unused_mut)]
let mut h_polyval = polyval::mulx(&h);
#[cfg(feature = "zeroize")]
h.zeroize();
#[allow(clippy::let_and_return)]
let result = GHash(Polyval::new_with_init_block(&h_polyval, init_block));
#[cfg(feature = "zeroize")]
h_polyval.zeroize();
result
}
}
impl KeyInit for GHash {
/// Initialize GHASH with the given `H` field element
#[inline]
fn new(h: &Key) -> Self {
Self::new_with_init_block(h, 0)
}
}
struct GHashBackend<'b, B: UhfBackend>(&'b mut B);
impl<'b, B: UhfBackend> BlockSizeUser for GHashBackend<'b, B> {
type BlockSize = B::BlockSize;
}
impl<'b, B: UhfBackend> ParBlocksSizeUser for GHashBackend<'b, B> {
type ParBlocksSize = B::ParBlocksSize;
}
impl<'b, B: UhfBackend> UhfBackend for GHashBackend<'b, B> {
fn proc_block(&mut self, x: &universal_hash::Block<B>) {
let mut x = x.clone();
x.reverse();
self.0.proc_block(&x);
}
}
impl BlockSizeUser for GHash {
type BlockSize = U16;
}
impl UniversalHash for GHash {
fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
struct GHashClosure<C: UhfClosure>(C);
impl<C: UhfClosure> BlockSizeUser for GHashClosure<C> {
type BlockSize = C::BlockSize;
}
impl<C: UhfClosure> UhfClosure for GHashClosure<C> {
fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B) {
self.0.call(&mut GHashBackend(backend));
}
}
self.0.update_with_backend(GHashClosure(f));
}
/// Get GHASH output
#[inline]
fn finalize(self) -> Tag {
let mut output = self.0.finalize();
output.reverse();
output
}
}
opaque_debug::implement!(GHash);