/** * Returns a copy of the string's internal value, which should be zeroed. * Optionally, it can return an empty string. * * @return string */ public function __toString() : string { if (!$this->disallowInline) { return Util::safeStrcpy($this->internalStringValue); } return ''; }
/** * Get the actual key material * * @return string */ public function getRawKeyMaterial() { return Util::safeStrcpy($this->keyMaterial); }
/** * Recalculate and verify the HMAC of the input file * * @param ReadOnlyFile $input The file we are verifying * @param resource|string $mac (hash context) * @param Config $config Version-specific settings * @return array Hashes of various chunks * @throws CannotPerformOperation * @throws InvalidMessage */ private static final function streamVerify(ReadOnlyFile $input, $mac, Config $config) : array { $start = $input->getPos(); // Grab the stored MAC: $cipher_end = $input->getSize() - $config->MAC_SIZE; $input->reset($cipher_end); $stored_mac = $input->readBytes($config->MAC_SIZE); $input->reset($start); $chunkMACs = []; $break = false; while (!$break && $input->getPos() < $cipher_end) { /** * Would a full BUFFER read put it past the end of the * ciphertext? If so, only return a portion of the file. */ if ($input->getPos() + $config->BUFFER >= $cipher_end) { $break = true; $read = $input->readBytes($cipher_end - $input->getPos()); } else { $read = $input->readBytes($config->BUFFER); } /** * We're updating our HMAC and nothing else */ \Sodium\crypto_generichash_update($mac, $read); // Copy the hash state then store the MAC of this chunk $chunkMAC = Util::safeStrcpy($mac); $chunkMACs[] = \Sodium\crypto_generichash_final($chunkMAC, $config->MAC_SIZE); } /** * We should now have enough data to generate an identical MAC */ $finalHMAC = \Sodium\crypto_generichash_final($mac, $config->MAC_SIZE); /** * Use hash_equals() to be timing-invariant */ if (!\hash_equals($finalHMAC, $stored_mac)) { throw new InvalidMessage('Invalid message authentication code'); } $input->reset($start); return $chunkMACs; }