123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- <?php
- namespace Aws\Crypto\Polyfill;
- class Gmac
- {
- use NeedsTrait;
- const BLOCK_SIZE = 16;
-
- protected $buf;
-
- protected $bufLength = 0;
-
- protected $h;
-
- protected $hf;
-
- protected $key;
-
- protected $x;
-
- public function __construct(Key $aesKey, $nonce, $keySize = 256)
- {
- $this->buf = new ByteArray(16);
- $this->h = new ByteArray(
- \openssl_encrypt(
- \str_repeat("\0", 16),
- "aes-{$keySize}-ecb",
- $aesKey->get(),
- OPENSSL_RAW_DATA | OPENSSL_NO_PADDING
- )
- );
- $this->key = $aesKey;
- $this->x = new ByteArray(16);
- $this->hf = new ByteArray(
- \openssl_encrypt(
- $nonce,
- "aes-{$keySize}-ecb",
- $aesKey->get(),
- OPENSSL_RAW_DATA | OPENSSL_NO_PADDING
- )
- );
- }
-
- public function update(ByteArray $blocks)
- {
- if (($blocks->count() + $this->bufLength) < self::BLOCK_SIZE) {
-
- $this->buf->set($blocks, $this->bufLength);
- $this->bufLength += $blocks->count();
- return $this;
- }
-
- if ($this->bufLength > 0) {
-
- $tmp = new ByteArray(self::BLOCK_SIZE);
- $tmp->set($this->buf->slice(0, $this->bufLength));
- $remainingBlockLength = self::BLOCK_SIZE - $this->bufLength;
- $tmp->set($blocks->slice(0, $remainingBlockLength), $this->bufLength);
- $blocks = $blocks->slice($remainingBlockLength);
- $this->bufLength = 0;
- $this->x = $this->blockMultiply($this->x->exclusiveOr($tmp), $this->h);
- }
-
- $numBlocks = $blocks->count() >> 4;
- for ($i = 0; $i < $numBlocks; ++$i) {
- $tmp = $blocks->slice($i << 4, self::BLOCK_SIZE);
- $this->x = $this->blockMultiply($this->x->exclusiveOr($tmp), $this->h);
- }
- $last = $numBlocks << 4;
-
- for ($i = 0; $i < 16; ++$i) {
- $this->buf[$i] = 0;
- }
-
- if ($last < $blocks->count()) {
- $tmp = $blocks->slice($last);
- $this->buf->set($tmp);
- $this->bufLength += ($blocks->count() - $last);
- }
- return $this;
- }
-
- public function finish($aadLength, $ciphertextLength)
- {
- $lengthBlock = new ByteArray(16);
- $state = $this->flush();
-
- $lengthBlock->set(ByteArray::enc32be($aadLength >> 29), 0);
- $lengthBlock->set(ByteArray::enc32be($aadLength << 3), 4);
- $lengthBlock->set(ByteArray::enc32be($ciphertextLength >> 29), 8);
- $lengthBlock->set(ByteArray::enc32be($ciphertextLength << 3), 12);
- $state->update($lengthBlock);
- $output = $state->x->exclusiveOr($state->hf);
-
- $state->buf->zeroize();
- $state->x->zeroize();
- $state->h->zeroize();
- $state->hf->zeroize();
- return $output;
- }
-
- protected function bit(ByteArray $x, $i)
- {
- $byte = $i >> 3;
- return ($x[$byte] >> ((7 - $i) & 7)) & 1;
- }
-
- protected function blockMultiply(ByteArray $x, ByteArray $y)
- {
- static $fieldPolynomial = null;
- if (!$fieldPolynomial) {
- $fieldPolynomial = new ByteArray([
- 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- ]);
- }
- self::needs($x->count() === 16, 'Argument 1 must be a ByteArray of exactly 16 bytes');
- self::needs($y->count() === 16, 'Argument 2 must be a ByteArray of exactly 16 bytes');
- $v = clone $y;
- $z = new ByteArray(16);
- for ($i = 0; $i < 128; ++$i) {
-
- $b = $this->bit($x, $i);
- $z = ByteArray::select(
- $b,
- $z->exclusiveOr($v),
- $z
- );
-
- $b = $v[15] & 1;
- $v = $v->rshift();
- $v = ByteArray::select(
- $b,
- $v->exclusiveOr($fieldPolynomial),
- $v
- );
- }
- return $z;
- }
-
- public function flush()
- {
- if ($this->bufLength !== 0) {
- $this->x = $this->blockMultiply(
- $this->x->exclusiveOr($this->buf),
- $this->h
- );
- $this->bufLength = 0;
- }
- return $this;
- }
- }
|